재순위화 (Reranking)
재순위화는 1차 검색(retrieval)으로 가져온 문서들의 순서를 질문과의 관련성에 따라 다시 정렬하는 과정입니다. 1차 검색은 속도를 위해 근사적 유사도를 사용하지만, 재순위화는 더 정밀한 모델로 관련성을 재평가합니다.
왜 재순위화가 필요한가?
| 단계 | 모델 | 속도 | 정밀도 |
|---|
| 1차 검색 (Bi-encoder) | 쿼리/문서 독립 임베딩 | 빠름 (ms) | 보통 |
| 재순위화 (Cross-encoder) | 쿼리+문서 동시 입력 | 느림 (100ms~) | 높음 |
전략 비교 종합
| 재순위화 방법 | 정밀도 | 속도 | 비용 | 다국어 | 적합한 경우 |
|---|
| Cross-encoder (BGE) | 매우 높음 | 느림 | 무료 (로컬) | O | 한국어 프로덕션 |
| Cohere Rerank | 매우 높음 | 보통 | 유료 API | O | 빠른 통합, 관리형 |
| ColBERT | 높음 | 빠름 | 무료 (로컬) | 제한적 | 대규모 문서, 속도 중시 |
| FlashRank | 보통 | 매우 빠름 | 무료 (로컬) | 제한적 | 프로토타이핑, 경량 환경 |
재순위화 파이프라인 패턴
# 전체 파이프라인: 검색 → 재순위화 → 생성
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,
)
# 사용
results = retriever.invoke("질문")
# → 20개 후보에서 가장 관련성 높은 4개만 반환
한국어 RAG에서는 BAAI/bge-reranker-v2-m3를 기본으로 추천합니다. 다국어 성능이 뛰어나고 한국어에서도 높은 정밀도를 보입니다. API 호출 방식을 선호한다면 Cohere Rerank v3.5를 사용하세요.
세부 전략 가이드