RAG나 임베딩 검색을 만들면 결국 이런 작업을 해야 한다.
질문을 벡터로 바꾼다.
문서 조각들도 벡터로 저장해둔다.
질문 벡터와 가장 가까운 문서 벡터를 찾는다.
예를 들어 사용자가 이렇게 묻는다고 하자: "택배가 아직 안 왔을 때 보상 받을 수 있나요?"
이 질문은 문서의 정확한 문장과 단어가 다를 수 있는데,
문서에는 "배송 지연으로 인한 보상 기준은 다음과 같다." 라고 쓰여있을 수 있다.
즉, 키워드는 완전히 같지 않고, 그러나 의미는 가깝다.
임베딩 검색은 이런 의미 유사성을 이용하는데, 문제는 문서가 많아졌을 때다.
문서 조각 1,000개 → 하나씩 비교 가능
문서 조각 100만 개 → 하나씩 비교하면 느림
문서 조각 1억 개 → 단순 비교는 거의 불가능
그래서 필요한 것이 Vector DB와 ANN 검색이다.
Vector DB
무엇을 저장하는가
Vector DB는 벡터만 저장하는 게 아니라 보통 다음을 함께 저장한다.
- 벡터
- 원본 텍스트 또는 chunk ID
- 메타데이터(metadata)
- 검색 인덱스
e.g:
{
"id": "chunk_1024",
"text": "배송 지연 보상 기준은 ...",
"vector": [0.12, -0.03, 0.88, ...],
"metadata": {
"document_id": "policy_2026_배송",
"category": "배송",
"version": "2026-06",
"created_at": "2026-06-15"
}
}
Vector DB의 역할은 단순하다.
질문 벡터가 들어오면 저장된 벡터 중 가까운 것들을 빠르게 찾아준다.
일반 DB와 무엇이 다른가
일반적인 관계형 DB는 정확한 조건 검색에 강하다.
SELECT * FROM documents
WHERE category = '배송'
AND version = '2026-06';
이런 검색은 정확히 일치하는 값을 찾는다.
반면 Vector DB는 "이 질문 벡터와 의미적으로 가까운 문서 벡터는 무엇인가?" 라는 질문을 처리한다.
즉, 검색 기준이 다르다.
| 구분 | 일반 DB | Vector DB |
| 검색 기준 | 정확한 값, 조건 | 벡터 간 거리/유사도 |
| 예시 | category = '배송' | 질문과 의미가 가까운 문서 |
| 강점 | 필터링, 정합성, 트랜잭션 | 의미 검색, 유사도 검색 |
| RAG에서 역할 | 메타데이터 필터 | 관련 chunk 검색 |
현실의 RAG 시스템에서는 둘을 같이 쓴다.
메타데이터로 후보를 제한하고, 벡터 유사도로 가까운 문서를 찾는다.
Exact Search
Exact Search는 저장된 모든 벡터와 질문 벡터를 전부 비교한다.
질문 벡터 q
문서 벡터 d1, d2, d3, ..., d1,000,000
q와 d1 비교
q와 d2 비교
q와 d3 비교
...
q와 d1,000,000 비교
가장 정확하지만 데이터가 많으면 느려진다.
거리 계산 한 번은 빠를 수 있지만, 수백만, 수천만 개와 비교하면 비용이 커지는 것.
지도를 생각하면, 서울에서 내 위치와 가장 가까운 카페를 찾고 싶다고 하자.
그 때 Exact Search는 서울의 모든 카페와 내 위치 사이의 거리를 하나씩 계산한다.
카페가 100개면 괜찮지만, 카페가 100만 개면 비효율적이다.
ANN(Approximate Nearest Neighbor) 검색
정확한 최근접 이웃을 반드시 찾는 대신, 매우 가까운 후보를 훨씬 빠르게 찾는 방식.
- Exact Search:
- 가장 가까운 벡터를 정확히 찾음
- 느릴 수 있음
- ANN Search:
- 거의 가까운 벡터를 빠르게 찾음
- 약간의 오차 가능
여기서 approximate는 대충 아무거나 찾는다는 뜻이 아니라
검색 속도를 크게 높이기 위해 정확도 일부와 속도를 맞바꾸는 것이다.
RAG에서는 보통 top-k 후보를 여러 개 가져온다.
그래서 1등이 완벽히 정확하지 않아도, 관련 문서가 top-k 안에 들어오면 실용적으로 충분한 경우가 많다.
반대로 top-k 안에 필요한 근거가 아예 들어오지 않으면, 뒤의 LLM은 좋은 답을 만들기 어렵다.
그래서 ANN 검색은 “가장 가까운 1개를 반드시 맞히는 기술”이라기보다 “충분히 빠르게 좋은 후보 묶음을 가져오는 기술”로 이해하는 편이 좋다.
Recall과 Latency Trade-off
더 정확하게 찾을수록 느려진다.
더 빠르게 찾을수록 일부 관련 문서를 놓칠 수 있다.
검색 품질은 보통 recall로 본다.
Exact Search로 찾은 진짜 top-k 결과 중 ANN이 몇 개를 찾아냈는가?
e.g:
Exact top-10 결과: A, B, C, D, E, F, G, H, I, J
ANN top-10 결과: A, B, C, D, F, H, K, L, M, N
겹친 결과: A, B, C, D, F, H = 6개
Recall@10 = 6 / 10 = 0.6
실무에서는 다음을 함께 본다.
- Recall@k
- Latency p50 / p95 / p99
- Index size
- Memory usage
- Update cost

Exact Search와 ANN Search의 차이
거리/유사도 선택
벡터 검색에서는 가까움을 어떻게 정의할지 정해야 한다.
| 기준 | 의미 | 주의 |
| Cosine Similarity | 방향이 비슷한가 | 텍스트 임베딩에서 자주 사용 |
| Dot Product | 내적이 큰가 | 벡터 크기 영향 가능 |
| Euclidean Distance | 좌표상 거리가 가까운가 | 크기와 위치 모두 반영 |
중요한 점은, 임베딩 모델이 어떤 유사도 기준으로 학습되었는지 확인해야 한다는 것.
모델이 cosine 기준으로 쓰라고 만들어졌는데, DB에서 euclidean 기준으로 검색하면 의도와 다를 수 있다.
또 벡터를 L2 normalize하면 cosine similarity와 dot product가 사실상 같은 순위를 줄 수 있다.
HNSW(Hierarchical Navigable Small World graph)
- 가까운 벡터끼리 길을 연결해둔다.
- 검색할 때 모든 점을 보지 않고,
- 길을 따라가며 점점 더 가까운 점으로 이동한다.
지도 비유로 보면:
모든 건물을 하나씩 확인하지 않고, 큰 도로 → 작은 도로 → 골목길 순서로 목적지 근처까지 이동한다.
계층 구조
HNSW는 여러 층의 그래프를 만든다.
- 상위 layer: 점이 적고 멀리 이동하기 좋음
- 하위 layer: 점이 많고 세밀하게 탐색하기 좋음
- 검색 흐름:
- 상위 layer에서 대략 가까운 위치로 이동
- 아래 layer로 내려감
- 더 가까운 점으로 이동
- 가장 아래 layer에서 후보를 정밀하게 찾음
주요 파라미터
- M
- 각 노드가 연결할 이웃 수
- M이 클수록 그래프 연결이 풍부해짐
- 검색 recall이 좋아질 수 있음
- 메모리 사용량 증가
- 인덱스 생성 비용 증가
- efConstruction
- 인덱스를 만들 때 얼마나 넓게 후보를 볼지 결정
- 크면 인덱스 품질 증가 but 생성 시간 증가
- efSearch
- 검색할 때 얼마나 넓게 탐색할지 결정한다.
- 크면 recall 증가 but latency 증가
efSearch를 높이면 더 정확하지만 느려진다.
efSearch를 낮추면 더 빠르지만 놓치는 문서가 늘 수 있다.
운영에서는 보통 목표 latency를 먼저 정한 뒤 efSearch를 올려가며 recall이 충분한 지점을 찾는다.
검색 품질만 보고 efSearch를 크게 잡으면 사용자가 느끼는 응답 속도가 나빠질 수 있다.

IVF(Inverted File Index)
벡터 공간을 여러 구역으로 나눠두는 방식.
지도 비유:
전국의 모든 카페를 하나씩 비교하지 않는다.
먼저 서울/부산/대구 같은 큰 구역을 고른다.
그 구역 안에서 가까운 카페를 찾는다.
벡터 검색에서는 먼저 전체 벡터를 여러 cluster로 나눈다.
cluster 1
cluster 2
cluster 3
...
질문 벡터가 들어오면 가장 가까운 cluster 몇 개만 탐색한다.
IVF에서 중요한 위험은 질문과 가까운 벡터가 선택하지 않은 cluster에 숨어 있을 수 있다는 점이다.
그래서 nprobe를 너무 작게 잡으면 빠르지만 중요한 후보를 놓칠 수 있다.
nlist와 nprobe
- nlist
- 몇 개의 cluster로 나눌지 결정한다.
- nlist가 크다 → 구역이 많고 세밀함
- nlist가 작다 → 구역이 적고 큼
- nprobe
- 검색할 때 몇 개의 cluster를 볼지 결정한다.
- nprobe가 크다 → 더 많은 구역 탐색 → recall 증가, latency 증가
- nprobe가 작다 → 적은 구역 탐색 → 빠름, 놓칠 가능성 증가
PQ(Product Quantization)
벡터를 압축해서 저장하는 방식.
고차원 벡터를 그대로 저장하면 메모리를 많이 쓴다.
e.g:
1536차원 float 벡터
문서 chunk 1억 개
이런 규모에서는 저장 공간과 메모리가 큰 문제가 된다.
PQ는 벡터를 여러 조각으로 나누고, 각 조각을 대표 코드로 근사한다.
즉, 원본 벡터를 그대로 저장하지 않고, 압축된 코드로 저장하는 것.
쉽게 말해 정밀한 좌표를 그대로 들고 있는 대신, “이 조각은 대표 패턴 17번에 가깝다”처럼 짧은 코드로 바꿔 저장하는 것이다.
그래서 메모리는 줄지만 원본 벡터와 완전히 같지는 않다.
- 장점:
- 메모리 사용량 감소
- 검색 속도 개선 가능
- 단점:
- 근사 오차 발생
- 정확도 하락 가능
PQ는 대규모 검색에서 자주 쓰지만, 검색 품질과 메모리 사이의 절충 관계를 이해하고 써야 한다.
메타데이터 필터링(Metadata Filtering)
벡터 유사도만으로 검색하면 관련 없는 문서가 섞일 수 있다.
예를 들어 사용자가 다음과 같이 묻는다고 하자.
"2026년 해외배송 환불 규정 알려줘"
벡터 유사도만 보면 2024년 문서가 가까울 수도 있다.
그래서 메타데이터 필터를 같이 건다.
version = 2026
category = 해외배송
status = active
검색 흐름은 두 가지 방식이 있다.
- Pre-filter
- 메타데이터로 먼저 후보를 줄인 뒤 벡터 검색
- 빠르고 안전하다.
- 후보가 너무 줄어 관련 문서를 놓칠 수 있다.
- Post-filter:
- 벡터 검색 후 메타데이터 조건에 맞지 않는 결과 제거
- 검색 후보를 넓게 볼 수 있다.
- 필터 후 결과가 부족할 수 있다.
Hybrid Search
- 벡터 검색과 키워드 검색을 함께 쓰는 방식.
- 벡터 검색: 동의어와 의미 유사성을 잘 찾음
- 키워드 검색: 정확한 용어, 코드, 조항 번호, 상품명에 강함
예를 들어 "제12조 위약금 산정 기준"이라는 질문이 있다고 하자.
이 경우 제12조 같은 정확한 키워드는 매우 중요하다.
벡터 검색만 쓰는 경우, 숫자간의 의미는 벡터에게 결국 숫자이기 떄문에 다른 조항이 나올 수 있다.
이런 경우를 보완하기 위해, Hybrid Search는 둘의 점수를 결합한다.
최종 점수 = 벡터 점수 + 키워드 점수
단, 두 점수의 스케일이 다르므로 정규화가 필요하다.
Reranker
Vector DB는 보통 빠르게 top-k 후보를 가져오는 역할을 한다.
하지만 top-k 안에서 순서가 완벽하지 않을 수 있다.
Reranker는 후보 문서와 질문을 다시 함께 보고 순서를 재정렬한다.
검색 흐름:
- Vector DB에서 top-50 후보 검색
- Reranker가 질문-문서 쌍을 다시 평가
- top-5만 LLM 프롬프트에 전달
Vector DB 검색은 빠른 1차 후보 추출이다.
Reranker는 느리지만 더 정밀한 2차 판단이다.
RAG에서의 위치
RAG 파이프라인에서 Vector DB는 검색(retrieval) 단계에 있다.
문서 수집
→ chunking
→ embedding
→ Vector DB 저장
→ 사용자 질문 embedding
→ Vector DB 검색
→ reranking
→ LLM 답변 생성
LLM은 주어진 근거 안에서 답변하기 때문에, Vector DB 품질이 낮으면 좋은 답변을 만들기 어렵다.
관련 문서를 못 찾음
→ LLM에게 근거가 안 들어감
→ 답변이 틀리거나 모른다고 해야 함
운영에서 봐야 할 것
인덱스 재생성
문서가 바뀌면 embedding과 index도 바뀌어야 한다.
문서 수정
→ chunk 재생성
→ embedding 재계산
→ vector index update 또는 rebuild
버전 관리
임베딩 모델이 바뀌면 기존 벡터와 새 벡터를 섞어 쓰면 안 된다.
embedding_model = text-embedding-A
embedding_model = text-embedding-B
모델이 다르면 벡터 공간도 다를 수 있다.
버전별로 분리하거나 전체 재색인이 필요하다.
모니터링
검색 시스템에서는 다음을 모니터링한다.
- 검색 latency
- empty result 비율
- top-k 평균 score
- 사용자가 클릭한 문서
- LLM 답변 실패율
- 문서 버전 불일치
정리
- Vector DB는 질문 벡터와 가까운 문서 벡터를 빠르게 찾기 위한 저장소이자 검색 인프라.
- ANN은 모든 벡터를 정확히 비교하지 않고, 가까운 후보를 빠르게 찾기 위한 근사 검색 방식.
- 더 정확하게 찾을수록 느려지고,
- 더 빠르게 찾을수록 일부 관련 문서를 놓칠 수 있다.
GitHub 댓글