OpenAI 相容 API 的 Structured Outputs:JSON Schema 指南
說明 Responses 與 Chat Completions 如何使用嚴格 JSON Schema,並涵蓋應用驗證、拒絕、截斷與路由相容測試。
Structured Outputs 讓應用要求模型回傳符合既定 Schema 的 JSON,而不只是用 Prompt 說「請輸出 JSON」。在 OpenAI-compatible API 中,同一份 JSON Schema 可用於 Responses 或 Chat Completions,但外層欄位不同,而且必須針對實際模型與路由驗證支援程度。
安全的生產模式有三層:模型支援時使用 strict Schema、應用端再次解析與驗證 JSON,最後再套用商業規則。符合 Schema 能消除大量格式錯誤,但不能證明內容在事實或語意上正確。
Structured Outputs 不等於 JSON Mode
| 方法 | 產生有效 JSON | 強制符合 Schema | 適用情境 |
|---|---|---|---|
| 只靠 Prompt | 不保證 | 否 | 可以接受解析失敗的原型 |
| JSON Mode | 支援且完整生成時是 | 否 | 結構彈性、由應用驗證的 JSON |
strict: true Structured Outputs |
須處理完成狀態與拒絕 | 在支援的 JSON Schema 子集中是 | 型別化擷取與應用流程 |
OpenAI Structured Outputs 指南建議在模型與 Endpoint 支援時優先使用 Structured Outputs。若模型應回覆可預測的資料物件,使用 Structured Response Format;若模型要請求應用執行動作,則使用 Function Calling。兩者都可使用嚴格 Schema,但 Call ID 與結果訊息屬於不同協定。
先定義 Schema,再選擇 Endpoint
假設客服分流需要 category、priority、requires_human 與 summary:
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["billing", "technical", "account"]
},
"priority": { "type": "integer", "minimum": 1, "maximum": 3 },
"requires_human": { "type": "boolean" },
"summary": { "type": "string" }
},
"required": ["category", "priority", "requires_human", "summary"],
"additionalProperties": false
}
將所有欄位列為 required,並設定 additionalProperties: false,能讓下游程式取得穩定物件。但這不代表所有 JSON Schema 關鍵字都可攜。OpenAI 支援文件列出的子集,其他 OpenAI-compatible 供應商可能支援不同子集,甚至完全沒有 Strict Schema Mode。
使用 Responses API 傳送 Schema
Responses API 將 Schema 放在 text.format:
{
"model": "<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>",
"input": "The customer was charged twice and wants a refund.",
"text": {
"format": {
"type": "json_schema",
"name": "support_ticket",
"schema": {
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["billing", "technical", "account"] },
"priority": { "type": "integer", "minimum": 1, "maximum": 3 },
"requires_human": { "type": "boolean" },
"summary": { "type": "string" }
},
"required": ["category", "priority", "requires_human", "summary"],
"additionalProperties": false
},
"strict": true
}
}
}
呼叫 POST https://modelflare.dev/v1/responses 時,使用 Authorization: Bearer <YOUR_API_KEY> 與 Content-Type: application/json。Responses 的生成內容位於帶型別的 Output Items。SDK 可能提供聚合文字或 Parsed Output Helper,但直接使用 HTTP 時,不應假設結構化物件位於最上層;要先讀取完成的 Response、找到文字輸出,再執行 JSON 解析。
使用 Chat Completions 傳送同一份 Schema
Chat Completions 將相同 Schema 放在 response_format.json_schema:
{
"model": "<MODEL_WITH_VERIFIED_STRUCTURED_OUTPUT_SUPPORT>",
"messages": [
{ "role": "user", "content": "The customer was charged twice and wants a refund." }
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "support_ticket",
"schema": {
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["billing", "technical", "account"] },
"priority": { "type": "integer", "minimum": 1, "maximum": 3 },
"requires_human": { "type": "boolean" },
"summary": { "type": "string" }
},
"required": ["category", "priority", "requires_human", "summary"],
"additionalProperties": false
},
"strict": true
}
}
}
Chat Completions 通常在 choices[0].message.content 回傳 JSON 文字;它仍是字串,必須解析。
| 用途 | Responses API | Chat Completions |
|---|---|---|
| Schema 容器 | text.format |
response_format.json_schema |
| Format Type | text.format.type |
response_format.type |
| Schema 名稱 | text.format.name |
response_format.json_schema.name |
| Schema 本文 | text.format.schema |
response_format.json_schema.schema |
| Strict Flag | text.format.strict |
response_format.json_schema.strict |
| 結果位置 | Typed Output Items / Helper | choices[0].message.content |
Modelflare 的 OpenAI 相容層會在支援的 OpenAI/Codex 路由中轉換兩種 Wrapper,但轉換不能為本身不支援 Structured Outputs 的上游模型創造能力。其他作為 Raw Chat Completions Pass-through 的模型家族,仍以上游供應商的精確協定為準。
分開驗證結構與語意
模型可能回傳:
{
"category": "billing",
"priority": 2,
"requires_human": true,
"summary": "Customer reports a duplicate charge and requests a refund."
}
結構驗證
使用 JSON Schema Validator 或 Typed SDK Helper 檢查 Required Properties、額外欄位、型別、Enum 與數值範圍。即使供應商承諾 Strict Adherence,應用端驗證仍能防範不支援的路由、整合錯誤、截斷與未來協定變更。
語意與商業規則驗證
Schema 無法判斷客戶是否真的重複扣款、priority: 2 是否正確,或退款是否必須人工核准。高影響流程應把模型物件視為建議分類,與權威資料比對,並在確定性程式碼中執行權限、財務限制與安全規則。結構正確的 JSON 絕不能繞過授權或計費邊界。
處理不完整與例外輸出
拒絕
模型可能因安全原因拒絕請求。應先檢查 Response Status 與 Refusal Representation,再尋找 JSON;不要把拒絕誤報為解析錯誤。
截斷與輸出限制
若生成在物件完成前停止,Schema 無法補回缺少的結尾。檢查 Completion Status 與 Stop Reason,並為最大合法物件設定足夠但有界的 Output Limit。
不支援的 Schema 關鍵字
Strict 實作通常只支援 JSON Schema 子集。先使用 Object、Array、Primitive、Enum、Required 與明確的 Additional Properties;導入 Reference、Recursive Shape、複雜 Union 或進階 Validation 前,查閱目前供應商文件。
首次使用 Schema 的延遲
部分供應商會預處理並快取新 Schema,第一次請求可能較慢。重複使用穩定且版本化的 Schema,不要每次動態產生唯一 Schema;效能比較也要分開首次與穩態資料。
模型或路由不相容
Endpoint 可能接受一般 Chat Completions,卻拒絕 json_schema、忽略 strict,或把欄位轉送給不支援的模型。200 加上看似 JSON 的內容仍不是 Strict Adherence 證明;必須使用邊界與無效輸入驗證。
生產前執行相容性測試
| 測試 | 應保存的證據 |
|---|---|
| 最小 Required Object | Status、Model、Route、Parsed Object、Validation Result |
| 每個 Enum Value | 能否產生與解析每個允許值 |
| 資訊不足 | 使用有界替代值,或要求澄清 |
| 觸發安全政策 | 拒絕格式與應用處理 |
| 低 Output Limit | Completion Status 與截斷處理 |
| 不支援 Schema Feature | 明確錯誤或靜默忽略 |
| Responses 與 Chat Wrapper | 是否產生等價應用物件 |
| 重複穩定 Schema | 首次與穩態時間 |
比較模型時必須固定 Schema、Prompt、Region、Streaming Mode 與 Output Limit,並記錄測試日期,因為模型可用性與供應商行為會改變。
測試工作流程後再選 Endpoint
應用已採用 Typed Output Items、Responses Streaming Events 或更大的 Responses Tool Workflow 時,選擇 Responses;既有 Message-based Integration 穩定且路由支援 response_format 時,可選 Chat Completions。更完整的取捨見 Responses API 與 Chat Completions。
無論使用哪個 Endpoint:
- 只保留一份版本化 JSON Schema 真相來源;
- 轉成 Endpoint Wrapper 時不改變語意;
- 完成後再次驗證 Response;
- 結構驗證後才套用確定性的商業規則;
- 分開監控 Parse、Refusal、Truncation 與 Compatibility Failure。
初次遷移可先閱讀 OpenAI-Compatible API 指南,串流與不完整事件可參考 AI API Streaming 指南,並在模型與價格確認目前模型範圍,再針對 API Key 實際使用的路由驗證 Structured Outputs。
Structured Outputs 的價值,是把模型回應收斂成可靠的應用介面;它不會取代事實查核、授權與計費邏輯。「OpenAI-compatible」仍是必須逐項測試的主張,而不是從 Base URL 就能推導的保證。