2 min read
벡터 검색 평가 지표 설계
Recall@K, MRR, NDCG를 서비스 맥락에 맞게 해석해 검색 품질을 관리하는 기준

도입
벡터 검색 품질은 임베딩 모델 선택만으로 결정되지 않는다. 실무에서는 인덱스 파라미터와 리랭킹, 평가셋 품질이 결과를 크게 좌우하지만 이 부분이 자주 생략된다. 이 글은 오프라인/온라인 지표를 연결해 검색 품질을 지속적으로 개선하는 방법을 다룬다.

문제 정의
검색 정확도가 낮은데도 원인을 특정하지 못하는 경우가 많다.
- 평가셋이 실제 사용자 질의를 반영하지 않아 점수와 체감 품질이 다르다.
- Recall만 추적하고 Precision을 보지 않아 노이즈 문서가 증가한다.
- 인덱스 파라미터 변경 실험이 기록되지 않아 회귀를 반복한다.
평가 설계는 단일 지표가 아니라 다층 지표가 필요하다. Recall@k, nDCG, 응답 지연, 비용을 함께 봐야 한다.
핵심 개념
| 관점 | 설계 기준 | 검증 포인트 |
|---|---|---|
| 오프라인 정확도 | Recall@k + nDCG | 테스트셋 기준 추세 |
| 온라인 품질 | 검색 후 클릭/완료율 | 실제 유저 체감 |
| 성능 | query latency + QPS | SLO 준수율 |
| 비용 | 토큰/임베딩 비용 | 요청당 원가 |
지표는 서로 충돌할 수 있다. 품질을 올리면 비용이 증가하고, 속도를 올리면 정확도가 떨어질 수 있으므로 목표 우선순위를 명확히 해야 한다.
코드 예시 1: Recall@k 계산
export function recallAtK(retrieved: string[], relevant: Set<string>, k: number) {
const topK = retrieved.slice(0, k);
const hit = topK.filter((id) => relevant.has(id)).length;
return hit / Math.max(relevant.size, 1);
}
export function ndcgAtK(gains: number[], k: number) {
const top = gains.slice(0, k);
const dcg = top.reduce((acc, gain, i) => acc + gain / Math.log2(i + 2), 0);
const ideal = [...gains].sort((a, b) => b - a).slice(0, k);
const idcg = ideal.reduce((acc, gain, i) => acc + gain / Math.log2(i + 2), 0);
return idcg === 0 ? 0 : dcg / idcg;
}
코드 예시 2: 실험 레지스트리 기록
INSERT INTO vector_search_experiments (
experiment_id,
embedding_model,
index_type,
top_k,
recall_at_10,
ndcg_at_10,
latency_p95_ms,
cost_per_1k_queries
) VALUES (
'exp_20260303_hnsw_m64',
'text-embedding-3-large',
'hnsw',
20,
0.84,
0.79,
145,
0.63
);
아키텍처 흐름
Mermaid diagram rendering...
트레이드오프
- top-k를 늘리면 recall은 오르지만 지연 시간과 비용이 증가한다.
- 리랭킹을 추가하면 품질이 좋아지지만 파이프라인 복잡도가 높아진다.
- 평가셋 유지 비용이 들지만 품질 회귀를 조기에 발견할 수 있다.
정리
벡터 검색 평가는 모델 비교가 아니라 시스템 최적화 문제다. 오프라인 정확도와 온라인 지표를 함께 추적하고 실험 이력을 관리하면 품질을 안정적으로 개선할 수 있다.
이미지 출처
- Cover: source link
- License: Public domain / Author: Fibonacci .
- Note: Wikimedia Commons 무료 라이선스 이미지를 다운로드 후 1600px 기준 JPG로 최적화했습니다.