| """D2: ๊ฒ์ ๋ฐฑ์๋ ๋น๊ต - keyword vs FAISS vs Hybrid vs Hybrid+Rerank |
| |
| ๊ฐ์ ์ฟผ๋ฆฌ ์งํฉ์ ๋ํด 4๊ฐ์ง retrieval ๋ฐฉ์ ๋น๊ต |
| - keyword: ๋จ์ ๋จ์ด ๋น๋ ๋งค์นญ |
| - FAISS: sentence-transformer ์๋ฒ ๋ฉ + ์ฝ์ฌ์ธ ์ ์ฌ๋ |
| - Hybrid: BM25 + FAISS + Reciprocal Rank Fusion (production ํ์ค) |
| - Hybrid+Rerank: hybrid top-K ํ๋ณด๋ฅผ cross-encoder๋ก ์ฌ์ ๋ ฌ (production ์ ๋ฐ) |
| |
| ์คํ: python -m experiments.retrieval_compare.benchmark |
| ๊ฒฐ๊ณผ: results.md |
| """ |
| import statistics |
| import time |
| from pathlib import Path |
|
|
| from agents.rag.faiss_store import faiss_search |
| from agents.rag.hybrid_store import hybrid_search |
| from agents.rag.rerank import rerank |
| from agents.rag.store import keyword_search |
|
|
| OUT_DIR = Path(__file__).parent |
|
|
| QUERIES = [ |
| ("CD ์ฐํฌ ์ง์ ", "Photo Step CD-X ์ฐํฌ ์์ธ ๋ ์ฆ ๋
ธ๊ด"), |
| ("CMP ์ง์ ", "CMP ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์ SLURRY_FLOW"), |
| ("Etch ์ง์ ", "Etch ํธ๋ ์น ๊น์ด ๋ถ์กฑ ์๊ฐ ๊ฐ์ค"), |
| ("์๋ฏธ ์ฐํ 1", "๋
ธ๊ด ์ฅ๋น ํ๋ฉด ์ค์ผ ์ฒญ์"), |
| ("์๋ฏธ ์ฐํ 2", "ํ๊ณต์ ์์จ ์์ค ์ ๋ ์ํฅ"), |
| ("์๋ฏธ ์ฐํ 3", "์ ๋น ์ฃผ๊ธฐ ํ์ค ๊ฐ์ด๋"), |
| ] |
|
|
|
|
| def hybrid_rerank_search(query, top_k=3): |
| candidates = hybrid_search(query, top_k=10) |
| return rerank(query, candidates, top_k) |
|
|
|
|
| BACKENDS = [ |
| ("keyword", keyword_search), |
| ("faiss", faiss_search), |
| ("hybrid", hybrid_search), |
| ("hybrid+rerank", hybrid_rerank_search), |
| ] |
|
|
|
|
| def main(): |
| |
| print("=== ์๋ฐ์
(๋ชจ๋ธ ๋ก๋) ===") |
| for name, fn in BACKENDS: |
| t0 = time.time() |
| fn("warmup query", top_k=1) |
| print(f" {name}: {time.time()-t0:.2f}s") |
| print() |
|
|
| rows = [] |
| for label, q in QUERIES: |
| record = {"label": label, "query": q, "results": {}, "latency_ms": {}} |
| print(f"[{label}] '{q}'") |
| for name, fn in BACKENDS: |
| t0 = time.time() |
| res = fn(q, top_k=3) |
| ms = (time.time() - t0) * 1000 |
| record["results"][name] = res |
| record["latency_ms"][name] = ms |
| print(f" {name:14s} ({ms:7.2f}ms): {res}") |
| rows.append(record) |
| print() |
|
|
| write_results(rows) |
| print(f"--- ์ ์ฅ: {OUT_DIR / 'results.md'} ---") |
|
|
|
|
| def write_results(rows): |
| avg_lat = { |
| name: statistics.mean(r["latency_ms"][name] for r in rows) |
| for name, _ in BACKENDS |
| } |
|
|
| lines = [ |
| "# D2. Retrieval ๋ฐฑ์๋ ๋น๊ต (production-grade)", |
| "", |
| "์ฟผ๋ฆฌ ์งํฉ์ ๋ํด 4๊ฐ์ง ๋ฐฑ์๋์ ๊ฒ์ ๊ฒฐ๊ณผยทlatency๋ฅผ ๋น๊ตํฉ๋๋ค.", |
| "ํ์ฌ knowledge ์ฝํผ์ค ์ฝ 10๊ฐ ํ๊ตญ์ด ๋๋ฉ์ธ ๋ฌธ์.", |
| "", |
| "## ์คํ ์ค์ ", |
| "", |
| "- ์ฝํผ์ค: `agents/rag/knowledge/*.md`", |
| "- ๋ฐฑ์๋ 4์ข
:", |
| " - **keyword**: ๋จ์ด ๋น๋ ๋งค์นญ (baseline)", |
| " - **FAISS**: sentence-transformer ์๋ฒ ๋ฉ + ์ฝ์ฌ์ธ (dense vector)", |
| " - **Hybrid**: BM25 + FAISS + RRF (production ํ์ค)", |
| " - **Hybrid+Rerank**: hybrid top-10 ํ๋ณด๋ฅผ BAAI/bge-reranker-base๋ก ์ฌ์ ๋ ฌ (production ์ ๋ฐ)", |
| f"- ์ฟผ๋ฆฌ {len(rows)}๊ฑด (์๋ฏธ ์ฐํ 3๊ฑด ํฌํจ)", |
| "", |
| "## ์ฟผ๋ฆฌ๋ณ ๊ฒฐ๊ณผ", |
| "", |
| ] |
|
|
| for r in rows: |
| lines.append(f"### {r['label']} - `{r['query']}`") |
| lines.append("") |
| lines.append("| ๋ฐฑ์๋ | ๊ฒฐ๊ณผ | latency |") |
| lines.append("|---|---|---|") |
| for name, _ in BACKENDS: |
| res = ", ".join(r["results"][name]) or "(empty)" |
| lines.append(f"| {name} | {res} | {r['latency_ms'][name]:.2f}ms |") |
| lines.append("") |
|
|
| lines += [ |
| "## ์ง๊ณ - ํ๊ท Latency", |
| "", |
| "| ๋ฐฑ์๋ | ํ๊ท latency |", |
| "|---|---|", |
| ] |
| for name, _ in BACKENDS: |
| lines.append(f"| {name} | {avg_lat[name]:.2f} ms |") |
|
|
| lines += [ |
| "", |
| "## ํธ๋ ์ด๋์คํ", |
| "", |
| "| ์ธก๋ฉด | keyword | FAISS | Hybrid | Hybrid+Rerank |", |
| "|---|---|---|---|---|", |
| "| ๋๋ฉ์ธ ์ฉ์ด ์ ํ ๋งค์นญ | โ
| โ | โ
| โ
|", |
| "| ์๋ฏธยท๋์์ด ๋งค์นญ | โ | โ
| โ
| โ
|", |
| "| ์ ๋ฐํ ๊ด๋ จ์ฑ ํ๊ฐ | โ | โ | โ | โ
|", |
| "| Latency | ๋งค์ฐ ๋น ๋ฆ | ๋ณดํต | ๋ณดํต | ๋๋ฆผ (CrossEncoder) |", |
| "| ๋ชจ๋ธ ์์กด์ฑ | ์์ | ST(~120MB) | ST(~120MB) | ST + Reranker(~280MB) |", |
| "| ์ฝํผ์ค ํ์ฅ(100+) ๊ฒฌ๊ณ ์ฑ | ์ฝํจ | ๊ฐํจ | **๋งค์ฐ ๊ฐํจ** | **๋งค์ฐ ๊ฐํจ** |", |
| "", |
| "## ์ฑํ", |
| "", |
| "**๊ธฐ๋ณธ backend = `hybrid_rerank`**. production ํ์ค ํจํด. ํ๊ฒฝ๋ณ์ `RAG_BACKEND`๋ก 4๊ฐ์ง ๋ชจ๋ ์ ํ ๊ฐ๋ฅ.", |
| "", |
| "- ์ฝํผ์ค 100๋ฌธ์ ์ด์: hybrid_rerank์ ์ ๋ฐ๋ ์ฐ์ ๊ฒฐ์ ์ ", |
| "- MVPยท์์ฐ ํ๊ฒฝ: hybrid๋ ์ถฉ๋ถ (rerank ๋ชจ๋ธ ๋ค์ด๋ก๋ ์๊ฐ ์ ์ฝ)", |
| "- ๋จ์ ํค์๋ ๊ฒ์๋ง ํ์: keyword (์์กด์ฑ ์์)", |
| "", |
| ] |
| (OUT_DIR / "results.md").write_text("\n".join(lines), encoding="utf-8") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|