feat(search): Phase 2.1 QueryAnalyzer + LRU cache + confidence 3-tier
QueryAnalyzer 스켈레톤 구현. 자연어 쿼리를 구조화된 분석 결과로 변환. Phase 2.1은 debug 노출 + tier 판정까지만 — retrieval 경로는 변경 X (회귀 0 목표). multilingual/filter 실제 분기는 2.2/2.3에서 이 분석 결과를 활용. app/prompts/query_analyze.txt - gemma-4 JSON-only 응답 규약 - intent/query_type/domain_hint/language_scope/normalized_queries/ hard_filters/soft_filters/expanded_terms/analyzer_confidence - 4가지 예시 (자연어 법령, 정확 조항, 뉴스 다국어, 의미 불명) - classify.txt 구조 참고 app/services/search/query_analyzer.py - LLM_TIMEOUT_MS=800 (MLX 멈춤 시 검색 전체 멈춤 방지, 절대 늘리지 말 것) - MAX_NORMALIZED_QUERIES=3 (multilingual explosion 방지) - in-memory FIFO LRU (maxsize=1000, TTL=86400) - cache key = sha256(query + PROMPT_VERSION + primary.model) → 모델/프롬프트 변경 시 자동 invalidate - 저신뢰(<0.5) / 실패 결과 캐시 금지 - weight 합=1.0 정규화 (fusion 왜곡 방지) - 실패 시 analyzer_confidence=float 0.0 (None 금지, TypeError 방지) app/api/search.py - ?analyze=true|false 파라미터 (default False — 회귀 영향 0) - query_analyzer.analyze() 호출 + timing["analyze_ms"] 기록 - _analyzer_tier(conf) → "ignore" | "original_fallback" | "merge" | "analyzed" (tier 게이트: 0.5 / 0.7 / 0.85) - debug.query_analysis 필드 채움 + notes에 tier/fallback_reason - logger 라인에 analyzer conf/tier 병기 app/services/search_telemetry.py - record_search_event(analyzer_confidence=None) 추가 - base_ctx에 analyzer_confidence 기록 (다층 confidence 시드) - result confidence와 분리된 축 — Phase 2.2+에서 failure 분류에 활용 검증: - python3 -m py_compile 통과 - 런타임 검증은 GPU 재배포 후 수행 (fixed 7 query + 평가셋) 참조: ~/.claude/plans/zesty-painting-kahan.md (Phase 2.1 섹션) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -244,6 +244,7 @@ async def record_search_event(
|
||||
results: list[Any],
|
||||
mode: str,
|
||||
confidence: float | None = None,
|
||||
analyzer_confidence: float | None = None,
|
||||
) -> None:
|
||||
"""검색 응답 직후 호출. 실패 트리거에 해당하면 로그 INSERT.
|
||||
|
||||
@@ -253,6 +254,13 @@ async def record_search_event(
|
||||
confidence 파라미터:
|
||||
- None이면 results 기준으로 자체 계산 (legacy 호출용).
|
||||
- 명시적으로 전달되면 그 값 사용 (Phase 0.5+: fusion 적용 전 raw 신호 기준).
|
||||
|
||||
analyzer_confidence (Phase 2.1):
|
||||
- QueryAnalyzer의 쿼리 분석 신뢰도 (result confidence와 다른 축).
|
||||
- `result.confidence` 가 낮더라도 `analyzer_confidence` 가 높으면
|
||||
"retrieval failure" (corpus에 정답 없음)로 해석 가능.
|
||||
- 반대로 analyzer_confidence < 0.5 이면 "query understanding failure" 해석.
|
||||
- Phase 2.1에서는 context에만 기록 (failure_reason 분류는 Phase 2.2+에서).
|
||||
"""
|
||||
if user_id is None:
|
||||
return
|
||||
@@ -260,7 +268,10 @@ async def record_search_event(
|
||||
if confidence is None:
|
||||
confidence = compute_confidence(results, mode)
|
||||
result_count = len(results)
|
||||
base_ctx = _build_context(results, mode, extra={"confidence": confidence})
|
||||
extra_ctx: dict[str, Any] = {"confidence": confidence}
|
||||
if analyzer_confidence is not None:
|
||||
extra_ctx["analyzer_confidence"] = float(analyzer_confidence)
|
||||
base_ctx = _build_context(results, mode, extra=extra_ctx)
|
||||
|
||||
# ── 1) reformulation 체크 (이전 쿼리가 있으면 그걸 로깅) ──
|
||||
prior = await _record_and_get_prior(user_id, query)
|
||||
|
||||
Reference in New Issue
Block a user