博客 AI / JSON Schema

AI 为什么需要 JSON Schema?Structured Output、Function Calling 与 JSON Schema 完整解析

你在接 ChatGPT、Gemini 或 DeepSeek 时,文档里会同时出现Function CallingStructured OutputJSON Schema。它们看起来像三套能力,其实是同一套契约语言的三种用法。

JSON Schema用来描述「这份 JSON 必须长什么样」。当前主流是2020-12。Function Calling 用它约束工具参数;Structured Output 用它约束模型最终回答。AI 需要它,不是因为 JSON 更时髦,而是因为自然语言无法被下游代码稳定消费。

本文将说明:

先记住这一点:模型输出 JSON,和输出符合 schema 的 JSON,是两件事。JSON Schema 定义的是后者。Function Calling 管「调用哪个工具、参数对不对」;Structured Output 管「最终答案长什么样」。下面按「为什么 → 是什么 → 工具参数 → 最终回答 → 怎么选 → 怎么校验」拆开。

一句话分清三个概念

先把三个词放到同一张表里。它们共享 JSON Schema 这门语言,但约束的对象不同。

概念 约束对象 典型字段 / 标准 解决什么
JSON Schema JSON 的字段、类型、必填、枚举 JSON Schema 2020-12 契约本身:数据必须长什么样
Function Calling tool_calls.arguments tools[].parameters 模型要调哪个工具、参数是否合法
Structured Output 最终回答的 JSON response_format.json_schema / responseSchema 最终结果能否直接入库、进管道

混用这三个词,通常是因为文档把「能力名」和「契约语言」写在一起。记住分层:JSON Schema 是语言;Function Calling 和 Structured Output 是两种用法。

AI 为什么不能只用自然语言

如果你只在 prompt 里写「请返回 JSON」,常见失败模式如下。

失败模式 典型表现 根因
语法错误 缺引号、尾随逗号、单引号 模型按自然语言习惯生成,未约束 token 序列
字段漂移 同 prompt 两次输出字段名不同 无 schema 契约,模型自由发挥
类型错误 数字变字符串、数组变对象 prompt 描述模糊,无 type 硬约束
不可回归 同一用例两次结果无法 fixture 对比 自然语言没有稳定的字段集合

这些问题在 demo 阶段可以靠重试或二次解析掩盖。进了生产 Agent、数据管道和自动化流程,就会直接导致下游崩溃。JSON Schema 解决的是格式契约:生成前先声明字段、类型和必填项。

JSON Schema 是契约,不是文档

JSON Schema 是描述 JSON 数据结构的标准。在 AI 集成里,它不是给人看的注释,而是机器可执行的契约:

  1. 1
    声明字段名和类型

    properties 里每个 key 对应一个输出字段,type 指定 string / integer / array 等。

  2. 2
    限定必填与枚举

    required 列出必填字段;enum 限制取值范围,避免模型「创造性」填值。

  3. 3
    挡住多余字段

    additionalProperties: false 禁止未声明的 key。Strict Schema 通常强制这一项。

一份工单 schema 示例
{
  "type": "object",
  "properties": {
    "ticket_id": {
      "type": "string",
      "description": "Support ticket ID, e.g. TCK-1042"
    },
    "priority": {
      "type": "string",
      "enum": ["low", "medium", "high"]
    },
    "summary": {
      "type": "string",
      "description": "One-sentence problem summary"
    }
  },
  "required": ["ticket_id", "priority", "summary"],
  "additionalProperties": false
}

这份 schema 本身不关心它出现在 tools 还是 response_format 里。它只回答:这份 JSON 合法吗?下面两节把它分别接到 Function Calling 和 Structured Output。

Function Calling:用 schema 约束工具参数

Function Calling 让模型返回结构化的工具调用,而不是猜答案。每个工具的tools[].parameters 就是 JSON Schema:

OpenAI 风格 Function Calling:parameters 即 schema
{
  "model": "gpt-4o",
  "messages": [
    { "role": "user", "content": "Create a high-priority ticket for checkout timeout." }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "create_ticket",
        "description": "Create a support ticket from the user request.",
        "parameters": {
          "type": "object",
          "properties": {
            "ticket_id": { "type": "string" },
            "priority": { "type": "string", "enum": ["low", "medium", "high"] },
            "summary": { "type": "string" }
          },
          "required": ["ticket_id", "priority", "summary"],
          "additionalProperties": false
        }
      }
    }
  ]
}

模型返回的tool_calls[0].function.arguments 是一段 JSON 字符串。它「尽量」符合 parameters,但不保证每次都合法——缺字段、类型错、语法坏都可能出现。解析和校验是你的业务层职责。

Agent 循环、MCP inputSchema 和更完整的工具写法,见AI Agent 与 JSON Schema 完整解析

Structured Output:用 schema 约束最终回答

Structured Output 约束的不是工具参数,而是模型最终回答。OpenAI 用response_format;Gemini 用responseSchema。底层都是 JSON Schema:

OpenAI Strict Structured Output:同一份工单 schema
{
  "model": "gpt-4o-2024-08-06",
  "messages": [
    { "role": "user", "content": "Extract a support ticket from this email." }
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "support_ticket",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "ticket_id": { "type": "string" },
          "priority": { "type": "string", "enum": ["low", "medium", "high"] },
          "summary": { "type": "string" }
        },
        "required": ["ticket_id", "priority", "summary"],
        "additionalProperties": false
      }
    }
  }
}

打开strict: true 后,模型在推理阶段被 schema 引导——不是生成后再碰运气,而是生成时就只能产出 conform 的 JSON。

ChatGPT 与 Gemini 的配置对比、JSON Mode 和 Strict Schema 的保证程度,见2026 AI Structured Output 指南

同一份 schema,两处用法

这是本文要强调的一点:不要为工具参数和最终回答各写一套互相漂移的字段。工单还是那三个字段,只是挂载点不同。

Python:一份 TICKET_SCHEMA,两处挂载
TICKET_SCHEMA = {
    "type": "object",
    "properties": {
        "ticket_id": {"type": "string"},
        "priority": {"type": "string", "enum": ["low", "medium", "high"]},
        "summary": {"type": "string"},
    },
    "required": ["ticket_id", "priority", "summary"],
    "additionalProperties": False,
}

# 1) Function Calling: constrain tool arguments
tools = [{
    "type": "function",
    "function": {
        "name": "create_ticket",
        "description": "Create a support ticket.",
        "parameters": TICKET_SCHEMA,
    },
}]

# 2) Structured Output: constrain the final answer
response_format = {
    "type": "json_schema",
    "json_schema": {
        "name": "support_ticket",
        "strict": True,
        "schema": TICKET_SCHEMA,
    },
}

同一份契约,三条落地:

  1. 1
    工具调用

    模型决定 create_ticket,arguments 必须符合 schema。

  2. 2
    最终回答

    不调工具时,最终 JSON 仍然是同一套字段,可直接入库。

  3. 3
    业务校验

    无论数据来自 tool_calls 还是 message.content,都走同一套 parse + validate。

四条路径怎么选

2026 年接入 LLM 时,结构化数据通常有四条路径:

路径 API 配置 保证什么 适用场景
纯 Prompt 无特殊配置 不保证格式 快速原型、人工阅读
JSON Mode response_format: json_object 合法 JSON 对象 简单提取、字段结构宽松
Function Calling tools[].parameters arguments 尽量符合 parameters 要调外部工具 / 写库 / 发请求
Structured Output json_schema + strict: true 严格 conform 到 schema 最终结果要入库、进管道

Agent 里四层怎么拼(LLM、Function Calling、MCP、JSON Schema),见2026 AI Agent 技术栈

生产级写法与校验

Structured Output 和 Function Calling 的成功率,高度依赖 schema 质量。业务层仍要自己校验。

  1. 1
    每个 property 写 description

    模型读 description 决定怎么填值。「Support ticket ID, e.g. TCK-1042」比裸字段名准确率高很多。

  2. 2
    用 enum 而非描述暗示选项

    「可选 low/medium/high」不如enum 可靠。

  3. 3
    设 additionalProperties: false

    OpenAI Strict 模式通常强制此选项。根对象加上additionalProperties: false,避免模型塞进未声明字段。

  4. 4
    嵌套不要太深

    超过 3 层嵌套或大量 oneOf 会增加出错概率。复杂结构拆成多次调用往往更稳。

Python:parse + JSON Schema validate
import json
from jsonschema import validate, ValidationError

def parse_model_json(raw: str, schema: dict) -> dict:
    try:
        data = json.loads(raw)
    except json.JSONDecodeError as e:
        raise ValueError(f"Invalid JSON: {e}") from e
    try:
        validate(instance=data, schema=schema)
    except ValidationError as e:
        raise ValueError(f"Schema mismatch: {e.message}") from e
    return data

无论数据来自 ChatGPT、Gemini 还是 DeepSeek,都走同一套 parse → validate → 业务逻辑。开发阶段把 schema 和实际输出贴进 JSONNote,比 print 调试快。

用 JSONNote 调试模型 JSON

最耗时的环节往往不是写 API,而是看模型返回的 JSON 哪里不符合契约。JSONNote 在浏览器本地运行:

  1. 1
    校验 schema 与输出

    把 API 返回的 JSON 和你的 schema 贴进JSON Schema 页面,立刻看到哪些字段不符合契约。

  2. 2
    格式化 API 响应

    JSON 格式化检查语法错误和缩进。

  3. 3
    对比两次调用

    JSON Diff 对比两次 structured output 或 tool arguments 的差异,做回归检查。

常见问题

Function Calling 和 Structured Output 有什么区别?

Function Calling 约束的是 tool_calls.arguments(模型决定调哪个工具、参数是什么);Structured Output 约束的是模型最终回答的 JSON。两者底层都用 JSON Schema,但作用层不同。Agent 场景常组合使用:tools 处理外部动作,Structured Output 处理最终结构化结果。

只用 JSON Mode 够不够?

不够。JSON Mode(response_format.type=json_object)只保证输出是合法 JSON 对象,不约束字段和类型。生产环境复杂结构用 Structured Output(json_schema + strict:true 或 Gemini responseSchema)。

开了 Strict Schema 还需要手动校验吗?

需要。API 层约束不能替代业务层 validate。模型可能返回空 content、网络截断或边缘 case——try/except 解析 + JSON Schema validate 是生产标配。

JSON Schema 用哪个版本?

2026 年主流 LLM API 和 MCP 工具契约统一使用 JSON Schema 2020-12。支持 type、properties、required、enum、items、additionalProperties 等核心关键字。

一份 schema 能同时给工具和最终输出用吗?

能。同一份对象定义可以同时放进 tools[].parameters 和 response_format.json_schema.schema。字段、类型、枚举保持一份真相,避免两套契约漂移。

总结

AI 需要 JSON Schema,是因为它把模型输出从「看起来像数据」变成「机器可校验的契约」。

JSON Schema 是语言;Function Calling 用它约束工具参数;Structured Output 用它约束最终回答。

写一份 schema,两处挂载,再加业务层 validate。用 JSONNote 本地格式化、校验和 Diff,是从 demo 到生产的最短路径。

← 返回博客