| """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]] |
|
|