博客 • AI / JSON Schema
AI 为什么需要 JSON Schema?Structured Output、Function Calling 与 JSON Schema 完整解析
你在接 ChatGPT、Gemini 或 DeepSeek 时,文档里会同时出现Function Calling、Structured Output和JSON Schema。它们看起来像三套能力,其实是同一套契约语言的三种用法。
JSON Schema用来描述「这份 JSON 必须长什么样」。当前主流是2020-12。Function Calling 用它约束工具参数;Structured Output 用它约束模型最终回答。AI 需要它,不是因为 JSON 更时髦,而是因为自然语言无法被下游代码稳定消费。
本文将说明:
- 三个概念各自约束什么
- 为什么纯自然语言输出不够
- Function Calling 如何用 schema 约束工具参数
- Structured Output 如何用 schema 约束最终回答
- 同一份 schema 怎么两处复用,以及怎么选、怎么校验
先记住这一点:模型输出 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
声明字段名和类型
properties 里每个 key 对应一个输出字段,type 指定 string / integer / array 等。
-
2
限定必填与枚举
required 列出必填字段;enum 限制取值范围,避免模型「创造性」填值。
-
3
挡住多余字段
additionalProperties: false 禁止未声明的 key。Strict 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:
{
"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:
{
"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,两处用法
这是本文要强调的一点:不要为工具参数和最终回答各写一套互相漂移的字段。工单还是那三个字段,只是挂载点不同。
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
工具调用
模型决定 create_ticket,arguments 必须符合 schema。
-
2
最终回答
不调工具时,最终 JSON 仍然是同一套字段,可直接入库。
-
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
每个 property 写 description
模型读 description 决定怎么填值。「Support ticket ID, e.g. TCK-1042」比裸字段名准确率高很多。
-
2
用 enum 而非描述暗示选项
「可选 low/medium/high」不如
enum可靠。 -
3
设 additionalProperties: false
OpenAI Strict 模式通常强制此选项。根对象加上
additionalProperties: false,避免模型塞进未声明字段。 -
4
嵌套不要太深
超过 3 层嵌套或大量 oneOf 会增加出错概率。复杂结构拆成多次调用往往更稳。
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
校验 schema 与输出
把 API 返回的 JSON 和你的 schema 贴进JSON Schema 页面,立刻看到哪些字段不符合契约。
-
2
格式化 API 响应
用JSON 格式化检查语法错误和缩进。
-
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 到生产的最短路径。