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

← 返回博客