结构化输出与契约

本节目标

区分“像 JSON”“可解析 JSON”“符合 schema”和“业务语义正确”,建立从模型输出到业务动作之间的验证层。

四层检查

假设期望输出 {"label":"billing","reason":"重复扣款","evidence":"扣了两次"}:

  1. 语法:能否被 JSON 解析器读取?单引号、尾逗号和 Markdown 代码围栏都可能导致失败。
  2. 结构:字段是否存在、类型是否正确、枚举是否合法、是否出现多余字段?JSON Schema 可描述这层。
  3. 业务规则:unknown 是否必须附带原因;证据引用是否真的来自输入;币种、总额或状态之间是否自洽?
  4. 授权:即使前三层通过,是否允许自动退款、发邮件或删除数据?高影响动作仍需独立授权或人工确认。

供应商的 schema 约束能力、支持的关键字与失败表示会变化。以 2026-07-21 的 OpenAI 文档为例,JSON mode 只保证输出是有效 JSON,不保证匹配你的 schema;Structured Outputs 在受支持的模型、接口与 schema 子集上提供 schema 遵循保证。即便如此,应用仍须处理拒答、输出未完成和“结构合法但语义错误”的值。Google 当前文档同样说明只支持 JSON Schema 子集,并要求应用验证语义值。不能因为两个功能都叫“结构化输出”,就假定同一份 Draft 2020-12 schema 可原样跨供应商使用。

一个最小 schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "label": {"type": "string", "enum": ["billing", "technical", "other"]},
    "reason": {"type": "string", "minLength": 1, "maxLength": 160},
    "evidence": {"type": ["string", "null"], "maxLength": 120}
  },
  "required": ["label", "reason", "evidence"],
  "additionalProperties": false
}

字段阅读(JSON 示例必须保持可解析,因此把解释放在代码块外):

  • $schema 声明这份示例按照哪个 JSON Schema 草案来理解;它不表示所有供应商接口都完整支持该草案。
  • 根级 type: object 要求模型返回一个对象,而不是数组、字符串或裸数字。
  • properties 是允许出现的字段集合;其中 label 只能取三个枚举分类,reason 必须是非空且不超过 160 个字符的解释。
  • evidence 允许字符串或 null,以便“没有可引用证据”成为显式状态,而不是让模型编造内容。
  • required 要求三个字段都出现;即使 evidence 没有值,也要明确返回 null。
  • additionalProperties: false 拒绝未经契约声明的额外键,避免下游悄悄消费模型临时新增的字段。

提示中解释字段语义,API 层尽可能启用供应商当前支持的 schema 功能,程序端再解析和校验。三处应从同一契约资产生成或做漂移测试,避免提示、API 参数和代码各自演化。本库版本见 response.schema.json;为了保持标准库零依赖,离线验证器并不是通用 JSON Schema 引擎,而是只接受手写运行时已实现的精确教学子集。根对象、三个字段及 anyOf 分支均有关键字白名单,出现 pattern、allOf 等未实现约束会失败关闭;随后再执行“billing/technical 必须给证据”和“证据必须能在输入中找到”等业务规则。

失败处理

  • 解析失败:记录经过脱敏的响应片段、请求 ID 和提示版本;只在策略允许时重试。
  • schema 不符:不要在业务代码里“猜着修”;策略允许时可发起次数受限的修复请求,但修复结果必须重新通过全部校验,连续失败应停止而不是无限重试。
  • 内容拒绝或安全拦截:作为显式结果处理,不伪装成空成功。
  • 输出截断:缩小任务、提高合理的输出上限或改用分步流程;不能直接拼接半个 JSON。
  • 语义不可信:降级为人工复核,不把 confidence 当校准概率。

练习与自测

为“从发票文本抽取币种和总额”写 schema,并回答:总额为字符串还是数字?千位分隔符如何处理?文本没有币种时是 null、unknown 还是失败?若这些没有明确,schema 还不是完整合同。

掌握检查

  • 我能分别解释 JSON 语法、schema、业务规则和授权四层。
  • 我不会把 JSON mode 说成 schema 遵循保证。
  • 我会显式处理拒答、未完成输出、额外字段和语义错误。
  • 我能让提示说明、API schema 与程序验证共同引用同一契约版本。

下一步

进入 模板、变量与版本管理,让合同与提示可以追踪和发布。

参考资料