AI_Menu_Search / scripts /04_evaluate.py
Juhaha
HF Spaces 데모 배포 (Streamlit + Qdrant 임베디드, 색인 빌드타임 생성)
fbd1091
Raw
History Blame Contribute Delete
3.82 kB
"""
Step 4: 검색 품질 평가 (Hit@K 메트릭)
실행: python scripts/04_evaluate.py
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from rich.console import Console
from rich.table import Table
from core.search_engine import MenuSearchEngine
console = Console()
# (쿼리, 정답 menu_id) 평가셋 — 실제 SCR_ 형식 ID 기준 (real_menus.json 검증)
EVAL_SET = [
# 국내주식 - 관심/시세 (search_count 상위)
("관심종목 보고싶어", "SCR_1000"), # 국내관심, sc=12,739,646
("삼성전자 호가 보여줘", "SCR_1050"), # 호가, sc=9,120,154
("종목 차트 보고싶어", "SCR_1200"), # 종목차트, sc=11,006,235
# 국내주식 - 계좌/주문
("국내주식 잔고 확인", "SCR_1300"), # 국내잔고, sc=14,981,128
("미체결 주문 확인", "SCR_1301"), # 미체결, sc=1,895,282
("오늘 손익 얼마야", "SCR_1309"), # 실현손익, sc=875,319
("예약주문 걸어놓고 싶어", "SCR_1180"), # 예약주문, sc=107,490
("내 조건검색식 편집하고 싶어", "SCR_1871"), # 조건검색, sc=311,728
# 해외주식
("미국 주식 주문하고 싶어", "SCR_3030"), # 해외주식주문, sc=1,615,638
("해외주식 잔고 확인", "SCR_3032"), # 해외잔고, sc=4,127,850
("애플 주식 현재가 호가", "SCR_3010"), # 해외호가, sc=1,662,209
# 파생상품 (CFD)
("CFD 주문하고 싶어", "SCR_2020"), # 파생 CFD 주문, sc=117
# 자산/뱅킹
("입출금 하고싶어", "SCR_5000"), # 입출금, sc=1,210,154
("이체내역 조회", "SCR_5006"), # 이체내역조회, sc=224,757
# search_count 낮은 메뉴 (다양성 확보)
("주식더모으기 설정", "SCR_1182"), # 주식더모으기, sc=0
]
def evaluate(engine: MenuSearchEngine, k_values=(1, 3, 5)):
hits = {k: 0 for k in k_values}
details = []
for query, correct_id in EVAL_SET:
results = engine.search(query, top_n=max(k_values), threshold=0.0)
returned_ids = [r["menu_id"] for r in results]
top1 = results[0]["menu_name"] if results else "-"
top1_sim = results[0]["similarity_pct"] if results else "-"
row = {"query": query, "correct": correct_id, "top1": top1, "top1_sim": top1_sim}
for k in k_values:
row[f"hit@{k}"] = correct_id in returned_ids[:k]
if row[f"hit@{k}"]:
hits[k] += 1
details.append(row)
# 상세 결과 테이블
table = Table(title="검색 품질 평가 상세", show_lines=True)
table.add_column("쿼리", style="white", max_width=30)
table.add_column("Top-1 결과", style="cyan")
table.add_column("유사도", style="yellow")
table.add_column("Hit@1", style="green")
table.add_column("Hit@3", style="green")
table.add_column("Hit@5", style="green")
for row in details:
table.add_row(
row["query"],
row["top1"],
row["top1_sim"],
"✅" if row["hit@1"] else "❌",
"✅" if row["hit@3"] else "❌",
"✅" if row["hit@5"] else "❌",
)
console.print(table)
# 요약
total = len(EVAL_SET)
console.print("\n[bold]=== 평가 요약 ===[/bold]")
for k in k_values:
rate = hits[k] / total * 100
color = "green" if rate >= 70 else "yellow" if rate >= 50 else "red"
console.print(f" Hit@{k}: [{color}]{hits[k]}/{total} ({rate:.1f}%)[/{color}]")
if __name__ == "__main__":
engine = MenuSearchEngine.get_instance()
evaluate(engine)