输出契约
让下游系统可以消费的格式、字段与异常状态约定。
一句话理解:输出契约是 Agent 与下游消费者之间的正式约定:交付什么结构、每个字段是什么含义、成功与各种“不成功”分别怎么表示、版本如何演进;它让 Agent 的结果可以被界面、系统和其他 Agent 可靠地使用。
Demo 阶段,Agent 的输出只给开发者自己看,写成一段文字完全没问题。进入生产后,同一份输出可能同时被四方消费:客服工作台要展示结论和话术,工单系统要读取处置动作,监控看板要统计退款原因分布,另一个“退款审批 Agent”要接着处理。任何一方理解错一个字段,都会出问题。
更隐蔽的风险来自“不成功”的情况:查不到数据、工具超时、需要人工介入。如果这些情况没有被约定,Agent 可能把“系统暂时无法获取支付状态”写成一句话塞进 reason,而下游程序会把它当作一个正常结论记录下来。
结构化输出 解决的是“格式能不能被解析”,输出契约解决的是“格式背后的含义是否被双方一致理解”。
一份输出同时被多方消费,契约就站在 Agent 与它们之间:
契约包含什么
| 要素 | 说明 | 常见遗漏 |
|---|---|---|
| 消费者 | 谁在使用这份输出,各自需要哪些字段 | 只考虑界面,忘了统计和审计 |
| 结构与字段 | 字段名、类型、是否必填、取值范围 | 字段含义只存在于开发者脑子里 |
| 枚举值 | 每个枚举值的精确定义与判定标准 | 新增枚举值时没有通知下游 |
| 状态语义 | 成功、部分成功、需要补充信息、无法完成、需人工介入分别如何表示 | 只定义了成功时的结构 |
| 人读与机读的分离 | 给人看的文本与给程序用的字段分开 | 程序去解析一段自然语言 |
| 版本 | 契约版本号、兼容策略、变更流程 | 悄悄改字段导致下游报错 |
| 校验与处理 | 不符合契约时谁来处理、如何处理 | 默认“模型不会出错” |
客服退款 Agent 的输出契约
下面是一份可以直接放进需求文档的契约说明。它在 一份好指令的构成 中输出格式的基础上,补充了版本号、缺失信息和执行故障状态,这也是真实项目里契约通常的演进方式;采用这份契约时,指令中的输出格式要同步更新。
字段定义:
| 字段 | 类型 | 必填 | 含义与规则 | 消费者 |
|---|---|---|---|---|
schema_version |
string | 是 | 契约版本,当前为 "1.2" |
所有 |
status |
enum | 是 | 本次任务的完成状态,见下方状态语义 | 所有 |
order_no |
string | 是 | 必须与输入订单号一致 | 工单系统、审计 |
refund_decision |
enum | 是 | 符合退款政策、部分符合、不符合、需要补充证据、无法判断 |
看板、工单系统 |
reason |
string | 是 | 一句话判断依据;状态非 resolved 时说明缺少什么 |
客服工作台 |
refund_amount |
number 或 null | 是 | 建议退款金额(元),不得超过可退余额;无法确定时为 null | 工单系统、财务 |
evidence |
array | 是 | 每项含 source(工具名)、time、detail;无证据时为空数组 |
客服工作台、审计 |
actions |
array | 是 | 每项含 owner 枚举、action、system;无动作时为空数组 |
工单系统 |
customer_message |
string 或 null | 是 | 客户话术,不含到账时间与审批结果承诺;不适合联系客户时为 null | 客服工作台 |
missing_info |
array | 是 | 缺失或获取失败的数据项,例如 payment_status |
客服工作台、监控 |
need_human_review |
boolean | 是 | 是否需要人工复核 | 工单系统 |
escalation_reason |
string 或 null | 是 | 需要复核的原因 | 主管工作台 |
状态语义与下游处理:
| status | 含义 | 客服工作台 | 工单系统 |
|---|---|---|---|
resolved |
已作出退款判定,给出可执行方案 | 展示结论、证据与话术 | 按 actions 生成待确认任务 |
need_more_info |
需要用户补充信息才能继续(如缺订单号、质量问题照片) | 展示需要补充的内容 | 不创建任务 |
unable_to_confirm |
已尽力调查,但数据不足或矛盾,无法得出结论 | 展示已知部分与 missing_info |
创建“人工排查”任务 |
tool_failure |
关键数据源不可用,调查无法进行 | 提示稍后重试 | 记录故障,触发监控告警 |
注意 业务结果 与 执行故障 被区分开了:unable_to_confirm 是 Agent 正常工作后得出的“查不清”,而 tool_failure 是系统问题。混在一起的话,监控看板上“无法判断率上升”到底是业务变复杂了还是某个接口挂了,就无从分辨。
示例:数据不足时的输出
{
"schema_version": "1.2",
"status": "unable_to_confirm",
"order_no": "A-10231",
"refund_decision": "无法判断",
"reason": "订单签收 3 天,仍在无理由退款时效内,但支付记录与已退金额暂时无法获取,无法计算可退金额",
"refund_amount": null,
"evidence": [
{"source": "get_order", "time": "2026-09-14 08:14", "detail": "订单状态为已签收,实付 268 元(示例数字)"}
],
"actions": [
{"owner": "客服", "action": "人工核实该订单的历史退款记录", "system": "支付管理后台"}
],
"customer_message": "您好,我们正在核实这笔订单的支付与退款记录,已提交相关团队加急排查,有结果后会尽快联系您。",
"missing_info": ["payment_status", "refunded_amount"],
"need_human_review": true,
"escalation_reason": "关键数据获取失败,无法完成判定"
}
契约如何落地:四层保障
契约不是写在文档里就生效的,需要在四个位置同时落实:
JSON Schema 部分的写法示意(节选,完整结构按上表补齐):
{
"type": "object",
"properties": {
"schema_version": {"type": "string", "enum": ["1.2"]},
"status": {"type": "string", "enum": ["resolved", "need_more_info", "unable_to_confirm", "tool_failure"]},
"customer_message": {"anyOf": [{"type": "string"}, {"type": "null"}]},
"missing_info": {"type": "array", "items": {"type": "string"}},
"need_human_review": {"type": "boolean"}
},
"required": ["schema_version", "status", "customer_message", "missing_info", "need_human_review"],
"additionalProperties": false
}
Schema 支持的特性各家不同,例如 Claude 的结构化输出不支持字符串长度和数值范围约束,这些规则要放到第 3 层由程序保证。可空字段、anyOf 等写法也请以所用平台的文档为准并实际测试。
契约设计的几条经验
- 每个状态都要让消费者知道“下一步做什么”。 如果一个状态出现后下游不知道怎么处理,说明这个状态定义得不对。
- 所有字段都必填,用空数组和 null 表达“没有”。 下游不必区分“字段不存在”和“字段为空”,逻辑更简单。
- 人读字段和机读字段分开。
customer_message给人看,actions与refund_amount给系统用。不要让程序去解析一段话术,也不要让客服去读 JSON。 - 枚举值是契约中最敏感的部分。 新增、删除或改名任何一个枚举值,都要按版本变更处理,并通知所有消费者。
- 版本号从第一天就加上。 兼容的变更(例如新增一个可选的展示字段)升小版本;不兼容的变更(改字段含义、删枚举值)升大版本,并给下游留出迁移期。
常见误区
- “有了 JSON Schema 就有了契约。” Schema 只描述结构,不描述含义、状态语义和处理方式。契约需要文档、校验和测试共同构成。
- “出错时让 Agent 在文字里说明就行。” 自然语言的错误说明无法被程序识别和统计,必须用状态和结构化字段表达。
- “字段越多,信息越全,下游越方便。” 每个字段都增加模型出错的机会和维护成本。只保留有明确消费者的字段。
设计要点
- 列出所有消费者,以及他们各自依赖的字段。
- 为成功、需补充信息、无法完成、执行故障分别定义状态,并写明下游处理方式。
- 区分业务结果与系统故障,区分人读字段与机读字段。
- 在指令、Schema、程序校验、契约测试四层落实契约。
- 为契约加版本号,并建立变更评审流程。
练习
为「销售分析 Agent」设计一份输出契约(约 45 分钟):
- 场景:每周一自动分析上周销售数据,结果同时发给区域经理(阅读)、补货系统(自动创建补货建议)和经营看板(统计)。
- 列出三个消费者分别需要的字段,合并成一份字段定义表(类型、必填、含义、消费者)。
- 至少定义 4 个状态,包括“数据延迟未就绪”和“发现异常但无法归因”,并写出每个状态下三个消费者的处理方式。
- 写出 3 条 Schema 无法表达、需要程序校验的规则。
延伸阅读
- Claude Structured outputs:支持与不支持的 JSON Schema 特性。
- OpenAI Structured Outputs:
text.format与严格模式。
下一步
指令、示例、规则和契约都有了,但它们一定会不断修改。最后一课「Prompt 的迭代与版本管理」讲如何用测试集驱动修改,避免“改好一个、坏掉一片”。