| """D6 ํ์: ํ๊ตญ์ด reranker(dongjin-kr/ko-reranker) ํจ๊ณผ ํ๊ฐ |
| |
| D6์์ BAAI/bge-reranker-base๊ฐ Hybrid ๋๋น ํจ๊ณผ ์์์ด ํ์ธ๋จ (์์ด ํ์ต ๋ชจ๋ธ + ํ๊ตญ์ด ์ฝํผ์ค mismatch). |
| ํ๊ตญ์ด ํนํ reranker๋ก ๊ฒฐ๊ณผ๊ฐ ๋ค์งํ๋์ง ๊ฒ์ฆ. |
| |
| ํ๊ฐ ๋ฐฉ๋ฒ: |
| - D2์ 6๊ฐ ๋ํ ์ฟผ๋ฆฌ(์ง์ + ์๋ฏธ ์ฐํ) ์ฌ์ฉ |
| - 3๊ฐ ๋ชจ๋ ร 6 ์ฟผ๋ฆฌ = 18 ์กฐํฉ |
| - hybrid (no rerank, baseline) |
| - hybrid + BAAI/bge-reranker-base (์์ด reranker) |
| - hybrid + Dongjin-kr/ko-reranker (ํ๊ตญ์ด reranker) |
| - ๊ฐ ๋ชจ๋์ top-3 ๊ฒฐ๊ณผ๋ฅผ CRAG grader(gpt-4o-mini)๋ก 0~1 ์ ์ |
| - avg score / ๋ชจ๋๋ณ ๋น๊ต โ ํ๊ตญ์ด reranker๊ฐ ์๋ฏธ ์๋ ๊ฐ์ ๊ฐ์ ธ์ค๋์ง ํ๋จ |
| |
| ์คํ: python -m experiments.reranker_compare.benchmark |
| """ |
| import os |
| import time |
| from pathlib import Path |
|
|
| import matplotlib.pyplot as plt |
| import numpy as np |
|
|
| from agents.rag.crag import grade_retrieval |
| from agents.rag.hybrid_store import hybrid_search |
| from agents.rag.store import load_document |
|
|
| plt.rcParams["font.family"] = ["Apple SD Gothic Neo", "AppleGothic", "DejaVu Sans"] |
| plt.rcParams["axes.unicode_minus"] = False |
|
|
| OUT_DIR = Path(__file__).parent |
| CHART_DIR = OUT_DIR / "charts" |
|
|
| QUERIES = [ |
| ("CD ์ฐํฌ ์ง์ ", "Photo Step CD-X ์ฐํฌ ์์ธ ๋ ์ฆ ๋
ธ๊ด"), |
| ("CMP ์ง์ ", "CMP ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์ SLURRY_FLOW"), |
| ("Etch ์ง์ ", "Etch ํธ๋ ์น ๊น์ด ๋ถ์กฑ ์๊ฐ ๊ฐ์ค"), |
| ("์๋ฏธ ์ฐํ 1", "๋
ธ๊ด ์ฅ๋น ํ๋ฉด ์ค์ผ ์ฒญ์"), |
| ("์๋ฏธ ์ฐํ 2", "ํ๊ณต์ ์์จ ์์ค ์ ๋ ์ํฅ"), |
| ("์๋ฏธ ์ฐํ 3", "์ ๋น ์ฃผ๊ธฐ ํ์ค ๊ฐ์ด๋"), |
| ] |
|
|
| MODES = [ |
| ("hybrid (no rerank)", None), |
| ("BAAI/bge-reranker-base (์์ด)", "BAAI/bge-reranker-base"), |
| ("Dongjin-kr/ko-reranker (ํ๊ตญ์ด)", "Dongjin-kr/ko-reranker"), |
| ] |
|
|
| TOP_K = 3 |
| CANDIDATES = 10 |
|
|
|
|
| def _rerank_with_model(query: str, candidates: list[str], model_name: str, top_k: int) -> list[str]: |
| """๋ชจ๋ธ ๋ช
์์ ์ง์ ํ cross-encoder rerank""" |
| os.environ["RERANK_MODEL"] = model_name |
| |
| from agents.rag.rerank import _build_reranker |
|
|
| docs = [load_document(d) for d in candidates] |
| pairs = [[query, doc] for doc in docs] |
| scores = _build_reranker(model_name).predict(pairs) |
| ranked = sorted(zip(candidates, scores), key=lambda x: -x[1]) |
| return [doc_id for doc_id, _ in ranked[:top_k]] |
|
|
|
|
| def collect(): |
| print("=== ์๋ฐ์
(BAAI + ko-reranker ๋ก๋) ===") |
| t0 = time.time(); _rerank_with_model("warmup", ["FMEA-PH-007"], "BAAI/bge-reranker-base", 1); print(f" BAAI: {time.time()-t0:.1f}s") |
| t0 = time.time(); _rerank_with_model("warmup", ["FMEA-PH-007"], "Dongjin-kr/ko-reranker", 1); print(f" ko-reranker: {time.time()-t0:.1f}s") |
|
|
| rows = [] |
| for label, query in QUERIES: |
| print(f"\n[{label}] '{query}'") |
| |
| candidates = hybrid_search(query, top_k=CANDIDATES) |
| result_row = {"label": label, "query": query, "modes": {}} |
| for mode_name, model in MODES: |
| if model is None: |
| |
| doc_ids = candidates[:TOP_K] |
| rerank_ms = 0.0 |
| else: |
| t0 = time.time() |
| doc_ids = _rerank_with_model(query, candidates, model, TOP_K) |
| rerank_ms = (time.time() - t0) * 1000 |
| docs = [{"doc_id": d, "snippet": load_document(d)[:600]} for d in doc_ids if load_document(d)] |
| grades = grade_retrieval(query, docs) |
| avg_score = sum(g.get("score", 0.0) for g in grades) / max(len(grades), 1) |
| result_row["modes"][mode_name] = { |
| "doc_ids": doc_ids, |
| "avg_score": round(avg_score, 3), |
| "rerank_ms": rerank_ms, |
| "grades": grades, |
| } |
| print(f" {mode_name:38s} avg={avg_score:.3f} ms={rerank_ms:.0f} docs={doc_ids}") |
| rows.append(result_row) |
| return rows |
|
|
|
|
| def aggregate(rows): |
| return { |
| mode_name: { |
| "avg_score": np.mean([r["modes"][mode_name]["avg_score"] for r in rows]), |
| "rerank_ms": np.mean([r["modes"][mode_name]["rerank_ms"] for r in rows]), |
| } |
| for mode_name, _ in MODES |
| } |
|
|
|
|
| def make_chart(agg, rows): |
| CHART_DIR.mkdir(exist_ok=True) |
| mode_names = [n for n, _ in MODES] |
| short_names = ["No Rerank", "BAAI (EN)", "ko-reranker"] |
| avg_scores = [agg[n]["avg_score"] for n in mode_names] |
| colors = ["#94a3b8", "#3b82f6", "#ef4444"] |
|
|
| fig, ax = plt.subplots(figsize=(8.5, 5.5)) |
| bars = ax.bar(short_names, avg_scores, color=colors) |
| for b, v in zip(bars, avg_scores): |
| ax.text(b.get_x() + b.get_width() / 2, v + 0.01, f"{v:.3f}", |
| ha="center", fontsize=10, fontweight="bold") |
| ax.set_ylim(0, 1.05) |
| ax.set_ylabel("ํ๊ท LLM relevance score (6 ์ฟผ๋ฆฌ ํ๊ท )") |
| ax.set_title("Reranker ๋น๊ต - ํ๊ตญ์ด reranker๊ฐ D6 ๊ฒฐ๊ณผ๋ฅผ ๋ค์ง๋?") |
| ax.grid(axis="y", alpha=0.3) |
| fig.tight_layout() |
| fig.savefig(CHART_DIR / "reranker_comparison.png", dpi=150) |
| plt.close(fig) |
|
|
|
|
| def write_results(rows, agg): |
| base_score = agg["hybrid (no rerank)"]["avg_score"] |
| en_score = agg["BAAI/bge-reranker-base (์์ด)"]["avg_score"] |
| ko_score = agg["Dongjin-kr/ko-reranker (ํ๊ตญ์ด)"]["avg_score"] |
|
|
| lines = [ |
| "# D9 (D6 ํ์): ํ๊ตญ์ด reranker ํ๊ฐ", |
| "", |
| "D6์์ `BAAI/bge-reranker-base`(์์ด ํ์ต)๊ฐ Hybrid ๋๋น ํจ๊ณผ ์์์ด ํ์ธ๋์ด,", |
| "ํ๊ตญ์ด ํนํ reranker `Dongjin-kr/ko-reranker`๋ก ์ฌํ๊ฐํฉ๋๋ค.", |
| "", |
| "## ์คํ ์ค์ ", |
| "", |
| "- ์ฟผ๋ฆฌ: D2์ 6๊ฐ ๋ํ ์ฟผ๋ฆฌ (์ง์ 3, ์๋ฏธ ์ฐํ 3)", |
| "- ๋ฐฑ์๋: hybrid (BM25+FAISS+RRF) top-10 ํ๋ณด๋ฅผ ๋ reranker๋ก ์ฌ์ ๋ ฌ", |
| "- ์ฑ์ : CRAG grader (gpt-4o-mini)๊ฐ top-3 ๊ฒฐ๊ณผ๋ฅผ 0~1๋ก ํ๊ฐ", |
| "- ๋น๊ต: hybrid (no rerank) / BAAI (์์ด) / ko-reranker (ํ๊ตญ์ด)", |
| "", |
| "## ๊ฒฐ๊ณผ ์์ฝ (6 ์ฟผ๋ฆฌ ํ๊ท )", |
| "", |
| "| ๋ชจ๋ | ํ๊ท relevance | rerank ํ๊ท latency | vs No Rerank |", |
| "|---|---|---|---|", |
| f"| hybrid (no rerank) | {base_score:.3f} | 0 ms | baseline |", |
| f"| BAAI/bge-reranker-base (์์ด) | {en_score:.3f} | {agg['BAAI/bge-reranker-base (์์ด)']['rerank_ms']:.0f} ms | {(en_score - base_score):+.3f} |", |
| f"| Dongjin-kr/ko-reranker (ํ๊ตญ์ด) | {ko_score:.3f} | {agg['Dongjin-kr/ko-reranker (ํ๊ตญ์ด)']['rerank_ms']:.0f} ms | {(ko_score - base_score):+.3f} |", |
| "", |
| "## ์๊ฐํ", |
| "", |
| "", |
| "", |
| "## ์ฟผ๋ฆฌ๋ณ ์์ธ", |
| "", |
| "| ์ฟผ๋ฆฌ | hybrid | BAAI (EN) | ko-reranker (KO) |", |
| "|---|---|---|---|", |
| ] |
| for r in rows: |
| cells = [f"{r['modes'][n]['avg_score']:.2f}" for n, _ in MODES] |
| lines.append(f"| {r['label']} | " + " | ".join(cells) + " |") |
|
|
| |
| ko_wins = ko_score > en_score and ko_score > base_score |
| ko_helps = ko_score > base_score |
| decision = "ko-reranker ์ฑํ" if ko_wins else ("ko-reranker ๊ฒํ ๊ฐ๋ฅ (no rerank๋ณด๋จ ์ฐ์)" if ko_helps else "๋ reranker ๋ชจ๋ ๋ณธ ์ฝํผ์ค์์ hybrid์ ๋ฏธ๋ฌ") |
|
|
| lines += [ |
| "", |
| "## ํต์ฌ ์ธ์ฌ์ดํธ", |
| "", |
| f"1. **No Rerank baseline**: {base_score:.3f}", |
| f"2. **์์ด reranker (BAAI)**: {en_score:.3f} (vs baseline {(en_score - base_score):+.3f}) - D6์์ ๋ณธ ํจํด ์ฌํ์ธ", |
| f"3. **ํ๊ตญ์ด reranker (Dongjin-kr)**: {ko_score:.3f} (vs baseline {(ko_score - base_score):+.3f})", |
| f"4. **๊ฒฐ๋ก **: {decision}", |
| "", |
| "## ์ฑํ", |
| "", |
| ] |
| if ko_wins: |
| lines += [ |
| f"**๊ธฐ๋ณธ reranker๋ฅผ `Dongjin-kr/ko-reranker`๋ก ๊ถ์ฅ** (`RERANK_MODEL` ํ๊ฒฝ๋ณ์).", |
| f"ํ๊ตญ์ด ๋๋ฉ์ธ์์ ์์ด reranker ๋๋น +{(ko_score - en_score):.3f} ์ ์ ์ฐ์, baseline ๋๋น +{(ko_score - base_score):.3f} ์ฐ์.", |
| ] |
| elif ko_helps: |
| lines += [ |
| "**ko-reranker๋ ์์ด reranker๋ณด๋จ ์๋ฏธ ์๋ ๊ฐ์ ** (baseline ๋๋น ์์).", |
| "ํ์ง๋ง hybrid ๋จ๋
๋๋น ์ฐ์๊ฐ ๊ฒฐ์ ์ ์ด์ง ์์ ๊ธฐ๋ณธ backend๋ hybrid ์ ์ง.", |
| "์ฝํผ์ค 100+ ํ์ฅ ์ ko-reranker๋ก ์ฌํ๊ฐ ๊ถ์ฅ (ํ๊ฒฝ๋ณ์ `RAG_BACKEND=hybrid_rerank` + `RERANK_MODEL=Dongjin-kr/ko-reranker`).", |
| ] |
| else: |
| lines += [ |
| f"**๋ reranker ๋ชจ๋ ๋ณธ ์ฝํผ์ค์์ hybrid ๋จ๋
์ ๋ฏธ๋ฌ** (BAAI {(en_score - base_score):+.3f}, ko-reranker {(ko_score - base_score):+.3f}).", |
| "๊ทผ๋ณธ ์์ธ: ์ฝํผ์ค๊ฐ ~10๋ฌธ์๋ก ์์ hybrid top-3์ด ์ด๋ฏธ ์ ๋ต์ ๊ทผ์ โ reranker๊ฐ ๋ ์ข๊ฒ ์ ๋ ฌํ ์ฌ์ง ๋ถ์กฑ.", |
| "**D6 ๊ฒฐ๋ก (์ฝํผ์ค ํ์ฅ์ด reranker ํจ์ฉ์ ์ ๊ฒฐ ์กฐ๊ฑด) ์ฌํ์ธ**. ์ฝํผ์ค 100+ ์ ์ฌํ๊ฐ.", |
| ] |
| lines.append("") |
| (OUT_DIR / "results.md").write_text("\n".join(lines), encoding="utf-8") |
| print(f"--- ์ ์ฅ: {OUT_DIR / 'results.md'} ---") |
|
|
|
|
| def main(): |
| rows = collect() |
| print("\n--- ์ง๊ณ ---") |
| agg = aggregate(rows) |
| for n, v in agg.items(): |
| print(f" {n}: avg={v['avg_score']:.3f}, ms={v['rerank_ms']:.0f}") |
| make_chart(agg, rows) |
| write_results(rows, agg) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|