Files
resume-agent/backend/app/chat_intents.py
T

76 lines
3.3 KiB
Python

"""Chat intent registry: taxonomy, descriptions, few-shots, and output schema.
Single source of truth for Builder free-text intents. The LLM classifier may only
choose from this registry; handlers are bound deterministically in code (LLM
proposes, code disposes). Bump CHAT_INTENT_REGISTRY_VERSION on any taxonomy change.
"""
from __future__ import annotations
from enum import StrEnum
from typing import Literal
from pydantic import Field
from .llm_services import StrictSchema
CHAT_INTENT_REGISTRY_VERSION = "1"
class ChatIntent(StrEnum):
PROVIDE_FACTS = "provide_facts"
NEW_ENTRY = "new_entry"
EDIT_ENTRY = "edit_entry"
EDIT_IDENTITY = "edit_identity"
REVISE_PROPOSAL = "revise_proposal"
NO_INFO = "no_info"
ASK_QUESTION = "ask_question"
CHITCHAT = "chitchat"
UNCLEAR = "unclear"
INTENT_DESCRIPTIONS: dict[ChatIntent, str] = {
ChatIntent.PROVIDE_FACTS: "在给当前草稿补充事实(含回答追问):动作、方法、工具、规模、结果等",
ChatIntent.NEW_ENTRY: "想新增另一段经历(教育/工作/实习/项目/校园),不是在改当前这段",
ChatIntent.EDIT_ENTRY: "想修改某段已确认写入简历的经历,可提到公司/学校/项目名",
ChatIntent.EDIT_IDENTITY: "想改当前这段的基础信息:学校、公司、职位、时间等",
ChatIntent.REVISE_PROPOSAL: "对当前候选优化稿的调整指令:保留原文、不要跳过、再专业一点等",
ChatIntent.NO_INFO: "明确表示没有、无、暂无,是对追问的否定回答",
ChatIntent.ASK_QUESTION: "在提问:关于简历怎么写、流程、建议等;不是在提供事实",
ChatIntent.CHITCHAT: "寒暄、感谢、好的、可以等纯应答,不含新事实",
ChatIntent.UNCLEAR: "无法判断意图,需要向用户澄清",
}
INTENT_FEWSHOTS: tuple[dict[str, object], ...] = (
{"message": "负责后端接口开发,使用 Python 和 FastAPI,覆盖 3 个业务流程", "intent": ChatIntent.PROVIDE_FACTS},
{"message": "新增一段教育经历", "intent": ChatIntent.NEW_ENTRY},
{"message": "修改一下我之前写的那个 AI Career Copilot 项目经历", "intent": ChatIntent.EDIT_ENTRY},
{"message": "把学校名字改成东莞城市学院", "intent": ChatIntent.EDIT_IDENTITY},
{"message": "保留原文,不要用这版优化稿", "intent": ChatIntent.REVISE_PROPOSAL},
{"message": "没有", "intent": ChatIntent.NO_INFO},
{"message": "这段经历你觉得怎么写比较好?", "intent": ChatIntent.ASK_QUESTION},
{"message": "好的,谢谢", "intent": ChatIntent.CHITCHAT},
{"message": "嗯……那个嘛", "intent": ChatIntent.UNCLEAR},
)
class ExtractedFact(StrictSchema):
"""One atomic fact copied or tightly paraphrased from the user's own message."""
text: str
kind: Literal["action", "method", "tool", "scale", "result", "other"] = "other"
class ChatTurnClassification(StrictSchema):
"""Structured output of the chat intent classifier (one call per message)."""
intent: ChatIntent
confidence: float = Field(default=0.5, ge=0, le=1)
target_section: str | None = None
target_entry_hint: str | None = None
facts: list[ExtractedFact] = Field(default_factory=list)
identity_updates: dict[str, str] | None = None
revision_instruction: str | None = None
user_question: str | None = None
reason: str = ""