落地并存测服全端:智能体 Graph/路由、后台切 8180、主账与部署脚本齐备,便于线上重发与验收。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-09-13 21:15:58 +08:00
co-authored by Cursor
parent 0eb1adecc8
commit 8103b3b651
143 changed files with 8968 additions and 277 deletions
@@ -0,0 +1,251 @@
"""
DeepSeek A:`ordered_actions` / `route_decision` 工具合同与解析。
本文件职责:
- 给出唯一 strict tool schema(对齐现网 framework_route_contract 垂直切片);
- 把模型 tool_call 参数校验并投影为 RouteDecision;
- 不产生业务副作用(不建单、不发消息、不改六态)。
为何独立成文件:schema 与 IntentRouter / HTTP 客户端解耦,便于单测与合同演进。
"""
from __future__ import annotations
import json
import logging
import unicodedata
from dataclasses import dataclass, field
from typing import Any, Mapping, Optional
from agent.routing.decision import RouteDecision
logger = logging.getLogger(__name__)
ORDERED_ACTIONS_TOOL_NAME = "route_decision"
# action_type(模型枚举)→ 业务意图(RouteDecision.intent)
ACTION_INTENTS: dict[str, str] = {
"ATTACHMENT_DOCUMENT_INQUIRY": "attachment_inquiry",
"ATTACHMENT_IMAGE_INQUIRY": "image_inquiry",
"MULTI_SEGMENT_TRANSPORT": "multi_segment_transport",
"TMS_READ_ONLY_QUOTE": "tms_read_only_quote",
"ORDINARY_TEXT_INQUIRY": "ordinary_text_inquiry",
"ORDINARY_TEXT_OTHER": "ordinary_text_other",
}
class OrderedActionsError(ValueError):
"""ordered_actions 合同被违反(缺键、枚举不符、证据非法等)。"""
def _nfc(value: str) -> str:
"""非空 NFC 规范化;首尾空白视为非法(与现网一致)。"""
result = unicodedata.normalize("NFC", str(value))
if not result or result != result.strip():
raise OrderedActionsError("字符串须为非空 NFC 且无首尾空白")
return result
def ordered_actions_tool_definition() -> dict[str, Any]:
"""
返回 DeepSeek A 唯一 strict tool。
模型必须且只能调用本 tool;不得输出用户可见正文。
"""
action_types = sorted(ACTION_INTENTS)
intents = sorted(set(ACTION_INTENTS.values()))
target_schema = {
"type": "object",
"additionalProperties": False,
"properties": {"work_order_no": {"type": "string"}},
"required": ["work_order_no"],
}
evidence_schema = {
"type": "object",
"additionalProperties": False,
"properties": {
"source_ref": {"type": "string"},
"content_digest": {"type": "string"},
},
"required": ["source_ref", "content_digest"],
}
action_schema = {
"type": "object",
"additionalProperties": False,
"properties": {
"action_type": {"type": "string", "enum": action_types},
"order": {"type": "integer", "const": 1},
"target": target_schema,
"evidence": evidence_schema,
},
"required": ["action_type", "order", "target", "evidence"],
}
parameters = {
"type": "object",
"additionalProperties": False,
"properties": {
"decision_id": {"type": "string"},
"intent": {"type": "string", "enum": intents},
# 工具入参用单数;解析后统一成 ordered_actions 列表
"ordered_action": action_schema,
},
"required": ["decision_id", "intent", "ordered_action"],
}
return {
"type": "function",
"function": {
"name": ORDERED_ACTIONS_TOOL_NAME,
"description": (
"Return exactly one frozen business route decision "
"for the current inbound event."
),
"strict": True,
"parameters": parameters,
},
}
@dataclass(frozen=True)
class OrderedActionsResult:
"""校验后的 A 路由冻结结果(一条入站一条)。"""
decision_id: str
intent: str
action_type: str
work_order_no: str
evidence_source_ref: str
evidence_content_digest: str
raw: dict[str, Any] = field(default_factory=dict)
def to_route_decision(self, *, confidence: float = 1.0) -> RouteDecision:
"""投影为唯一 RouteDecision(仍无副作用)。"""
return RouteDecision(
intent=self.intent,
thread_id=self.work_order_no or "",
confidence=confidence,
raw={
"decision_id": self.decision_id,
"action_type": self.action_type,
"ordered_actions": self.raw,
"source": "deepseek_a",
},
)
def _coerce_tool_args(value: Any) -> dict[str, Any]:
"""接受 dict 或 JSON 字符串。"""
if isinstance(value, dict):
return value
if isinstance(value, str):
try:
data = json.loads(value)
except json.JSONDecodeError as exc:
raise OrderedActionsError("tool arguments 不是合法 JSON") from exc
if not isinstance(data, dict):
raise OrderedActionsError("tool arguments 必须是对象")
return data
raise OrderedActionsError("tool arguments 类型非法")
def parse_ordered_actions_arguments(
value: Mapping[str, Any] | str | dict[str, Any],
) -> OrderedActionsResult:
"""
解析并校验 route_decision tool 参数。
副作用:无。失败抛 OrderedActionsError。
"""
data = _coerce_tool_args(value)
decision_id = _nfc(str(data.get("decision_id") or ""))
intent = _nfc(str(data.get("intent") or ""))
action = data.get("ordered_action")
if action is None and isinstance(data.get("ordered_actions"), list):
actions = data["ordered_actions"]
if len(actions) != 1 or not isinstance(actions[0], dict):
raise OrderedActionsError("ordered_actions 必须恰好一条")
action = actions[0]
if not isinstance(action, dict):
raise OrderedActionsError("缺少 ordered_action")
action_type = _nfc(str(action.get("action_type") or ""))
if action_type not in ACTION_INTENTS:
raise OrderedActionsError(f"未知 action_type: {action_type}")
if ACTION_INTENTS[action_type] != intent:
raise OrderedActionsError("action_type 与 intent 不一致")
if action.get("order") != 1:
raise OrderedActionsError("order 必须为 1(当前垂直切片)")
target = action.get("target")
if not isinstance(target, dict):
raise OrderedActionsError("target 必须为对象")
work_order_no = str(target.get("work_order_no") or "").strip()
# 允许空工单号(新询价);若有值则 NFC
if work_order_no:
work_order_no = _nfc(work_order_no)
evidence = action.get("evidence")
# 工具 schema 是单对象;兼容列表写法
if isinstance(evidence, list):
if len(evidence) != 1 or not isinstance(evidence[0], dict):
raise OrderedActionsError("evidence 须恰好一条")
evidence = evidence[0]
if not isinstance(evidence, dict):
raise OrderedActionsError("evidence 必须为对象")
source_ref = _nfc(str(evidence.get("source_ref") or ""))
digest = str(evidence.get("content_digest") or "").lower()
if len(digest) != 64 or any(c not in "0123456789abcdef" for c in digest):
raise OrderedActionsError("content_digest 必须是 64 位小写 hex")
frozen = {
"decision_id": decision_id,
"intent": intent,
"ordered_actions": [
{
"action_type": action_type,
"order": 1,
"target": {"work_order_no": work_order_no or None},
"evidence": [
{"source_ref": source_ref, "content_digest": digest},
],
}
],
}
logger.info(
"ordered_actions 已校验 decision_id=%s intent=%s action=%s",
decision_id,
intent,
action_type,
)
return OrderedActionsResult(
decision_id=decision_id,
intent=intent,
action_type=action_type,
work_order_no=work_order_no,
evidence_source_ref=source_ref,
evidence_content_digest=digest,
raw=frozen,
)
def extract_tool_arguments_from_chat_raw(
raw: Optional[Mapping[str, Any]],
*,
tool_name: str = ORDERED_ACTIONS_TOOL_NAME,
) -> dict[str, Any]:
"""
从 OpenAI 兼容 chat 响应中取出指定 tool 的 arguments。
未找到则抛 OrderedActionsError。
"""
if not raw:
raise OrderedActionsError("空模型响应")
choices = raw.get("choices") or []
if not choices:
raise OrderedActionsError("无 choices")
message = (choices[0] or {}).get("message") or {}
tool_calls = message.get("tool_calls") or []
for call in tool_calls:
fn = (call or {}).get("function") or {}
if str(fn.get("name") or "") == tool_name:
return _coerce_tool_args(fn.get("arguments"))
raise OrderedActionsError(f"未调用 tool: {tool_name}")