generated from kgod/ai-review-template
feat: builder 简历生成 + 轻度优化 + 简历导入交付副本
自内部仓库剥离深度优化与 RAG 知识库后的交付版本: - Builder 对话式简历生成(FSM + 意图路由 LLM 兜底增强) - 条目级轻度优化:事实覆盖门禁 + STAR/bullet 修复链,功能/简介/成果与技术栈同级保护 - 简历导入:DOCX/PDF 解析、结构归一、手机号脱敏 - PostgreSQL 运行时 + Alembic 迁移链 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
"""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())
|
||||
Reference in New Issue
Block a user