크로스인코더 리랭커

앞단 검색이 좁혀준 후보 20개쯤을 다시 정렬하는 모델.

바이인코더 vs 크로스인코더

방식속도정확도
바이인코더 (Dense 검색)질문과 청크를 따로 벡터화 후 거리 비교빠름 (미리 계산 가능)보통
크로스인코더질문과 청크를 붙여서 함께 읽고 점수느림 (매번 계산)높음

크로스인코더는 미리 계산해둘 수 없다. 질문이 와야 계산이 시작된다. 그래서 전체 30,000청크에 못 쓰고, 앞단이 20개로 좁혀준 뒤에만 쓴다.

질문 → [Dense/BM25로 20개 추림] → [크로스인코더가 20개 재정렬] → 상위 5개
        빠름                        느리지만 정확

언제 효과가 큰가

정답이 후보 안에는 있는데 등수가 낮을 때. 후보에 아예 없으면 리랭커도 못 만든다 — 앞단이 못 찾은 건 끝이다.

우리 상황이 정확히 이렇다: Dense가 정답을 상위 20에 갖고 있으면서 15등, 20등에 놓는 경우가 많다. 리랭커가 유망한 이유.

실측 — 채택 (2026-07-29, 164문항, e5-small 베이스)

가설이 맞았다. 승격 기준 +0.05의 두 배를 넘겼다.

dense 단독+리랭커차이
MRR@100.64020.7443+0.104
nDCG@100.60610.7013+0.095
Recall@50.61880.7110+0.092

세 지표가 같이 올랐다. MRR만 오르고 Recall이 떨어졌다면 “1등은 잘 맞히는데 나머지를 놓친다”는 뜻이라 위험했을 것이다.

유형별로도 손해 본 곳이 없다 — 단일세부 +0.137, 직답 +0.189, 탐색비교 +0.034, 후속 +0.005. 뒤 둘은 여러 문서를 걸치는 유형이라 개선폭이 작다.

상세 → 검색 실험 결과

이 폭은 e5-small 위에서의 값

임베딩이 좋아지면 리랭커가 고칠 게 줄어 +0.104보다 작아질 것으로 본다. 방향(플러스)은 유지되겠지만 크기는 재봐야 한다. 리랭커 모델끼리는 아직 비교 안 했다 — 쓴 건 bge-reranker-v2-m3 하나뿐. → 검색 실험 결과 §3

비용

모델BAAI/bge-reranker-v2-m3568M 파라미터
실행GPU 필요 (우리는 VM L4 23GB). GPU가 없으면 dense 단독으로 자동 강등(RERANKER_REQUIRE_GPU=True)
속도VM L4에서 문항당 0.27초 (164문항 45초) / 맥 CPU 13.27초 — 49배
위험웹 서버에서 동시 요청 시 모델 중복 로드 → OOM. 이중검사 락 + MODEL_LOAD_TIMEOUT_S=300 유한 대기로 해소

왜 GPU가 필요한가 — 49배가 나오는 이유

바이인코더는 청크 벡터를 미리 계산해 저장해둔다. 질문이 오면 질문 하나만 벡터로 바꿔 거리를 비교하면 끝이라, 질문 시점에 모델이 읽는 텍스트는 질문 1개뿐이다.

크로스인코더는 그게 안 된다. 점수가 (질문, 청크) 에 대해 정의되므로 미리 계산할 대상이 없고, 질문마다 질문 + 청크를 붙인 입력 20개를 통째로 순전파해야 한다.

바이인코더  질문 1개 순전파        → 나머지는 저장된 벡터와 거리 계산(산수)
크로스인코더 (질문+청크) 20개 순전파 → 매 질문마다 처음부터

568M 모델의 순전파 20회는 GPU에서는 병렬로 흘러 0.27초에 끝나지만, CPU에서는 그 연산이 그대로 노출돼 13.27초가 된다. 이 49배 차이는 모델이 느려서가 아니라 질문 시점에 해야 하는 연산량 자체가 크기 때문이고, 그래서 후보를 20개로 좁힌 뒤에만 쓰는 것이다.

맥은 MPS가 아니라 CPU로 돈다 — _load_cross_encoder가 MPS 경로 불안정을 이유로 cuda/cpu만 쓴다. 실측 조건: 후보 20개, 워밍업 분리, 3회 중앙값 → 검색 실험 결과 §5

관련

Dense 검색 · 하이브리드 검색 · MRR