让大模型输出的不再是“看起来像 JSON 的文本”,而是能够被程序稳定消费、校验和落库的结构化数据。

在 AI 应用里,最难处理的往往不是模型“会不会回答”,而是它能不能按照程序需要的形状回答。字段缺失、类型错误、额外解释文字、数组层级变化,任何一种情况都可能让后续代码直接报错。

01. 为什么只提示“请返回 JSON”还不够

很多项目最初都会这样写 Prompt:

请分析下面的文本,并返回 JSON:
{
  "sentiment": "positive | negative",
  "score": 0 到 1
}

这种写法通常能得到“像 JSON 的结果”,但它并不构成可靠的接口契约。模型可能把 score 写成字符串,也可能增加 reason 字段,甚至在 JSON 前后补一段解释。对人来说问题不大,对程序来说却意味着解析、校验和重试。

JSON mode 主要解决第一层;Structured Outputs 把约束推进到第二层;第三层仍然需要业务代码继续验证。

02. JSON Schema 到底是什么

JSON Schema 可以理解为“JSON 数据的说明书和验收规则”。普通 JSON 描述一份具体数据,JSON Schema 描述这份数据应该长什么样。

具体数据

{
  "title": "Structured Outputs 入门",
  "category": "backend",
  "published": true
}

对应的 JSON Schema

{
  "type": "object",
  "properties": {
    "title": { "type": "string" },
    "category": {
      "type": "string",
      "enum": ["frontend", "backend", "ai"]
    },
    "published": { "type": "boolean" }
  },
  "required": ["title", "category", "published"],
  "additionalProperties": false
}

最简单的 schema 是空对象 {},它接受任何合法 JSON。实际开发中,我们会通过 typepropertiesrequired 等关键字逐步收紧规则。正式项目还建议使用 $schema 声明采用的规范版本,例如 Draft 2020-12。

一个容易忽略的区别

JSON Schema 本身是一套通用规范;OpenAI Structured Outputs 只支持其中的一个子集。因此,“在普通 JSON Schema validator 中合法”不代表“可以原样提交给 OpenAI API”。

03. 先掌握这些常用关键字

{
  "type": "object",
  "properties": {
    "title": { "type": "string" },
    "summary": { "type": ["string", "null"] },
    "level": {
      "type": "string",
      "enum": ["beginner", "intermediate", "advanced"]
    },
    "keywords": {
      "type": "array",
      "items": { "type": "string" }
    }
  },
  "required": ["title", "summary", "level", "keywords"],
  "additionalProperties": false
}

type
限定数据类型,例如 object、string、number、array。

properties
声明对象允许出现的字段。

required
指定必须返回的字段。

enum
把取值限制在固定集合内。

items
描述数组元素的结构。

additionalProperties
控制是否允许额外字段。

在 OpenAI Structured Outputs 中,所有字段都需要放进 required。如果某个字段业务上允许缺失,可以把它写成 ["string", "null"],用 null 模拟“可选”。

04. JSON mode 与 Structured Outputs 的差别

不要把 Structured Outputs 理解成“模型突然更聪明”

它解决的是输出格式可靠性,而不是事实正确性。模型仍然可能在合法字段中填入错误内容,所以数据库查询、金额、日期和权限判断仍需额外校验。

05.不要只处理“成功返回”

Structured Outputs 能显著降低格式错误,但并不意味着每次请求都一定返回 schema 对象。至少需要考虑下面三类分支:

常见错误:把所有返回值都直接交给 JSON parser

refusal、incomplete 和网络错误都不应被当作普通业务 JSON 处理。先判断响应状态,再进入解析流程,错误信息会清晰很多。

06. OpenAI 对 JSON Schema 的限制

OpenAI 当前支持 JSON Schema 的一个子集。写 schema 时,下面几条尤其重要:

  • 根节点必须是 object,不能在顶层直接使用 anyOf
  • 所有字段都必须列入 required;可选字段可通过与 null 的联合类型表达。
  • 每个 object 都必须设置 additionalProperties: false
  • 输出字段顺序会遵循 schema 中的 key 顺序,可利用这一点保持结果稳定。
  • schema 存在规模限制,包括对象属性总数、嵌套深度、字符串总长度和 enum 数量。
  • 第一次使用某个新 schema 时,服务端可能需要额外处理时间;相同 schema 的后续请求通常不会重复承担这部分延迟。

官方文档当前给出的主要规模上限包括:总 object property 数最多 5000、嵌套最多 10 层、全部属性名和 enum 等字符串总长度最多 120,000 字符、所有 enum 合计最多 1000 个值。复杂业务不要把整套数据库模型机械塞进一个 schema,更合理的做法是按任务拆分。

07. 工程实践:Schema 要像 API 契约一样设计

先设计消费端,再设计输出端

不要从“模型能返回什么”出发,而要从“下一步代码需要什么”出发。前端要渲染卡片,就定义卡片所需字段;数据库要写入记录,就定义写入前真正需要的数据。字段越少,约束越明确,整体可靠性通常越高。

字段名承担的是接口语义

resultdata 这类泛化字段不利于维护。更具体的 risk_levelevidencerecommended_action 能让 Prompt、schema 和业务代码形成一致的语义。

枚举值要稳定,不要追求“自然语言好看”

程序内部更适合使用 low / medium / high 这类固定标识,再由 UI 做中文映射。直接让模型输出“风险较低”“暂时没有明显风险”等自由文本,会让条件判断重新变得脆弱。

把格式校验和业务校验分开

Structured Outputs 可以保证 confidence 是 number,却不一定保证它处于 0 到 1,也不会判断模型依据是否真实。格式层通过后,再进行数值范围、数据库存在性、权限和事实核验。

适合使用 Structured Outputs 的场景

信息抽取、分类结果、表单填充、Agent 工具参数、UI 数据模型、批量内容审核、工作流节点输入输出,以及任何需要稳定接入程序逻辑的模型响应。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐