RAG 검색 품질 높이기 — 재순위와 하이브리드 검색

📌 3줄 요약
· RAG의 답변 품질은 결국 검색 단계가 얼마나 정확한 조각을 가져오느냐에 달려 있습니다.
· 하이브리드 검색은 의미 기반(벡터)과 키워드 기반(BM25)을 합쳐 서로의 약점을 메웁니다.
· 재순위(Re-ranking)는 넉넉히 뽑은 후보를 다시 정밀 채점해 상위 몇 개만 남기는 마무리 단계입니다.
📖 목차

  1. 왜 ‘기본 검색’만으로는 부족한가
  2. 하이브리드 검색 — 의미와 키워드를 함께
  3. 재순위(Re-ranking) — 정밀 채점 한 번 더
  4. 흐름을 코드로 감 잡기
  5. 두 기법 비교와 조합
  6. 직접 적용할 때 실무 팁
  7. 자주 묻는 질문(FAQ)
▼ 개선된 검색 파이프라인 한눈에 보기
❓ 질문

🔀 하이브리드 검색

📚 후보 다수

🎯 재순위

✍️ 답 생성

RAG(검색증강생성)를 만들어 본 사람이라면 비슷한 경험을 합니다. 파이프라인은 다 갖췄는데 답변이 자꾸 엉뚱한 방향으로 흐르는 경우입니다. 원인을 따라가 보면 대부분 검색 단계에 있습니다. LLM에게 아무리 좋은 프롬프트를 줘도, 프롬프트에 끼워 넣은 문서 조각이 질문과 무관하면 좋은 답이 나올 수 없습니다. 이번 글에서는 검색 품질을 끌어올리는 두 가지 핵심 기법, 하이브리드 검색재순위(Re-ranking)를 설명합니다.


🔍 왜 ‘기본 검색’만으로는 부족한가

가장 흔한 RAG 구성은 질문과 문서를 각각 벡터로 바꿔 의미가 가까운 조각을 꺼내는 방식입니다. 이 방법은 표현이 달라도 뜻이 비슷하면 찾아낸다는 큰 장점이 있습니다. 예를 들어 “환불 규정”으로 물어도 “반품 시 대금 반환”이라 적힌 문서를 연결해 줍니다.

하지만 약점도 분명합니다. 벡터 검색은 정확한 고유명사·코드·제품 번호처럼 ‘의미’보다 ‘철자 그 자체’가 중요한 경우에 오히려 약합니다. 예컨대 ERR-4021 같은 오류 코드나 특정 모델명을 물으면, 의미상 비슷해 보이는 다른 조각을 가져오는 실수가 생깁니다.

의미 기반 검색은 ‘뜻’에 강하고 ‘정확한 단어’에 약합니다. 키워드 기반 검색은 그 반대입니다. 두 방식은 서로의 빈틈을 메워줍니다.


🔀 하이브리드 검색 — 의미와 키워드를 함께

하이브리드 검색(Hybrid Search)은 이름 그대로 서로 다른 검색 방식을 동시에 돌려 결과를 합치는 접근입니다. 대표적으로 두 축을 함께 씁니다.

① 의미 검색 (Dense)
임베딩 벡터로 뜻이 가까운 조각을 찾음. 동의어·의역에 강함.
② 키워드 검색 (Sparse)
BM25 같은 전통적 검색으로 단어가 정확히 겹치는 조각을 찾음. 고유명사·코드에 강함.

두 검색이 각각 후보 목록을 내놓으면, 이들을 하나의 순위로 합쳐야 합니다. 이때 자주 쓰이는 방법이 RRF(Reciprocal Rank Fusion)입니다. 점수의 절대값을 직접 더하는 대신 각 목록에서의 등수를 기준으로 합산하기 때문에, 서로 척도가 다른 두 검색 결과를 무난하게 섞을 수 있습니다.


🎯 재순위(Re-ranking) — 정밀 채점 한 번 더

검색을 아무리 잘해도 상위 결과에 관련 없는 조각이 섞이기 마련입니다. 재순위는 이 문제를 다루는 마무리 단계입니다. 아이디어는 단순합니다. 먼저 후보를 넉넉히(예: 20~30개) 뽑은 뒤, 더 정밀한 모델로 질문과 각 후보를 한 쌍씩 다시 채점해 상위 몇 개만 남기는 것입니다.

여기서 흔히 쓰이는 것이 크로스 인코더(Cross-Encoder)입니다. 일반 임베딩 검색은 질문과 문서를 따로 벡터로 만들어 비교하지만, 크로스 인코더는 질문과 문서를 함께 입력해 둘의 관련성을 직접 판정합니다. 그만큼 정확도가 높지만 계산 비용이 커서, 전체 문서가 아니라 추려낸 후보에만 적용하는 것이 정석입니다.

“넓게 검색해서 후보를 모으고(Recall 확보), 좁게 재순위해서 정답을 위로 올린다(Precision 확보)” — 이 2단계 구성이 검색 품질 개선의 기본 골격입니다.


💻 흐름을 코드로 감 잡기

라이브러리마다 이름은 다르지만, 뼈대는 아래처럼 ‘검색 → 합치기 → 재순위 → 상위 선택’ 순서입니다.

# 1) 두 갈래로 후보를 넉넉히 검색
dense_hits  = vectordb.search(question, top_k=20)   # 의미 기반
sparse_hits = bm25.search(question, top_k=20)       # 키워드 기반

# 2) 등수 기반으로 결과 합치기 (RRF)
candidates = reciprocal_rank_fusion(dense_hits, sparse_hits)

# 3) 크로스 인코더로 질문-후보 쌍을 재채점
scored = reranker.score(question, candidates)       # 후보에만 적용
top_docs = sort_by_score(scored)[:4]                # 상위 4개만 사용

# 4) 상위 조각을 프롬프트에 넣어 답 생성
context = "\n\n".join(top_docs)
answer  = llm.generate(f"다음 자료만 근거로 답하라.\n{context}\n\n[질문] {question}")

핵심은 검색을 한 번 더 걸러낸다는 흐름입니다. 검색과 생성 사이에 ‘합치기’와 ‘재순위’라는 두 필터를 끼워 넣는 것이 전부입니다.


⚖️ 두 기법 비교와 조합

구분 하이브리드 검색 재순위
역할 놓치는 조각을 줄여 후보를 넓게 확보 후보를 다시 채점해 정답을 위로
강점 의미·키워드 약점을 상호 보완 상위 결과의 정밀도가 크게 향상
비용 검색 두 번 + 합치기 (비교적 가벼움) 후보마다 모델 추론 (상대적으로 무거움)

둘은 경쟁 관계가 아니라 순서대로 이어 붙이는 조합입니다. 하이브리드 검색으로 후보를 넓게 모으고, 재순위로 그 안에서 정답을 위로 올리면 두 기법의 장점을 모두 취할 수 있습니다.


💡 직접 적용할 때 챙길 실무 팁

  • 후보 수(top_k) 조절 — 재순위 전 후보는 넉넉히, 재순위 후 최종은 적게. 후보가 너무 적으면 정답이 애초에 목록에 없을 수 있습니다.
  • 순서를 지키기 — ‘넓게 검색 → 좁게 재순위’ 순서가 기본. 검색을 좁게 하면 재순위로도 없는 정답을 만들 수 없습니다.
  • 키워드 검색 병행 — 제품 코드·법조항·고유명사가 많은 도메인일수록 BM25 병행 효과가 큽니다.
  • 비용과 지연 관리 — 재순위는 후보 수에 비례해 느려집니다. 응답 속도가 중요하면 후보 수를 줄이거나 경량 재순위 모델을 고려하세요.
  • 측정하며 조정 — 실제 질문 세트로 ‘정답 조각이 상위에 들어왔는지’를 확인하며 값을 맞추는 것이 감보다 확실합니다.

❓ 자주 묻는 질문 (FAQ)

Q. 하이브리드 검색과 재순위 중 하나만 한다면?
A. 상황에 따라 다릅니다. 고유명사·코드 검색이 자주 어긋난다면 하이브리드가, 관련 없는 조각이 상위에 자주 섞인다면 재순위가 먼저 효과를 봅니다. 여유가 되면 둘을 함께 쓰는 편이 안정적입니다.

Q. 재순위를 쓰면 항상 느려지나요?
A. 후보에만 적용하므로 전체 문서를 다시 채점하는 것보다는 가볍지만, 후보 수만큼 추론이 늘어나 지연이 생깁니다. 최종에 필요한 만큼만 후보를 잡는 것이 요령입니다.

Q. 임베딩 검색을 크로스 인코더로 완전히 대체하면 안 되나요?
A. 크로스 인코더로 전체 문서를 매번 채점하면 비용이 지나치게 큽니다. 그래서 ‘빠른 검색으로 후보를 좁힌 뒤 정밀 채점’하는 2단계 구성이 현실적인 선택입니다.


마무리

RAG의 품질을 좌우하는 것은 화려한 생성 모델이 아니라 검색이 정답 조각을 상위에 올려놓느냐입니다. 하이브리드 검색은 의미와 키워드의 약점을 서로 메워 후보를 넓히고, 재순위는 그 후보를 다시 정밀하게 걸러 정답을 위로 끌어올립니다. 두 기법을 순서대로 이어 붙이는 것만으로도 답변의 근거가 눈에 띄게 단단해집니다. 검색 파이프라인에 이 2단계 필터를 더해 보는 것을 권합니다.

댓글 남기기

How are you? good!에서 더 알아보기

지금 구독하여 계속 읽고 전체 아카이브에 액세스하세요.

계속 읽기