Files
resume-agent/backend/app/chat_intent_shadow.py
T
hypandClaude ae2d9b128d feat: builder 简历生成 + 轻度优化 + 简历导入交付副本
自内部仓库剥离深度优化与 RAG 知识库后的交付版本:
- Builder 对话式简历生成(FSM + 意图路由 LLM 兜底增强)
- 条目级轻度优化:事实覆盖门禁 + STAR/bullet 修复链,功能/简介/成果与技术栈同级保护
- 简历导入:DOCX/PDF 解析、结构归一、手机号脱敏
- PostgreSQL 运行时 + Alembic 迁移链

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-05 11:08:30 +08:00

61 lines
2.3 KiB
Python

"""P0 shadow rollout: run the LLM intent classifier beside rule routing, log only.
Observation-only — the LLM result never influences routing. Disagreements are
logged as `chat_intent_shadow` events to build the P1 golden dataset.
"""
from __future__ import annotations
import dataclasses
import logging
from typing import Any
from .chat_intent_classifier import (
ChatIntentClassifier,
LLMChatIntentClassifier,
RuleBasedChatIntentClassifier,
)
from .chat_intents import CHAT_INTENT_REGISTRY_VERSION
from .llm_services import OpenAICompatibleStructuredClient, log_ai_event
from .settings import Settings
class ChatIntentShadowLogger:
"""Compares LLM vs rule classification per message. Never used for routing."""
def __init__(self, primary: ChatIntentClassifier, rules: ChatIntentClassifier) -> None:
self.primary = primary
self.rules = rules
def observe(self, message: str, *, state_summary: dict[str, Any]) -> None:
rule_result = self.rules.classify(message, state_summary=state_summary)
try:
llm_result = self.primary.classify(message, state_summary=state_summary)
except Exception as exc:
log_ai_event(
"chat_intent_shadow_error",
level=logging.WARNING,
exception=type(exc).__name__,
trace_id=getattr(exc, "trace_id", None),
)
return
log_ai_event(
"chat_intent_shadow",
registry_version=CHAT_INTENT_REGISTRY_VERSION,
rule_intent=rule_result.intent.value,
llm_intent=llm_result.intent.value,
llm_confidence=llm_result.confidence,
disagreement=llm_result.intent != rule_result.intent,
)
def build_chat_intent_shadow(settings: Settings, client: Any | None = None) -> ChatIntentShadowLogger | None:
"""Shadow only when explicitly enabled *and* an LLM provider is configured."""
if settings.intent_router_mode != "shadow" or not settings.use_openai:
return None
llm_settings = settings
if settings.intent_model:
llm_settings = dataclasses.replace(settings, openai_model=settings.intent_model)
completion = OpenAICompatibleStructuredClient(llm_settings, client)
return ChatIntentShadowLogger(LLMChatIntentClassifier(completion), RuleBasedChatIntentClassifier())