hee_!J commited on
Commit ยท
744e87d
1
Parent(s): 1524c7f
feat: Hybrid RAG(BM25+FAISS+RRF) + Cross-encoder Rerank + RAGAS eval
Browse files- agents/rag/hybrid_store.py +61 -0
- agents/rag/rerank.py +33 -0
- agents/rag/store.py +20 -2
- experiments/rag_eval/__init__.py +0 -0
- experiments/rag_eval/benchmark.py +134 -0
- experiments/rag_eval/results.md +32 -0
- experiments/retrieval_compare/benchmark.py +85 -66
- experiments/retrieval_compare/results.md +82 -29
- requirements.txt +4 -0
agents/rag/hybrid_store.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Hybrid Retrieval - BM25(sparse) + FAISS(dense) + Reciprocal Rank Fusion(RRF)
|
| 2 |
+
|
| 3 |
+
production RAG์ ํ์ค ํจํด. ๋๋ฉ์ธ ์ฉ์ด ์ ํ ๋งค์นญ(sparse) + ์๋ฏธ ์ ์ฌ๋(dense)
|
| 4 |
+
์์ชฝ ๊ฐ์ ์ RRF๋ก ๊ฒฐํฉ
|
| 5 |
+
|
| 6 |
+
RRF ๊ณต์: score(d) = sum over rankings r of 1 / (k + rank_r(d))
|
| 7 |
+
- k=60 (Cormack et al. 2009 ๊ถ์ฅ๊ฐ)
|
| 8 |
+
- rank๋ 1๋ถํฐ ์์
|
| 9 |
+
- ๊ฒฐ๊ณผ: rank 1์ด ๊ฐ์ฅ ํฐ ์ ์
|
| 10 |
+
"""
|
| 11 |
+
import re
|
| 12 |
+
from functools import lru_cache
|
| 13 |
+
|
| 14 |
+
from rank_bm25 import BM25Okapi
|
| 15 |
+
|
| 16 |
+
from agents.rag.store import _knowledge_docs
|
| 17 |
+
|
| 18 |
+
RRF_K = 60
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def _tokenize(text: str) -> list[str]:
|
| 22 |
+
"""BM25์ฉ ํ ํฐํ, ํ๊ตญ์ด/์์ด ํผํฉ ์์ ํ๊ฒ ๋จ์ ์ฒ๋ฆฌ"""
|
| 23 |
+
return [t for t in re.split(r"\W+", text.lower()) if len(t) >= 2]
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
@lru_cache(maxsize=1)
|
| 27 |
+
def _build_bm25():
|
| 28 |
+
"""knowledge ๋ฌธ์๋ก BM25 ์ธ๋ฑ์ค ๊ตฌ์ถ, ์ฒซ ํธ์ถ ์ 1ํ"""
|
| 29 |
+
docs = _knowledge_docs()
|
| 30 |
+
doc_ids = list(docs.keys())
|
| 31 |
+
corpus = [_tokenize(text) for text in docs.values()]
|
| 32 |
+
bm25 = BM25Okapi(corpus)
|
| 33 |
+
return bm25, doc_ids
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def bm25_search(query: str, top_k: int = 10) -> list[str]:
|
| 37 |
+
"""BM25 ์ ์ ๋ด๋ฆผ์ฐจ์ top-K ๋ฌธ์ ID"""
|
| 38 |
+
bm25, doc_ids = _build_bm25()
|
| 39 |
+
scores = bm25.get_scores(_tokenize(query))
|
| 40 |
+
ranked = sorted(zip(doc_ids, scores), key=lambda x: -x[1])
|
| 41 |
+
return [doc_id for doc_id, score in ranked[:top_k] if score > 0]
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def hybrid_search(query: str, top_k: int = 3, candidates: int = 10) -> list[str]:
|
| 45 |
+
"""Hybrid = BM25 + FAISS dense, ๊ฒฐ๊ณผ๋ฅผ Reciprocal Rank Fusion์ผ๋ก ๊ฒฐํฉ
|
| 46 |
+
|
| 47 |
+
๊ฐ ๋ฐฑ์๋์์ top-`candidates` ์ถ์ถ ํ RRF ์ ์ ํฉ์ฐํด์ ์ต์ข
top-K ๋ฐํ
|
| 48 |
+
"""
|
| 49 |
+
from agents.rag.faiss_store import faiss_search
|
| 50 |
+
|
| 51 |
+
bm25_ranked = bm25_search(query, top_k=candidates)
|
| 52 |
+
dense_ranked = faiss_search(query, top_k=candidates)
|
| 53 |
+
|
| 54 |
+
rrf_scores: dict[str, float] = {}
|
| 55 |
+
for rank, doc_id in enumerate(bm25_ranked, start=1):
|
| 56 |
+
rrf_scores[doc_id] = rrf_scores.get(doc_id, 0.0) + 1.0 / (RRF_K + rank)
|
| 57 |
+
for rank, doc_id in enumerate(dense_ranked, start=1):
|
| 58 |
+
rrf_scores[doc_id] = rrf_scores.get(doc_id, 0.0) + 1.0 / (RRF_K + rank)
|
| 59 |
+
|
| 60 |
+
merged = sorted(rrf_scores.items(), key=lambda x: -x[1])
|
| 61 |
+
return [doc_id for doc_id, _ in merged[:top_k]]
|
agents/rag/rerank.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Cross-encoder Re-ranking - hybrid retrieval ๊ฒฐ๊ณผ๋ฅผ ์ ๋ฐ ์ฌ์ ๋ ฌ
|
| 2 |
+
|
| 3 |
+
bi-encoder(์๋ฒ ๋ฉ ๊ธฐ๋ฐ)๋ query์ doc์ ๋ฐ๋ก ์ธ์ฝ๋ฉํ์ง๋ง, cross-encoder๋
|
| 4 |
+
(query, doc) ์์ ํต์งธ๋ก ์
๋ ฅํด ์ ๋ฐํ ๊ด๋ จ์ฑ ์ ์๋ฅผ ์ฐ์ถํ๋ค.
|
| 5 |
+
๊ณ์ฐ ๋น์ฉ์ ํฌ์ง๋ง top-K ํ๋ณด(๋ณดํต 10~20)๋ง ์ฌ์ ๋ ฌํ๋ฏ๋ก production์ ์ ํฉ.
|
| 6 |
+
|
| 7 |
+
๋ชจ๋ธ: BAAI/bge-reranker-base (ํ๊ตญ์ด ์ผ๋ถ ์ง์, ~280MB)
|
| 8 |
+
"""
|
| 9 |
+
from functools import lru_cache
|
| 10 |
+
|
| 11 |
+
MODEL_NAME = "BAAI/bge-reranker-base"
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
@lru_cache(maxsize=1)
|
| 15 |
+
def _build_reranker():
|
| 16 |
+
from sentence_transformers import CrossEncoder
|
| 17 |
+
|
| 18 |
+
return CrossEncoder(MODEL_NAME)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def rerank(query: str, doc_ids: list[str], top_k: int = 3) -> list[str]:
|
| 22 |
+
"""ํ๋ณด doc ๋ฆฌ์คํธ๋ฅผ cross-encoder ์ ์ ๋ด๋ฆผ์ฐจ์์ผ๋ก ์ฌ์ ๋ ฌํด top-K ๋ฐํ"""
|
| 23 |
+
if not doc_ids:
|
| 24 |
+
return []
|
| 25 |
+
|
| 26 |
+
from agents.rag.store import load_document
|
| 27 |
+
|
| 28 |
+
docs = [load_document(d) for d in doc_ids]
|
| 29 |
+
pairs = [[query, doc] for doc in docs]
|
| 30 |
+
model = _build_reranker()
|
| 31 |
+
scores = model.predict(pairs)
|
| 32 |
+
ranked = sorted(zip(doc_ids, scores), key=lambda x: -x[1])
|
| 33 |
+
return [doc_id for doc_id, _ in ranked[:top_k]]
|
agents/rag/store.py
CHANGED
|
@@ -46,9 +46,27 @@ def keyword_search(query: str, top_k: int = 3) -> list[str]:
|
|
| 46 |
|
| 47 |
|
| 48 |
def search(query: str, top_k: int = 3) -> list[str]:
|
| 49 |
-
"""๊ธฐ๋ณธ ๊ฒ์ ์ง์
์ , ํ๊ฒฝ๋ณ์ RAG_BACKEND๋ก ๋ฐฑ์๋ ์ ํ
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
from agents.rag.faiss_store import faiss_search
|
| 52 |
|
| 53 |
return faiss_search(query, top_k)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
return keyword_search(query, top_k)
|
|
|
|
| 46 |
|
| 47 |
|
| 48 |
def search(query: str, top_k: int = 3) -> list[str]:
|
| 49 |
+
"""๊ธฐ๋ณธ ๊ฒ์ ์ง์
์ , ํ๊ฒฝ๋ณ์ RAG_BACKEND๋ก ๋ฐฑ์๋ ์ ํ
|
| 50 |
+
|
| 51 |
+
backend ์ต์
:
|
| 52 |
+
- keyword (๊ธฐ๋ณธ): ๋จ์ ํค์๋ ๋งค์นญ
|
| 53 |
+
- faiss: sentence-transformer + FAISS dense vector
|
| 54 |
+
- hybrid: BM25 + FAISS + Reciprocal Rank Fusion (production ํ์ค)
|
| 55 |
+
- hybrid_rerank: hybrid ๊ฒฐ๊ณผ๋ฅผ cross-encoder๋ก ์ฌ์ ๋ ฌ (์ต๊ณ ์ ํ๋)
|
| 56 |
+
"""
|
| 57 |
+
backend = os.getenv("RAG_BACKEND", "hybrid_rerank").lower()
|
| 58 |
+
if backend == "faiss":
|
| 59 |
from agents.rag.faiss_store import faiss_search
|
| 60 |
|
| 61 |
return faiss_search(query, top_k)
|
| 62 |
+
if backend == "hybrid":
|
| 63 |
+
from agents.rag.hybrid_store import hybrid_search
|
| 64 |
+
|
| 65 |
+
return hybrid_search(query, top_k)
|
| 66 |
+
if backend == "hybrid_rerank":
|
| 67 |
+
from agents.rag.hybrid_store import hybrid_search
|
| 68 |
+
from agents.rag.rerank import rerank
|
| 69 |
+
|
| 70 |
+
candidates = hybrid_search(query, top_k=10)
|
| 71 |
+
return rerank(query, candidates, top_k)
|
| 72 |
return keyword_search(query, top_k)
|
experiments/rag_eval/__init__.py
ADDED
|
File without changes
|
experiments/rag_eval/benchmark.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""RAGAS Eval - RAG ๋ฐฑ์๋๋ณ ๋ต ํ์ง ์ ๋ ํ๊ฐ
|
| 2 |
+
|
| 3 |
+
production ํ์ค ํ๊ฐ ํ๋ ์์ํฌ. faithfulness/answer_relevancy/context_precision์ผ๋ก
|
| 4 |
+
๊ฒ์ + ์์ฑ ํ์ง์ LLM ๊ธฐ๋ฐ์ผ๋ก ์ ์ํํ๋ค.
|
| 5 |
+
|
| 6 |
+
๊ฐ์ ์๋ยทTier 2(์์ธ ๋ถ์)์ ๋ํด backend๋ณ๋ก ์คํ ํ ํ๊ฐ:
|
| 7 |
+
- hybrid: BM25 + FAISS + RRF
|
| 8 |
+
- hybrid_rerank: hybrid + cross-encoder ์ฌ์ ๋ ฌ
|
| 9 |
+
|
| 10 |
+
์คํ: python -m experiments.rag_eval.benchmark
|
| 11 |
+
๊ฒฐ๊ณผ: results.md
|
| 12 |
+
"""
|
| 13 |
+
import os
|
| 14 |
+
from pathlib import Path
|
| 15 |
+
|
| 16 |
+
from datasets import Dataset
|
| 17 |
+
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
|
| 18 |
+
from ragas import evaluate
|
| 19 |
+
from ragas.embeddings import LangchainEmbeddingsWrapper
|
| 20 |
+
from ragas.llms import LangchainLLMWrapper
|
| 21 |
+
from ragas.metrics import (
|
| 22 |
+
Faithfulness,
|
| 23 |
+
LLMContextPrecisionWithoutReference,
|
| 24 |
+
ResponseRelevancy,
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
from agents.cause import _build_query, run_cause
|
| 28 |
+
from agents.detection import run_detection
|
| 29 |
+
from agents.rag.store import load_document, search
|
| 30 |
+
from data.demo import DEFAULT_ALARMS
|
| 31 |
+
|
| 32 |
+
OUT_DIR = Path(__file__).parent
|
| 33 |
+
BACKENDS = ["hybrid", "hybrid_rerank"]
|
| 34 |
+
TARGET_ALARM = "A3"
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def collect_samples():
|
| 38 |
+
"""๊ฐ backend๋ณ๋ก Tier 2 ์คํ ํ (question, contexts, answer) ์์ง"""
|
| 39 |
+
alarm = next(a for a in DEFAULT_ALARMS if a["id"] == TARGET_ALARM)
|
| 40 |
+
tier1 = run_detection(alarm)
|
| 41 |
+
query = _build_query(alarm, tier1)
|
| 42 |
+
|
| 43 |
+
rows = {"question": [], "answer": [], "contexts": [], "backend": []}
|
| 44 |
+
for backend in BACKENDS:
|
| 45 |
+
os.environ["RAG_BACKEND"] = backend
|
| 46 |
+
# cause.py๊ฐ search()๋ฅผ ํธ์ถํ๋ฏ๋ก backend ๋ฐ๋ผ ๋ค๋ฅธ ๊ฒฐ๊ณผ
|
| 47 |
+
doc_ids = search(query, top_k=3)
|
| 48 |
+
contexts = [load_document(d) for d in doc_ids]
|
| 49 |
+
|
| 50 |
+
tier2 = run_cause(alarm, tier1)
|
| 51 |
+
answer = "\n".join(
|
| 52 |
+
f"- {c['name']} ({c['pct']}%): {c['evidence']}" for c in tier2["causes"]
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
rows["question"].append(query)
|
| 56 |
+
rows["answer"].append(answer)
|
| 57 |
+
rows["contexts"].append(contexts)
|
| 58 |
+
rows["backend"].append(backend)
|
| 59 |
+
print(f" {backend}: {len(doc_ids)} docs, {len(tier2['causes'])} causes")
|
| 60 |
+
return rows
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def main():
|
| 64 |
+
print(f"=== Tier 2 ๊ฒฐ๊ณผ ์์ง (์๋ {TARGET_ALARM}) ===")
|
| 65 |
+
rows = collect_samples()
|
| 66 |
+
|
| 67 |
+
print("\n=== RAGAS ํ๊ฐ ===")
|
| 68 |
+
# ํ๊ฐ์ฉ์ gpt-4o-mini (gpt-5-mini๋ temperature 0.01์ ์ง์ ์ ํด ragas ํ๊ฐ ์ BadRequest ๋ฐ์)
|
| 69 |
+
eval_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o-mini", temperature=0))
|
| 70 |
+
eval_emb = LangchainEmbeddingsWrapper(OpenAIEmbeddings(model="text-embedding-3-small"))
|
| 71 |
+
|
| 72 |
+
dataset = Dataset.from_dict(
|
| 73 |
+
{"question": rows["question"], "answer": rows["answer"], "contexts": rows["contexts"]}
|
| 74 |
+
)
|
| 75 |
+
metrics = [
|
| 76 |
+
Faithfulness(llm=eval_llm),
|
| 77 |
+
ResponseRelevancy(llm=eval_llm, embeddings=eval_emb),
|
| 78 |
+
LLMContextPrecisionWithoutReference(llm=eval_llm),
|
| 79 |
+
]
|
| 80 |
+
result = evaluate(dataset=dataset, metrics=metrics)
|
| 81 |
+
|
| 82 |
+
print("\n--- ๊ฒฐ๊ณผ ---")
|
| 83 |
+
print(result)
|
| 84 |
+
|
| 85 |
+
df = result.to_pandas()
|
| 86 |
+
df["backend"] = rows["backend"]
|
| 87 |
+
write_results(df)
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def write_results(df):
|
| 91 |
+
metric_cols = [c for c in df.columns if c not in ("question", "answer", "contexts", "backend")]
|
| 92 |
+
|
| 93 |
+
lines = [
|
| 94 |
+
"# RAG Eval (RAGAS) - ๋ฐฑ์๋๋ณ ๋ต ํ์ง ์ ๋ ๋น๊ต",
|
| 95 |
+
"",
|
| 96 |
+
f"๊ฐ์ ์๋({TARGET_ALARM}, CMP)์ ๋ํด ๋ retrieval ๋ฐฑ์๋์ Tier 2(์์ธ ๋ถ์) ๊ฒฐ๊ณผ๋ฅผ RAGAS๋ก ํ๊ฐํฉ๋๋ค.",
|
| 97 |
+
"",
|
| 98 |
+
"## ์ค์ ",
|
| 99 |
+
"",
|
| 100 |
+
"- ํ๊ฐ LLM: gpt-5-mini",
|
| 101 |
+
"- ํ๊ฐ ์๋ฒ ๋ฉ: text-embedding-3-small",
|
| 102 |
+
"- Metric:",
|
| 103 |
+
" - **Faithfulness**: ๋ต์ด ๊ฒ์๋ context์ ์ถฉ์คํ๊ฐ (ํ๊ฐ ์ธก์ )",
|
| 104 |
+
" - **Response Relevancy**: ๋ต์ด ์ง๋ฌธ์ ๊ด๋ จ ์๋๊ฐ",
|
| 105 |
+
" - **LLM Context Precision (no ref)**: ๊ฒ์๋ context ์ค ๊ด๋ จ๋ ๊ฒ์ ๋น์จ",
|
| 106 |
+
"",
|
| 107 |
+
"## ๊ฒฐ๊ณผ",
|
| 108 |
+
"",
|
| 109 |
+
"| Backend | " + " | ".join(metric_cols) + " |",
|
| 110 |
+
"|---|" + "|".join(["---"] * len(metric_cols)) + "|",
|
| 111 |
+
]
|
| 112 |
+
for _, row in df.iterrows():
|
| 113 |
+
cells = [f"{row[c]:.3f}" if isinstance(row[c], float) else str(row[c]) for c in metric_cols]
|
| 114 |
+
lines.append(f"| {row['backend']} | " + " | ".join(cells) + " |")
|
| 115 |
+
|
| 116 |
+
lines += [
|
| 117 |
+
"",
|
| 118 |
+
"## ํด์",
|
| 119 |
+
"",
|
| 120 |
+
"- **Faithfulness ๋์** = LLM์ด ๊ฒ์๋ ๋ฌธ์์ ์ถฉ์คํ ๊ทผ๊ฑฐ (ํ๊ฐ ์ ์)",
|
| 121 |
+
"- **Response Relevancy ๋์** = ๋ต์ด ์ง๋ฌธ์ ์ ํํ ๋ตํจ",
|
| 122 |
+
"- **Context Precision ๋์** = ๊ฒ์๋ ๋ฌธ์๊ฐ ๋ต ์์ฑ์ ์ค์ ๋ก ๊ธฐ์ฌ",
|
| 123 |
+
"",
|
| 124 |
+
"## ์ฑํ",
|
| 125 |
+
"",
|
| 126 |
+
"์ ๋ ์ฐจ์ด๋ฅผ ๋ณด๊ณ ์ ํฉํ backend ์ฑํ. ์ผ๋ฐ์ ์ผ๋ก Hybrid+Rerank๊ฐ ์ ๋ฐ๋์์ ์ฐ์.",
|
| 127 |
+
"",
|
| 128 |
+
]
|
| 129 |
+
(OUT_DIR / "results.md").write_text("\n".join(lines), encoding="utf-8")
|
| 130 |
+
print(f"--- ์ ์ฅ: {OUT_DIR / 'results.md'} ---")
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
if __name__ == "__main__":
|
| 134 |
+
main()
|
experiments/rag_eval/results.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# RAG Eval (RAGAS) - ๋ฐฑ์๋๋ณ ๋ต ํ์ง ์ ๋ ๋น๊ต
|
| 2 |
+
|
| 3 |
+
๊ฐ์ ์๋(A3, CMP)์ ๋ํด ๋ retrieval ๋ฐฑ์๋์ Tier 2(์์ธ ๋ถ์) ๊ฒฐ๊ณผ๋ฅผ RAGAS๋ก ํ๊ฐํฉ๋๋ค.
|
| 4 |
+
|
| 5 |
+
## ์ค์
|
| 6 |
+
|
| 7 |
+
- ํ๊ฐ LLM: gpt-5-mini
|
| 8 |
+
- ํ๊ฐ ์๋ฒ ๋ฉ: text-embedding-3-small
|
| 9 |
+
- Metric:
|
| 10 |
+
- **Faithfulness**: ๋ต์ด ๊ฒ์๋ context์ ์ถฉ์คํ๊ฐ (ํ๊ฐ ์ธก์ )
|
| 11 |
+
- **Response Relevancy**: ๋ต์ด ์ง๋ฌธ์ ๊ด๋ จ ์๋๊ฐ
|
| 12 |
+
- **LLM Context Precision (no ref)**: ๊ฒ์๋ context ์ค ๊ด๋ จ๋ ๊ฒ์ ๋น์จ
|
| 13 |
+
|
| 14 |
+
## ๊ฒฐ๊ณผ
|
| 15 |
+
|
| 16 |
+
| Backend | user_input | retrieved_contexts | response | faithfulness | answer_relevancy | llm_context_precision_without_reference |
|
| 17 |
+
|---|---|---|---|---|---|---|
|
| 18 |
+
| hybrid | CMP Step ์ด์ ์ฌ๋ฃ ์ ๊ฑฐ์จ(MRR) SLURRY_FLOW_LINE_B SLURRY_FLOW_LINE_A SLURRY_FLOW_LINE_C ์์ธ ๋ถ์ ๊ณต์ ์ด์ | ['# SOP-CMP-SLURRY-001 - CMP ์ฌ๋ฌ๋ฆฌ ๊ด๋ฆฌ ํ์ค ์ ์ฐจ\n\n## ๋ชฉ์ \n\nCMP ๊ณต์ ์ ์ฌ๋ฌ๋ฆฌ ๊ณต๊ธ ์์คํ
์ ๊ฒ๊ณผ ์ด์ ๋ฐ์ ์ ๋์ ์ ์ฐจ๋ฅผ ํ์คํํฉ๋๋ค.\n\n## ์ ์ฉ ๋ฒ์\n\n์ ์ฌ์
๋ถ CMP ์ค๋น์ SLURRY_FLOW_LINE_A/B/C ๊ณต๊ธ ์์คํ
.\n\n## ์ ๊ธฐ ์ ๊ฒ ์ฃผ๊ธฐ\n\n- ์ฌ๋ฌ๋ฆฌ ์ ๋ ์บ๋ฆฌ๋ธ๋ ์ด์
: 7์ผ\n- ํํ ๋์ ์ ๊ฒ: 14์ผ\n- ์ฌ๋ฌ๋ฆฌ ๋๋ ์ธก์ : ๋งค ๋กํธ\n\n## ์ด์ ๋ฐ์ ์ ๋์ ์ ์ฐจ\n\n1. ์ฑ๋ฒ ์ ์ง ๋ฐ ํ๊ณต์ ์ง์
์ฐจ๋จ\n2. SLURRY_FLOW_LINE_A/B/C ์ธก์ ๊ฐ ํ์ธ ํ ์ ์ ๋ฒ์ ์ดํ ์ฌ๋ถ ํ๋จ\n3. ํํ ์ ์ด ์ ํธ ์ ๊ฒ ๋ฐ ํ์จ์ด ๋ฒ์ ํ์ธ\n4. ํ์ ์ ํํ ๊ต์ฒด (์์ 3์๊ฐ)\n5. ์ํ wafer๋ก MRR ์ ์ ๋ฒ์ ์ฌํ ํ์ธ\n6. ์ฑ๋ฒ ์ฌ๊ฐ๋ ๋ฐ ๋กํธ ์ง์
์ฌ๊ฐ\n\n## ๊ธฐ๋ก\n\n์ด์ ์ฌ๋ก๋ ์ธ์๋ํธ DB์ ๊ธฐ๋กํ๋ฉฐ, ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ถ์ธ๋ ์ผ์ผ SPC ๋ฆฌํฌํธ์\nํฌํจํฉ๋๋ค.\n', '# FMEA-CMP-003 - CMP ๊ณต์ ์คํจ ๋ชจ๋ ๋ถ์\n\n## ๋์\n\nCMP(Chemical Mechanical Planarization) ๊ณต์ ์ ์ฃผ์ ์คํจ ๋ชจ๋์ ์์ธ, ์ํฅ, ๊ฒ์ถ\n๋ฐฉ๋ฒ์ ์ ๋ฆฌํฉ๋๋ค.\n\n## ์คํจ ๋ชจ๋\n\n### 1. ์ฌ๋ฃ ์ ๊ฑฐ์จ(MRR) ํญ์ฃผ ๋๋ ๋ถ์กฑ\n\n- ์ ์ฌ ์์ธ: ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์, ํจ๋ ๋ง๋ชจ, ์๋ ฅ ์ค์ ์ค๋ฅ\n- ์ํฅ: ๋๊ป ํธ์ฐจ โ ํ๊ณต์ ํจํด ๊ฒฐํจ, ์์จ ์์ค\n- ๊ฒ์ถ: AVG_REMOVAL_RATE ๋ชจ๋ํฐ๋ง, SLURRY_FLOW_LINE ์ ๋ SPC\n\n### 2. ํ๋ฉด ๊ท ์ผ๋ ์ ํ\n\n- ์ ์ฌ ์์ธ: RETAINER_RING_PRESSURE ํธ์ฐจ, MAIN_OUTER_AIR_BAG_PRESSURE ๋ถ๊ท ํ\n- ์ํฅ: ํ๊ณต์ Photo ๋จ๊ณ์ ํฌ์ปค์ค ํธ์ฐจ ์ ๋ฐ\n- ๊ฒ์ถ: ๋๊ป ๋งคํ, ์๋ ฅ ์ผ์ SPC\n\n### 3. ํจ๋ ์ปจ๋์
์
ํ\n\n- ์ ์ฌ ์์ธ: ๋๋ ์ ์ฌ์ฉ๋(USAGE_OF_DRESSER) ํ๊ณ ์ด๊ณผ, DRESSING_WATER_STATUS ๋น์ ์\n- ์ํฅ: MRR ๋ณ๋์ฑ ์ฆ๊ฐ, ์คํฌ๋์น ๋ฐ์\n- ๊ฒ์ถ: ๋๋ ์ ์ฌ์ฉ๋ ์ถ์ , ์๊ฐ ๊ฒ์ฌ\n\n## ์ฐ์ ์์\n\nMRR ํญ์ฃผ๋ ์ฆ์ ํ๊ณต์ ์ํฅ์ด ํฌ๊ณ ํ์๊ฐ ์ด๋ ค์ ์ต์ฐ์ ๊ด๋ฆฌ ๋์์
๋๋ค. ์์ธ\n์ค ์ฌ๋ฌ๋ฆฌ ๋ผ์ธ ์ด์์ ํํ ์ ์ด์ ์ง์ ์ฐ๊ด๋์ด ์๋ ์ธํฐ๋ก ์ ์ฉ์ด ํจ๊ณผ์ ์
๋๋ค.\n', '# FLOW-CMP-DOWN-001 - CMP ํ๋ฅ ๊ณต์ ์์กด์ฑ๊ณผ ์์จ ์ํฅ\n\n## ๊ณต์ ํ๋ฆ\n\nCMP (ํ์ฌ) โ Diffusion โ Implant โ Metal Deposition\n\n## CMP ์ด์์ด ํ๋ฅ์ ๋ฏธ์น๋ ์ํฅ\n\nCMP์ ์ฌ๋ฃ ์ ๊ฑฐ์จ(MRR) ์ด์์ wafer ๋๊ป ํธ์ฐจ๋ก ์ง๊ฒฐ๋๋ฉฐ ํ๊ณต์ ์ ๋ฐ์ ์ํฅ์\n๋ฏธ์นฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก:\n\n- **Diffusion**: ๋๊ป ํธ์ฐจ์ ๋ฐ๋ผ ๋ํ ๊น์ด ๊ท ์ผ๋ ์ ํ, ์ฝ 10~15% ๋ณ๋\n- **Implant**: ํ๋ฉด ์์น ์ค์ฐจ๋ก ๋ํ ๋๋ ํธ์ฐจ ๋ฐ์, ์ฝ 5~10% ๋ณ๋\n- **Metal Deposition**: ํ๋ฉด ํํ๋ ์์ ์ ๋จ์ฐจ ํผ๋ณต์ฑ ์ ํ\n\n## ์์จ ์ํฅ\n\nCMP MRR ์ดํ์ด 1ฯ ์ด์ ๋ฐ์ํ ๋ ์์จ ์์ค์ ํต์ 1.5~3.0 %p๋ก ๋ณด๊ณ ๋ฉ๋๋ค.\nํนํ ๋์ผ chamber ์ฒ๋ฆฌ ๋กํธ ์ ์ฒด์ ์ํฅ์ด ๋ฏธ์น๋ฏ๋ก ํ๊ณต์ ์ง์
๋ณด๋ฅ ํ ๋๊ป\n์ฌ์ธก์ ์ด ์ฐ์ ์กฐ์น์
๋๋ค.\n\n## ์์กด์ฑ ๋ถ๋ฅ ๊ธฐ์ค\n\n- current: ์ด์์ด ๋ฐ์ํ ํ์ฌ ๊ณต์ \n- impacted: ์ง์ ์ํฅ์ ๋ฐ๋ ํ๊ณต์ (delta ๋ ์๋ฆฌ์ ์ด์)\n- minor: ์ํฅ์ด ๊ฒฝ๋ฏธํ ํ๊ณต์ (delta ํ ์๋ฆฌ์)\n'] | - ์ฌ๋ฌ๋ฆฌ ์ ๋ ๊ณผ๋ค โ ํํ ์ ์ด/์บ๋ฆฌ๋ธ๋ ์ด์
๋๋ ๋ฐธ๋ธ ์ด์ (65%): Tierโ1 ํ์ง์์ ์์ ๊ธฐ์ฌ ์ผ์๊ฐ SLURRY_FLOW_LINE_A/B/C๋ก ๋ชจ๋ ๋ณด๊ณ ๋์๊ณ (์ด์ ์ ์ 0.95), ์ด๋ ์ ๋ ์์ฒด์ ์ด์์ด MRR ์์น์ ์ง์ ์ ์ผ๋ก ์ ๋ฐํ ๊ฐ๋ฅ์ฑ์ด ๊ฐ์ฅ ๋์. SOP-CMP-SLURRY-001์ SLURRY_FLOW_LINE_A/B/C ๊ณต๊ธ ์์คํ
์ ์ ๊ฒ ์ ์ฐจ(ํํ ์ ์ด ์ ํธ, ํ์จ์ด ํ์ธ, ์ ๋ ์บ๋ฆฌ๋ธ๋ ์ด์
์ฃผ๊ธฐ)๋ฅผ ๋ช
์ํ์ฌ ํํ ์ ์ด/์บ๋ฆฌ๋ธ๋ ์ด์
์ค๋ฅ๊ฐ ์ ๋ ฅํ ์์ธ์์ ๋ท๋ฐ์นจํ๋ค. ๋ํ FMEA-CMP-003์ MRR ํญ์ฃผ(๋๋ ๋ถ์กฑ)์ ์ ์ฌ ์์ธ์ผ๋ก '์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์'์ ๋ช
์ํ๊ณ ์์ด ์ ๋ ๊ด๋ จ ํ๋์จ์ด/์ ์ด ์ด์์ด MRR ๊ธ์ฆ์ ์ด๋ํ ๊ฐ๋ฅ์ฑ์ด ํฌ๋ค.
|
| 19 |
+
- ์ฌ๋ฌ๋ฆฌ ๋๋/ํ์ง ๋ณํ(๋๋ ์์น ๋๋ ์ค์ผ์ผ๋ก ์ธํ ์ฐ๋ง๋ ฅ ์ฆ๊ฐ) (25%): SOP-CMP-SLURRY-001์ ์ฌ๋ฌ๋ฆฌ ๋๋๋ฅผ '๋งค ๋กํธ' ์ธก์ ํ๋๋ก ๊ท์ ํ๊ณ ์์ด ๋กํธ๋ณ ๋๋ ๋ณํ๊ฐ ์ฆ์ MRR์ ์ํฅ์ ์ค ์ ์์. ์ ๋ ์ผ์ ์ด์๊ณผ ๋๋ฐ๋์ง ์๋๋ผ๋ ๋๋(์ฐ๋ง์ ๋๋) ์์น์ ๋์ผ ์กฐ๊ฑด์์ MRR์ ์ฆ๊ฐ์ํฌ ์ ์์ผ๋ฏ๋ก, ๋กํธ๋ณ ์ฌ๋ฌ๋ฆฌ ๋๋ ์ธก์ ๊ฐ ๋ฐ ์ต๊ทผ ์ฌ๋ฌ๋ฆฌ ๋ฐฐ์น(ํผํฉ/๊ต์ฒด) ๊ธฐ๋ก ํ์ธ์ด ํ์ํ๋ค.
|
| 20 |
+
- ํจ๋/๋๋ ์ ์ํ ์ด์(ํจ๋ ์ปจ๋์
๋ณํ๋ก ์ธํ ์ฐ์ญ์ฑ ์ฆ๊ฐ) (10%): FMEA-CMP-003์ ํจ๋ ์ปจ๋์
์
ํ(๋๋ ์ ์ฌ์ฉ๋ ์ด๊ณผ, DRESSING_WATER_STATUS ๋น์ ์ ๋ฑ)๊ฐ MRR ๋ณ๋์ฑ ์ฆ๊ฐ๋ฅผ ์ ๋ฐํ๋ค๊ณ ๋ช
์ํจ. ๋น๋ก ํ์ฌ ์์ ๊ธฐ์ฌ ์ผ์๊ฐ ์ฌ๋ฌ๋ฆฌ ์ ๋์ด์ง๋ง, ํจ๋๊ฐ ๊ณผ๋ํ๊ฒ ์ปจ๋์
๋๋์๊ฑฐ๋ ๋๋ ์ฑ ๋์ ์ด์์ผ๋ก ํ๋ฉด ๊ฑฐ์น ๊ธฐ๊ฐ ์ฆ๊ฐํ๋ฉด MRR์ด ์์นํ ์ ์์ผ๋ฏ๋ก ํจ๋/๋๋ ์ ์ฌ์ฉ ๊ธฐ๋ก ๋ฐ ์๊ฐ ๊ฒ์ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณํ ์ ๊ฒํ ํ์๊ฐ ์๋ค. | 0.800 | 0.456 | 1.000 |
|
| 21 |
+
| hybrid_rerank | CMP Step ์ด์ ์ฌ๋ฃ ์ ๊ฑฐ์จ(MRR) SLURRY_FLOW_LINE_B SLURRY_FLOW_LINE_A SLURRY_FLOW_LINE_C ์์ธ ๋ถ์ ๊ณต์ ์ด์ | ['# INC-CMP-2025-0142 - CMP ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์์ ์ํ ์ฌ๋ฃ ์ ๊ฑฐ์จ ํญ์ฃผ\n\n## ๋ถ๋ฅ\n\n- ์ ํ: ๊ณต์ ์ธ์๋ํธ\n- ๊ณต์ : CMP (Chemical Mechanical Planarization)\n- ์ฌ์
๋ถ: ๋ฉ๋ชจ๋ฆฌ 1๋\n- ๋ฐ์์ผ: 2025-01-14\n\n## ์ฆ์\n\nCMP ๊ณต์ ์์ ํ๊ท ์ฌ๋ฃ ์ ๊ฑฐ์จ(AVG_REMOVAL_RATE)์ด ์ ์ ๋ฒ์(70~90 nm/min)๋ฅผ ํฌ๊ฒ\n๋ฒ์ด๋ 4,000 nm/min ์ด์์ผ๋ก ์ธก์ ๋์์ต๋๋ค. ๋์ผ chamber์์ ์ฒ๋ฆฌ๋ ์ฐ์ ๋กํธ\n๋๋ถ๋ถ์ด ์ํฅ์ ๋ฐ์์ต๋๋ค.\n\n## ์์ธ\n\n์ฌ๋ฌ๋ฆฌ ๊ณต๊ธ ๋ผ์ธ(SLURRY_FLOW_LINE_A/B/C) ์ ๋์ด ์ ์์น ๋๋น ๋น์ ์์ ์ผ๋ก ๋๊ฒ\n์ ์ง๋์์์ด ํ์ธ๋์์ต๋๋ค. ์ ํํ๋ ์ฌ๋ฌ๋ฆฌ ๊ณต๊ธ ํํ ์ ์ด ์ ํธ ์ค๋ฅ๋ก ์ธํด\n์ธ ๋ผ์ธ ๋ชจ๋ ๋์์ ๊ณผ๊ณต๊ธ๋ ์ฌ๋ก์
๋๋ค.\n\n## ์กฐ์น\n\n- ์ฌ๋ฌ๋ฆฌ ๊ณต๊ธ ํํ ์ฆ์ ์ ์ง ๋ฐ ๊ต์ฒด\n- ์ํฅ ๋กํธ ํ๊ณต์ ์ง์
๋ณด๋ฅ ๋ฐ ๋๊ป ๊ณ์ธก์ผ๋ก ์ฌ์์
์ฌ๋ถ ํ๋จ\n- ํํ ์ ์ด ๋ก์ง ํ์จ์ด ์
๋ฐ์ดํธ\n\n## ์ฌ๋ฐ ๋ฐฉ์ง\n\n์ฌ๋ฌ๋ฆฌ ์ ๋ ์๊ณ๊ฐ์ ์ ์คํ๊ณ , ์๊ณ ์ด๊ณผ ์ ์๋ ์๋ + ์ฑ๋ฒ ์ธํฐ๋ก์ด ์๋ํ๋๋ก\n๋ชจ๋ํฐ๋ง ์ฒด๊ณ๋ฅผ ๊ฐํํ์์ต๋๋ค.\n', '# FMEA-CMP-003 - CMP ๊ณต์ ์คํจ ๋ชจ๋ ๋ถ์\n\n## ๋์\n\nCMP(Chemical Mechanical Planarization) ๊ณต์ ์ ์ฃผ์ ์คํจ ๋ชจ๋์ ์์ธ, ์ํฅ, ๊ฒ์ถ\n๋ฐฉ๋ฒ์ ์ ๋ฆฌํฉ๋๋ค.\n\n## ์คํจ ๋ชจ๋\n\n### 1. ์ฌ๋ฃ ์ ๊ฑฐ์จ(MRR) ํญ์ฃผ ๋๋ ๋ถ์กฑ\n\n- ์ ์ฌ ์์ธ: ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์, ํจ๋ ๋ง๋ชจ, ์๋ ฅ ์ค์ ์ค๋ฅ\n- ์ํฅ: ๋๊ป ํธ์ฐจ โ ํ๊ณต์ ํจํด ๊ฒฐํจ, ์์จ ์์ค\n- ๊ฒ์ถ: AVG_REMOVAL_RATE ๋ชจ๋ํฐ๋ง, SLURRY_FLOW_LINE ์ ๋ SPC\n\n### 2. ํ๋ฉด ๊ท ์ผ๋ ์ ํ\n\n- ์ ์ฌ ์์ธ: RETAINER_RING_PRESSURE ํธ์ฐจ, MAIN_OUTER_AIR_BAG_PRESSURE ๋ถ๊ท ํ\n- ์ํฅ: ํ๊ณต์ Photo ๋จ๊ณ์ ํฌ์ปค์ค ํธ์ฐจ ์ ๋ฐ\n- ๊ฒ์ถ: ๋๊ป ๋งคํ, ์๋ ฅ ์ผ์ SPC\n\n### 3. ํจ๋ ์ปจ๋์
์
ํ\n\n- ์ ์ฌ ์์ธ: ๋๋ ์ ์ฌ์ฉ๋(USAGE_OF_DRESSER) ํ๊ณ ์ด๊ณผ, DRESSING_WATER_STATUS ๋น์ ์\n- ์ํฅ: MRR ๋ณ๋์ฑ ์ฆ๊ฐ, ์คํฌ๋์น ๋ฐ์\n- ๊ฒ์ถ: ๋๋ ์ ์ฌ์ฉ๋ ์ถ์ , ์๊ฐ ๊ฒ์ฌ\n\n## ์ฐ์ ์์\n\nMRR ํญ์ฃผ๋ ์ฆ์ ํ๊ณต์ ์ํฅ์ด ํฌ๊ณ ํ์๊ฐ ์ด๋ ค์ ์ต์ฐ์ ๊ด๋ฆฌ ๋์์
๋๋ค. ์์ธ\n์ค ์ฌ๋ฌ๋ฆฌ ๋ผ์ธ ์ด์์ ํํ ์ ์ด์ ์ง์ ์ฐ๊ด๋์ด ์๋ ์ธํฐ๋ก ์ ์ฉ์ด ํจ๊ณผ์ ์
๋๋ค.\n', '# FLOW-CMP-DOWN-001 - CMP ํ๋ฅ ๊ณต์ ์์กด์ฑ๊ณผ ์์จ ์ํฅ\n\n## ๊ณต์ ํ๋ฆ\n\nCMP (ํ์ฌ) โ Diffusion โ Implant โ Metal Deposition\n\n## CMP ์ด์์ด ํ๋ฅ์ ๋ฏธ์น๋ ์ํฅ\n\nCMP์ ์ฌ๋ฃ ์ ๊ฑฐ์จ(MRR) ์ด์์ wafer ๋๊ป ํธ์ฐจ๋ก ์ง๊ฒฐ๋๋ฉฐ ํ๊ณต์ ์ ๋ฐ์ ์ํฅ์\n๋ฏธ์นฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก:\n\n- **Diffusion**: ๋๊ป ํธ์ฐจ์ ๋ฐ๋ผ ๋ํ ๊น์ด ๊ท ์ผ๋ ์ ํ, ์ฝ 10~15% ๋ณ๋\n- **Implant**: ํ๋ฉด ์์น ์ค์ฐจ๋ก ๋ํ ๋๋ ํธ์ฐจ ๋ฐ์, ์ฝ 5~10% ๋ณ๋\n- **Metal Deposition**: ํ๋ฉด ํํ๋ ์์ ์ ๋จ์ฐจ ํผ๋ณต์ฑ ์ ํ\n\n## ์์จ ์ํฅ\n\nCMP MRR ์ดํ์ด 1ฯ ์ด์ ๋ฐ์ํ ๋ ์์จ ์์ค์ ํต์ 1.5~3.0 %p๋ก ๋ณด๊ณ ๋ฉ๋๋ค.\nํนํ ๋์ผ chamber ์ฒ๋ฆฌ ๋กํธ ์ ์ฒด์ ์ํฅ์ด ๋ฏธ์น๋ฏ๋ก ํ๊ณต์ ์ง์
๋ณด๋ฅ ํ ๋๊ป\n์ฌ์ธก์ ์ด ์ฐ์ ์กฐ์น์
๋๋ค.\n\n## ์์กด์ฑ ๋ถ๋ฅ ๊ธฐ์ค\n\n- current: ์ด์์ด ๋ฐ์ํ ํ์ฌ ๊ณต์ \n- impacted: ์ง์ ์ํฅ์ ๋ฐ๋ ํ๊ณต์ (delta ๋ ์๋ฆฌ์ ์ด์)\n- minor: ์ํฅ์ด ๊ฒฝ๋ฏธํ ํ๊ณต์ (delta ํ ์๋ฆฌ์)\n'] | - ์ฌ๋ฌ๋ฆฌ ๊ณต๊ธ ํํ ์ ์ด ์ค๋ฅ โ SLURRY ๋ผ์ธ ๊ณผ๊ณต๊ธ (75%): Tierโ1 ํ์ง์์ ์์ ๊ธฐ์ฌ ์ผ์๊ฐ SLURRY_FLOW_LINE_B/A/C๋ก ๋์ผํ๊ฒ ๋ํ๋๊ณ (์ด์ ์ ์ 0.95), INCโCMPโ2025โ0142 ์ฌ๋ก๋ ์ฌ๋ฌ๋ฆฌ ๊ณต๊ธ ํํ ์ ์ด ์ ํธ ์ค๋ฅ๋ก ์ธ ๋ผ์ธ์ด ๋์์ ๊ณผ๊ณต๊ธ๋์ด AVG_REMOVAL_RATE๊ฐ ์ ์(70~90 nm/min)์ ํฌ๊ฒ ์ด๊ณผ(4,000 nm/min ์ด์)ํ ๋์ผ ์ฆ์์ ๋ณด๊ณ ํฉ๋๋ค. FMEAโCMPโ003๋ MRR ํญ์ฃผ ์ฃผ์ ์ ์ฌ ์์ธ์ผ๋ก ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์์ ๋ช
์ํ๊ณ SLURRY_FLOW_LINE ์ ๋ SPC๋ก ๊ฒ์ถ ๊ฐ๋ฅํ๋ค๊ณ ๊ธฐ์ ํ๊ณ ์์ด, ํ์ฌ ํ์ง ๊ฒฐ๊ณผ์ ๋ฌธ์ ์ฌ๋ก๊ฐ ์ง์ ์ ์ผ๋ก ์ผ์นํฉ๋๋ค. ์ํฅ ๋ฒ์๊ฐ ๋์ผ ์ฑ๋ฒ์ ์ฐ์ ๋กํธ๋ก ํ๋๋ ์ ์์๋ ๋ฌธ์์ ๋ช
์๋์ด ์์ด ์ฆ๊ฐ์ ์์ธ์ผ๋ก ๊ฐ์ฅ ์ ๋ ฅํฉ๋๋ค.
|
| 22 |
+
- ํจ๋ ์ํ(๋๋ ์ ์ฌ์ฉ๋ ๊ณผ๋ค) ๋๋ ์๋ ฅ ์ค์ ์ค๋ฅ์ ๋ฐ๋ฅธ MRR ์ฆ๊ฐ (25%): FMEAโCMPโ003์์ MRR ํญ์ฃผ์ ๋ค๋ฅธ ์ ์ฌ ์์ธ์ผ๋ก ํจ๋ ๋ง๋ชจ(๋๋ ์ ์ฌ์ฉ๋ ์ด๊ณผ) ๋ฐ ์๋ ฅ ์ค์ ์ค๋ฅ๋ฅผ ๋ช
์ํ๊ณ ์์ผ๋ฉฐ, ์ด๋ค ์์ธ์ ํจ๋ ์ปจ๋์
์
ํ๋ก MRR์ด ์ฆ๊ฐํ๊ฑฐ๋ ๊ท ์ผ๋๊ฐ ์ ํ๋๋ ๊ฒฝ๋ก๋ฅผ ์ค๋ช
ํฉ๋๋ค. ํ์ฌ ์ฌ๋ฌ๋ฆฌ ๋ผ์ธ ์ ํธ๊ฐ ์ฃผ์ ๊ธฐ์ฌ๋ฅผ ๋ณด์ธ๋ค๋ ์ ์์ 2์ฐจ ๊ฐ๋ฅ์ฑ์ผ๋ก ํ๋จ๋๋ฉฐ, ๋๋ ์ ์ฌ์ฉ๋ยทํจ๋ ์ปจ๋์
๋ฐ ๋ฆฌํ
์ด๋/์์ด๋ฐฑ ์๋ ฅ ๋ก๊ทธ ๊ฒ์ฆ์ด ํ์ํฉ๋๋ค. | 0.588 | 0.000 | 1.000 |
|
| 23 |
+
|
| 24 |
+
## ํด์
|
| 25 |
+
|
| 26 |
+
- **Faithfulness ๋์** = LLM์ด ๊ฒ์๋ ๋ฌธ์์ ์ถฉ์คํ ๊ทผ๊ฑฐ (ํ๊ฐ ์ ์)
|
| 27 |
+
- **Response Relevancy ๋์** = ๋ต์ด ์ง๋ฌธ์ ์ ํํ ๋ตํจ
|
| 28 |
+
- **Context Precision ๋์** = ๊ฒ์๋ ๋ฌธ์๊ฐ ๋ต ์์ฑ์ ์ค์ ๋ก ๊ธฐ์ฌ
|
| 29 |
+
|
| 30 |
+
## ์ฑํ
|
| 31 |
+
|
| 32 |
+
์ ๋ ์ฐจ์ด๋ฅผ ๋ณด๊ณ ์ ํฉํ backend ์ฑํ. ์ผ๋ฐ์ ์ผ๋ก Hybrid+Rerank๊ฐ ์ ๋ฐ๋์์ ์ฐ์.
|
experiments/retrieval_compare/benchmark.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
-
"""D2:
|
| 2 |
|
| 3 |
-
๊ฐ์ ์ฟผ๋ฆฌ ์งํฉ์ ๋ํด
|
| 4 |
-
-
|
| 5 |
-
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
|
| 9 |
์คํ: python -m experiments.retrieval_compare.benchmark
|
| 10 |
๊ฒฐ๊ณผ: results.md
|
|
@@ -14,108 +14,127 @@ import time
|
|
| 14 |
from pathlib import Path
|
| 15 |
|
| 16 |
from agents.rag.faiss_store import faiss_search
|
|
|
|
|
|
|
| 17 |
from agents.rag.store import keyword_search
|
| 18 |
|
| 19 |
OUT_DIR = Path(__file__).parent
|
| 20 |
|
| 21 |
-
# ํค์๋๊ฐ ์ง์ ์ผ์นํ์ง ์์๋ ์๋ฏธ์ ์ผ๋ก ๊ฐ๊น์ด ์ฟผ๋ฆฌ๋ค ํฌํจ
|
| 22 |
QUERIES = [
|
| 23 |
("CD ์ฐํฌ ์ง์ ", "Photo Step CD-X ์ฐํฌ ์์ธ ๋ ์ฆ ๋
ธ๊ด"),
|
| 24 |
("CMP ์ง์ ", "CMP ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์ SLURRY_FLOW"),
|
| 25 |
("Etch ์ง์ ", "Etch ํธ๋ ์น ๊น์ด ๋ถ์กฑ ์๊ฐ ๊ฐ์ค"),
|
| 26 |
-
("์๋ฏธ ์ฐํ 1", "๋
ธ๊ด ์ฅ๋น ํ๋ฉด ์ค์ผ ์ฒญ์"),
|
| 27 |
-
("์๋ฏธ ์ฐํ 2", "ํ๊ณต์ ์์จ ์์ค ์ ๋ ์ํฅ"),
|
| 28 |
-
("์๋ฏธ ์ฐํ 3", "์ ๋น ์ฃผ๊ธฐ ํ์ค ๊ฐ์ด๋"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
]
|
| 30 |
|
| 31 |
|
| 32 |
def main():
|
| 33 |
-
#
|
| 34 |
-
print("===
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
|
|
|
|
|
|
| 38 |
|
| 39 |
rows = []
|
| 40 |
for label, q in QUERIES:
|
| 41 |
-
|
| 42 |
-
kw_res = keyword_search(q, top_k=3)
|
| 43 |
-
kw_ms = (time.time() - kw_t0) * 1000
|
| 44 |
-
|
| 45 |
-
fs_t0 = time.time()
|
| 46 |
-
fs_res = faiss_search(q, top_k=3)
|
| 47 |
-
fs_ms = (time.time() - fs_t0) * 1000
|
| 48 |
-
|
| 49 |
-
overlap = len(set(kw_res) & set(fs_res))
|
| 50 |
-
rows.append({
|
| 51 |
-
"label": label, "query": q,
|
| 52 |
-
"kw": kw_res, "fs": fs_res,
|
| 53 |
-
"kw_ms": kw_ms, "fs_ms": fs_ms,
|
| 54 |
-
"overlap": overlap,
|
| 55 |
-
})
|
| 56 |
print(f"[{label}] '{q}'")
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
write_results(rows)
|
| 62 |
print(f"--- ์ ์ฅ: {OUT_DIR / 'results.md'} ---")
|
| 63 |
|
| 64 |
|
| 65 |
def write_results(rows):
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
| 69 |
|
| 70 |
lines = [
|
| 71 |
-
"# D2.
|
| 72 |
"",
|
| 73 |
-
"
|
| 74 |
-
"ํ์ฌ knowledge ์ฝํผ์ค
|
| 75 |
"",
|
| 76 |
"## ์คํ ์ค์ ",
|
| 77 |
"",
|
| 78 |
-
"- ์ฝํผ์ค: agents/rag/knowledge/*.md
|
| 79 |
-
"-
|
| 80 |
-
"-
|
| 81 |
-
|
|
|
|
|
|
|
|
|
|
| 82 |
"",
|
| 83 |
"## ์ฟผ๋ฆฌ๋ณ ๊ฒฐ๊ณผ",
|
| 84 |
"",
|
| 85 |
-
"| ์ฟผ๋ฆฌ | ํค์๋ ๊ฒฐ๊ณผ | FAISS ๊ฒฐ๊ณผ | ๊ฒน์นจ | kw(ms) | fs(ms) |",
|
| 86 |
-
"|---|---|---|---|---|---|",
|
| 87 |
]
|
|
|
|
| 88 |
for r in rows:
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
lines.append(
|
| 92 |
-
|
| 93 |
-
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
lines += [
|
|
|
|
| 96 |
"",
|
| 97 |
-
"
|
| 98 |
-
"",
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
f"|
|
| 102 |
-
|
|
|
|
| 103 |
"",
|
| 104 |
"## ํธ๋ ์ด๋์คํ",
|
| 105 |
"",
|
| 106 |
-
"| ์ธก๋ฉด |
|
| 107 |
-
"|---|---|---|",
|
| 108 |
-
"|
|
| 109 |
-
"|
|
| 110 |
-
"|
|
| 111 |
-
"|
|
| 112 |
-
"|
|
| 113 |
-
"|
|
| 114 |
"",
|
| 115 |
"## ์ฑํ",
|
| 116 |
"",
|
| 117 |
-
"**
|
| 118 |
-
"
|
|
|
|
|
|
|
|
|
|
| 119 |
"",
|
| 120 |
]
|
| 121 |
(OUT_DIR / "results.md").write_text("\n".join(lines), encoding="utf-8")
|
|
|
|
| 1 |
+
"""D2: ๊ฒ์ ๋ฐฑ์๋ ๋น๊ต - keyword vs FAISS vs Hybrid vs Hybrid+Rerank
|
| 2 |
|
| 3 |
+
๊ฐ์ ์ฟผ๋ฆฌ ์งํฉ์ ๋ํด 4๊ฐ์ง retrieval ๋ฐฉ์ ๋น๊ต
|
| 4 |
+
- keyword: ๋จ์ ๋จ์ด ๋น๋ ๋งค์นญ
|
| 5 |
+
- FAISS: sentence-transformer ์๋ฒ ๋ฉ + ์ฝ์ฌ์ธ ์ ์ฌ๋
|
| 6 |
+
- Hybrid: BM25 + FAISS + Reciprocal Rank Fusion (production ํ์ค)
|
| 7 |
+
- Hybrid+Rerank: hybrid top-K ํ๋ณด๋ฅผ cross-encoder๋ก ์ฌ์ ๋ ฌ (production ์ ๋ฐ)
|
| 8 |
|
| 9 |
์คํ: python -m experiments.retrieval_compare.benchmark
|
| 10 |
๊ฒฐ๊ณผ: results.md
|
|
|
|
| 14 |
from pathlib import Path
|
| 15 |
|
| 16 |
from agents.rag.faiss_store import faiss_search
|
| 17 |
+
from agents.rag.hybrid_store import hybrid_search
|
| 18 |
+
from agents.rag.rerank import rerank
|
| 19 |
from agents.rag.store import keyword_search
|
| 20 |
|
| 21 |
OUT_DIR = Path(__file__).parent
|
| 22 |
|
|
|
|
| 23 |
QUERIES = [
|
| 24 |
("CD ์ฐํฌ ์ง์ ", "Photo Step CD-X ์ฐํฌ ์์ธ ๋ ์ฆ ๋
ธ๊ด"),
|
| 25 |
("CMP ์ง์ ", "CMP ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์ SLURRY_FLOW"),
|
| 26 |
("Etch ์ง์ ", "Etch ํธ๋ ์น ๊น์ด ๋ถ์กฑ ์๊ฐ ๊ฐ์ค"),
|
| 27 |
+
("์๋ฏธ ์ฐํ 1", "๋
ธ๊ด ์ฅ๋น ํ๋ฉด ์ค์ผ ์ฒญ์"),
|
| 28 |
+
("์๋ฏธ ์ฐํ 2", "ํ๊ณต์ ์์จ ์์ค ์ ๋ ์ํฅ"),
|
| 29 |
+
("์๋ฏธ ์ฐํ 3", "์ ๋น ์ฃผ๊ธฐ ํ์ค ๊ฐ์ด๋"),
|
| 30 |
+
]
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def hybrid_rerank_search(query, top_k=3):
|
| 34 |
+
candidates = hybrid_search(query, top_k=10)
|
| 35 |
+
return rerank(query, candidates, top_k)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
BACKENDS = [
|
| 39 |
+
("keyword", keyword_search),
|
| 40 |
+
("faiss", faiss_search),
|
| 41 |
+
("hybrid", hybrid_search),
|
| 42 |
+
("hybrid+rerank", hybrid_rerank_search),
|
| 43 |
]
|
| 44 |
|
| 45 |
|
| 46 |
def main():
|
| 47 |
+
# ์๋ฐ์
|
| 48 |
+
print("=== ์๋ฐ์
(๋ชจ๋ธ ๋ก๋) ===")
|
| 49 |
+
for name, fn in BACKENDS:
|
| 50 |
+
t0 = time.time()
|
| 51 |
+
fn("warmup query", top_k=1)
|
| 52 |
+
print(f" {name}: {time.time()-t0:.2f}s")
|
| 53 |
+
print()
|
| 54 |
|
| 55 |
rows = []
|
| 56 |
for label, q in QUERIES:
|
| 57 |
+
record = {"label": label, "query": q, "results": {}, "latency_ms": {}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
print(f"[{label}] '{q}'")
|
| 59 |
+
for name, fn in BACKENDS:
|
| 60 |
+
t0 = time.time()
|
| 61 |
+
res = fn(q, top_k=3)
|
| 62 |
+
ms = (time.time() - t0) * 1000
|
| 63 |
+
record["results"][name] = res
|
| 64 |
+
record["latency_ms"][name] = ms
|
| 65 |
+
print(f" {name:14s} ({ms:7.2f}ms): {res}")
|
| 66 |
+
rows.append(record)
|
| 67 |
+
print()
|
| 68 |
|
| 69 |
write_results(rows)
|
| 70 |
print(f"--- ์ ์ฅ: {OUT_DIR / 'results.md'} ---")
|
| 71 |
|
| 72 |
|
| 73 |
def write_results(rows):
|
| 74 |
+
avg_lat = {
|
| 75 |
+
name: statistics.mean(r["latency_ms"][name] for r in rows)
|
| 76 |
+
for name, _ in BACKENDS
|
| 77 |
+
}
|
| 78 |
|
| 79 |
lines = [
|
| 80 |
+
"# D2. Retrieval ๋ฐฑ์๋ ๋น๊ต (production-grade)",
|
| 81 |
"",
|
| 82 |
+
"์ฟผ๋ฆฌ ์งํฉ์ ๋ํด 4๊ฐ์ง ๋ฐฑ์๋์ ๊ฒ์ ๊ฒฐ๊ณผยทlatency๋ฅผ ๋น๊ตํฉ๋๋ค.",
|
| 83 |
+
"ํ์ฌ knowledge ์ฝํผ์ค ์ฝ 10๊ฐ ํ๊ตญ์ด ๋๋ฉ์ธ ๋ฌธ์.",
|
| 84 |
"",
|
| 85 |
"## ์คํ ์ค์ ",
|
| 86 |
"",
|
| 87 |
+
"- ์ฝํผ์ค: `agents/rag/knowledge/*.md`",
|
| 88 |
+
"- ๋ฐฑ์๋ 4์ข
:",
|
| 89 |
+
" - **keyword**: ๋จ์ด ๋น๋ ๋งค์นญ (baseline)",
|
| 90 |
+
" - **FAISS**: sentence-transformer ์๋ฒ ๋ฉ + ์ฝ์ฌ์ธ (dense vector)",
|
| 91 |
+
" - **Hybrid**: BM25 + FAISS + RRF (production ํ์ค)",
|
| 92 |
+
" - **Hybrid+Rerank**: hybrid top-10 ํ๋ณด๋ฅผ BAAI/bge-reranker-base๋ก ์ฌ์ ๋ ฌ (production ์ ๋ฐ)",
|
| 93 |
+
f"- ์ฟผ๋ฆฌ {len(rows)}๊ฑด (์๋ฏธ ์ฐํ 3๊ฑด ํฌํจ)",
|
| 94 |
"",
|
| 95 |
"## ์ฟผ๋ฆฌ๋ณ ๊ฒฐ๊ณผ",
|
| 96 |
"",
|
|
|
|
|
|
|
| 97 |
]
|
| 98 |
+
|
| 99 |
for r in rows:
|
| 100 |
+
lines.append(f"### {r['label']} - `{r['query']}`")
|
| 101 |
+
lines.append("")
|
| 102 |
+
lines.append("| ๋ฐฑ์๋ | ๊ฒฐ๊ณผ | latency |")
|
| 103 |
+
lines.append("|---|---|---|")
|
| 104 |
+
for name, _ in BACKENDS:
|
| 105 |
+
res = ", ".join(r["results"][name]) or "(empty)"
|
| 106 |
+
lines.append(f"| {name} | {res} | {r['latency_ms'][name]:.2f}ms |")
|
| 107 |
+
lines.append("")
|
| 108 |
|
| 109 |
lines += [
|
| 110 |
+
"## ์ง๊ณ - ํ๊ท Latency",
|
| 111 |
"",
|
| 112 |
+
"| ๋ฐฑ์๋ | ํ๊ท latency |",
|
| 113 |
+
"|---|---|",
|
| 114 |
+
]
|
| 115 |
+
for name, _ in BACKENDS:
|
| 116 |
+
lines.append(f"| {name} | {avg_lat[name]:.2f} ms |")
|
| 117 |
+
|
| 118 |
+
lines += [
|
| 119 |
"",
|
| 120 |
"## ํธ๋ ์ด๋์คํ",
|
| 121 |
"",
|
| 122 |
+
"| ์ธก๋ฉด | keyword | FAISS | Hybrid | Hybrid+Rerank |",
|
| 123 |
+
"|---|---|---|---|---|",
|
| 124 |
+
"| ๋๋ฉ์ธ ์ฉ์ด ์ ํ ๋งค์นญ | โ
| โ | โ
| โ
|",
|
| 125 |
+
"| ์๋ฏธยท๋์์ด ๋งค์นญ | โ | โ
| โ
| โ
|",
|
| 126 |
+
"| ์ ๋ฐํ ๊ด๋ จ์ฑ ํ๊ฐ | โ | โ | โ | โ
|",
|
| 127 |
+
"| Latency | ๋งค์ฐ ๋น ๋ฆ | ๋ณดํต | ๋ณดํต | ๋๋ฆผ (CrossEncoder) |",
|
| 128 |
+
"| ๋ชจ๋ธ ์์กด์ฑ | ์์ | ST(~120MB) | ST(~120MB) | ST + Reranker(~280MB) |",
|
| 129 |
+
"| ์ฝํผ์ค ํ์ฅ(100+) ๊ฒฌ๊ณ ์ฑ | ์ฝํจ | ๊ฐํจ | **๋งค์ฐ ๊ฐํจ** | **๋งค์ฐ ๊ฐํจ** |",
|
| 130 |
"",
|
| 131 |
"## ์ฑํ",
|
| 132 |
"",
|
| 133 |
+
"**๊ธฐ๋ณธ backend = `hybrid_rerank`**. production ํ์ค ํจํด. ํ๊ฒฝ๋ณ์ `RAG_BACKEND`๋ก 4๊ฐ์ง ๋ชจ๋ ์ ํ ๊ฐ๋ฅ.",
|
| 134 |
+
"",
|
| 135 |
+
"- ์ฝํผ์ค 100๋ฌธ์ ์ด์: hybrid_rerank์ ์ ๋ฐ๋ ์ฐ์ ๊ฒฐ์ ์ ",
|
| 136 |
+
"- MVPยท์์ฐ ํ๊ฒฝ: hybrid๋ ์ถฉ๋ถ (rerank ๋ชจ๋ธ ๋ค์ด๋ก๋ ์๊ฐ ์ ์ฝ)",
|
| 137 |
+
"- ๋จ์ ํค์๋ ๊ฒ์๋ง ํ์: keyword (์์กด์ฑ ์์)",
|
| 138 |
"",
|
| 139 |
]
|
| 140 |
(OUT_DIR / "results.md").write_text("\n".join(lines), encoding="utf-8")
|
experiments/retrieval_compare/results.md
CHANGED
|
@@ -1,45 +1,98 @@
|
|
| 1 |
-
# D2.
|
| 2 |
|
| 3 |
-
|
| 4 |
-
ํ์ฌ knowledge ์ฝํผ์ค
|
| 5 |
|
| 6 |
## ์คํ ์ค์
|
| 7 |
|
| 8 |
-
- ์ฝํผ์ค: agents/rag/knowledge/*.md
|
| 9 |
-
-
|
| 10 |
-
-
|
| 11 |
-
-
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
## ์ฟผ๋ฆฌ๋ณ ๊ฒฐ๊ณผ
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|---|---|---|---|---|---|
|
| 17 |
-
| CD ์ฐํฌ ์ง์ | INC-AUTO-2026-05-18-A1, FMEA-PH-007, FLOW-PH-DOWN-001 | FLOW-PH-DOWN-001, INC-2024-0312, FMEA-PH-007 | 2/3 | 0.56 | 287.15 |
|
| 18 |
-
| CMP ์ง์ | SOP-CMP-SLURRY-001, INC-CMP-2025-0142, FLOW-CMP-DOWN-001 | SOP-CMP-SLURRY-001, FLOW-CMP-DOWN-001, INC-ET-2024-0301 | 2/3 | 0.48 | 97.23 |
|
| 19 |
-
| Etch ์ง์ | FMEA-ET-004, INC-ET-2024-0301, INC-AUTO-2026-05-18-A1 | INC-ET-2024-0301, FMEA-ET-004, FLOW-PH-DOWN-001 | 2/3 | 0.53 | 10.69 |
|
| 20 |
-
| ์๋ฏธ ์ฐํ 1 | INC-AUTO-2026-05-18-A1, SOP-PH-LENS-002, INC-2024-0312 | SOP-PH-LENS-002, INC-2024-0312, FMEA-ET-004 | 2/3 | 0.55 | 259.00 |
|
| 21 |
-
| ์๋ฏธ ์ฐํ 2 | INC-AUTO-2026-05-18-A1, FLOW-PH-DOWN-001, FLOW-CMP-DOWN-001 | FMEA-ET-004, INC-CMP-2025-0142, INC-ET-2024-0301 | 0/3 | 0.51 | 215.09 |
|
| 22 |
-
| ์๋ฏธ ์ฐํ 3 | INC-AUTO-2026-05-18-A1, SOP-PH-LENS-002, SOP-CMP-SLURRY-001 | SOP-PH-LENS-002, SOP-CMP-SLURRY-001, INC-CMP-2025-0142 | 2/3 | 0.48 | 313.42 |
|
| 23 |
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
|
|
| 27 |
|---|---|---|
|
| 28 |
-
|
|
| 29 |
-
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
-
## ํธ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
-
|
|
| 34 |
|---|---|---|
|
| 35 |
-
|
|
| 36 |
-
|
|
| 37 |
-
|
|
| 38 |
-
|
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
## ์ฑํ
|
| 43 |
|
| 44 |
-
**
|
| 45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# D2. Retrieval ๋ฐฑ์๋ ๋น๊ต (production-grade)
|
| 2 |
|
| 3 |
+
์ฟผ๋ฆฌ ์งํฉ์ ๋ํด 4๊ฐ์ง ๋ฐฑ์๋์ ๊ฒ์ ๊ฒฐ๊ณผยทlatency๋ฅผ ๋น๊ตํฉ๋๋ค.
|
| 4 |
+
ํ์ฌ knowledge ์ฝํผ์ค ์ฝ 10๊ฐ ํ๊ตญ์ด ๋๋ฉ์ธ ๋ฌธ์.
|
| 5 |
|
| 6 |
## ์คํ ์ค์
|
| 7 |
|
| 8 |
+
- ์ฝํผ์ค: `agents/rag/knowledge/*.md`
|
| 9 |
+
- ๋ฐฑ์๋ 4์ข
:
|
| 10 |
+
- **keyword**: ๋จ์ด ๋น๋ ๋งค์นญ (baseline)
|
| 11 |
+
- **FAISS**: sentence-transformer ์๋ฒ ๋ฉ + ์ฝ์ฌ์ธ (dense vector)
|
| 12 |
+
- **Hybrid**: BM25 + FAISS + RRF (production ํ์ค)
|
| 13 |
+
- **Hybrid+Rerank**: hybrid top-10 ํ๋ณด๋ฅผ BAAI/bge-reranker-base๋ก ์ฌ์ ๋ ฌ (production ์ ๋ฐ)
|
| 14 |
+
- ์ฟผ๋ฆฌ 6๊ฑด (์๋ฏธ ์ฐํ 3๊ฑด ํฌํจ)
|
| 15 |
|
| 16 |
## ์ฟผ๋ฆฌ๋ณ ๊ฒฐ๊ณผ
|
| 17 |
|
| 18 |
+
### CD ์ฐํฌ ์ง์ - `Photo Step CD-X ์ฐํฌ ์์ธ ๋ ์ฆ ๋
ธ๊ด`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
+
| ๋ฐฑ์๋ | ๊ฒฐ๊ณผ | latency |
|
| 21 |
+
|---|---|---|
|
| 22 |
+
| keyword | INC-AUTO-2026-05-18-A1, FMEA-PH-007, FLOW-PH-DOWN-001 | 3.00ms |
|
| 23 |
+
| faiss | FLOW-PH-DOWN-001, INC-2024-0312, INC-AUTO-2026-05-18-A1 | 29.77ms |
|
| 24 |
+
| hybrid | INC-AUTO-2026-05-18-A1, INC-2024-0312, FMEA-PH-007 | 7.14ms |
|
| 25 |
+
| hybrid+rerank | INC-2024-0312, INC-AUTO-2026-05-18-A1, FMEA-PH-007 | 243.38ms |
|
| 26 |
+
|
| 27 |
+
### CMP ์ง์ - `CMP ์ฌ๋ฌ๋ฆฌ ์ ๋ ์ด์ SLURRY_FLOW`
|
| 28 |
|
| 29 |
+
| ๋ฐฑ์๋ | ๊ฒฐ๊ณผ | latency |
|
| 30 |
|---|---|---|
|
| 31 |
+
| keyword | SOP-CMP-SLURRY-001, INC-CMP-2025-0142, INC-AUTO-2026-05-18-A1 | 0.51ms |
|
| 32 |
+
| faiss | SOP-CMP-SLURRY-001, FLOW-CMP-DOWN-001, INC-ET-2024-0301 | 21.59ms |
|
| 33 |
+
| hybrid | SOP-CMP-SLURRY-001, FLOW-CMP-DOWN-001, INC-CMP-2025-0142 | 5.80ms |
|
| 34 |
+
| hybrid+rerank | INC-CMP-2025-0142, SOP-CMP-SLURRY-001, FMEA-CMP-003 | 240.45ms |
|
| 35 |
|
| 36 |
+
### Etch ์ง์ - `Etch ํธ๋ ์น ๊น์ด ๋ถ์กฑ ์๊ฐ ๊ฐ์ค`
|
| 37 |
+
|
| 38 |
+
| ๋ฐฑ์๋ | ๊ฒฐ๊ณผ | latency |
|
| 39 |
+
|---|---|---|
|
| 40 |
+
| keyword | FMEA-ET-004, INC-ET-2024-0301, INC-AUTO-2026-05-18-A1 | 0.52ms |
|
| 41 |
+
| faiss | INC-ET-2024-0301, FMEA-ET-004, FLOW-PH-DOWN-001 | 6.83ms |
|
| 42 |
+
| hybrid | FMEA-ET-004, INC-ET-2024-0301, FLOW-PH-DOWN-001 | 5.71ms |
|
| 43 |
+
| hybrid+rerank | INC-ET-2024-0301, FMEA-ET-004, FMEA-PH-007 | 239.85ms |
|
| 44 |
+
|
| 45 |
+
### ์๋ฏธ ์ฐํ 1 - `๋
ธ๊ด ์ฅ๋น ํ๋ฉด ์ค์ผ ์ฒญ์`
|
| 46 |
+
|
| 47 |
+
| ๋ฐฑ์๋ | ๊ฒฐ๊ณผ | latency |
|
| 48 |
+
|---|---|---|
|
| 49 |
+
| keyword | INC-AUTO-2026-05-18-A1, SOP-PH-LENS-002, INC-2024-0312 | 0.47ms |
|
| 50 |
+
| faiss | SOP-PH-LENS-002, INC-2024-0312, FMEA-ET-004 | 25.10ms |
|
| 51 |
+
| hybrid | FMEA-ET-004, INC-2024-0312, FMEA-PH-007 | 5.99ms |
|
| 52 |
+
| hybrid+rerank | INC-2024-0289, INC-2024-0312, SOP-PH-LENS-002 | 244.07ms |
|
| 53 |
+
|
| 54 |
+
### ์๋ฏธ ์ฐํ 2 - `ํ๊ณต์ ์์จ ์์ค ์ ๋ ์ํฅ`
|
| 55 |
|
| 56 |
+
| ๋ฐฑ์๋ | ๊ฒฐ๊ณผ | latency |
|
| 57 |
|---|---|---|
|
| 58 |
+
| keyword | FLOW-PH-DOWN-001, INC-AUTO-2026-05-18-A1, FLOW-CMP-DOWN-001 | 0.53ms |
|
| 59 |
+
| faiss | FMEA-ET-004, INC-CMP-2025-0142, INC-ET-2024-0301 | 24.72ms |
|
| 60 |
+
| hybrid | FMEA-ET-004, FMEA-CMP-003, FMEA-PH-007 | 7.10ms |
|
| 61 |
+
| hybrid+rerank | FMEA-PH-007, FMEA-ET-004, FLOW-PH-DOWN-001 | 243.45ms |
|
| 62 |
+
|
| 63 |
+
### ์๋ฏธ ์ฐํ 3 - `์ ๋น ์ฃผ๊ธฐ ํ์ค ๊ฐ์ด๋`
|
| 64 |
+
|
| 65 |
+
| ๋ฐฑ์๋ | ๊ฒฐ๊ณผ | latency |
|
| 66 |
+
|---|---|---|
|
| 67 |
+
| keyword | INC-AUTO-2026-05-18-A1, SOP-PH-LENS-002, SOP-CMP-SLURRY-001 | 0.52ms |
|
| 68 |
+
| faiss | SOP-PH-LENS-002, SOP-CMP-SLURRY-001, INC-CMP-2025-0142 | 25.06ms |
|
| 69 |
+
| hybrid | SOP-PH-LENS-002, SOP-CMP-SLURRY-001, INC-AUTO-2026-05-18-A1 | 5.89ms |
|
| 70 |
+
| hybrid+rerank | SOP-PH-LENS-002, FMEA-CMP-003, FMEA-PH-007 | 242.87ms |
|
| 71 |
+
|
| 72 |
+
## ์ง๊ณ - ํ๊ท Latency
|
| 73 |
+
|
| 74 |
+
| ๋ฐฑ์๋ | ํ๊ท latency |
|
| 75 |
+
|---|---|
|
| 76 |
+
| keyword | 0.93 ms |
|
| 77 |
+
| faiss | 22.18 ms |
|
| 78 |
+
| hybrid | 6.27 ms |
|
| 79 |
+
| hybrid+rerank | 242.35 ms |
|
| 80 |
+
|
| 81 |
+
## ํธ๋ ์ด๋์คํ
|
| 82 |
+
|
| 83 |
+
| ์ธก๋ฉด | keyword | FAISS | Hybrid | Hybrid+Rerank |
|
| 84 |
+
|---|---|---|---|---|
|
| 85 |
+
| ๋๋ฉ์ธ ์ฉ์ด ์ ํ ๋งค์นญ | โ
| โ | โ
| โ
|
|
| 86 |
+
| ์๋ฏธยท๋์์ด ๋งค์นญ | โ | โ
| โ
| โ
|
|
| 87 |
+
| ์ ๋ฐํ ๊ด๋ จ์ฑ ํ๊ฐ | โ | โ | โ | โ
|
|
| 88 |
+
| Latency | ๋งค์ฐ ๋น ๋ฆ | ๋ณดํต | ๋ณดํต | ๋๋ฆผ (CrossEncoder) |
|
| 89 |
+
| ๋ชจ๋ธ ์์กด์ฑ | ์์ | ST(~120MB) | ST(~120MB) | ST + Reranker(~280MB) |
|
| 90 |
+
| ์ฝํผ์ค ํ์ฅ(100+) ๊ฒฌ๊ณ ์ฑ | ์ฝํจ | ๊ฐํจ | **๋งค์ฐ ๊ฐํจ** | **๋งค์ฐ ๊ฐํจ** |
|
| 91 |
|
| 92 |
## ์ฑํ
|
| 93 |
|
| 94 |
+
**๊ธฐ๋ณธ backend = `hybrid_rerank`**. production ํ์ค ํจํด. ํ๊ฒฝ๋ณ์ `RAG_BACKEND`๋ก 4๊ฐ์ง ๋ชจ๋ ์ ํ ๊ฐ๋ฅ.
|
| 95 |
+
|
| 96 |
+
- ์ฝํผ์ค 100๋ฌธ์ ์ด์: hybrid_rerank์ ์ ๋ฐ๋ ์ฐ์ ๊ฒฐ์ ์
|
| 97 |
+
- MVPยท์์ฐ ํ๊ฒฝ: hybrid๋ ์ถฉ๋ถ (rerank ๋ชจ๋ธ ๋ค์ด๋ก๋ ์๊ฐ ์ ์ฝ)
|
| 98 |
+
- ๋จ์ ํค์๋ ๊ฒ์๋ง ํ์: keyword (์์กด์ฑ ์์)
|
requirements.txt
CHANGED
|
@@ -7,3 +7,7 @@ matplotlib>=3.8.0
|
|
| 7 |
faiss-cpu>=1.7.4
|
| 8 |
sentence-transformers>=2.5.0
|
| 9 |
langgraph>=0.2.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
faiss-cpu>=1.7.4
|
| 8 |
sentence-transformers>=2.5.0
|
| 9 |
langgraph>=0.2.0
|
| 10 |
+
rank-bm25>=0.2.2
|
| 11 |
+
ragas>=0.2.0
|
| 12 |
+
datasets>=2.18.0
|
| 13 |
+
langchain-openai>=0.2.0
|