Files
C.E.L_Slide_test2/tests/matching/phase7.py
T
KyeongminandClaude Opus 4.8 b836e79ee1 wip: phase_z2 evidence 파이프라인 + matching 실험(phase2~26) + 프론트 trace 패널 진행분 스냅샷
- src: phase_z2 composition/mapper/pipeline/placement_planner/retry, ai_fallback(prompts/schema/validate), mdx_text_atoms 신규
- Front: PipelineTracePanel 신규, FramePanel/SlideCanvas/Home/designAgentApi 등 갱신 + 테스트 4종 추가
- templates/phase_z2: catalog(component_expansion_registry, node_slot_mapping 신규), frames, families, slide_base 갱신
- tests/matching: phase2~26 매칭 실험 스크립트·리포트·온톨로지 전체 (미커밋 진행분)
- tests: b4_v4 evidence, task5~28.5 시리즈, regression(imp95 baseline) 등 신규 테스트 대량 추가
- docs/reference: MDX 구조 인벤토리, MDX→Frame 구조 계약 문서
- scripts: mdx 계약/parity/coverage/viewport 체크, gitea comment, run sync 유틸
- .gitignore: tmp*.json, chromedriver, .orchestrator, *.pkl, Front_test* 등 임시/스냅샷 제외

미완성 작업의 보존용 스냅샷 커밋 (2026-07-02)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 17:03:42 +09:00

181 lines
7.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Phase 7 — 2~3단계 파이프라인 검증
한 줄 결론: semantic 단독 승자를 찾지 말고, lexical(BM25)로 top-k 후보 뽑은 뒤
semantic(청킹+SBERT 또는 Cross)으로 rerank → 필요시 구조 감점
검증 목표:
1. Kiwi+BM25 Top-3/Top-5 recall — 파이프라인의 이론적 상한 (방향 3)
2. BM25 top-5 → Cross rerank: 4/4 가능?
3. BM25 top-5 → 청킹+SBERT rerank: 4/4 가능?
4. 각 rerank에 구조 감점 추가 시 변화
"""
import sys
import json
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from common import load_figma_texts
from extract_units import extract_units
from methods import (
method_kiwi_bm25, method_cross_encoder, method_sbert_chunk,
method_hybrid_bm25_cross, method_hybrid_bm25_sbert_chunk,
method_hybrid_bm25_cross_struct, method_hybrid_bm25_sbert_chunk_struct,
)
ROOT = Path(r"d:\ad-hoc\kei\design_agent")
PREVIEW_DIR = ROOT / "data" / "figma_previews"
# (유닛키, 표시 이름, 정답 short ID)
TARGET_UNITS = [
("MDX01-2-details", "1. (MDX 1) 팝업 — DX와 BIM의 구분", "18"),
("MDX02-2.2-table", "2. (MDX 2) 2.2 DX 시행 주체별 기대효과", "14"),
("MDX03-1", "3. (MDX 03) 1. DX 시행을 위한 필수요건", "13"),
("MDX03-2", "4. (MDX 03) 2. Process 혁신과 Product 변화", "29"),
]
def short_id(fid, frame_to_short):
return frame_to_short.get(str(fid), "?")
def main():
units = extract_units()
figma = load_figma_texts()
with open(PREVIEW_DIR / "index.json", encoding="utf-8") as f:
idx_data = json.load(f)
frame_to_short = {info["frame_id"]: sid for sid, info in idx_data.items()}
# 각 유닛에 대해 각 전략의 top3 수집
strategies = [
("Kiwi+BM25 단독", method_kiwi_bm25, False),
("Cross 단독", method_cross_encoder, False),
("청킹+SBERT 단독", method_sbert_chunk, False),
("BM25 top5 → Cross rerank", lambda m, f: method_hybrid_bm25_cross(m, f, top_k=5), False),
("BM25 top5 → 청킹+SBERT rerank", lambda m, f: method_hybrid_bm25_sbert_chunk(m, f, top_k=5), False),
("BM25+Cross + 구조 감점(α=0.3)", lambda m, f: method_hybrid_bm25_cross_struct(m, f, top_k=5, alpha=0.3), False),
("BM25+SBERT-청크 + 구조 감점", lambda m, f: method_hybrid_bm25_sbert_chunk_struct(m, f, top_k=5, alpha=0.3), False),
]
print("[Phase 7] 파이프라인 전략 검증 시작\n")
# 1단계: Kiwi+BM25 Top-3 / Top-5 recall 확인 (방향 3)
print("=" * 70)
print("방향 3 — Kiwi+BM25 Top-k Recall 검증 (파이프라인 이론 상한)")
print("=" * 70)
recall_top3 = 0
recall_top5 = 0
bm25_top5_by_unit = {}
for uid, display, correct_id in TARGET_UNITS:
text = units[uid]
ranked = method_kiwi_bm25(text, figma)
top5_ids = [short_id(fid, frame_to_short) for fid, _ in ranked[:5]]
bm25_top5_by_unit[uid] = top5_ids
top3 = top5_ids[:3]
in_top3 = correct_id in top3
in_top5 = correct_id in top5_ids
if in_top3:
recall_top3 += 1
if in_top5:
recall_top5 += 1
mark3 = "✓" if in_top3 else "✗"
mark5 = "✓" if in_top5 else "✗"
print(f" {display[:45]:45s} 정답={correct_id}")
print(f" Top-5: {top5_ids} | Top-3 {mark3} Top-5 {mark5}")
print(f"\n → Kiwi+BM25 Top-3 recall: {recall_top3}/4")
print(f" → Kiwi+BM25 Top-5 recall: {recall_top5}/4")
# 2단계: 각 전략의 1순위 정답률
print("\n" + "=" * 70)
print("방향 1 — 파이프라인 전략별 1순위 정답률")
print("=" * 70)
strategy_results = {}
for sname, fn, _ in strategies:
results = []
top3_by_unit = {}
for uid, _, correct_id in TARGET_UNITS:
text = units[uid]
ranked = fn(text, figma)
top3 = [short_id(fid, frame_to_short) for fid, _ in ranked[:3]]
top3_by_unit[uid] = top3
results.append(top3[0] == correct_id)
strategy_results[sname] = (results, top3_by_unit)
marks = ["✓" if r else "✗" for r in results]
score = sum(results)
print(f" {sname:35s} {' '.join(marks)} = {score}/4")
# MD 리포트
png_rel = "../../data/figma_previews/"
lines = []
lines.append("# Phase 7 — 2~3단계 파이프라인 검증")
lines.append("")
lines.append("**한 줄 결론(사용자)**: semantic 단독 승자 말고, Kiwi+BM25로 top-k 후보 → "
"청킹+SBERT나 Cross로 rerank → 필요시 구조 감점, 2~3단계 파이프라인으로.")
lines.append("")
lines.append(f"**방향 3 — Kiwi+BM25 recall**: Top-3 {recall_top3}/4, Top-5 {recall_top5}/4")
lines.append("(retriever 단계에서 정답이 후보군에 들어있는가 = 파이프라인 이론 상한)")
lines.append("")
# Kiwi+BM25 Top-5 상세
lines.append("### Kiwi+BM25 Top-5 후보 목록")
lines.append("")
lines.append("| 유닛 | 정답 | Top-5 후보 | 정답 포함? |")
lines.append("|------|------|------------|----------|")
for uid, display, correct_id in TARGET_UNITS:
top5 = bm25_top5_by_unit[uid]
in_top5 = "✓" if correct_id in top5 else "✗"
top5_str = ", ".join(top5)
lines.append(f"| {display} | **{correct_id}** | {top5_str} | {in_top5} |")
lines.append("")
# 전략별 1순위 집계
lines.append("### 전략별 1순위 정답률 집계")
lines.append("")
lines.append("| 전략 | MDX1 팝업(18) | MDX2 2.2(14) | MDX03-1(13) | MDX03-2(29) | 합계 |")
lines.append("|------|---------------|--------------|-------------|-------------|------|")
for sname, fn, _ in strategies:
results, top3_by = strategy_results[sname]
marks = []
for idx, (uid, _, correct_id) in enumerate(TARGET_UNITS):
t3 = top3_by[uid]
mark = "✓" if results[idx] else f"✗({t3[0]})"
marks.append(mark)
score = sum(results)
lines.append(f"| {sname} | {marks[0]} | {marks[1]} | {marks[2]} | {marks[3]} | **{score}/4** |")
lines.append("")
# 각 유닛 상세: 전략별 Top-3
lines.append("---")
lines.append("")
lines.append("## 유닛별 전략 Top-3 상세")
lines.append("")
for uid, display, correct_id in TARGET_UNITS:
lines.append(f"### {display} — 정답 Frame **{correct_id}**")
lines.append("")
lines.append("| 전략 | 1순위 | 2순위 | 3순위 |")
lines.append("|------|-------|-------|-------|")
for sname, fn, _ in strategies:
_, top3_by = strategy_results[sname]
t3 = top3_by[uid]
row = [sname]
for sid in t3:
info = idx_data.get(sid, {})
png = info.get("png", "")
title = info.get("title_text", "").strip().replace("\n", " ") or ""
if len(title) > 15:
title = title[:15] + "…"
mark = "⭐ " if sid == correct_id else ""
cell = f"{mark}![{sid}]({png_rel}{png})<br>**{sid}**<br>{title}"
row.append(cell)
lines.append("| " + " | ".join(row) + " |")
lines.append("")
out_path = Path(__file__).parent / "MATRIX_PHASE7.md"
out_path.write_text("\n".join(lines), encoding="utf-8")
print(f"\n완료: {out_path}")
if __name__ == "__main__":
main()