Files
group_fqcd_jr/app/service/intent_classifier.py
T

66 lines
2.6 KiB
Python

"""统一意图分类出口,业务 Agent 不得自行解析模型分类结果。"""
import json
from typing import Any, Protocol
from pydantic import BaseModel, ConfigDict, Field, ValidationError
from app.core.contracts import IntentResult
from app.core.errors import RecoverableAgentError, ValidationAgentError
from app.service.model_gateway import ModelGenerationService
class IntentEndpointResolver(Protocol):
async def resolve(self, *, agent_type: str, task_type: str) -> list[Any]: ...
class _IntentPayload(BaseModel):
model_config = ConfigDict(extra="forbid")
intent: str = Field(min_length=1, max_length=64)
confidence: float = Field(ge=0, le=1)
class IntentClassifier:
"""使用已路由模型输出严格 JSON,并绑定 Agent 声明的意图集合。"""
def __init__(self, model_service: ModelGenerationService, *, threshold: float = 0.65) -> None:
if not 0 <= threshold <= 1:
raise ValueError("intent threshold must be between 0 and 1")
self.model_service = model_service
self.threshold = threshold
async def classify(
self, *, message: str, supported_intents: tuple[str, ...], endpoints: list[Any]
) -> IntentResult:
if not message.strip():
raise ValidationAgentError("待分类消息不能为空")
if not supported_intents:
raise ValidationAgentError("Agent 未声明支持的意图")
prompt = (
"请仅输出 JSON,不要 Markdown。字段必须为 intent 和 confidence。"
f"intent 只能从 {list(supported_intents)!r} 中选择,confidence 为 0 到 1 的数字。"
f"用户消息:{message}"
)
execution = await self.model_service.generate(endpoints, prompt)
payload = self._parse(execution.text)
if payload.intent not in supported_intents:
raise ValidationAgentError("模型返回了未声明的意图")
return IntentResult(
intent=payload.intent,
confidence=payload.confidence,
needs_clarification=payload.confidence < self.threshold,
)
@staticmethod
def _parse(text: str) -> _IntentPayload:
candidate = text.strip()
if candidate.startswith("```"):
candidate = candidate.removeprefix("```")
candidate = candidate.removeprefix("json").removesuffix("```").strip()
try:
value = json.loads(candidate)
return _IntentPayload.model_validate(value)
except (json.JSONDecodeError, ValidationError, TypeError) as exc:
raise RecoverableAgentError("模型意图输出不是有效 JSON") from exc