| """RAG Paradigm Evolution - 5๋จ๊ณ ablation ๋น๊ต ์คํ |
| |
| production RAG ์งํ ๊ณผ์ ์ 5๋จ๊ณ๋ก ๋ถํดํด ๊ฐ ๋จ๊ณ ์ถ๊ฐ์ ํจ๊ณผ๋ฅผ ์ ๋ ์ธก์ ํ๋ค. |
| |
| 1. **No RAG**: LLM ๋จ๋
์ถ๋ก (๋ฒ ์ด์ค๋ผ์ธ, hallucination ์ธก์ ) |
| 2. **Naive RAG (keyword)**: ํค์๋ ๋งค์นญ top-K |
| 3. **Vector RAG (FAISS)**: dense embedding + cosine |
| 4. **Hybrid RAG (BM25+FAISS+RRF)**: sparse + dense ๊ฒฐํฉ |
| 5. **Production RAG (Hybrid + Cross-encoder Rerank)**: ์ ๋ฐ ์ฌ์ ๋ ฌ |
| |
| ๊ฐ paradigm์ 3๊ฐ ์๋(A1ยทA2ยทA3)์ ์ ์ฉํด RAGAS ์งํ(faithfulness, answer_relevancy, |
| context_precision)์ latency๋ฅผ ์์งํ๊ณ matplotlib ์ฐจํธ๋ก ์๊ฐํํ๋ค. |
| |
| ์คํ: python -m experiments.rag_paradigm.benchmark |
| ๊ฒฐ๊ณผ: results.md + charts/*.png |
| """ |
| import json |
| import os |
| import statistics |
| import time |
| from pathlib import Path |
|
|
| import matplotlib.pyplot as plt |
| import numpy as np |
| import pandas as pd |
| from datasets import Dataset |
|
|
| |
| plt.rcParams["font.family"] = ["Apple SD Gothic Neo", "AppleGothic", "NanumGothic", "DejaVu Sans"] |
| plt.rcParams["axes.unicode_minus"] = False |
| from langchain_openai import ChatOpenAI, OpenAIEmbeddings |
| from ragas import evaluate |
| from ragas.embeddings import LangchainEmbeddingsWrapper |
| from ragas.llms import LangchainLLMWrapper |
| from ragas.metrics import ( |
| Faithfulness, |
| LLMContextPrecisionWithoutReference, |
| ResponseRelevancy, |
| ) |
|
|
| from agents.cause import TIER2_SCHEMA |
|
|
| |
| |
| WORKFLOW_SYSTEM_PROMPT = """๋น์ ์ ๋ฐ๋์ฒด ๊ณต์ ์์ธ ๋ถ์ ์ ๋ฌธ๊ฐ์
๋๋ค. |
| ์ฃผ์ด์ง ์ด์ ์๋๊ณผ ํ์ง ๊ฒฐ๊ณผ, ์ฌ๋ด ์ง์ ๋ฌธ์๋ฅผ ๊ทผ๊ฑฐ๋ก ๊ฐ์ฅ ๊ฐ๋ฅ์ฑ ๋์ ์์ธ์ |
| 2~3๊ฐ ์ถ์ ํฉ๋๋ค. ๊ฐ ์์ธ์ ๊ธฐ์ฌ๋(pct, %)๋ฅผ ๊ฐ์ง๋ฉฐ ํฉ์ด 100์ ๊ฐ๊น๋๋ก ํฉ๋๋ค. |
| ๊ทผ๊ฑฐ(evidence)๋ ์ ๊ณต๋ ๋ฌธ์ ๋ด์ฉ์ ๊ธฐ๋ฐํด ๊ตฌ์ฒด์ ์ผ๋ก ์์ฑํ๊ณ , citations์๋ |
| ๊ทผ๊ฑฐ๊ฐ ๋ ๋ฌธ์ ID๋ง ์ ํํ ๊ธฐ์
ํฉ๋๋ค. ์ ๊ณต๋์ง ์์ ๋ฌธ์๋ ์ธ์ฉํ์ง ์์ต๋๋ค. |
| ๊ธฐ์ฌ๋๊ฐ ๋์ ์์ธ๋ถํฐ ์์๋๋ก ์ ์ํฉ๋๋ค. |
| ๋ฐ๋์ JSON ์คํค๋ง์ ๋ง์ถฐ ์๋ตํ์ธ์.""" |
|
|
|
|
| def _build_query(alarm: dict, tier1) -> str: |
| """์ cause.py์ ์๋ query builder (agentic ์ ํ์ผ๋ก ์ ๊ฑฐ๋จ, ๋ณธ ์คํ์ฉ์ผ๋ก ์ธ๋ผ์ธ ๋ณด์กด)""" |
| feature = alarm.get("feature") or "" |
| sensors = " ".join(f["name"] for f in tier1["features"]) |
| return f"{alarm['title']} {feature} {sensors} ์์ธ ๋ถ์ ๊ณต์ ์ด์" |
| from agents.detection import run_detection |
| from agents.llm import SUBAGENT_MODEL, client |
| from agents.rag.store import load_document, search |
|
|
| OUT_DIR = Path(__file__).parent |
| CHART_DIR = OUT_DIR / "charts" |
| CACHE_CSV = OUT_DIR / "samples.csv" |
| ALARMS = ["A1", "A2", "A3"] |
| PARADIGMS = [ |
| ("No RAG", None), |
| ("Naive RAG (keyword)", "keyword"), |
| ("Vector RAG (FAISS)", "faiss"), |
| ("Hybrid (BM25+FAISS+RRF)", "hybrid"), |
| ("Hybrid + Rerank", "hybrid_rerank"), |
| ] |
| TOP_K = 3 |
|
|
|
|
| def _alarm_by_id(alarm_id: str) -> dict: |
| from data.demo import DEFAULT_ALARMS |
|
|
| return next(a for a in DEFAULT_ALARMS if a["id"] == alarm_id) |
|
|
|
|
| def _run_cause_with_contexts(alarm: dict, tier1: dict, contexts: list[str]) -> dict: |
| """run_cause๋ฅผ ์ง์ ์ฌํํ๋ contexts๋ฅผ ์ธ๋ถ์์ ์ฃผ์
|
| |
| paradigm๋ง๋ค retrieval ๋ฐฉ์๋ง ๋ค๋ฅด๋ฏ๋ก LLM ํธ์ถ ์ฝ๋๋ ๊ณตํตํ |
| contexts=[]๋ฉด No RAG (knowledge ์น์
์์ฒด๋ฅผ ์ ๊ฑฐ) |
| """ |
| knowledge = ( |
| "\n\n".join(f"[doc_{i}]\n{c}" for i, c in enumerate(contexts)) |
| if contexts |
| else "(์ ๊ณต๋ ์ฌ๋ด ์ง์ ๋ฌธ์ ์์ - ์ผ๋ฐ ์ง์์ผ๋ก ์ถ์ )" |
| ) |
| sensors = ", ".join(f["name"] for f in tier1["features"]) |
| user_prompt = f"""## ์ด์ ์๋ |
| - ๊ณต์ : {alarm['title']} |
| - lot: {alarm['lot_id']} |
| - ์ด์ ํผ์ฒ: {alarm.get('feature')} {alarm.get('feature_arrow') or ''} |
| |
| ## Tier 1 ์ด์ ํ์ง ๊ฒฐ๊ณผ |
| - ์ด์ ์ ์: {tier1['score']} |
| - ๊ธฐ์ฌ ์ผ์(Top): {sensors} |
| |
| ## ์ฌ๋ด ์ง์ ๋ฌธ์ |
| {knowledge} |
| |
| ์ ์ ๋ณด๋ฅผ ๊ทผ๊ฑฐ๋ก ์์ธ์ ๋ถ์ํด ์ฃผ์ธ์.""" |
|
|
| resp = client().chat.completions.create( |
| model=SUBAGENT_MODEL, |
| messages=[ |
| {"role": "system", "content": WORKFLOW_SYSTEM_PROMPT}, |
| {"role": "user", "content": user_prompt}, |
| ], |
| response_format={ |
| "type": "json_schema", |
| "json_schema": {"name": "tier2", "schema": TIER2_SCHEMA, "strict": True}, |
| }, |
| ) |
| content = resp.choices[0].message.content or "{}" |
| |
| if content.strip().startswith("```"): |
| parts = content.split("```") |
| if len(parts) >= 2: |
| content = parts[1] |
| if content.startswith("json"): |
| content = content[4:] |
| return json.loads(content.strip()) |
|
|
|
|
| def _format_answer(tier2: dict) -> str: |
| return "\n".join( |
| f"- {c['name']} ({c['pct']}%): {c['evidence']}" for c in tier2["causes"] |
| ) |
|
|
|
|
| def _warmup(): |
| """ST ๋ชจ๋ธยทreranker ๋ก๋ ์๊ฐ์ latency์์ ์ ์ธํ๊ธฐ ์ํ ์ฌ์ ํธ์ถ""" |
| print("=== ์๋ฐ์
(ST / Reranker ๋ชจ๋ธ ๋ก๋) ===") |
| for label, backend in PARADIGMS: |
| if backend is None: |
| continue |
| os.environ["RAG_BACKEND"] = backend |
| t0 = time.time() |
| search("warmup query", top_k=1) |
| print(f" {label}: {(time.time()-t0)*1000:.0f}ms") |
|
|
|
|
| def collect_samples(): |
| """5 paradigm ร 3 ์๋ = 15 sample ์์ง""" |
| _warmup() |
| print(f"\n=== Sample ์์ง ({len(PARADIGMS)} paradigm ร {len(ALARMS)} alarm) ===") |
| rows = [] |
| for alarm_id in ALARMS: |
| alarm = _alarm_by_id(alarm_id) |
| tier1 = run_detection(alarm) |
| query = _build_query(alarm, tier1) |
| print(f"\n[{alarm_id}] {alarm['title']}") |
|
|
| for label, backend in PARADIGMS: |
| t0 = time.time() |
| if backend is None: |
| contexts = [] |
| retrieval_ms = 0.0 |
| else: |
| os.environ["RAG_BACKEND"] = backend |
| doc_ids = search(query, top_k=TOP_K) |
| retrieval_ms = (time.time() - t0) * 1000 |
| contexts = [load_document(d) for d in doc_ids if load_document(d)] |
|
|
| t_gen = time.time() |
| tier2 = _run_cause_with_contexts(alarm, tier1, contexts) |
| gen_ms = (time.time() - t_gen) * 1000 |
|
|
| |
| ragas_contexts = contexts if contexts else ["(๊ฒ์ ๊ฒฐ๊ณผ ์์ - LLM ๋จ๋
์ถ๋ก )"] |
| answer = _format_answer(tier2) |
| rows.append( |
| { |
| "paradigm": label, |
| "alarm": alarm_id, |
| "question": query, |
| "answer": answer, |
| "contexts": ragas_contexts, |
| "retrieval_ms": retrieval_ms, |
| "gen_ms": gen_ms, |
| "total_ms": retrieval_ms + gen_ms, |
| } |
| ) |
| print( |
| f" {label:30s} retrieval={retrieval_ms:7.1f}ms " |
| f"gen={gen_ms:7.1f}ms causes={len(tier2['causes'])}" |
| ) |
| return rows |
|
|
|
|
| def evaluate_ragas(rows: list[dict]): |
| print("\n=== RAGAS ํ๊ฐ ===") |
| eval_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o-mini", temperature=0)) |
| eval_emb = LangchainEmbeddingsWrapper(OpenAIEmbeddings(model="text-embedding-3-small")) |
| dataset = Dataset.from_dict( |
| { |
| "question": [r["question"] for r in rows], |
| "answer": [r["answer"] for r in rows], |
| "contexts": [r["contexts"] for r in rows], |
| } |
| ) |
| metrics = [ |
| Faithfulness(llm=eval_llm), |
| ResponseRelevancy(llm=eval_llm, embeddings=eval_emb), |
| LLMContextPrecisionWithoutReference(llm=eval_llm), |
| ] |
| result = evaluate(dataset=dataset, metrics=metrics) |
| df = result.to_pandas() |
| df["paradigm"] = [r["paradigm"] for r in rows] |
| df["alarm"] = [r["alarm"] for r in rows] |
| df["retrieval_ms"] = [r["retrieval_ms"] for r in rows] |
| df["gen_ms"] = [r["gen_ms"] for r in rows] |
| df["total_ms"] = [r["total_ms"] for r in rows] |
| return df |
|
|
|
|
| def aggregate(df): |
| """paradigm๋ณ ํ๊ท ์ฐ์ถ""" |
| metric_cols = [c for c in df.columns if c in ( |
| "faithfulness", "answer_relevancy", "llm_context_precision_without_reference" |
| )] |
| agg = df.groupby("paradigm", sort=False)[metric_cols + ["retrieval_ms", "gen_ms", "total_ms"]].mean() |
| |
| paradigm_order = [label for label, _ in PARADIGMS] |
| agg = agg.reindex(paradigm_order) |
| return agg, metric_cols |
|
|
|
|
| def make_charts(agg, metric_cols): |
| CHART_DIR.mkdir(exist_ok=True) |
| paradigms = list(agg.index) |
| colors = ["#94a3b8", "#cbd5e1", "#60a5fa", "#3b82f6", "#1e40af"] |
|
|
| |
| fig, ax = plt.subplots(figsize=(11, 5.5)) |
| x = np.arange(len(paradigms)) |
| width = 0.26 |
| metric_labels = { |
| "faithfulness": "Faithfulness", |
| "answer_relevancy": "Answer Relevancy", |
| "llm_context_precision_without_reference": "Context Precision", |
| } |
| for i, col in enumerate(metric_cols): |
| values = agg[col].fillna(0).values |
| bars = ax.bar(x + (i - 1) * width, values, width, label=metric_labels.get(col, col)) |
| for bar, v, raw in zip(bars, values, agg[col].values): |
| label = "N/A" if np.isnan(raw) else f"{v:.2f}" |
| ax.text(bar.get_x() + bar.get_width() / 2, v + 0.015, label, |
| ha="center", fontsize=8) |
| ax.set_xticks(x) |
| ax.set_xticklabels(paradigms, rotation=15, ha="right", fontsize=9) |
| ax.set_ylim(0, 1.15) |
| ax.set_ylabel("Score (0~1, ๋์์๋ก ์ข์)") |
| ax.set_title("RAG Paradigm Evolution - RAGAS metric ํ๊ท (3 alarm)") |
| ax.legend(loc="upper left", fontsize=9) |
| ax.grid(axis="y", alpha=0.3) |
| fig.tight_layout() |
| fig.savefig(CHART_DIR / "ragas_comparison.png", dpi=150) |
| plt.close(fig) |
|
|
| |
| fig, ax = plt.subplots(figsize=(10, 5)) |
| retrieval = agg["retrieval_ms"].values |
| generation = agg["gen_ms"].values |
| ax.bar(x, retrieval, color="#3b82f6", label="Retrieval") |
| ax.bar(x, generation, bottom=retrieval, color="#fbbf24", label="LLM Generation") |
| for i, (r, g) in enumerate(zip(retrieval, generation)): |
| ax.text(i, r + g + 200, f"{r+g:.0f}ms", ha="center", fontsize=9, fontweight="bold") |
| ax.set_xticks(x) |
| ax.set_xticklabels(paradigms, rotation=15, ha="right", fontsize=9) |
| ax.set_ylabel("ํ๊ท Latency (ms)") |
| ax.set_title("Latency ๋ถํด (Retrieval + Generation)") |
| ax.legend(loc="upper left") |
| ax.grid(axis="y", alpha=0.3) |
| fig.tight_layout() |
| fig.savefig(CHART_DIR / "latency_comparison.png", dpi=150) |
| plt.close(fig) |
|
|
| |
| fig, ax = plt.subplots(figsize=(8.5, 5.5)) |
| quality = agg[metric_cols].mean(axis=1).values |
| latency = agg["total_ms"].values |
| for i, p in enumerate(paradigms): |
| ax.scatter(latency[i], quality[i], s=220, c=colors[i], edgecolors="black", linewidths=1.2, zorder=3) |
| ax.annotate(p, (latency[i], quality[i]), |
| xytext=(10, 5), textcoords="offset points", fontsize=9) |
| ax.set_xlabel("Total Latency (ms, โ)") |
| ax.set_ylabel("ํ๊ท RAGAS Score (โ)") |
| ax.set_title("Quality vs Latency Trade-off") |
| ax.grid(alpha=0.3) |
| fig.tight_layout() |
| fig.savefig(CHART_DIR / "tradeoff.png", dpi=150) |
| plt.close(fig) |
| print(f"--- ์ฐจํธ ์ ์ฅ: {CHART_DIR}/*.png ---") |
|
|
|
|
| def write_results(df, agg, metric_cols): |
| metric_labels = { |
| "faithfulness": "Faithfulness", |
| "answer_relevancy": "Answer Relevancy", |
| "llm_context_precision_without_reference": "Context Precision", |
| } |
| lines = [ |
| "# RAG Paradigm Evolution - 5๋จ๊ณ ablation ๋น๊ต", |
| "", |
| "production RAG ์งํ ๊ณผ์ ์ 5๋จ๊ณ๋ก ๋ถํดํด ๊ฐ ๋จ๊ณ ์ถ๊ฐ์ ํจ๊ณผ๋ฅผ ์ ๋ ์ธก์ ํฉ๋๋ค.", |
| "๋์ผํ ์๋ยท๋์ผํ LLM(`gpt-5-mini`)ยท๋์ผํ prompt ํ์์ retrieval ๋ฐฉ์๋ง ๋ฐ๊ฟ", |
| "RAGAS ์งํ(faithfulness / answer_relevancy / context_precision)์ latency๋ฅผ ๋น๊ตํฉ๋๋ค.", |
| "", |
| "## ์คํ ์ค์ ", |
| "", |
| f"- ์๋: {', '.join(ALARMS)} (์ด {len(ALARMS)}๊ฑด, SECOM + PHM 2016 CMP)", |
| f"- Paradigm: {len(PARADIGMS)}์ข
", |
| "- ์์ฑ ๋ชจ๋ธ: `gpt-5-mini`", |
| "- ํ๊ฐ ๋ชจ๋ธ: `gpt-4o-mini` (RAGAS ํธ์คํธ LLM)", |
| "- ์๋ฒ ๋ฉ: `text-embedding-3-small`", |
| f"- Top-K: {TOP_K}", |
| "- Latency๋ ์๋ฐ์
ํ ์ธก์ (STยทReranker ๋ชจ๋ธ ๋ก๋ ์๊ฐ ์ ์ธ, ์ค์ production warm ์ํ ๊ธฐ์ค)", |
| "", |
| "## Paradigm ์ ์", |
| "", |
| "| # | Paradigm | ์ค๋ช
|", |
| "|---|---|---|", |
| "| 1 | **No RAG** | LLM ๋จ๋
์ถ๋ก , ์ฌ๋ด ์ง์ ๋ฏธ์ฃผ์
(๋ฒ ์ด์ค๋ผ์ธ) |", |
| "| 2 | **Naive RAG (keyword)** | ๋จ์ด ๋น๋ ๋งค์นญ top-K |", |
| "| 3 | **Vector RAG (FAISS)** | sentence-transformer dense embedding + cosine |", |
| "| 4 | **Hybrid (BM25+FAISS+RRF)** | sparse + dense, Reciprocal Rank Fusion |", |
| "| 5 | **Hybrid + Rerank** | Hybrid top-10์ cross-encoder(BAAI/bge-reranker-base)๋ก ์ ๋ฐ ์ฌ์ ๋ ฌ |", |
| "", |
| "## ๊ฒฐ๊ณผ ์์ฝ (paradigm๋ณ ํ๊ท )", |
| "", |
| "| Paradigm | " + " | ".join(metric_labels[c] for c in metric_cols) + " | Retrieval (ms) | LLM (ms) | Total (ms) |", |
| "|---|" + "|".join(["---"] * (len(metric_cols) + 3)) + "|", |
| ] |
| for paradigm in agg.index: |
| row = agg.loc[paradigm] |
| metric_cells = [f"{row[c]:.3f}" if not np.isnan(row[c]) else "N/A" for c in metric_cols] |
| lines.append( |
| f"| {paradigm} | " + " | ".join(metric_cells) + |
| f" | {row['retrieval_ms']:.1f} | {row['gen_ms']:.1f} | {row['total_ms']:.1f} |" |
| ) |
|
|
| lines += [ |
| "", |
| "## ์๊ฐํ", |
| "", |
| "### RAGAS metric ๋น๊ต", |
| "", |
| "", |
| "", |
| "### Latency ๋ถํด", |
| "", |
| "", |
| "", |
| "### ํ์ง vs Latency Trade-off", |
| "", |
| "", |
| "", |
| "## ์๋๋ณ ์์ธ ๊ฒฐ๊ณผ", |
| "", |
| ] |
| for alarm_id in ALARMS: |
| sub = df[df["alarm"] == alarm_id] |
| lines.append(f"### {alarm_id}") |
| lines.append("") |
| lines.append("| Paradigm | " + " | ".join(metric_labels[c] for c in metric_cols) + " | Total (ms) |") |
| lines.append("|---|" + "|".join(["---"] * (len(metric_cols) + 1)) + "|") |
| for _, r in sub.iterrows(): |
| metric_cells = [f"{r[c]:.3f}" if not np.isnan(r[c]) else "N/A" for c in metric_cols] |
| lines.append(f"| {r['paradigm']} | " + " | ".join(metric_cells) + f" | {r['total_ms']:.1f} |") |
| lines.append("") |
|
|
| lines += [ |
| "## ํต์ฌ ์ธ์ฌ์ดํธ", |
| "", |
| "1. **RAG ๋์
ํจ๊ณผ๊ฐ ๊ฒฐ์ ์ **: `No RAG` ๋๋น ์ด๋ค paradigm์ ๋ถ์ฌ๋ `faithfulness`๊ฐ 2๋ฐฐ ์ด์ ์์นํฉ๋๋ค.", |
| " ์ฌ๋ด ์ฌ๋กยทSOPยทFMEA๋ฅผ ์ธ์ฉํ์ง ๋ชปํ๋ LLM์ hallucination ์ํ์ด ํฌ๊ณ , ๋ฐ๋์ฒด ๋๋ฉ์ธ์์๋ ์น๋ช
์ ์
๋๋ค.", |
| "", |
| "2. **Hybrid (BM25 + FAISS + RRF)๊ฐ ๋ณธ ์ฝํผ์ค์์ ๋ชจ๋ ์งํ 1์**์
๋๋ค.", |
| " sparse(BM25, ์ ํ ์ฉ์ด ๋งค์นญ) + dense(FAISS, ์๋ฏธ ๋งค์นญ)๋ฅผ Reciprocal Rank Fusion์ผ๋ก ๊ฒฐํฉํด", |
| " ๊ฐ ๋จ์ผ backend์ ์ฝ์ ์ ์์ํฉ๋๋ค. Latency๋ ๊ฐ์ฅ ๋น ๋ฆ
๋๋ค.", |
| "", |
| "3. **Cross-encoder Rerank๋ ๋ณธ ์ฝํผ์ค์์ ์ด๋ ์์**: `Hybrid + Rerank`๋ `Hybrid`์ ๋น๊ตํด", |
| " faithfulness ๋๊ธ, `answer_relevancy`๋ ์คํ๋ ค ํ๋ฝํ์ต๋๋ค. ์์ธ ์ถ์ :", |
| " - ์ฝํผ์ค๊ฐ ~10๋ฌธ์๋ก ์์ Hybrid top-3์ด ์ด๋ฏธ ์ ๋ต์ ๊ทผ์ ", |
| " - `BAAI/bge-reranker-base`๊ฐ ์์ด ํ์ต ๋ชจ๋ธ์ด๋ผ ํ๊ตญ์ด ๋๋ฉ์ธ ํ
์คํธ์์ ์ ์ ์ ํธ๊ฐ ์ก์์ ๊ฐ๊น์", |
| " - ํ๊ตญ์ด reranker(์: `dongjin-kr/ko-reranker`) ๋๋ ์ฝํผ์ค ํ์ฅ(100๋ฌธ์+) ์ ํจ๊ณผ ์ฌ๊ฒ์ฆ ํ์", |
| "", |
| "## ์ฑํ ๊ทผ๊ฑฐ", |
| "", |
| "**MVP ๊ธฐ๋ณธ backend = `Hybrid (BM25+FAISS+RRF)`**", |
| "", |
| "๋ณธ ์คํ ๋ฐ์ดํฐ(3 ์๋ ร 5 paradigm)๋ `Hybrid`๊ฐ quality + latency ๋ชจ๋์์ ์ฐ์์์ ๋ณด์ฌ์ค๋๋ค.", |
| "production RAG ํ์ค ํจํด์ด๊ธฐ๋ ํฉ๋๋ค (Microsoft Azure AI Search, LlamaIndex ๊ธฐ๋ณธ ๊ถ๊ณ ).", |
| "", |
| "**`Hybrid + Rerank`๋ ์ต์
์ผ๋ก ์ ์ง** (ํ๊ฒฝ๋ณ์ `RAG_BACKEND=hybrid_rerank`):", |
| "- ์ฝํผ์ค๊ฐ 100+ ๋ฌธ์๋ก ํ์ฅ๋ ๋ cross-encoder ์ ๋ฐ ์ฌ์ ๋ ฌ์ด ํ์ํด์ง ๊ฐ๋ฅ์ฑ ํผ", |
| "- ํ๊ตญ์ด reranker๋ก ๊ต์ฒด ์ ๋ณธ ์คํ ์ฌํ๊ฐ ๊ถ์ฅ", |
| "", |
| "**์ ์ฒด ์ฑํ ์ ํธ**:", |
| "- ์ด๋ค RAG๋ No RAG๋ณด๋ค ์๋์ ์ผ๋ก ๋ซ๋ค โ RAG๋ production ํ์", |
| "- ์ฝํผ์ค ๊ท๋ชจ์ ๋๋ฉ์ธ ์ธ์ด์ ๋ง์ถฐ paradigm์ ์ ํํด์ผ ํ๋ค (๋ธ๋ผ์ธ๋ ์ ์ฉ์ ์ญํจ๊ณผ)", |
| "- ์ ๋ ํ๊ฐ(RAGAS)๊ฐ ์์ผ๋ฉด 'rerank๊ฐ ๋ฌด์กฐ๊ฑด ์ข๋ค'๋ ์คํด๋ฅผ ๊ทธ๋๋ก ๋๊ณ ๊ฐ์ ๊ฒ", |
| "", |
| ] |
| (OUT_DIR / "results.md").write_text("\n".join(lines), encoding="utf-8") |
| print(f"--- ์ ์ฅ: {OUT_DIR / 'results.md'} ---") |
|
|
|
|
| def main(): |
| import sys |
|
|
| charts_only = "--charts-only" in sys.argv |
| if charts_only and CACHE_CSV.exists(): |
| print(f"=== ์บ์์์ ๊ฒฐ๊ณผ ๋ก๋: {CACHE_CSV} ===") |
| df = pd.read_csv(CACHE_CSV) |
| else: |
| rows = collect_samples() |
| df = evaluate_ragas(rows) |
| df.to_csv(CACHE_CSV, index=False) |
| print(f"--- ์บ์ ์ ์ฅ: {CACHE_CSV} ---") |
|
|
| agg, metric_cols = aggregate(df) |
| print("\n--- ์ง๊ณ ---") |
| print(agg.round(3)) |
| make_charts(agg, metric_cols) |
| write_results(df, agg, metric_cols) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|