Cross-encoder Reranking
Cross-encoder는 쿼리와 문서를 하나의 입력으로 결합하여 관련성 점수를 직접 예측하는 재순위화 모델입니다.
Bi-encoder vs Cross-encoder
| 항목 | Bi-encoder | Cross-encoder |
|---|
| 입력 방식 | 쿼리, 문서를 독립 인코딩 | 쿼리+문서를 함께 인코딩 |
| 상호작용 | 없음 (독립 벡터) | 토큰 수준의 상호작용 |
| 속도 | 빠름 (사전 인코딩 가능) | 느림 (매번 쌍으로 인코딩) |
| 정밀도 | 보통 | 높음 |
| 사용 단계 | 1차 검색 (대량 후보) | 재순위화 (소량 후보) |
| 확장성 | 수백만 문서 가능 | 수십~수백 문서 |
LangChain 구현
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain_community.cross_encoders import HuggingFaceCrossEncoder
# Cross-encoder 모델 로드
model = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-v2-m3")
compressor = CrossEncoderReranker(model=model, top_n=4)
# 재순위화 적용
reranking_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=retriever, # 1차 검색기 (top-20)
)
results = reranking_retriever.invoke("RAG에서 검색 품질을 높이는 방법은?")
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_community.cross_encoders import HuggingFaceCrossEncoder
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain.retrievers import ContextualCompressionRetriever
# 1차 검색: 넓게 가져오기 (top-20)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma(collection_name="docs", embedding_function=embeddings)
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 20})
# 재순위화: 정밀하게 좁히기 (top-4)
model = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-v2-m3")
compressor = CrossEncoderReranker(model=model, top_n=4)
retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=base_retriever,
)
# 사용: 20개 후보에서 가장 관련성 높은 4개만 반환
results = retriever.invoke("Self-RAG의 Reflection Token 역할")
주요 Cross-encoder 모델
| 모델 | 크기 | 다국어 | 한국어 | 특징 |
|---|
BAAI/bge-reranker-v2-m3 | 568M | O | 우수 | 다국어 최강, 프로덕션 추천 |
BAAI/bge-reranker-large | 560M | O | 우수 | 범용 고성능 |
BAAI/bge-reranker-base | 278M | O | 좋음 | 속도-성능 균형 |
cross-encoder/ms-marco-MiniLM-L-12-v2 | 33M | X | X | 영어 전용, 경량 |
cross-encoder/ms-marco-MiniLM-L-6-v2 | 22M | X | X | 영어 전용, 초경량 |
모델 선택 가이드
| 요구사항 | 추천 모델 |
|---|
| 한국어 RAG | BAAI/bge-reranker-v2-m3 |
| 영어 전용 + 속도 중시 | cross-encoder/ms-marco-MiniLM-L-6-v2 |
| 영어 전용 + 품질 중시 | cross-encoder/ms-marco-MiniLM-L-12-v2 |
| 다국어 + 균형 | BAAI/bge-reranker-base |
| 최고 품질 (언어 무관) | BAAI/bge-reranker-v2-m3 |
성능 최적화
Top-K 설정
1차 검색의 K값과 재순위화의 top_n을 적절히 설정해야 합니다.
| 1차 검색 K | 재순위화 top_n | 효과 |
|---|
| 10 | 3~4 | 빠르지만 관련 문서 누락 가능 |
| 20 | 4~5 | 균형 잡힌 기본 설정 |
| 50 | 5~10 | 높은 재현율, 느린 속도 |
1차 검색의 K값을 너무 작게 설정하면 관련 문서가 후보에서 제외되어 재순위화의 효과가 제한됩니다. 반대로 너무 크면 Cross-encoder의 처리 시간이 증가합니다.
GPU 가속
import torch
# GPU 사용 가능 시 자동 활용
model = HuggingFaceCrossEncoder(
model_name="BAAI/bge-reranker-v2-m3",
model_kwargs={"device": "cuda" if torch.cuda.is_available() else "cpu"},
)
한국어 RAG 프로덕션 추천: BAAI/bge-reranker-v2-m3 + 1차 검색 top-20 + 재순위화 top-4. GPU가 없어도 CPU에서 동작하며, 20개 문서 재순위화에 약 200~500ms 소요됩니다.