博客 • 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 到生產的最短路徑。