fabagent / agents /rag /rerank.py
hee_!J
feat(experiments): D9 ํ•œ๊ตญ์–ด reranker ํ‰๊ฐ€ (Dongjin-kr/ko-reranker)
1d550b9
Raw
History Blame Contribute Delete
1.41 kB
"""Cross-encoder Re-ranking - hybrid retrieval ๊ฒฐ๊ณผ๋ฅผ ์ •๋ฐ€ ์žฌ์ •๋ ฌ
bi-encoder(์ž„๋ฒ ๋”ฉ ๊ธฐ๋ฐ˜)๋Š” query์™€ doc์„ ๋”ฐ๋กœ ์ธ์ฝ”๋”ฉํ•˜์ง€๋งŒ, cross-encoder๋Š”
(query, doc) ์Œ์„ ํ†ต์งธ๋กœ ์ž…๋ ฅํ•ด ์ •๋ฐ€ํ•œ ๊ด€๋ จ์„ฑ ์ ์ˆ˜๋ฅผ ์‚ฐ์ถœํ•œ๋‹ค.
๊ณ„์‚ฐ ๋น„์šฉ์€ ํฌ์ง€๋งŒ top-K ํ›„๋ณด(๋ณดํ†ต 10~20)๋งŒ ์žฌ์ •๋ ฌํ•˜๋ฏ€๋กœ production์— ์ ํ•ฉ.
๋ชจ๋ธ ์˜ต์…˜ (ํ™˜๊ฒฝ๋ณ€์ˆ˜ RERANK_MODEL):
- BAAI/bge-reranker-base (๊ธฐ๋ณธ, ์˜์–ด ํ•™์Šต, ํ•œ๊ตญ์–ด ์ผ๋ถ€ ์ง€์›, ~280MB)
- Dongjin-kr/ko-reranker (ํ•œ๊ตญ์–ด ํŠนํ™”, ~280MB) - D6 ํ›„์† ํ‰๊ฐ€์šฉ
"""
import os
from functools import lru_cache
DEFAULT_MODEL = "BAAI/bge-reranker-base"
def _model_name() -> str:
return os.getenv("RERANK_MODEL", DEFAULT_MODEL)
@lru_cache(maxsize=2)
def _build_reranker(model_name: str):
from sentence_transformers import CrossEncoder
return CrossEncoder(model_name)
def rerank(query: str, doc_ids: list[str], top_k: int = 3) -> list[str]:
"""ํ›„๋ณด doc ๋ฆฌ์ŠคํŠธ๋ฅผ cross-encoder ์ ์ˆ˜ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์žฌ์ •๋ ฌํ•ด top-K ๋ฐ˜ํ™˜"""
if not doc_ids:
return []
from agents.rag.store import load_document
docs = [load_document(d) for d in doc_ids]
pairs = [[query, doc] for doc in docs]
model = _build_reranker(_model_name())
scores = model.predict(pairs)
ranked = sorted(zip(doc_ids, scores), key=lambda x: -x[1])
return [doc_id for doc_id, _ in ranked[:top_k]]