hee_!J commited on
Commit
4347250
·
1 Parent(s): 1ef2506

docs: D10 시리즈 검증 narrative + Journey 10단계 추가

Browse files
README.md CHANGED
@@ -120,7 +120,8 @@ PHM 2016 CMP는 실제 CMP 공정 센서 데이터로 step-specific 추론이
120
  | **D6** | RAG paradigm 5단계 ablation | **Hybrid** 채택 | faithfulness: No RAG 0.32 → Hybrid 0.82 (2.5x). Hybrid가 모든 지표 1위 |
121
  | **D7** | Workflow vs Agentic 비교 | **Agentic** 채택 | tool 0→13, 인용 깊이 +25%, 비용 2.6x, latency 2.3x, reasoning trace 확보 |
122
  | **D8** | CRAG (Self-correction) ON vs OFF | CRAG **활성 유지** (관측 가치) | 품질 변화 -0.1%p (동급), refinement 발동률 20%, relevance_score 노출, 비용 +31% |
123
- | **D9** | 한국어 reranker (Dongjin-kr/ko-reranker) vs 영어(BAAI) vs hybrid | 둘 다 hybrid에 미달 | hybrid 0.734 / BAAI 0.714 / ko 0.703 (D6 결론 재확인, 쿼리별로는 ko가 CMP·lens 우위) |
 
124
 
125
  ### D6 핵심 그래프
126
 
@@ -210,7 +211,24 @@ PHM 2016 CMP는 실제 CMP 공정 센서 데이터로 step-specific 추론이
210
  - **결과**: hybrid 0.734 (baseline), BAAI 0.714 (-0.020), **ko-reranker 0.703 (-0.031)**
211
  - **반전 안에 반전**: 쿼리별로 보면 ko-reranker가 CMP(+0.10), 의미 우회 1(+0.083)에선 우위. Etch(-0.18), 의미 우회 2(-0.20)에선 손실. 전체 평균은 무승부
212
  - **해석**: 한국어 reranker가 영어보단 도메인 적합성 약간 우위지만, **본 코퍼스 규모(~10문서)에선 hybrid top-3이 이미 충분히 정밀해 어떤 reranker도 의미 있는 이득 없음**
213
- - **결론**: D6 가설 부분적 재확인 - 한국어 reranker 채택 보류, hybrid 단독 유지. 코퍼스 100+ 확장reranker 효용시화의 선결조건임두 번 확인
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
  ### 8. Supervisor agent - LLM-driven 동적 workflow routing
216
 
@@ -348,7 +366,7 @@ fabagent/
348
  ## 한계와 향후 확장
349
 
350
  - **SECOM의 익명성**: 590개 센서가 어느 공정·물리량인지 비공개라 A1/A2의 step 라벨은 시연용 narrative
351
- - **knowledge 문서**: 시연용 합성 도메인 문서 (실 fab 사내 SOP·인시던트 DB로 교체 가능)
352
  - **도구 mock data**: PM 이력·yield baseline·downstream 의존성은 in-memory mock (실 fab은 MES/EAP/YMS 어댑터로 교체)
353
  - **한국어 reranker 검증 완료(D9)**: hybrid 단독에 미달, 코퍼스 확장이 reranker 효용의 선결조건임을 확인
354
  - **Supervisor fast_track 시연 부재**: 현 3개 데모 알람은 모두 proceed_full 선택 - fast_track/escalate 시연을 위해선 더 다양한 알람 시나리오 필요
 
120
  | **D6** | RAG paradigm 5단계 ablation | **Hybrid** 채택 | faithfulness: No RAG 0.32 → Hybrid 0.82 (2.5x). Hybrid가 모든 지표 1위 |
121
  | **D7** | Workflow vs Agentic 비교 | **Agentic** 채택 | tool 0→13, 인용 깊이 +25%, 비용 2.6x, latency 2.3x, reasoning trace 확보 |
122
  | **D8** | CRAG (Self-correction) ON vs OFF | CRAG **활성 유지** (관측 가치) | 품질 변화 -0.1%p (동급), refinement 발동률 20%, relevance_score 노출, 비용 +31% |
123
+ | **D9** | 한국어 reranker (Dongjin-kr/ko-reranker) vs 영어(BAAI) vs hybrid (12 docs) | 둘 다 hybrid에 미달 | hybrid 0.734 / BAAI 0.714 / ko 0.703 |
124
+ | **D10** | **D9 후속**: 코퍼스 12→34 확장 후 reranker 재평가 | **가설 검증 - 효과 완전 반전** | hybrid **0.592** / BAAI **0.709 (+0.117)** / ko **0.675 (+0.083)** |
125
 
126
  ### D6 핵심 그래프
127
 
 
211
  - **결과**: hybrid 0.734 (baseline), BAAI 0.714 (-0.020), **ko-reranker 0.703 (-0.031)**
212
  - **반전 안에 반전**: 쿼리별로 보면 ko-reranker가 CMP(+0.10), 의미 우회 1(+0.083)에선 우위. Etch(-0.18), 의미 우회 2(-0.20)에선 손실. 전체 평균은 무승부
213
  - **해석**: 한국어 reranker가 영어보단 도메인 적합성 약간 우위지만, **본 코퍼스 규모(~10문서)에선 hybrid top-3이 이미 충분히 정밀해 어떤 reranker도 의미 있는 이득 없음**
214
+ - **결론(잠정)**: D6 가설 부분적 재확인 - 코퍼스 규모가 진짜 원인라는 제시
215
+
216
+ ### 10. 코퍼스 12 → 34 확장 + D10으로 가설 검증
217
+
218
+ - **시작**: D9까지 누적된 가설 "코퍼스 규모가 reranker 효용의 선결조건". 이를 정량 검증하려면 코퍼스 확장 필수
219
+ - **방법**: 합법적 공개 자료로 12개 → 34개 확장
220
+ - 한국어 위키백과 12개 (반도체 공정 전반: Photo/Etch/CMP/이온주입/박막/포토레지스트/EUV 등)
221
+ - SK하이닉스 뉴스룸 6개 (실제 산업 운영 관점: 식각·포토·CMP·세정)
222
+ - 삼성반도체 공식 3개 (8대 공정·용어집·EUV)
223
+ - SKC 소재 1개, PHM Society 2016 챌린지 1개
224
+ - 모든 출처는 CC BY-SA 또는 공개 자료, 파일별 attribution 명시
225
+ - **D10 결과 (re-run D9 with 34 docs)**:
226
+ - hybrid: 0.734 → **0.592** (-0.142, noise 증가)
227
+ - BAAI: -0.020 → **+0.117** (반전!)
228
+ - ko-reranker: -0.031 → **+0.083** (반전!)
229
+ - **검증 완료**: 가설 정확히 입증. 확장 코퍼스에서는 BM25/FAISS가 일반 자료 noise를 흡수하지만 cross-encoder가 그중에서 정답을 골라냄
230
+ - **결정**: 코퍼스 30+ 환경에서는 `RAG_BACKEND=hybrid_rerank` 권장. 데모용 12개에선 hybrid 유지
231
+ - **시리즈 의의**: D6 → D9 → D10이 portfolio narrative로 완성. "통념 → 정량 반박 → 가설 → 정량 검증"의 사이클이 정량 평가의 가치 자체를 증명
232
 
233
  ### 8. Supervisor agent - LLM-driven 동적 workflow routing
234
 
 
366
  ## 한계와 향후 확장
367
 
368
  - **SECOM의 익명성**: 590개 센서가 어느 공정·물리량인지 비공개라 A1/A2의 step 라벨은 시연용 narrative
369
+ - **knowledge 문서**: 합성 12개 + 공개 자료(위키/SK하이닉스/삼성/SKC/PHM) 22개 = **총 34개**. 실 fab 수천 문서 대비 여전히 작지만, D10에서 코퍼스 규모와 reranker 효용의 관계는 정량 검증됨
370
  - **도구 mock data**: PM 이력·yield baseline·downstream 의존성은 in-memory mock (실 fab은 MES/EAP/YMS 어댑터로 교체)
371
  - **한국어 reranker 검증 완료(D9)**: hybrid 단독에 미달, 코퍼스 확장이 reranker 효용의 선결조건임을 확인
372
  - **Supervisor fast_track 시연 부재**: 현 3개 데모 알람은 모두 proceed_full 선택 - fast_track/escalate 시연을 위해선 더 다양한 알람 시나리오 필요
experiments/README.md CHANGED
@@ -14,7 +14,8 @@
14
  | **D6** | RAG paradigm 5단계 ablation | No RAG / Naive / FAISS / Hybrid / +Rerank | **Hybrid** | [rag_paradigm/results.md](rag_paradigm/results.md) |
15
  | **D7** | Workflow vs Agentic | 단일 LLM 호출 vs tool-using 루프 | **Agentic** | [agentic_vs_workflow/results.md](agentic_vs_workflow/results.md) |
16
  | **D8** | CRAG ON vs OFF | self-correction (grader + refinement) | CRAG **활성 유지** (관측 가치) | [crag_eval/results.md](crag_eval/results.md) |
17
- | **D9** | 한국어 reranker (Dongjin-kr/ko-reranker) | vs BAAI(영어) vs hybrid | 둘 다 hybrid에 미달 | [reranker_compare/results.md](reranker_compare/results.md) |
 
18
 
19
  ## 핵심 결정 요약
20
 
@@ -149,7 +150,24 @@
149
  | 의미 우회 2 (yield 영향) | 0.817 | **0.867** | 0.617 | BAAI |
150
  | 의미 우회 3 (PM 가이드) | 0.517 | 0.550 | 0.533 | tie |
151
 
152
- **시행착오 (D6 → D9)**: D6에서 영어 reranker의 부진 원인을 "한국어 모델로 풀린다"고 가설. D9에서 검증한 결과 - **한국어 reranker가 CMP·lens cleanup 쿼리에선 명확히 우위지만, Etch·yield 쿼리에선 큰 손실**. 6 쿼리 평균은 hybrid baseline 미달. **결론: D6 가설의 진짜 문제는 영어/한국어가 아니라 코퍼스 규모**. ~10문서에선 hybrid top-3이미 정밀해 reranker 좋게 렬할 여지 부족. 채택 결정: **hybrid 유지, ko-reranker는 환경변수 옵션(`RERANK_MODEL=Dongjin-kr/ko-reranker`)으로만 보존**. 코퍼스 100+ 확장이 reranker 효용의 선결조건임을 두 번 확인.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
  ## 실행 방법
155
 
 
14
  | **D6** | RAG paradigm 5단계 ablation | No RAG / Naive / FAISS / Hybrid / +Rerank | **Hybrid** | [rag_paradigm/results.md](rag_paradigm/results.md) |
15
  | **D7** | Workflow vs Agentic | 단일 LLM 호출 vs tool-using 루프 | **Agentic** | [agentic_vs_workflow/results.md](agentic_vs_workflow/results.md) |
16
  | **D8** | CRAG ON vs OFF | self-correction (grader + refinement) | CRAG **활성 유지** (관측 가치) | [crag_eval/results.md](crag_eval/results.md) |
17
+ | **D9** | 한국어 reranker (Dongjin-kr/ko-reranker) | vs BAAI(영어) vs hybrid (12 docs) | 둘 다 hybrid에 미달 | [reranker_compare/results.md](reranker_compare/results.md) |
18
+ | **D10** | D9 후속: 코퍼스 12→34 확장 후 reranker 재평가 | hybrid / BAAI / ko-reranker (34 docs) | **가설 검증 - 효과 완전 반전** | [reranker_compare/results.md](reranker_compare/results.md) |
19
 
20
  ## 핵심 결정 요약
21
 
 
150
  | 의미 우회 2 (yield 영향) | 0.817 | **0.867** | 0.617 | BAAI |
151
  | 의미 우회 3 (PM 가이드) | 0.517 | 0.550 | 0.533 | tie |
152
 
153
+ **시행착오 (D6 → D9)**: D6에서 영어 reranker의 부진 원인을 "한국어 모델로 풀린다"고 가설. D9에서 검증한 결과 - **한국어 reranker가 CMP·lens cleanup 쿼리에선 명확히 우위지만, Etch·yield 쿼리에선 큰 손실**. 6 쿼리 평균은 hybrid baseline 미달. **결론: D6 가설의 진짜 문제는 영어/한국어가 아니라 코퍼스 규모**. 이 가설을 D10에서 검증.
154
+
155
+ ### D10. 확장 코퍼스(34 docs)에서 reranker 효과 검증 → **가설 입증, 효과 완전 반전**
156
+
157
+ | 모드 | D9 (12 docs) | **D10 (34 docs)** | 변화 |
158
+ |---|---|---|---|
159
+ | hybrid (no rerank) | 0.734 | **0.592** | -0.142 (noise↑) |
160
+ | BAAI/bge-reranker-base | 0.714 (-0.020) | **0.709 (+0.117)** | **반전!** |
161
+ | Dongjin-kr/ko-reranker | 0.703 (-0.031) | **0.675 (+0.083)** | **반전!** |
162
+
163
+ ![Reranker 비교 (D10, 34 docs)](reranker_compare/charts/reranker_comparison.png)
164
+
165
+ **시리즈 의의 (D6 → D9 → D10)**:
166
+ - **D6**: production 표준이 작은 코퍼스에서 역효과 발견 ("rerank가 무조건 좋다"는 통념 정량 반박)
167
+ - **D9**: 한국어 reranker로도 안 풀림 → 영어/한국어 문제가 아니라 "**코퍼스 규모가 진짜 원인**"이라는 가설 제시
168
+ - **D10**: 코퍼스 12 → 34 확장 후 재실행. **hybrid baseline -0.14, reranker 효과 +0.12로 완전 반전** → 가설 정량 입증
169
+
170
+ **핵심 메시지**: 정량 평가 없이는 잘못된 통념을 그대로 끌고 갈 뻔했고, 정량 평가 덕분에 진짜 원인을 분리하고 검증할 수 있었다. 채택: 코퍼스 30+ 환경에서는 `RAG_BACKEND=hybrid_rerank` 권장, 데모용 코퍼스는 hybrid 유지.
171
 
172
  ## 실행 방법
173
 
experiments/rag_paradigm/benchmark.py CHANGED
@@ -38,7 +38,17 @@ from ragas.metrics import (
38
  ResponseRelevancy,
39
  )
40
 
41
- from agents.cause import SYSTEM_PROMPT, TIER2_SCHEMA
 
 
 
 
 
 
 
 
 
 
42
 
43
 
44
  def _build_query(alarm: dict, tier1) -> str:
@@ -99,7 +109,7 @@ def _run_cause_with_contexts(alarm: dict, tier1: dict, contexts: list[str]) -> d
99
  resp = client().chat.completions.create(
100
  model=SUBAGENT_MODEL,
101
  messages=[
102
- {"role": "system", "content": SYSTEM_PROMPT},
103
  {"role": "user", "content": user_prompt},
104
  ],
105
  response_format={
@@ -107,7 +117,15 @@ def _run_cause_with_contexts(alarm: dict, tier1: dict, contexts: list[str]) -> d
107
  "json_schema": {"name": "tier2", "schema": TIER2_SCHEMA, "strict": True},
108
  },
109
  )
110
- return json.loads(resp.choices[0].message.content)
 
 
 
 
 
 
 
 
111
 
112
 
113
  def _format_answer(tier2: dict) -> str:
 
38
  ResponseRelevancy,
39
  )
40
 
41
+ from agents.cause import TIER2_SCHEMA
42
+
43
+ # workflow 모드 (사전 retrieve 후 단일 LLM 호출)에 적합한 prompt
44
+ # agents.cause의 SYSTEM_PROMPT는 agentic 모드(tool 자율 호출) 전용이라 별도 정의
45
+ WORKFLOW_SYSTEM_PROMPT = """당신은 반도체 공정 원인 분석 전문가입니다.
46
+ 주어진 이상 알람과 탐지 결과, 사내 지식 문서를 근거로 가장 가능성 높은 원인을
47
+ 2~3개 추정합니다. 각 원인은 기여도(pct, %)를 가지며 합이 100에 가깝도록 합니다.
48
+ 근거(evidence)는 제공된 문서 내용에 기반해 구체적으로 작성하고, citations에는
49
+ 근거가 된 문서 ID만 정확히 기입합니다. 제공되지 않은 문서는 인용하지 않습니다.
50
+ 기여도가 높은 원인부터 순서대로 제시합니다.
51
+ 반드시 JSON 스키마에 맞춰 응답하세요."""
52
 
53
 
54
  def _build_query(alarm: dict, tier1) -> str:
 
109
  resp = client().chat.completions.create(
110
  model=SUBAGENT_MODEL,
111
  messages=[
112
+ {"role": "system", "content": WORKFLOW_SYSTEM_PROMPT},
113
  {"role": "user", "content": user_prompt},
114
  ],
115
  response_format={
 
117
  "json_schema": {"name": "tier2", "schema": TIER2_SCHEMA, "strict": True},
118
  },
119
  )
120
+ content = resp.choices[0].message.content or "{}"
121
+ # 일부 모델이 ```json ... ``` fence를 붙이는 경우 방어
122
+ if content.strip().startswith("```"):
123
+ parts = content.split("```")
124
+ if len(parts) >= 2:
125
+ content = parts[1]
126
+ if content.startswith("json"):
127
+ content = content[4:]
128
+ return json.loads(content.strip())
129
 
130
 
131
  def _format_answer(tier2: dict) -> str: