Agent 的输出不只是给人看的。很多时候,它的结果要交给下游程序处理:写入数据库、触发告警、生成报表。这时候自由发挥的文字就不够用了,需要模型输出结构化数据,而且要稳定。
一、为什么需要结构化输出
假设你让模型判断一条用户反馈的类别。自由文本的回答可能是:
- 「这条反馈属于物流问题。」
- 「类别:物流」
- 「我认为这是关于配送速度的投诉,应归入物流类。」
三种说法意思一样,但程序很难可靠地解析。如果要求模型输出:
{"category": "logistics", "confidence": 0.9, "summary": "用户反映配送超时 3 天"}
程序直接读字段就行。结构化输出的价值就是:让模型的结果能被程序可靠地消费。
二、实现结构化输出的几种方式
| 方式 | 做法 | 可靠程度 |
|---|---|---|
| 提示词要求 | 在提示里说明「请只输出 JSON,格式如下」并给出示例 | 大多数时候可行,偶尔会多出解释文字或格式错误 |
| JSON 模式 | 打开 API 的 JSON 输出开关,保证输出是合法 JSON | 语法合法,但字段不一定符合要求 |
| Schema 约束 | 给 API 提供 JSON Schema,输出严格符合结构 | 最可靠,前提是 API 支持 |
| 借道工具调用 | 定义一个「提交结果」的工具,让模型通过调用它来输出结果 | 可靠,适合所有支持工具调用的模型 |
「借道工具调用」是个很实用的技巧:工具的参数本来就有 Schema 约束,你定义一个 submit_result 工具,参数就是你要的结构,模型调用它的时候,参数自然就是结构化的。
三、设计输出结构的原则
- 字段名清晰:用
root_cause而不是rc。 - 能用枚举就用枚举:类别、严重程度这类字段限定可选值,避免模型自由发挥出「较严重」「比较严重」这类变体。
- 给推理留位置:在结论字段之前放一个
reasoning字段,让模型先写理由再给结论,往往能提升准确率。 - 允许「不知道」:提供
unknown选项或confidence字段,否则模型会被迫编一个答案。 - 结构不要太深:嵌套层级越多越容易出错,尽量扁平。
一个告警分析结果的示例结构:
{
"reasoning": "下单量 10 点后骤降,同期支付接口超时率 60%……",
"root_cause": "第三方支付网关超时",
"severity": "high", // 枚举:low / medium / high
"confidence": 0.85,
"actions": ["联系支付服务商", "切换备用支付渠道"],
"need_human": true
}
四、容错:模型偶尔不听话怎么办
即使用了约束手段,也要假设输出可能有问题。程序拿到结果后应该做校验:
- 解析:能否解析成 JSON。如果模型在 JSON 外面包了一层说明文字或代码块标记,先尝试提取。
- 结构校验:必填字段是否齐全、类型是否正确、枚举值是否合法。可以用 JSON Schema 校验库或 Pydantic 这类工具。
- 业务校验:数值是否在合理范围,比如 confidence 在 0 到 1 之间。
校验失败时,不要直接报错退出。更好的做法是把错误信息回给模型,让它修正:
你的输出缺少必填字段 severity,且 confidence 为 1.5,超出了 0 到 1 的范围。
请修正后重新输出完整结果。
模型通常一次就能改对。同时要设置重试上限,比如最多 2 次。超过上限时走降级逻辑:使用默认值、标记为待人工处理,或者返回部分结果。
五、什么时候不需要结构化
不是所有输出都要结构化。给人看的分析报告、解释、建议,用自然语言更好。常见的做法是混合:关键字段结构化给程序用,详细说明用文字给人看,比如上面示例里的 reasoning 字段。
本篇小结
- 结构化输出让模型结果能被程序可靠消费。
- 实现方式:提示词要求、JSON 模式、Schema 约束、借道工具调用,后两者最可靠。
- 结构设计:字段清晰、多用枚举、给推理留位置、允许「不知道」。
- 容错:解析 → 结构校验 → 业务校验,失败时回给模型修正,设重试上限和降级逻辑。
思考与练习
- 模型返回的 JSON 缺了一个必填字段,你的程序该怎么处理?写出处理流程。
- 为「用户反馈自动分类」设计一个输出结构,包括类别、情绪、是否需要人工跟进。
上一篇:AI Agent原理篇05:Tool Use / Function Calling 原理
下一篇:AI Agent原理篇07:上下文工程:给模型看什么、什么时候看
返回系列总目录