Structured Output(結構化輸出)是用 JSON Schema 限制 AI 回應格式,讓程式拿到可解析、欄位固定的 JSON。它適合資料擷取、分類、表單填寫、工作流程節點與 API 串接,不適合只想讓一般聊天回答看起來整齊的情境。
最重要的選擇只有一句話:要固定「回覆資料」就用 Structured Output;要模型決定是否呼叫你系統裡的函式,就用 Function Calling;只要求語法是 JSON、但不在意欄位是否完整,才使用 JSON Mode。
Structured Output 解決什麼問題?
一般提示詞可以要求「只回 JSON」,但模型仍可能多說一句說明、漏掉欄位、把數字變字串,或臨時新增鍵值。這種輸出看起來能讀,接進程式後卻容易失敗。
例如客服分類需要這個資料契約:
{
"category": "billing",
"priority": "high",
"summary": "使用者被重複扣款",
"needs_human": true
}
真正的需求包含更多規則:category 只能從允許值中選、needs_human 必須是布林值、所有欄位都必須存在,而且不能多出未定義欄位。這就是 JSON Schema 的工作。
JSON Mode、Structured Output、Function Calling 差在哪?
| 方法 | 保證合法 JSON | 保證符合 Schema | 適合用途 |
|---|---|---|---|
| 提示詞要求 JSON | 不保證 | 不保證 | 原型與人工閱讀 |
| JSON Mode | 是 | 否 | 只需要可解析 JSON |
| Structured Output | 是 | 是,依供應商支援的 Schema 子集 | 固定回覆格式、資料擷取與分類 |
| Function Calling | 工具參數依 Schema | 可要求嚴格參數 | 呼叫查詢、寫入、寄信等系統功能 |
OpenAI 官方文件也把兩種 Structured Outputs 使用方式分開:連接應用程式工具時用 Function Calling;要約束模型回覆給使用者的資料時,用 text.format 的 JSON Schema。
先設計一份小而嚴格的 JSON Schema
不要把整個資料庫欄位一次塞給模型。從下游真正需要的最小資料開始:
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["billing", "account", "technical", "other"]
},
"priority": {
"type": "string",
"enum": ["low", "medium", "high"]
},
"summary": {
"type": "string"
},
"needs_human": {
"type": "boolean"
}
},
"required": ["category", "priority", "summary", "needs_human"],
"additionalProperties": false
}
這裡有三個關鍵:enum 限制分類值,required 明列必填欄位,additionalProperties: false 禁止模型自創欄位。JSON Schema 預設允許額外欄位,所以正式資料契約常需要明確關閉。
OpenAI Responses API 實作範例
OpenAI 目前在 Responses API 使用 text.format 設定 JSON Schema。精簡的 JavaScript 範例如下:
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.responses.create({
model: "gpt-5.6",
input: "帳單被扣了兩次,請幫我處理。",
text: {
format: {
type: "json_schema",
name: "support_ticket",
strict: true,
schema: {
type: "object",
properties: {
category: {
type: "string",
enum: ["billing", "account", "technical", "other"]
},
priority: {
type: "string",
enum: ["low", "medium", "high"]
},
summary: { type: "string" },
needs_human: { type: "boolean" }
},
required: ["category", "priority", "summary", "needs_human"],
additionalProperties: false
}
}
}
});
const ticket = JSON.parse(response.output_text);
模型名稱、SDK 與支援的 Schema 功能會更新,實作時應對照官方文件。若專案已使用 Zod 或 Pydantic,可採官方 SDK 的解析輔助工具,讓型別與 Schema 來自同一份定義,降低前後不一致。
Claude 與 Gemini 也有 Structured Output 嗎?
有,但欄位名稱與支援範圍不同。
- Claude 使用
output_config.format取得符合指定格式的 JSON;工具參數則可使用strict: true。Anthropic 已將舊的output_format移到output_config.format。 - Gemini 在
response_format內設定mime_type: "application/json"與schema,同樣只支援 JSON Schema 的子集。
如果產品要跨供應商,不要把各家請求格式散落在業務程式中。可以建立一層模型介面,讓業務端只認得自己的 Schema、驗證結果與錯誤類型。更多整合原則可看 AI API 串接指南與 AI 設計模式。
什麼時候該用 Function Calling?
當模型的下一步是「做事」,而不是只回資料,就用 Function Calling。例如查訂單、建立工單、寄送郵件或更新行事曆。模型只負責產生符合 Schema 的工具名稱與參數,真正執行仍由你的程式負責。
不要讓模型輸出一段看似 SQL 或 API 指令後直接執行。正式環境至少要做:
- 驗證工具名稱與參數。
- 在伺服器端重新檢查使用者權限。
- 對寫入、付款與刪除動作加入確認。
- 限制模型可操作的資源範圍。
- 記錄請求、工具結果與失敗原因。
Agent 與工具呼叫的邊界,可接著看 AI Agent 指南與 MCP 介紹。
結構正確,為什麼資料還是可能錯?
Structured Output 解決「形狀」,不解決「真偽」。模型可以回傳完全符合 Schema 的錯誤日期、分類或金額。正式上線還需要第二層業務驗證:
- 金額不能是負數,日期不能超出允許範圍。
- ID 必須存在於資料庫,不能只符合字串格式。
- 分類信心不足時,轉人工而不是硬選一個答案。
- 回答涉及來源時,確認引用內容真的支持結論。
- 遇到拒答、內容過濾或輸出截斷時,不要當成合法空資料。
我不建議以「JSON.parse 成功」作為唯一成功條件。應把 Schema 驗證、業務驗證與實際任務正確率分開監控。
上線前檢查表
- Schema 是否只包含下游真正需要的欄位。
- 每個物件是否明確設定
required與額外欄位規則。 - 是否處理
null、空陣列、拒答、截斷與逾時。 - 是否對模型輸出再做伺服器端驗證。
- 是否有代表正常、邊界、惡意輸入與多語言的測試集。
- 更新模型或 Schema 前,是否重新跑完整評測。
提示詞只能改善模型理解;資料契約、驗證與權限仍是工程責任。可搭配 Prompt 工程指南設計更清楚的欄位描述,但不要用提示詞取代程式驗證。
常見問題
Structured Output 是什麼?
它是用 JSON Schema 約束模型回覆格式,讓輸出具有固定欄位、型別與必填規則。適合需要把 AI 回應交給程式繼續處理的情境。
Structured Output 和 JSON Mode 有什麼差別?
JSON Mode 主要保證輸出是合法 JSON,不保證欄位符合你的資料契約。Structured Output 會依 Schema 約束欄位、型別與必填規則,較適合正式串接。
Structured Output 和 Function Calling 怎麼選?
只要模型回傳固定資料,用 Structured Output。需要模型選擇並呼叫查詢、寫入或其他系統功能時,用 Function Calling,並由伺服器驗證權限後執行。
有 Structured Output 就不用驗證資料嗎?
仍然要驗證。Schema 只能保證資料形狀,不能保證內容真實、ID 存在、金額合理或使用者有權執行後續動作。