第 1.9.3 节:让模型、工具、API 和日志共用一套字段契约
模型、工具、API 与日志不能只停留在口头约定,还需要落实为字段、校验和失败处理。完成本节后,你应该能够把模型、工具、API 与日志落成字段表、校验规则、错误处理和验收样例。
实现步骤或决策流程
推荐技术流
本章推荐的技术流不是“先学 Pydantic(数据校验库)所有语法”,而是从业务边界倒推契约。
| 步骤 | 做什么 | 为什么 |
|---|---|---|
| 1 | 画出客服工作台的数据流 | 先知道数据从用户、模型、工具、API(应用程序接口)、前端到日志怎么流动。 |
| 2 | 标出边界数据 | 模型输出、工具输入、工具结果、前端状态和日志都是高风险边界。 |
| 3 | 统一核心字段名 | intent(意图)、risk_level(风险等级)、next_action(下一步动作)等字段不要各层各叫一套。 |
| 4 | 定义字段含义和枚举 | 先统一业务含义,再考虑技术实现。 |
| 5 | 增加 schema_version(契约版本) | 字段规则会演进,必须能追踪不同版本。 |
| 6 | 设计校验结果字段 | 用 validation_status(校验状态)和 validation_error(校验错误)表达失败原因。 |
| 7 | 设计失败动作 | 根据风险决定重试、追问、降级、转人工或拒绝工具执行。 |
| 8 | 让前端消费同一套状态 | 前端不应该自己猜“该显示什么”。 |
| 9 | 让日志记录同一套字段 | 排查问题时可以按追踪编号复盘全链路。 |
| 10 | 用验收用例固定契约 | 每次改 Prompt(提示词)、工具或字段时,用同一批样例回归。 |
这条技术流的核心理由是:AI Agent(人工智能体)系统最容易坏在“边界理解不一致”。Pydantic(数据校验库)只是落地工具,真正要治理的是字段语义和失败路径。
字段契约
本节是本章最重要的交付物。字段契约不是把所有字段塞进一张大表,而是说明字段在业务流程里的含义、来源、取值和失败处理。
核心字段契约表
| 字段 | 中文含义 | 出现位置 | 推荐取值或说明 | 校验失败后果 |
|---|---|---|---|---|
schema_version | 契约版本 | 模型输出、API 响应、日志 | 例如 v1、v2;用于识别字段规则版本 | 版本缺失时按未知版本处理,高风险动作不得自动执行。 |
intent | 意图 | 模型输出、前端状态、验收用例 | order_status、refund_request、repair_request、complaint、product_question、unknown 等 | 未识别或不在枚举内时,进入追问、降级或转人工。 |
risk_level | 风险等级 | 模型输出、工具治理、前端提醒、日志 | low、medium、high | 缺失时按更高风险处理,不允许自动执行写入或资金相关动作。 |
next_action | 下一步动作 | 模型输出、流程路由、前端状态 | answer、ask_followup、search_knowledge、call_tool、create_ticket、handoff、reject | 未定义动作不能进入流程,应触发重试或降级。 |
missing_fields | 缺失字段 | 模型输出、前端追问、验收用例 | order_id、product_name、contact_info、issue_description 等 | 存在关键缺失字段时,不允许调用依赖该字段的工具。 |
tool_name | 工具名称 | 工具调用意图、工具日志 | get_order_status、search_after_sales_policy、create_support_ticket 等 | 未在工具白名单内时拒绝执行并记录日志。 |
tool_args | 工具参数 | 工具调用意图、工具输入校验 | 包含工具所需业务字段,例如订单编号、问题类型、用户确认状态 | 参数缺失、越权或类型不合格时拒绝工具执行。 |
validation_status | 校验状态 | 校验结果、API 响应、日志 | passed、failed、needs_retry、fallback(降级方案)、rejected | 决定能否继续流程;失败状态不能伪装成成功。 |
validation_error | 校验错误 | 校验结果、日志、内部诊断 | missing_required_field、invalid_enum、unsafe_action、tool_args_invalid、permission_denied 等 | 用于决定兜底方式和复盘原因。 |
retry_allowed | 是否允许重试 | 校验结果、流程控制 | true 或 false | 不允许重试时必须降级、转人工或拒绝执行。 |
fallback_action | 兜底动作 | 校验结果、前端状态、人工协作 | ask_user、safe_reply、handoff_to_human、block_tool、create_manual_review | 缺失时按安全兜底处理,高风险动作默认转人工或阻断。 |
trace_id | 追踪编号 | 全链路日志、API 响应、工具调用 | 系统生成的唯一追踪编号 | 缺失时仍可给用户安全回复,但必须记录监控告警,避免问题无法复盘。 |
这张表要让你形成一个习惯:每个字段都要回答“谁产生、谁消费、错了怎么办”。字段不是为了好看,而是为了让业务流程可控。
模型结构化输出契约
模型结构化输出负责把用户自然语言转成系统可以处理的判断结果。
| 字段 | 模型应该表达什么 | 系统怎么使用 |
|---|---|---|
intent(意图) | 用户当前主要诉求 | 决定走知识库、工具、工单、转人工还是拒答。 |
risk_level(风险等级) | 当前请求的业务风险 | 决定是否允许自动化、是否需要人工确认。 |
next_action(下一步动作) | 模型建议的下一步 | 由系统二次校验后路由,不是模型单方面决定。 |
missing_fields(缺失字段) | 继续处理还缺什么 | 前端用于追问,工具层用于阻断不完整调用。 |
tool_name(工具名称) | 如果需要工具,建议哪个工具 | 必须经过工具白名单和权限校验。 |
tool_args(工具参数) | 工具所需参数 | 必须经过字段、权限和业务对象归属校验。 |
注意:模型可以建议 tool_name(工具名称)和 tool_args(工具参数),但不能绕过系统直接执行工具。模型输出是“候选决策”,不是“最终权限”。
工具输入契约
工具输入契约负责保护真实业务系统。尤其是查订单、建工单、发起退款审批这类能力,不能只看模型是否“说得像”。
| 工具场景 | 必须校验的字段 | 不通过时如何处理 |
|---|---|---|
| 查订单状态 | 当前用户身份、订单编号、订单归属、trace_id(追踪编号) | 拒绝查询或要求用户选择自己的订单。 |
| 查售后政策 | 商品类别、购买时间、问题类型、政策版本 | 资料不足时转人工或提示无法判断,不让模型编造政策。 |
| 创建客服工单 | 用户身份、问题摘要、问题类型、用户确认状态、关联订单、trace_id(追踪编号) | 没有用户确认时不创建工单;缺关键字段时追问。 |
| 发起退款审批 | 订单归属、退款原因、售后政策依据、风险等级、人工确认状态 | 不直接退款;缺依据或高风险时进入人工审批。 |
工具输入契约的原则是:越接近真实业务状态改变,校验越严格。
API(应用程序接口)响应契约
API 响应契约要让前端知道“现在处于什么状态、用户能做什么、系统为什么这样处理”。
| 字段类别 | 前端需要知道什么 | 示例用途 |
|---|---|---|
| 展示内容 | 回复草稿、追问问题、工具结果摘要 | 展示给用户或人工客服编辑。 |
| 状态字段 | validation_status(校验状态)、next_action(下一步动作)、fallback_action(兜底动作) | 决定显示回答、追问、错误、转人工或审批按钮。 |
| 风险字段 | risk_level(风险等级)、是否需要人工确认 | 在工作台提醒客服关注高风险会话。 |
| 错误字段 | 可展示错误和内部错误的区分 | 用户看到温和提示,开发和运营看到可复盘原因。 |
| 追踪字段 | trace_id(追踪编号) | 客服或开发排查时能定位同一次请求。 |
前端不应该靠字符串猜状态。例如看到“订单系统暂时不可用”就自己判断是工具失败,这会导致页面逻辑失控。前端应该消费明确的状态字段。
日志字段契约
日志契约用于复盘,不是把所有原始数据无脑存下来。
| 日志字段 | 含义 | 注意事项 |
|---|---|---|
trace_id(追踪编号) | 串联用户输入、模型输出、工具调用、API 响应和前端展示 | 必须全链路一致。 |
schema_version(契约版本) | 当时使用的字段契约版本 | 方便排查版本升级引起的问题。 |
intent(意图) | 模型识别的用户诉求 | 可用于质检和统计。 |
risk_level(风险等级) | 风险判断结果 | 高风险误判要进入复盘。 |
tool_name(工具名称) | 请求或执行的工具 | 未执行也要记录“被拒绝原因”。 |
validation_status(校验状态) | 校验通过、失败、重试、兜底或拒绝 | 用于监控契约稳定性。 |
validation_error(校验错误) | 字段缺失、枚举错误、越权、工具参数错误等 | 不记录敏感原文,记录可诊断原因。 |
fallback_action(兜底动作) | 最终采取的安全处理 | 方便运营分析转人工和降级比例。 |
日志里不要记录 API Key(接口密钥)、完整身份证号、完整手机号、支付信息、内部密钥和未经脱敏的敏感原文。可追踪不等于无限制记录。
制作步骤
下面是一套适合本书作品集项目的制作步骤。它不依赖具体语法,但能指导你真正落地数据契约。
第 1 步:画出边界
先列出哪些地方会发生数据跨模块传递:
| 边界 | 数据从哪里来 | 数据到哪里去 |
|---|---|---|
| 用户入口到模型 | 用户问题、会话信息、身份摘要 | Prompt 和模型请求。 |
| 模型到后端 | 结构化输出 | 校验层和流程路由。 |
| 后端到工具 | 工具名称和工具参数 | 订单、知识库、工单系统。 |
| 工具到后端 | 工具执行结果和错误 | Agent 回答生成和日志。 |
| 后端到前端 | 状态、回复、追问、错误和追踪编号 | 用户界面和客服工作台。 |
| 后端到日志 | 摘要字段、状态、错误和兜底 | 审计、质检和排查。 |
只要跨边界,就不要靠“大家记得字段怎么写”。跨边界的数据必须有契约。
第 2 步:先定字段语义,不急着写模型
先把字段含义讲清楚:
| 字段 | 要先问清的问题 |
|---|---|
intent(意图) | 业务上到底有哪些意图?一个用户问题能不能有多个意图?主意图怎么选? |
risk_level(风险等级) | 什么情况算 high?投诉、退款、威胁曝光、隐私数据分别怎么处理? |
next_action(下一步动作) | 哪些动作是模型建议,哪些动作必须系统或人工决定? |
missing_fields(缺失字段) | 缺字段时是追问用户、让用户选择,还是转人工? |
tool_args(工具参数) | 哪些参数来自用户话术,哪些必须来自登录态或业务系统? |
语法可以晚一点写,字段语义不能晚一点定。语义不清的模型,只会把混乱自动化。
第 3 步:把字段分层
不要把所有字段都塞给所有模块。
| 字段层 | 示例 | 谁主要消费 |
|---|---|---|
| 业务判断字段 | intent(意图)、risk_level(风险等级)、next_action(下一步动作) | Agent 流程、前端、测试。 |
| 工具执行字段 | tool_name(工具名称)、tool_args(工具参数) | 工具治理层。 |
| 校验字段 | validation_status(校验状态)、validation_error(校验错误)、retry_allowed(是否允许重试) | 校验层、流程控制、日志。 |
| 兜底字段 | fallback_action(兜底动作) | 前端、人工协作、运营复盘。 |
| 追踪字段 | trace_id(追踪编号)、schema_version(契约版本) | 日志、监控、测试和排查。 |
分层的意义是降低耦合。比如前端不一定需要看到完整工具参数,但必须知道下一步动作和展示状态。
第 4 步:定义成功和失败的验收样例
每个字段都要通过样例验证。
| 样例 | 用户输入 | 期望字段 |
|---|---|---|
| 普通产品咨询 | “这款设备适合老人用吗?” | intent 为 product_question,risk_level 为 low,next_action 为 search_knowledge 或 answer。 |
| 缺订单的退款请求 | “我要退款,但是订单号忘了。” | intent 为 refund_request,missing_fields 包含 order_id,不能调用退款相关工具。 |
| 高风险投诉 | “你们不处理我就曝光。” | risk_level 为 high,next_action 倾向 handoff 或 create_ticket。 |
| 越权订单查询 | “帮我查这个别人给我的订单号。” | 工具参数校验失败,fallback_action 为 block_tool 或 handoff_to_human。 |
| 工具超时 | 订单系统无响应 | validation_status 为 fallback(降级方案),回复不得编造订单状态。 |
验收样例要覆盖失败,不要只覆盖顺利演示。
第 5 步:设计重试策略
重试不是万能解。重试要区分场景。
| 失败类型 | 是否建议重试 | 理由 |
|---|---|---|
| 输出格式轻微不合格 | 可以有限重试 | 可能是模型格式漂移,重试能修复。 |
| 缺少关键字段 | 视情况 | 如果用户本来没提供订单号,重试模型没有意义,应该追问用户。 |
| 工具参数越权 | 不重试 | 越权不是格式问题,必须拒绝或转人工。 |
| 高风险动作缺确认 | 不自动重试 | 需要用户或人工确认,不是模型重新生成能解决。 |
| 工具系统超时 | 可以工具层有限重试 | 但不能让模型编造工具结果。 |
项目里要明确 retry_allowed(是否允许重试),避免所有失败都被粗暴重试。
第 6 步:把兜底动作写成契约
兜底不要只写在注释或口头说明里。它应该成为字段的一部分。
| 兜底动作 | 适用场景 | 前端或系统行为 |
|---|---|---|
| ask_user | 缺少订单号、联系方式、商品名称等用户可补信息 | 展示追问,不调用工具。 |
| safe_reply | 低风险但资料不足 | 给出保守说明,不承诺业务结果。 |
| handoff_to_human | 高风险投诉、政策不明确、工具多次失败 | 创建或提示人工接管。 |
| block_tool | 工具越权、参数不合格、工具不在白名单 | 拒绝执行工具并记录原因。 |
| create_manual_review | 涉及退款、补偿、合规争议 | 进入人工审核流程。 |
有了 fallback_action(兜底动作),前端、客服和日志系统都能理解失败后的处理方式。
和后续章节关系
本章是后续很多能力的地基。
| 后续内容 | 和本章的关系 |
|---|---|
| FastAPI(后端接口框架)章节 | API 请求响应会直接依赖数据契约。 |
| 测试与日志章节 | 测试用例要验证契约,日志要记录契约版本、校验状态和错误原因。 |
| RAG(检索增强生成)章节 | 检索结果、引用来源、答案依据和不确定性也需要字段契约。 |
| MCP(模型上下文协议)章节 | 工具发现、工具输入和工具结果需要更标准化的契约边界。 |
| LangGraph(智能体状态图框架)章节 | 状态图节点之间传递的状态必须稳定,否则流程会漂移。 |
| 多模型适配章节 | 不同模型输出风格不同,更需要统一校验和适配层。 |
| 安全权限章节 | 越权、敏感信息、工具执行和人工审批都依赖字段契约表达风险。 |
| 可观测性章节 | trace_id(追踪编号)和校验日志会成为排查、告警和复盘的基础。 |
如果你把本章学扎实,后面很多技术会更容易理解。因为你已经知道:无论换什么框架,真实系统都需要稳定的数据边界。
版本与资料来源
具体 Pydantic(数据校验库)、FastAPI(后端接口框架)和模型 SDK(软件开发工具包)的写法会随版本变化,本章只固定工程设计原则、字段契约和失败处理思路。进入真实项目开发前,应重新核对官方文档。
主要资料入口:
- Pydantic(数据校验库)官方文档:https://docs.pydantic.dev/
- FastAPI(后端接口框架)官方文档:https://fastapi.tiangolo.com/
- OpenAI(模型服务商) Function Calling(函数调用)指南:https://developers.openai.com/api/docs/guides/function-calling
- Model Context Protocol(模型上下文协议)官方文档:https://modelcontextprotocol.io/
过时风险:Pydantic(数据校验库)、FastAPI(后端接口框架)、模型供应商的结构化输出能力和工具调用接口会持续更新。发布前需要核对当前官方文档,尤其是字段校验、错误格式、SDK(软件开发工具包)接口和工具调用参数。