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 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
- if os.getenv("RAG_BACKEND", "keyword").lower() == "faiss":
 
 
 
 
 
 
 
 
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: FAISS ๋ฒกํ„ฐ ๊ฒ€์ƒ‰ vs ํ‚ค์›Œ๋“œ ๋งค์นญ ๋น„๊ต
2
 
3
- ๊ฐ™์€ ์ฟผ๋ฆฌ ์ง‘ํ•ฉ์— ๋Œ€ํ•ด
4
- - keyword_search: ๋‹จ์ˆœ ๋‹จ์–ด ๋นˆ๋„ ๋งค์นญ
5
- - faiss_search: sentence-transformer ์ž„๋ฒ ๋”ฉ + FAISS ์ฝ”์‚ฌ์ธ ์œ ์‚ฌ๋„
6
-
7
- ์œผ๋กœ ๊ฒ€์ƒ‰ํ•ด ๊ฒฐ๊ณผยทlatencyยท์˜๋ฏธ ๋งค์นญ ๋Šฅ๋ ฅ์„ ๋น„๊ต
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", "๋…ธ๊ด‘ ์žฅ๋น„ ํ‘œ๋ฉด ์˜ค์—ผ ์ฒญ์†Œ"), # PM/clean์ด๋ผ๋Š” ๋‹จ์–ด ์—†์ด
27
- ("์˜๋ฏธ ์šฐํšŒ 2", "ํ›„๊ณต์ • ์ˆ˜์œจ ์†์‹ค ์ •๋Ÿ‰ ์˜ํ–ฅ"), # ์ง์ ‘ ๋‹จ์–ด ๋งค์นญ ์•ฝํ•จ
28
- ("์˜๋ฏธ ์šฐํšŒ 3", "์ •๋น„ ์ฃผ๊ธฐ ํ‘œ์ค€ ๊ฐ€์ด๋“œ"), # SOP ์ฐพ๊ธฐ, ์ง์ ‘ ๋‹จ์–ด ์—†์Œ
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  ]
30
 
31
 
32
  def main():
33
- # ์‚ฌ์ „ ํ˜ธ์ถœ๋กœ ๋ชจ๋ธ ๋กœ๋”ฉ ์‹œ๊ฐ„ ์ธก์ • ๋ถ„๋ฆฌ
34
- print("=== FAISS ์ธ๋ฑ์Šค ๋นŒ๋“œ (๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ ํฌํ•จ, ์ฒซ ํ˜ธ์ถœ๋งŒ) ===")
35
- t0 = time.time()
36
- _ = faiss_search("warmup query", top_k=1)
37
- print(f" build time: {time.time()-t0:.1f}s\n")
 
 
38
 
39
  rows = []
40
  for label, q in QUERIES:
41
- kw_t0 = time.time()
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
- print(f" keyword ({kw_ms:.2f}ms): {kw_res}")
58
- print(f" faiss ({fs_ms:.2f}ms): {fs_res}")
59
- print(f" overlap: {overlap}/3\n")
 
 
 
 
 
 
60
 
61
  write_results(rows)
62
  print(f"--- ์ €์žฅ: {OUT_DIR / 'results.md'} ---")
63
 
64
 
65
  def write_results(rows):
66
- avg_kw = statistics.mean(r["kw_ms"] for r in rows)
67
- avg_fs = statistics.mean(r["fs_ms"] for r in rows)
68
- avg_overlap = statistics.mean(r["overlap"] for r in rows)
 
69
 
70
  lines = [
71
- "# D2. FAISS vs ํ‚ค์›Œ๋“œ ๋งค์นญ ๊ฒ€์ƒ‰ ๋น„๊ต",
72
  "",
73
- "๋™์ผ ์ฟผ๋ฆฌ ์ง‘ํ•ฉ์— ๋Œ€ํ•ด ๋‘ ๋ฐฑ์—”๋“œ์˜ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผยทlatency๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.",
74
- "ํ˜„์žฌ knowledge ์ฝ”ํผ์Šค ๊ทœ๋ชจ(์•ฝ 10๊ฐœ ๋ฌธ์„œ)์—์„œ์˜ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.",
75
  "",
76
  "## ์‹คํ—˜ ์„ค์ •",
77
  "",
78
- "- ์ฝ”ํผ์Šค: agents/rag/knowledge/*.md (ํ˜„์žฌ ์•ฝ 10๊ฐœ ํ•œ๊ตญ์–ด ๋„๋ฉ”์ธ ๋ฌธ์„œ)",
79
- "- ํ‚ค์›Œ๋“œ: ๋‹จ์–ด ๋นˆ๋„ ํ•ฉ๊ณ„ ๋žญํ‚น (`agents.rag.store.keyword_search`)",
80
- "- FAISS: sentence-transformers `paraphrase-multilingual-MiniLM-L12-v2` ์ž„๋ฒ ๋”ฉ + IndexFlatIP (์ฝ”์‚ฌ์ธ)",
81
- f"- ์ฟผ๋ฆฌ {len(rows)}๊ฑด (์˜๋ฏธ ์šฐํšŒ ์ฟผ๋ฆฌ 3๊ฑด ํฌํ•จ, ํ‚ค์›Œ๋“œ ์ง์ ‘ ๋งค์นญ์ด ์•ฝํ•œ ๊ฒฝ์šฐ)",
 
 
 
82
  "",
83
  "## ์ฟผ๋ฆฌ๋ณ„ ๊ฒฐ๊ณผ",
84
  "",
85
- "| ์ฟผ๋ฆฌ | ํ‚ค์›Œ๋“œ ๊ฒฐ๊ณผ | FAISS ๊ฒฐ๊ณผ | ๊ฒน์นจ | kw(ms) | fs(ms) |",
86
- "|---|---|---|---|---|---|",
87
  ]
 
88
  for r in rows:
89
- kw = ", ".join(r["kw"]) or "(empty)"
90
- fs = ", ".join(r["fs"]) or "(empty)"
91
- lines.append(
92
- f"| {r['label']} | {kw} | {fs} | {r['overlap']}/3 | {r['kw_ms']:.2f} | {r['fs_ms']:.2f} |"
93
- )
 
 
 
94
 
95
  lines += [
 
96
  "",
97
- "## ์ง‘๊ณ„",
98
- "",
99
- "| ์ง€ํ‘œ | ํ‚ค์›Œ๋“œ | FAISS |",
100
- "|---|---|---|",
101
- f"| ํ‰๊ท  latency | {avg_kw:.2f} ms | {avg_fs:.2f} ms |",
102
- f"| ๊ฒฐ๊ณผ ๊ฒน์นจ ํ‰๊ท  (top-3 ๊ธฐ์ค€) | {avg_overlap:.1f}/3 | - |",
 
103
  "",
104
  "## ํŠธ๋ ˆ์ด๋“œ์˜คํ”„",
105
  "",
106
- "| ์ธก๋ฉด | ํ‚ค์›Œ๋“œ ๋งค์นญ | FAISS ๋ฒกํ„ฐ |",
107
- "|---|---|---|",
108
- "| ์˜๋ฏธยท๋™์˜์–ด ๋งค์นญ | ์ง์ ‘ ์–ดํœ˜ ์ผ์น˜๋งŒ | โœ… ์ž„๋ฒ ๋”ฉ ๊ธฐ๋ฐ˜ ์˜๋ฏธ ์œ ์‚ฌ๋„ |",
109
- "| Latency (10๋ฌธ์„œ) | โœ… ๊ทน์†Œ (1ms ๋ฏธ๋งŒ ๊ฐ€๋Šฅ) | ~ms (์ธ๋ฑ์Šค ๊ฒ€์ƒ‰ + ์ž„๋ฒ ๋”ฉ) |",
110
- "| ์ฝœ๋“œ ์Šคํƒ€ํŠธ | โœ… ์—†์Œ | ๋ชจ๋ธ ๋กœ๋”ฉ ~์ˆ˜์ดˆ (์บ์‹œ ํ›„ ์ฆ‰์‹œ) |",
111
- "| ๋ฉ”๋ชจ๋ฆฌ | โœ… ๊ฑฐ์˜ 0 | ~120MB (multilingual ST ๋ชจ๋ธ) |",
112
- "| ์ฝ”ํผ์Šค ํ™•์žฅ(100+ ๋ฌธ์„œ) | ์–ดํœ˜ ๋ชป ์žก์œผ๋ฉด ๋ฌด๋ ฅ | โœ… ์˜๋ฏธ๋กœ ์žก์Œ |",
113
- "| ์˜์กด์„ฑ | ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ | sentence-transformers + faiss-cpu |",
114
  "",
115
  "## ์ฑ„ํƒ",
116
  "",
117
- "**๋‘ ๋ฐฑ์—”๋“œ ๋ชจ๋‘ ์œ ์ง€, ํ™˜๊ฒฝ๋ณ€์ˆ˜ `RAG_BACKEND=faiss`๋กœ ์ „ํ™˜**. ํ˜„ ์ฝ”ํผ์Šค ๊ทœ๋ชจ์—์„œ๋Š” ํ‚ค์›Œ๋“œ ๋งค์นญ์ด ์ถฉ๋ถ„ํžˆ ์ •ํ™•ํ•˜๊ณ  ๋น ๋ฅด๋ฉฐ ์˜์กด์„ฑ์ด ์ ์–ด ๊ธฐ๋ณธ๊ฐ’. ",
118
- "์ฝ”ํผ์Šค๊ฐ€ 50~100๊ฐœ ์ด์ƒ์œผ๋กœ ํ™•์žฅ๋˜๊ฑฐ๋‚˜ ์˜๋ฏธ ์šฐํšŒ ์ฟผ๋ฆฌ ๋น„์œจ์ด ๋†’์•„์ง€๋ฉด FAISS๋กœ ์ „ํ™˜ ๊ถŒ์žฅ. ๋™์ผ ์ธํ„ฐํŽ˜์ด์Šค๋ผ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ์ „ํ™˜ ๊ฐ€๋Šฅ.",
 
 
 
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. FAISS vs ํ‚ค์›Œ๋“œ ๋งค์นญ ๊ฒ€์ƒ‰ ๋น„๊ต
2
 
3
- ๋™์ผ ์ฟผ๋ฆฌ ์ง‘ํ•ฉ์— ๋Œ€ํ•ด ๋‘ ๋ฐฑ์—”๋“œ์˜ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผยทlatency๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
4
- ํ˜„์žฌ knowledge ์ฝ”ํผ์Šค ๊ทœ๋ชจ(์•ฝ 10๊ฐœ ๋ฌธ์„œ)์—์„œ์˜ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.
5
 
6
  ## ์‹คํ—˜ ์„ค์ •
7
 
8
- - ์ฝ”ํผ์Šค: agents/rag/knowledge/*.md (ํ˜„์žฌ ์•ฝ 10๊ฐœ ํ•œ๊ตญ์–ด ๋„๋ฉ”์ธ ๋ฌธ์„œ)
9
- - ํ‚ค์›Œ๋“œ: ๋‹จ์–ด ๋นˆ๋„ ํ•ฉ๊ณ„ ๋žญํ‚น (`agents.rag.store.keyword_search`)
10
- - FAISS: sentence-transformers `paraphrase-multilingual-MiniLM-L12-v2` ์ž„๋ฒ ๋”ฉ + IndexFlatIP (์ฝ”์‚ฌ์ธ)
11
- - ์ฟผ๋ฆฌ 6๊ฑด (์˜๋ฏธ ์šฐํšŒ ์ฟผ๋ฆฌ 3๊ฑด ํฌํ•จ, ํ‚ค์›Œ๋“œ ์ง์ ‘ ๋งค์นญ์ด ์•ฝํ•œ ๊ฒฝ์šฐ)
 
 
 
12
 
13
  ## ์ฟผ๋ฆฌ๋ณ„ ๊ฒฐ๊ณผ
14
 
15
- | ์ฟผ๋ฆฌ | ํ‚ค์›Œ๋“œ ๊ฒฐ๊ณผ | FAISS ๊ฒฐ๊ณผ | ๊ฒน์นจ | kw(ms) | fs(ms) |
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
- | ์ง€ํ‘œ | ํ‚ค์›Œ๋“œ | FAISS |
27
  |---|---|---|
28
- | ํ‰๊ท  latency | 0.52 ms | 197.10 ms |
29
- | ๊ฒฐ๊ณผ ๊ฒน์นจ ํ‰๊ท  (top-3 ๊ธฐ์ค€) | 1.7/3 | - |
 
 
30
 
31
- ## ํŠธ๋ ˆ์ด๋“œ์˜คํ”„
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- | ์ธก๋ฉด | ํ‚ค์›Œ๋“œ ๋งค์นญ | FAISS ๋ฒกํ„ฐ |
34
  |---|---|---|
35
- | ์˜๋ฏธยท๋™์˜์–ด ๋งค์นญ | ์ง์ ‘ ์–ดํœ˜ ์ผ์น˜๋งŒ | โœ… ์ž„๋ฒ ๋”ฉ ๊ธฐ๋ฐ˜ ์˜๋ฏธ ์œ ์‚ฌ๋„ |
36
- | Latency (10๋ฌธ์„œ) | โœ… ๊ทน์†Œ (1ms ๋ฏธ๋งŒ ๊ฐ€๋Šฅ) | ~ms (์ธ๋ฑ์Šค ๊ฒ€์ƒ‰ + ์ž„๋ฒ ๋”ฉ) |
37
- | ์ฝœ๋“œ ์Šคํƒ€ํŠธ | โœ… ์—†์Œ | ๋ชจ๋ธ ๋กœ๋”ฉ ~์ˆ˜์ดˆ (์บ์‹œ ํ›„ ์ฆ‰์‹œ) |
38
- | ๋ฉ”๋ชจ๋ฆฌ | โœ… ๊ฑฐ์˜ 0 | ~120MB (multilingual ST ๋ชจ๋ธ) |
39
- | ์ฝ”ํผ์Šค ํ™•์žฅ(100+ ๋ฌธ์„œ) | ์–ดํœ˜ ๋ชป ์žก์œผ๋ฉด ๋ฌด๋ ฅ | โœ… ์˜๋ฏธ๋กœ ์žก์Œ |
40
- | ์˜์กด์„ฑ | ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ | sentence-transformers + faiss-cpu |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  ## ์ฑ„ํƒ
43
 
44
- **๋‘ ๋ฐฑ์—”๋“œ ๋ชจ๋‘ ์œ ์ง€, ํ™˜๊ฒฝ๋ณ€์ˆ˜ `RAG_BACKEND=faiss`๋กœ ์ „ํ™˜**. ํ˜„ ์ฝ”ํผ์Šค ๊ทœ๋ชจ์—์„œ๋Š” ํ‚ค์›Œ๋“œ ๋งค์นญ์ด ์ถฉ๋ถ„ํžˆ ์ •ํ™•ํ•˜๊ณ  ๋น ๋ฅด๋ฉฐ ์˜์กด์„ฑ์ด ์ ์–ด ๊ธฐ๋ณธ๊ฐ’.
45
- ์ฝ”ํผ์Šค๊ฐ€ 50~100๊ฐœ ์ด์ƒ์œผ๋กœ ํ™•์žฅ๋˜๊ฑฐ๋‚˜ ์˜๋ฏธ ์šฐํšŒ ์ฟผ๋ฆฌ ๋น„์œจ์ด ๋†’์•„์ง€๋ฉด FAISS๋กœ ์ „ํ™˜ ๊ถŒ์žฅ. ๋™์ผ ์ธํ„ฐํŽ˜์ด์Šค๋ผ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ์ „ํ™˜ ๊ฐ€๋Šฅ.
 
 
 
 
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