“请严格返回 JSON,不要输出其他内容。”

这句话很多开发者都写过,但程序照样可能遇到多余说明、字段缺失、类型错误,甚至结构完全正确、内容却不符合业务要求的结果。

本文以订单查询助手为例,讲清合法 JSON、符合 Schema 和业务正确三个层次,以及提示词约束、原生结构化输出、工具调用和应用端校验分别承担什么职责。

一、模型觉得自己答得很好,程序却直接报错

你想让模型把用户需求转成一个对象,结果它返回:

好的,以下是你需要的 JSON:

{"order_id": "A1023", "intent": "query_shipping"}

人一眼就能看懂,但如果程序把整段文本交给 JSON 解析器,前面那句“好的”就可能导致解析失败。

你继续强调“不要解释”,模型终于只返回对象了,却把字段名改成了 orderId。

程序仍然拿不到预期的 order_id。

好不容易字段名也对了,模型又填了一个用户根本没提供过的订单号。

这就像收集报名表:有人交作文,有人把年龄写进姓名栏,还有人每个格子都填满了,但内容是编的。

让结果能被程序使用,需要同时解决格式、结构和内容问题。

二、三个层次一定要分清

层次检查什么?典型问题
JSON 语法能不能解析成合法 JSON?多余说明、引号错误、内容截断
Schema 结构字段、类型、枚举是否符合约定?缺字段、类型错误、出现未知状态
业务语义内容是否符合用户输入和业务规则?编造订单号、查错订单、权限不符

下面这段数据可能是合法 JSON:

{
  "order_id": 1023,
  "intent": "随便查一下"
}

但如果接口约定订单号是字符串,意图只能取固定枚举,它就不符合结构要求。

再看这一段:

{
  "order_id": "A9999",
  "intent": "query_shipping"
}

字段和类型都可能正确。但用户说的是 A1023,它仍然是错误结果。

JSON 能解析,不等于字段符合要求;字段符合要求,也不等于业务正确。

三、什么是结构化输出?把“自由作文”变成“按表填报”

结构化输出,是让模型按预先约定的数据结构返回结果,使程序能够稳定地读取字段并继续处理。

这个约定常用 JSON Schema、类型定义或数据模型表达。

例如,订单查询助手可以设计一份表格:

字段类型用途
status枚举字符串可继续处理、需澄清或不支持
intent枚举字符串查询物流、查询退款或未知
order_id字符串或 null从用户提供的信息中提取订单号
missing_fields字符串数组还缺少哪些必要信息

其中 status 的“可继续处理”只表示提取阶段的信息条件满足,不表示已经查到订单,更不表示已经通过权限校验。

LangChain 的官方文档将结构化输出描述为返回可预测格式的数据,并提供模型提供方原生策略与工具调用策略等实现方式。

四、四种常见做法,区别在哪里?

做法主要机制能解决什么仍需处理什么
提示词要求返回 JSON用文字与示例约束模型快速约定输出风格模型仍可能偏离格式
JSON 模式在支持的平台上约束 JSON 输出提高 JSON 格式可靠性不一定严格符合业务 Schema
原生结构化输出按接口支持的 Schema 约束生成提高字段与结构一致性支持范围、异常结束、语义错误
工具调用形式用工具参数承载结果与工具接口或框架流程衔接严格程度取决于接口与配置

这些名称的具体行为与模型、平台和版本有关,不能只看到“JSON”或“strict”就认为所有要求都得到了保证。

原生结构化输出为什么更稳定?

可以用填表来理解:

提示词约束像在纸上写“请按格式填写”;约束生成则像给输入过程设置了格式限制,某些不符合结构的内容无法按普通自由输出的方式产生。

例如,Claude 官方文档介绍了把 Schema 编译为语法约束的方式。

这种机制主要帮助控制结构。

它不会因为订单号字段必须是字符串,就自动知道用户真正要查的是哪个订单。

工具调用是不是等于执行了业务操作?

也不是。

模型输出一组工具参数,首先只是形成了调用请求或结构化数据。是否实际执行查询、写库、退款等操作,由应用的后续逻辑决定。

有些框架借用工具调用机制收集结构化结果,这个“输出工具”本身不需要产生业务副作用。

五、完整案例:把用户的话转换成可处理的请求

用户说:

帮我查一下订单 A1023 的物流到哪了。

在下面这个示例设计中,期望输出为:

{
  "status": "ready",
  "intent": "query_shipping",
  "order_id": "A1023",
  "missing_fields": []
}

应用可以按以下顺序处理:

  1. 确认模型响应是否正常、完整结束。

  2. 解析结果并校验结构。

  3. 检查 ready 状态下是否真的存在订单号和受支持的意图。

  4. 根据登录身份查询订单归属与访问权限。

  5. 在校验通过后调用物流查询接口。

这里的用户身份、租户和实际权限应来自可信的会话与服务端系统,不能让模型随意填写一个 authorized: true 就算通过。

用户没给订单号,怎么办?

用户只说:

查一下我的物流。

如果上下文和已授权数据中也没有足够信息,可以返回:

{
  "status": "needs_clarification",
  "intent": "query_shipping",
  "order_id": null,
  "missing_fields": ["order_id"]
}

这样,前端可以明确地请求用户补充订单,而不是拿一个编造的订单号继续查询。

好的输出结构,会给“信息不足”留位置。

如果 Schema 强迫模型必须填写所有具体值,却没有表达未知的方式,就容易把模型推向猜测。

六、Schema 怎么设计,才能既好用又不添乱?

1. 用明确类型代替模糊描述

“数量”是整数还是字符串?“金额”是元还是分?“时间”采用什么时区?

这些需要提前约定。

在程序接口中,可以把金额设计成整数分,并明确币种;时间明确采用带时区的格式。

具体选型按业务要求决定,但不能让不同环节各自猜测单位。

2. 固定状态使用枚举

如果后端只识别 ready、needs_clarification、unsupported,就不要让模型自由创造“基本可以”“有点不确定”等状态名。

面向用户的解释可以自由一些,供程序分支判断的字段应尽量明确。

3. 区分字段缺失、null 和空字符串

表达可以约定的含义
字段缺失当前结构允许不提供该字段
null字段存在,但当前没有可用值
""一个长度为零的字符串
[]一个没有元素的数组

这些值不会天然表达完全相同的业务含义。

例如,missing_fields: [] 表示没有待补充字段,而 order_id: "" 未必是有效订单号。

4. 限制不需要的额外字段

可以在适用的 Schema 中限制未知字段,避免模型额外生成一个后端没有定义的 execute_now 或 is_admin。

但关闭额外字段仍然只是结构控制,不会替代权限校验。

5. 跨字段规则放在哪里?

例如:

status 为 ready 时,order_id 必须有可用值,missing_fields 必须为空。

这属于字段之间的联合约束。

部分规则可以通过支持的 Schema 表达,其他规则由应用校验器完成。

不要默认模型接口支持 JSON Schema 的全部功能。以 Claude 文档为例,原生结构化输出存在 Schema 支持范围限制。应根据实际接口能力生成约束,并在应用端补足验证。

七、返回 JSON 失败了,是不是让模型重试就行?

先区分失败原因,再选择处理方式。

失败类型更合理的处理
多余文本或格式不符优先改用更可靠的输出方式;必要时有限修复
字段类型或枚举错误提供明确校验错误,进行有预算的重试
输出被长度上限截断调整输出规模或预算,获取完整结果
用户信息不足澄清或使用设计好的未知状态
模型拒答进入对应响应分支
订单不存在或无权限按业务结果处理,不要求模型“修好”

原生结构化输出也需要识别异常结束。Claude 文档明确列出了拒答、达到输出长度上限等情况下的特殊处理需求。

尤其不能把“订单不存在”当成模型输出错误,让模型换一个订单号试到成功为止。

修复格式与修改事实,是两件完全不同的事。

能不能直接用正则截出大括号里面的内容?

对于边界明确的简单包装,应用可以进行严格、有限的预处理。

但“找到第一个左大括号和最后一个右大括号”无法可靠处理多个对象、嵌套文本、字符串中的括号等情况,也不能证明提取出来的对象就是预期结果。

即使成功解析,后面的结构和业务检查仍然需要完成。

八、流式 JSON,能不能边收到边执行?

通常应该把展示和执行分开。

一个尚未接收完整的 JSON 片段,可能缺少后续字段,也可能最终因为截断而失败。

前端可以使用适当的增量解析方式做预览,但订单查询、写库等后续操作应等待约定的完整结果通过校验。

如果业务采用明确的分块协议,可以逐块验证和处理;那需要提前定义每块的边界和语义,不是对任意半截 JSON 直接执行。

看起来像一个字段值,不代表它已经成为经过验证的业务输入。

九、怎样验证输出方案真的可靠?

不要只测试一句“帮我查订单 A1023”。

可以增加这些样本:

输入情况希望看到的行为
订单号和意图都明确正确提取,进入后续校验
缺少订单号标记需澄清,不编造
同时出现两个订单号按任务语义处理,必要时澄清
用户纠正先前订单号使用有效的最新要求
请求不在支持范围内返回明确的不支持状态
很长的文本输入保持字段提取与输出边界正确
输出截断、拒答或接口异常正确进入相应错误分支

评测时至少区分:

  • JSON 解析成功率。

  • Schema 校验通过率。

  • 字段提取正确率。

  • 端到端任务成功率。

同时记录拒答、截断和接口异常的比例,说明统计分母,避免只挑正常完成的响应来展示一个漂亮的格式通过率。

十、面试精简总结

我会把输出可靠性分成三层:合法 JSON、符合 Schema、满足业务语义。提示词可以帮助模型理解要求,但正式接口优先使用可用的原生结构化输出或适当的工具调用机制,再进行应用端校验。

Schema 需要定义类型、枚举、未知值和状态,避免为了填满字段而编造内容。拿到结果后先检查完成状态,再解析和校验结构,最后检查跨字段规则、资源归属及权限。

对格式错误可以有限修复,但信息不足应澄清,业务失败按真实结果处理,拒答和截断单独分支。结构化输出让数据更容易被程序处理,并不保证内容真实或操作已经获准。

一句话记忆:模型负责按表填写,程序负责验表,业务系统负责决定能不能办。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐