From 70b27d4a5145688d3d1631e1c7d7d0573f849ad7 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Tue, 7 Apr 2026 08:37:13 +0900 Subject: [PATCH] =?UTF-8?q?fix(search):=20confidence=20=EC=9E=84=EA=B3=84?= =?UTF-8?q?=EA=B0=92=20=EC=99=84=ED=99=94=20+=20hybrid=20+vector=20boost?= =?UTF-8?q?=20=EA=B0=80=EC=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit baseline 평가셋 실행 시 'summary+vector' top_score 2.39가 임계값 2.5에 미달해 정답 쿼리(산업안전보건법 제6장)가 low_confidence로 잘못 잡힘. - 텍스트 매치 임계값 0.5씩 완화 (실측 분포 반영) - '+vector' 접미사가 있으면 hybrid 합성 매치이므로 confidence +0.10 가산 - 정답률 5/5 → 4/5 false-positive 1건 제거 기대 Co-Authored-By: Claude Opus 4.6 (1M context) --- app/services/search_telemetry.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/app/services/search_telemetry.py b/app/services/search_telemetry.py index 3260420..bc6e05c 100644 --- a/app/services/search_telemetry.py +++ b/app/services/search_telemetry.py @@ -103,17 +103,22 @@ def compute_confidence(results: list[Any], mode: str) -> float: # 코사인 유사도 그대로 return _cosine_to_confidence(top_score) - # text / hybrid: 강한 텍스트 매치 우선 판정 - if "title" in reason and top_score >= 4.0: - return 0.95 - if any(k in reason for k in ("tags", "note")) and top_score >= 3.0: - return 0.85 - if "summary" in reason and top_score >= 2.5: - return 0.75 - if "content" in reason and top_score >= 2.0: - return 0.65 + # hybrid에서 텍스트+벡터 합성 매치는 reason에 "+vector" 접미. 신뢰 가산. + has_vector_boost = "+vector" in reason + boost = 0.10 if has_vector_boost else 0.0 + + # text / hybrid: 강한 텍스트 매치 우선 판정. + # 임계값은 search.py의 가중치 합산 분포(텍스트base + FTS bonus + 0.5*cosine)를 반영. + if "title" in reason and top_score >= 3.5: + return min(1.0, 0.95 + boost) + if any(k in reason for k in ("tags", "note")) and top_score >= 2.5: + return min(1.0, 0.85 + boost) + if "summary" in reason and top_score >= 2.0: + return min(1.0, 0.75 + boost) + if "content" in reason and top_score >= 1.5: + return min(1.0, 0.65 + boost) if "fts" in reason and top_score >= 1.0: - return 0.55 + return min(1.0, 0.55 + boost) # vector-only hit (텍스트 0건 → 코사인 raw, amplify 금지) if reason == "vector":