Structured Outputs 与 JSON Mode:如何验证真实数据
区分 JSON Mode 与 Schema 约束输出,用缺失字段、冲突金额和拒答样本验证抽取质量,并把业务正确性纳入模型选择。
发布 2026-09-29 · 更新 2026-09-29 · KeepRouter Editorial · 4 分钟阅读

JSON Mode 主要约束 JSON 语法;Schema 约束输出在模型和 API 支持时进一步限制字段、类型和结构。二者都不能保证字段值真实。文档抽取需要分别验证语法、结构和业务含义。
真正有用的是应用能安全处理的记录,而不只是 JSON.parse 不报错的文本。
先定义输出协议
OpenAI 结构化输出说明区分 JSON Mode、Schema 与拒答处理;Gemini 文档说明其支持的 Schema 子集。不能把某个平台的支持推断给所有兼容端点。
| 方式 | 主要帮助 | 应用仍需检查 |
|---|---|---|
| 提示词要求 JSON | 表达意图 | 语法、结构、事实 |
| JSON Mode | JSON 语法 | 必需字段、业务规则 |
| Schema 约束 | 支持的结构规则 | 来源真实性、跨字段关系 |
| 工具调用 | 请求一个应用动作 | 权限与执行安全 |
需要记录时使用输出结构,需要调用动作时才使用工具。不要让从文档抽取出的文本直接变成可执行操作。
明确“未知”怎样表达
发票可能没有到期日。如果强制要求一个日期字符串,就可能得到格式正确但虚构的日期。
{
"invoice_id": "INV-DEMO-17",
"currency": "USD",
"amount": "125.40",
"due_date": null,
"evidence": "Total due: USD 125.40"
}这是合成样例,不是真实发票或模型结果。金额使用十进制字符串或最小货币单位整数,避免浮点误差。保留支持金额的必要原文,别顺带保存无关个人资料。
缺失、无法识别和相互冲突应有不同处理:没有日期可返回 null,两个金额冲突则进入复核,不都变成一个可能被当作默认值的空字符串。
解析后再验证业务含义
Schema 能限定金额字段,却不能证明它对应原文。货币白名单、金额精度等规则应由独立代码检查:
from decimal import Decimal
record = {"currency": "USD", "amount": "125.40", "due_date": None}
if record["currency"] not in {"USD", "EUR"}:
raise ValueError("Unsupported currency")
amount = Decimal(record["amount"])
if not amount.is_finite() or amount < 0:
raise ValueError("Invalid amount")
if amount != amount.quantize(Decimal("0.01")):
raise ValueError("Unexpected precision")
print(amount)这个本地例子并非完整财务系统。退款或负数发票等例外需要自己的规则,还必须对照来源。通过验证不能直接授权付款或其他不可逆动作。
测试容易失败的文档
准备正常记录、缺失日期、冲突总额、模糊金额、不支持货币,以及夹带“忽略规则”指令的文档。最后一种用于检查源文本是否被误当作应用指令。
把字段正确与结构正确分开。假设一百份文档中九十八份能解析,但只有八十四份所需事实全部正确,可用记录就是八十四份。此处是计量说明,不是实测成绩。
拒答和截断保留独立状态。流式输出只返回半个对象时,不能因解析器恢复出几个字段就算成功。
用合格记录成本选模型
将首次请求、修正和失败的全部费用相加,再除以合格记录数。所有候选使用同一批文档和规则;不能为了让某个候选通过而单独放宽 schema。
使用 KeepRouter 前,在模型目录和 API 文档核对具体线路。普通聊天兼容不等于严格 Schema 支持。用迁移检查器检查请求,再参考文档抽取评估选择候选。
常见问题
严格 JSON 能保证事实正确吗?
不能。结构合规不代表数值与原文一致,还需检查证据、业务规则和缺失值处理。
缺失字段应该猜测补全吗?
不应该。使用 null 或待复核等明确状态,让下游根据状态处理,而不是接受编造值。
不同网关的 JSON Mode 完全一样吗?
不一定。需要核对模型、端点和支持的 Schema 子集,参数在不同线路可能被拒绝或表现不同。
参考的一手资料
本文最近复核 2026-09-29