pgvector 와 RAG
대규모 언어 모델 응답을 외부 지식과 결합하려는 흐름이 RAG (Retrieval-Augmented Generation) 라는 이름으로 자리 잡았습니다. 그 안에서 벡터 유사도 검색이 핵심 부품이고, PostgreSQL 의 pgvector extension 이 가장 가까운 자리에 있습니다.
목차
대규모 언어 모델 응답을 외부 지식과 결합하려는 흐름이 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 가 들어왔고 이후 버전에서 성능·메모리가 개선됐습니다.
필터가 있는 ANN 검색은 별도로 검증해야 합니다. HNSW 후보를 먼저 찾고 WHERE를 나중에 적용하므로, 소수 사용자·컬렉션의 행은 전역 후보에서 밀려 실제 데이터가 있어도 K개보다 적게 반환될 수 있습니다. pgvector 0.8 이상에서는 질의 트랜잭션에 SET LOCAL hnsw.iterative_scan = strict_order를 적용해 충분한 필터 결과가 나올 때까지 점진적으로 탐색할 수 있습니다. 전역 ef_search를 과도하게 높이는 방식보다 요청별 비용 경계가 분명하지만, hnsw.max_scan_tuples와 필터별 Recall@K·지연을 함께 측정해야 합니다.
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 를 참고합니다.
이 글에서 만나는 용어
data 카테고리의 다른 글
카테고리 전체 보기 →관련 글
완료된 파일만 RAG 검색 근거로 공개하기
파일 업로드와 검색 가능은 같은 상태가 아닙니다. 파싱·임베딩·저장이 끝나고 processed = TRUE가 된 검색 사본만 사용자 답변의 근거가 될 수 있습니다.
RAG 와 검색 — 청킹·임베딩·재정렬·하이브리드
RAG (Retrieval-Augmented Generation) 는 LLM 의 한정된 학습 시점·메모리 한계를 외부 지식으로 보완하려는 방식입니다. 검색·생성을 분리하면 모델을 다시 학습시키지 않고도 새로운 자료를 다룰 수 있습니다.
Google NotebookLM — 자료 기반 Gemini 노트북 (RAG 형 도구)
NotebookLM 은 Google 의 자료 우선 (source-grounded) AI 노트북. 사용자가 업로드한 PDF·구글 문서·웹사이트·YouTube·오디오에서만 답변을 합성하므로 hallucination 이 일반 챗봇보다 적음. 04-gemini-api 가 raw API, 08-google-ai-studio 가…