~/ai-dev.md
AI_DEV

벡터 검색만 붙이면 RAG가 될까: 검색 품질은 Recall과 Rerank로 따로 봐야 한다

10분 읽기·2026.06.11·출처 4·00
오늘의 질문

우리 RAG가 틀릴 때, 문제는 답변 모델일까 검색 파이프라인일까?

ai-dev.md
SURVIVE.exe

벡터 검색만 붙이면 RAG가 될까: 검색 품질은 Recall과 Rerank로 따로 봐야 한다

1. 왜 지금 봐야 하나

RAG를 처음 붙일 때 흔한 착각이 있다. “문서를 쪼개서 임베딩하고, vector DB에서 top-k를 가져오면 끝”이라는 생각이다. 그런데 실제 서비스에서는 사용자가 “환불 정책 알려줘”라고 묻지 않는다. “지난달 일본 플랜에서 법인카드 결제 취소하면 세금계산서는 어떻게 돼?”처럼 짧은 질문 안에 시간, 지역, 상품, 문서 종류, 예외 조건이 섞인다.

최근 공식 자료들의 방향도 단순 벡터 검색에서 한 단계 더 나아간다. Google은 Gemini Embedding 2 글에서 멀티모달 데이터를 하나의 embedding space로 다루고, index time과 query time에 task prefix를 적용하는 방식을 강조했다. OpenAI Retrieval 문서는 query rewrite, attribute filtering, ranking option, hybrid search weight를 제공한다. Anthropic은 chunk가 문맥을 잃는 문제를 Contextual Retrieval로 다루며, contextual embeddings와 BM25, reranking을 결합했을 때 retrieval failure가 더 줄었다고 설명한다. Databricks는 2026년 6월 글에서 query/filter generation과 reranking을 병렬화해 검색 시간을 3배 이상 줄이면서 품질을 유지하는 구조를 소개했다.

핵심은 하나다. RAG 품질은 “좋은 모델 하나”가 아니라 recall을 넓히는 단계와 precision을 높이는 단계를 분리해서 설계하고 측정하는 문제다.

2. 핵심 개념

RAG 파이프라인을 세 칸으로 나눠 보자.

첫째, 후보를 넓게 찾는 단계다. 사용자의 질문을 그대로 embedding해서 top-5만 가져오면 관련 문서를 놓칠 수 있다. 용어가 다르거나, 줄임말을 쓰거나, 날짜·지역·제품 조건이 메타데이터에 들어 있으면 semantic similarity만으로 부족하다. 이 단계의 목표는 “정답 후보가 어딘가에는 들어오게 만들기”다. 그래서 query rewrite, query expansion, attribute filter, hybrid search, 멀티쿼리 생성이 쓰인다.

둘째, 후보를 정확히 줄이는 단계다. recall을 넓히면 후보에는 잡음도 많아진다. 이제 필요한 것은 “가장 답에 도움이 되는 chunk를 앞에 세우는 능력”이다. 여기서 reranker, cross-encoder, LLM judge, score threshold, nDCG@k 같은 개념이 등장한다. 이 단계의 목표는 precision이다.

셋째, 선택된 근거로 답하게 하는 단계다. 여기서는 모델이 근거를 충실히 사용했는지, 없는 말을 만들지 않았는지, 출처를 제대로 인용했는지를 본다. RAG가 틀렸다고 바로 generation prompt만 고치면 안 된다. 검색이 틀렸는지, 정렬이 틀렸는지, 답변 생성이 틀렸는지 분해해야 한다.

정리하면 RAG는 “검색 + 생성”이 아니라 후보 생성 → 후보 정렬 → 근거 기반 생성 → 평가의 시스템이다.

3. 최신 이슈와 연결

Google Developers Blog의 Gemini Embedding 2 글은 embedding 입력 자체가 변하고 있음을 보여준다. 텍스트뿐 아니라 이미지, 비디오, 오디오, PDF를 같은 semantic space에 넣을 수 있고, RAG에서는 task: question answering, task: code retrieval 같은 prefix를 index time과 query time에 적용하라고 안내한다. 이것은 “임베딩 모델을 바꾸면 끝”이 아니라 “어떤 목적의 검색인지 embedding input contract를 명시하라”는 메시지에 가깝다.

OpenAI Retrieval 문서는 운영 기능에 더 가깝다. vector store 검색 결과에는 chunk, score, 원본 파일이 따라오고, rewrite_query=true로 검색에 유리한 질의 형태를 만들 수 있다. attribute filtering은 날짜, 지역, 파일명 같은 조건을 semantic search 전에 좁히는 장치다. ranking options에서는 score threshold와 hybrid search weight를 조정할 수 있다. 즉, OpenAI의 공식 문서도 “벡터 유사도 하나”가 아니라 query rewrite, filter, ranker, hybrid weighting을 별도 조정점으로 다룬다.

Anthropic의 Contextual Retrieval 글은 chunking의 부작용을 정면으로 다룬다. 문서를 쪼개면 chunk가 “이 숫자가 어느 회사의 어느 분기 실적인지” 같은 주변 문맥을 잃는다. Anthropic은 chunk마다 짧은 설명을 붙여 embedding과 BM25 index에 함께 넣는 방식을 제시했고, contextual embeddings, contextual BM25, reranking을 결합했을 때 top-20 retrieval failure가 크게 줄었다고 보고했다.

Databricks의 Instructed-Retriever-1 글은 latency까지 포함한다. 더 좋은 검색을 위해 agent가 순차적으로 생각하고 도구를 여러 번 부르면 느려진다. Databricks는 query/filter generation과 reranking을 병렬로 fan-out해 recall과 precision을 같이 높이되, 사용자 대기 시간을 줄이는 방향을 택했다. 실제 제품에서는 “정확하지만 30초 걸리는 RAG”도 실패다.

4. 개발자 관점 해석

개발자가 가져갈 판단 기준은 네 가지다.

첫째, embedding model 교체 전에 검색 실패 샘플을 모아야 한다. “답이 틀렸다”는 로그만으로는 부족하다. 질문, 기대 문서, 실제 retrieved chunks, chunk score, rerank score, 최종 답변을 한 줄에 남겨야 한다. 그래야 문제가 recall인지 precision인지 generation인지 보인다.

둘째, top-k는 품질 스위치가 아니라 비용·지연·잡음 스위치다. top-k를 늘리면 정답 후보가 들어올 가능성은 커지지만, 모델이 읽어야 할 잡음도 늘어난다. 반대로 top-k를 줄이면 빠르지만 필요한 근거를 놓친다. 그래서 top-k만 조정하지 말고 “넓게 가져온 뒤 rerank로 줄이는 구조”를 실험해야 한다.

셋째, hybrid search는 낡은 검색으로 돌아가는 것이 아니다. 오류 코드, API 이름, 고객 ID, 법 조항, 함수명처럼 exact match가 중요한 도메인에서는 BM25나 sparse search가 embedding보다 강할 때가 있다. semantic search와 lexical search를 rank fusion으로 합치는 방식은 현실적인 기본값이다.

넷째, RAG eval은 최종 답변 점수 하나로 끝나면 안 된다. 최소한 retrieval recall@k, MRR 또는 nDCG@k, answer groundedness를 분리해서 봐야 한다. 검색이 정답 문서를 못 가져왔는데 답변 모델을 탓하면 개선 방향이 틀어진다.

5. 내 프로젝트에 적용할 체크포인트

  • 검색 로그에 query, rewritten_query, filters, retrieved_chunk_ids, scores, reranked_order, answer, citations가 남는가?
  • “정답 문서가 top-k 안에 들어왔는가”를 평가할 golden set이 최소 20개라도 있는가?
  • 문서 chunk가 너무 작아서 회사명, 날짜, 제품명, 상위 제목을 잃고 있지 않은가?
  • exact keyword가 중요한 도메인인데 embedding-only로 운영하고 있지 않은가?
  • top-20 후보를 가져온 뒤 top-5로 rerank하는 실험을 해봤는가?
  • score threshold를 높였을 때 “모른다”고 답해야 할 질문과 “놓치면 안 되는 질문”이 어떻게 달라지는가?
  • 멀티모달 자료를 다룬다면 이미지나 PDF를 텍스트 추출만으로 처리해도 되는가, 아니면 멀티모달 embedding이 필요한가?
  • latency budget을 query rewrite, retrieval, reranking, generation으로 나눠 보고 있는가?

6. 오늘 10분 액션

오늘은 코드를 크게 바꾸지 말고, RAG 검색 품질을 눈으로 확인하는 작은 표를 만든다.

  1. 최근 사용자 질문 또는 내가 만든 대표 질문 10개를 고른다.
  2. 각 질문에 대해 “반드시 검색되어야 하는 문서 또는 chunk”를 하나씩 적는다.
  3. 현재 RAG에서 top-10 retrieved chunks를 저장한다.
  4. 각 질문마다 정답 chunk가 top-10 안에 있으면 1, 없으면 0을 표시한다.
  5. 정답 chunk가 들어왔는데 답이 틀린 케이스와, 정답 chunk 자체가 안 들어온 케이스를 분리한다.
  6. 안 들어온 케이스 2개만 골라 query rewrite, metadata filter, chunk context 추가 중 하나를 실험한다.

이 10분 액션의 목표는 멋진 eval dashboard가 아니다. “우리 문제는 검색인가, 정렬인가, 생성인가?”를 처음으로 분리해 보는 것이다.

7. 더 볼 자료

  • Google Developers Blog의 Gemini Embedding 2 글: task prefix, multimodal embedding, RAG 적용 사례를 확인하기 좋다.
  • OpenAI Retrieval 문서: vector store 검색에서 query rewrite, attribute filter, hybrid search weight를 어떤 조정점으로 제공하는지 볼 수 있다.
  • Anthropic Contextual Retrieval 글: chunk에 문맥을 붙이는 ingestion-time 개선과 BM25/rerank 결합 효과를 이해하기 좋다.
  • Databricks Instructed-Retriever-1 글: enterprise RAG에서 recall, precision, latency를 동시에 다루는 구조를 볼 수 있다.

중복 회피 메모

최근 ai_dev 글은 긴 컨텍스트 메모리 관리, 에이전트 권한 계약, prefill/decode 기반 LLM 서빙 지연을 다뤘다. 이번 글은 에이전트 상태나 서빙 병목이 아니라 RAG 검색 파이프라인 내부의 후보 생성, hybrid retrieval, reranking, retrieval eval 분리에 집중한다. 이전 RAG 관련 글이 “무엇을 기억하고 다시 가져올 것인가”에 가까웠다면, 이번 글은 “가져오는 단계가 제대로 작동하는지 어떻게 측정하고 고칠 것인가”에 초점을 둔다.

댓글 0

최신순 ▾
한 줄 남기기

혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)