huny.log

기술 포스트 · AI·LLM

RAG 재순위(re-ranking) — cross-encoder로 검색 정밀도를 한 단계 올리기

벡터 검색이 가져온 Top 50을 LLM에 그대로 넘기면 정밀도가 깨집니다. cross-encoder 재순위가 그 50개를 다시 정렬해 Top 5만 LLM에 넘기면 답변 품질이 한 단계 올라갑니다.

RAG 챗봇 답변이 자주 빗나간다면, 모델·프롬프트보다 검색 단계가 약할 가능성이 큽니다. 벡터 검색은 빠르지만 의미 매칭의 정밀도가 부족합니다. cross-encoder 재순위(re-ranking)는 1단계 검색의 Top 50을 다시 정렬해 정말 관련 있는 Top 5를 LLM에 넘깁니다. 한 단계 추가로 답변 품질이 눈에 띄게 올라갑니다.

마케터가 이 글을 읽어야 하는 이유: RAG 챗봇이 운영에 들어가 있다면, 답변 품질의 절반이 검색 단계에서 결정됩니다. 모델 교체보다 비용 효율적인 개선이 재순위 단계 추가입니다. 비용 약간 증가에 정밀도 큰 폭 상승. 사내 챗봇 신뢰도가 흔들리는 자리라면 가장 먼저 시도할 카드입니다.

벡터 검색이 빠르게 50개를 가져오고 cross-encoder가 그 50개를 다시 정렬해 Top 5만 LLM에 넘기는 2단계 흐름
빠른 1차 검색 + 정밀한 2차 재순위. 비용은 작게, 품질은 크게.

1. 왜 1차 검색만으로 부족한가

벡터 검색(bi-encoder 기반)은 사용자 질문과 문서를 각각 독립적으로 임베딩한 뒤 코사인 유사도로 비교합니다. 이 구조는 빠르지만 한 가지 약점이 있습니다.

질문과 문서가 서로 직접 비교되지 않고, 미리 만든 임베딩으로만 비교된다.

같은 단어라도 문맥이 다르면 의미가 다릅니다. “Meta 캠페인 ROAS”가 페이스북 광고를 의미하는지 메타분석을 의미하는지의 구분이 1차 검색에서는 약합니다. 그래서 Top 5가 깨끗하지 않고 무관한 문서가 자주 섞입니다.

검색 단계입력비교 방식정밀도속도
1차 (벡터)질문 임베딩미리 만든 문서 임베딩과 코사인중간매우 빠름
2차 (cross-encoder)질문 + 문서 쌍매번 함께 입력해 점수 출력매우 높음느림

cross-encoder는 정밀하지만 모든 문서에 적용하면 너무 느립니다. 그래서 1차 검색으로 Top 50을 빠르게 가져온 뒤 그 50개에만 cross-encoder를 적용하는 2단계 흐름이 표준이 되었습니다.

2. Cross-encoder의 한 줄 직관

cross-encoder는 질문과 문서를 한 번에 모델에 넣어 “얼마나 관련 있는가”의 점수를 직접 출력합니다.

입력: [질문] [SEP] [문서] → 출력: 관련도 점수 (0~1)

bi-encoder처럼 임베딩을 미리 만들어 둘 수 없습니다. 매 쿼리마다 50개 문서 각각에 대해 모델 forward를 돌려야 합니다. 그래서 느림. 대신 두 텍스트의 모든 토큰이 attention으로 직접 연결되니 의미 매칭의 정밀도가 폭발적입니다.

수식 직관:

bi-encoder는 로 두 임베딩의 코사인을 계산하지만, cross-encoder는 두 텍스트를 함께 모델에 넣어 단일 점수를 출력합니다. 토큰끼리 직접 attention하니 미묘한 문맥 차이를 잡아냅니다.

3. 2단계 검색의 표준 흐름

사용자 질문
1차 검색 (bi-encoder + vector DB)
→ Top 50 문서를 매우 빠르게 (수십 ms)
2차 재순위 (cross-encoder)
→ Top 50을 정밀 점수로 정렬
→ 상위 Top 5만 살림 (수백 ms)
Top 5를 LLM 프롬프트에 컨텍스트로 삽입
LLM이 답변 생성

각 단계의 책임이 분명해지고, 시스템 전체의 정밀도가 올라갑니다. 비용은 cross-encoder 50번 호출 = 수백 ms 지연 + 약간의 GPU/API 비용. 품질 개선이 비용을 항상 정당화한다는 게 RAG 운영 표준이 되어가는 이유입니다.

4. 코드 한 묶음 — sentence-transformers cross-encoder

이게 글에 박는 유일한 코드입니다.

from sentence_transformers import CrossEncoder
# 1. cross-encoder 모델 로드 (한 번만)
reranker = CrossEncoder("BAAI/bge-reranker-base")
# 2. 1차 검색 결과 (벡터 DB가 빠르게 가져온 Top 50)
query = "Meta 광고 ROAS 분기별 평균은?"
candidates = [
"2024 Q3 Meta 광고 ROAS 평균은 4.2였습니다...",
"메타분석에서 평균 효과크기는 0.35로...",
"TikTok ROAS는 평균 3.1, Meta는 4.2...",
# ... 47개 더
]
# 3. cross-encoder로 (질문, 문서) 쌍을 점수화
pairs = [(query, doc) for doc in candidates]
scores = reranker.predict(pairs)
# scores: [0.92, 0.18, 0.85, ...]
# 4. 점수 기준 정렬 후 Top 5만 살림
ranked = sorted(zip(scores, candidates), reverse=True)[:5]
top_5 = [doc for _, doc in ranked]
print(top_5)
# 1차 검색에서 메타분석 문서가 섞여 있었지만 cross-encoder가 점수 0.18로 떨궈냄.

50개 문서에 대해 각각 점수를 계산하니 수백 ms 지연이 추가됩니다. 그러나 잘못 섞여 들어왔던 메타분석 문서가 0.18 점수로 떨어져 Top 5에서 빠지고, 정확한 광고 ROAS 문서들이 살아 LLM 컨텍스트로 들어갑니다.

5. 모델 선택 — 어떤 cross-encoder를 쓸까

모델크기한국어 지원추론 속도
cross-encoder/ms-marco-MiniLM-L-6-v2작음 (22M)약함가장 빠름
cross-encoder/ms-marco-MiniLM-L-12-v2중간 (33M)약함빠름
BAAI/bge-reranker-base중간 (278M)강함 (multilingual)중간
BAAI/bge-reranker-large큼 (560M)매우 강함느림
Cohere Rerank API매니지드강함빠름 (클라우드)

한국어 RAG에는 BAAI/bge-reranker-base 이상을 권장합니다. 영어 전용 모델은 한국어 매칭이 약함. 매니지드 솔루션이 필요하면 Cohere Rerank API.

5-1. Cohere Rerank API의 자리

API 호출 한 번으로 100개 문서 재순위. 자체 호스팅 부담 없음. 비용은 1000번 검색당 약 $1-2. 챗봇 검색 트래픽이 일일 수만 건 이하면 합리적.

6. 1차 검색의 K값 — Top 몇 개를 재순위에 넘기나

K (1차 결과 수)효과비용
10정밀도 한도 (재순위가 살릴 수 있는 게 적음)매우 낮음
50표준 — 대부분 자리에 적합적당
100높은 recall, cross-encoder 100번 호출높음
200+거의 모든 후보 검토, 비용 폭발매우 높음

K=50이 표준이 되어가고 있습니다. 정밀도와 비용의 균형이 가장 좋은 자리. 매우 큰 코퍼스(수백만 문서)에서는 K=100이 안전.

7. 평가 — 재순위가 정말 도움이 됐나

재순위 단계 추가가 의미 있는지 측정하려면 RAG 평가 지표를 함께 봐야 합니다.

7-1. Context Relevance와 Recall

RAG 평가에서 다룬 4가지 지표 중 Context Relevance와 Context Recall이 재순위 효과를 직접 반영합니다. 재순위 ON/OFF를 토글해 같은 골든셋에서 두 지표를 비교.

시나리오Context RelevanceContext RecallFaithfulness
재순위 OFF (Top 5 직접)0.780.850.81
재순위 ON (Top 50 → Top 5)0.910.880.93

Context Relevance가 0.78 → 0.91로 큰 폭 상승. Faithfulness도 0.81 → 0.93. 재순위 단계가 답변 품질 전반에 영향을 미친다는 게 정량적으로 확인됩니다.

7-2. 응답 시간의 트레이드오프

재순위 단계 추가는 약 200-500ms 지연을 만듭니다. 사용자가 인식할 만한 지연이 아니지만 챗봇 응답이 이미 느린 자리(p95 5초+)에서는 추가 부담이 됩니다.

8. 운영 흐름의 안정화

8-1. 캐싱

같은 (질문, 문서) 쌍에 대해 점수를 캐시해두면 반복 질문 시 cross-encoder 호출이 줄어듭니다. 챗봇 트래픽의 20-40%가 같은 질문 패턴이라 캐시 히트율이 높음.

8-2. 배치 처리

cross-encoder는 배치 처리가 강합니다. 50개 쌍을 한 배치로 묶어 한 번에 forward하면 개별 호출보다 5-10배 빠름. PyTorch DataLoader 같은 표준 패턴 활용.

8-3. 모니터링 알림

재순위 점수의 분포를 매주 추적합니다. 갑자기 모든 점수가 낮아지면(예: 평균 0.3 이하) 임베딩 모델·코퍼스 변화 의심.

9. 마치며 — RAG 품질 개선의 가장 비용 효율적인 자리

RAG 챗봇 품질 개선에 큰 비용을 쓰기 전에 cross-encoder 재순위 단계를 한 번 시도해보는 게 가장 비용 효율적인 카드입니다. 모델 교체·프롬프트 튜닝보다 적은 비용으로 Context Relevance·Faithfulness가 큰 폭 상승하는 케이스가 흔합니다. 운영 중인 챗봇이 자주 빗나간다면 이 단계 추가를 분기 로드맵에 박아두세요.

다음 분기에 한 번만 시도해 볼 만한 것은 골든셋 50개에 대해 재순위 ON/OFF 비교를 한 번 돌려 정밀도 차이를 정량화하는 흐름입니다. 차이가 크면 즉시 운영 도입, 작으면 다른 단계로.

다음에 읽을 글

참고

AI·LLM 카테고리의 다른 글

전체 보기 →