pgvector 와 RAG
pgvector 와 RAG
대규모 언어 모델 응답을 외부 지식과 결합하려는 흐름이 RAG (Retrieval-Augmented Generation) 라는 이름으로 자리 잡았습니다. 그 안에서 벡터 유사도 검색이 핵심 부품이고, PostgreSQL 의 pgvector extension 이 가장 가까운 자리에 있습니다.
1. pgvector 에 대한 이야기
pgvector 는 Andrew Kane 이 2021 년에 공개한 PostgreSQL extension 입니다. vector 타입과 거리 연산자, 그리고 벡터 인덱스 (IVFFlat · HNSW) 를 더합니다.
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE chunks (
id BIGSERIAL PRIMARY KEY,
doc_id BIGINT NOT NULL,
content TEXT NOT NULL,
embedding vector(1536) NOT NULL
);
거리 연산자.
| 연산자 | 거리 |
|---|---|
<-> |
L2 (유클리드) |
<=> |
코사인 거리 |
<#> |
음수 내적 (inner product) — 작을수록 유사 |
ORDER BY embedding <=> $1 LIMIT 10 식으로 가장 가까운 K 개를 가져옵니다.
2. 벡터 유사도
텍스트·이미지를 고정 차원의 실수 벡터로 매핑하면, 의미가 가까운 항목이 벡터 공간에서도 가깝게 배치된다는 가정이 출발점입니다. 거리 측정 방식은 세 가지가 흔합니다.
- 코사인 유사도 — 방향만 봅니다. 길이 차이를 무시.
- L2 (유클리드) — 길이까지 봅니다.
- 내적 (inner product) — 정규화된 벡터끼리는 코사인과 사실상 같습니다.
OpenAI · Cohere 같은 임베딩 API 응답은 보통 정규화돼 있어 코사인이 자주 쓰입니다. 모델 문서가 권장 거리를 명시하는 경우가 많습니다.
3. IVFFlat
브루트포스 (Seq Scan + 거리 계산) 는 작은 데이터에서는 충분히 빠릅니다. 데이터가 커지면 ANN (Approximate Nearest Neighbor) 인덱스를 씁니다.
IVFFlat 은 벡터 공간을 K 개의 클러스터로 사전 분할 (lists) 하고, 검색 시 가장 가까운 일부 클러스터 (probes) 만 봅니다.
CREATE INDEX ON chunks USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
SET ivfflat.probes = 10;
SELECT id FROM chunks ORDER BY embedding <=> $1 LIMIT 10;
- 빌드 빠름 · 메모리 적음.
- 정확도와 속도가
lists·probes의 균형에서 결정됩니다. - 데이터가 많이 들어온 후 인덱스를 만들어야 클러스터링 품질이 좋습니다.
4. HNSW
Yu. A. Malkov · D. A. Yashunin 의 2018 년 논문에서 제안된 알고리즘입니다. 다층 그래프를 만들어 가까운 이웃을 빠르게 찾습니다.
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);
SET hnsw.ef_search = 40;
- 검색 정확도·속도가 일반적으로 우수합니다.
- 인덱스 크기·빌드 시간이 IVFFlat 보다 큽니다.
- 점진적 추가에 강합니다.
pgvector 0.5 이후 HNSW 가 들어왔고 이후 버전에서 성능·메모리가 개선됐습니다.
5. 임베딩 모델
| 모델 | 제공 | 차원 | 메모 |
|---|---|---|---|
OpenAI text-embedding-3-small |
OpenAI API | 1536 (또는 축소 가능) | 다국어 · 비교적 저렴 |
OpenAI text-embedding-3-large |
OpenAI API | 3072 | 고품질 |
Cohere embed-multilingual-v3.0 |
Cohere API | 1024 | 다국어 강함 |
| BGE (BAAI) | 오픈 가중치 | 384/768/1024 | 자체 호스팅 가능 |
| nomic-embed-text | Nomic | 768 | 오픈 가중치 |
| Sentence-Transformers | 오픈 | 다양 | 작은 모델 다수 |
차원이 클수록 정확도가 일반적으로 오르지만 저장·검색 비용도 비례합니다. Matryoshka 임베딩처럼 차원을 사후에 줄일 수 있는 모델도 있습니다.
6. 별도 벡터 DB 와의 비교
| 시스템 | 출자·시기 | 메모 |
|---|---|---|
| Pinecone | 2019, 매니지드 SaaS | 운영 단순 · 비용은 사용량 기반 |
| Qdrant | 2021, Rust | 자가 호스팅 가능 · 필터링 강함 |
| Weaviate | 2019, Go | 모듈식 · 하이브리드 검색 |
| Milvus | 2019, 오픈 | 대규모 · GPU 가속 |
| Chroma | 2022, Python | 로컬 개발 친화 |
| Vespa | 2017 오픈소스화 (Yahoo) | 검색·랭킹·벡터 결합 |
| Elasticsearch · OpenSearch | 2010 / 2021 | 풀텍스트 + 벡터 (kNN) |
별도 벡터 DB 의 강점.
- 매우 큰 규모 (수십억 이상) · 분산 샤딩.
- 사전 필터링·메타데이터 결합이 빠른 경우가 많음.
- 벡터 전용 운영 도구 (통계·튜닝).
pgvector 의 강점.
- 한 DB 안에서 벡터 + 관계형 데이터 + 트랜잭션을 결합.
- 운영 표면이 한 곳 (백업·인증·모니터링이 PostgreSQL 하나).
- 작은~중간 규모에서 충분한 성능.
선택은 데이터 규모·운영 인력·정확도 요구의 균형입니다.
7. RAG 파이프라인
원본 → 청킹 → 임베딩 → 저장 → 검색 → reranking → LLM 컨텍스트 → 응답
청킹 — 문서를 작은 조각으로 나눕니다. 너무 크면 검색의 조준이 흐려지고 너무 작으면 의미가 흩어집니다.
- 토큰·문자 수 고정 (예: 512 토큰, 50 토큰 오버랩).
- 마크다운 헤딩·문장 경계 기반.
- 의미 기반 (다른 모델로 경계 추정).
임베딩·저장 — 청크별 임베딩을 모델 API 또는 로컬 모델로 계산해 vector 컬럼에 저장합니다. 메타데이터 (문서 ID · 출처 URL · 작성일 · 태그) 도 함께 컬럼으로 둡니다.
검색 — 쿼리를 같은 모델로 임베딩하고 <=> 로 가장 가까운 K 개를 가져옵니다. 메타데이터 필터 (작성일·문서 종류) 와 결합하는 자리에서 RDBMS 의 WHERE 가 강점이 됩니다.
8. Reranking 과 하이브리드 검색
벡터 검색은 빠르지만 의미 정확도에 한계가 있습니다. 1 차로 3050 개를 가져온 뒤 cross-encoder · LLM 으로 재정렬해 상위 510 개를 LLM 컨텍스트로 보냅니다. Cohere Rerank · BGE Reranker · cross-encoder/ms-marco 같은 모델이 거론됩니다.
하이브리드 검색은 키워드 검색 (BM25 · tsvector) + 벡터 검색을 결합하는 방식입니다. 약어·고유명사가 많은 문서에서 키워드가 보완 역할을 합니다. RRF (Reciprocal Rank Fusion) 같은 단순한 결합 함수가 자주 쓰입니다.
9. 자주 걸리는 자리
모델 변경 후 재임베딩 의무 — 임베딩 모델을 바꾸면 벡터 공간이 달라집니다. 옛 벡터와 새 쿼리는 서로 다른 공간이라 비교 무의미. 마이그레이션 계획을 처음에 가집니다.
차원 불일치 — vector(1536) 컬럼에 다른 차원을 넣으려 하면 에러입니다. 모델별 차원을 분리 컬럼·테이블로.
인덱스 빌드 시점 — 데이터가 적을 때 IVFFlat 을 만들면 클러스터링이 부족합니다. 일정 양 적재 후 인덱스 생성을 권장합니다.
거리 연산자와 인덱스 일치 — 인덱스를 vector_cosine_ops 로 만들었으면 <=> 만 인덱스를 씁니다. 다른 연산자는 Seq Scan 입니다.
청크 경계의 의미 끊김 — 문장 중간에서 잘리면 검색이 흐려집니다. 오버랩 또는 경계 정렬.
컨텍스트 윈도 초과 — 검색 결과를 모두 LLM 에 넣으면 토큰 한도를 넘습니다. reranking 과 요약을 결합합니다.
하고픈 말
벡터 검색은 구현보다 청킹·reranking·메타데이터 설계가 더 어렵습니다. 인덱스 종류·차원 선택은 한 번 결정하면 다시 바꾸기가 부담이라 처음에 신중히 결정합니다.
Next
- supabase
- fcm-push
pgvector GitHub · pgvector 인덱스 가이드 · HNSW 논문 · OpenAI Embeddings · Pinecone Learn — RAG · Cohere Rerank 를 참고합니다.