限時優惠

2026 OpenAI Structured Outputs:JSON Schema 穩定輸出怎麼做?

部落格 AIDevelopment
2026-08-20 約 6 分鐘閱讀

這篇文章給需要把模型結果送進資料庫、工作流程或工具執行器的後端開發者。你會按時間軸完成 Schema 設計、首次呼叫、雙層驗證、異常分流與版本維護,並理解嚴格結構化輸出仍不能取代業務驗證。

本文要點

  1. 症狀:你已經要求模型「只輸出 JSON」,結果仍可能出現漏欄位、額外文字、拒絕或內容截斷。
  2. 最快解法:生產環境改用 OpenAI Structured Outputs + 嚴格 JSON Schema,再加上 API 狀態檢查、應用層語義驗證與回歸測試;不要把 strict: true 當成內容正確保證。
  3. 這篇適合正在替換 JSON mode、建立資料抽取管道,或維護工具呼叫專案的後端工程師。你會看到最終回應格式與工具參數的設定差異,也會知道哪些失敗必須重試、簡化 Schema,哪些情況應直接送入人工佇列。
2026 OpenAI Structured Outputs:JSON Schema 穩定輸出怎麼做?
2026 OpenAI Structured Outputs:JSON Schema 穩定輸出怎麼做?

症狀:你已經要求模型「只輸出 JSON」,結果仍可能出現漏欄位、額外文字、拒絕或內容截斷。 最快解法:生產環境改用 OpenAI Structured Outputs + 嚴格 JSON Schema,再加上 API 狀態檢查、應用層語義驗證與回歸測試;不要把 strict: true 當成內容正確保證。

這篇適合正在替換 JSON mode、建立資料抽取管道,或維護工具呼叫專案的後端工程師。你會看到最終回應格式與工具參數的設定差異,也會知道哪些失敗必須重試、簡化 Schema,哪些情況應直接送入人工佇列。

先從下游契約反推 Schema

不要先問模型「你想輸出什麼」,而要先列出資料庫、工作流程或工具執行器真正需要的欄位。例如發票抽取流程可能只需要 invoice_numbercurrencytotalitems;解釋文字應放在獨立的 notes 欄位,不能讓模型把說明混進 total 或整段 JSON 外層。

設計時先作四個決定:

  • 必填欄位:只有下游一定要用的欄位才列入 required;可選資訊要明確允許缺少或使用可接受的空值表示。
  • 型別與枚舉:金額、日期、識別碼不要全部當成自由文字;狀態欄位則以 enum 收窄可接受值。
  • 空值策略:先決定使用 null、空陣列,還是省略欄位,不要讓不同請求各自形成慣例。
  • 額外欄位策略:需要封閉契約時,設定 additionalProperties: false;若下游確實允許延伸,則把相容策略寫進版本文件,而不是默默接受未知欄位。

官方對 Structured Outputs 的說明指出,嚴格結構化輸出是以 Schema 約束回應形狀,並非對模型產生內容的事實性或業務語義作保證;你應先閱讀官方 Structured Outputs 說明,再按自己的驗證器支援範圍設計 Schema。

OpenAI 怎麼保證輸出符合 JSON Schema? 它能在支援的結構化輸出路徑上,依照你提交的 Schema 約束資料結構;但「符合 Schema」只回答欄位、型別與格式是否合規,不能回答地址是否真實、分類是否正確、兩個日期是否前後合理。因此完整保證來自 API 層與你的驗證流程,而不是提示詞單獨完成。

Schema 太複雜時,怎樣拆才不會失去契約?

當一個 Schema 同時描述訂單、客戶、付款、物流與多種例外分支,問題通常不只是可讀性變差,也可能增加維護、驗證與失敗排查成本。可按下游責任拆成幾個階段:先抽取核心訂單,再以已驗證的識別碼查詢客戶與物流,最後讓工具執行器接收一個較小的參數 Schema。

拆分原則是:

  1. 一次模型呼叫只負責一個可驗收的資料契約。
  2. 不要用巢狀自由文字承載另一套未定義格式。
  3. 把跨欄位規則留在應用層,例如 start<em>date 不得晚於 end</em>date
  4. 若同一組欄位在多個流程重複使用,建立版本化的共用定義,但不要為了重用而引入下游不需要的欄位。

第一次呼叫:分清回應格式與工具參數

在 Responses API 中,最容易出錯的是把舊介面範例與新介面設定混在一起。最終要交給資料庫或工作流程的結果,放在 text.format;要讓模型產生工具呼叫的參數,則在 tools 的函式定義內設定參數 Schema。兩者都是結構化資料,消費位置卻不同。

下面是最小化的 Python 形式,MODEL_ID 由你的部署設定提供,避免把過時的模型示例硬編進新專案:

import json
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

schema = {
    "type": "object",
    "properties": {
        "category": {"type": "string", "enum": ["bug", "question", "request"]},
        "priority": {"type": "string", "enum": ["low", "high"]},
        "summary": {"type": "string"}
    },
    "required": ["category", "priority", "summary"],
    "additionalProperties": False
}

response = client.responses.create(
    model=os.environ["MODEL_ID"],
    input="將這段客服訊息分類:付款頁面顯示錯誤,無法完成訂單。",
    text={
        "format": {
            "type": "json_schema",
            "name": "ticket_classification",
            "strict": True,
            "schema": schema
        }
    }
)

result = json.loads(response.output_text)

實際接入前,應以API 快速入門文件核對 SDK 呼叫形狀,並以模型介面參考確認你選用的模型與端點能力。不要只因模型名稱看似新,就假設它支援你所有的 Schema 特性。

若是 Function Calling,概念上則是把類似下列結構放到工具定義中:

tools = [{
    "type": "function",
    "name": "create_ticket",
    "description": "建立客服工單",
    "parameters": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "priority": {"type": "string", "enum": ["low", "high"]}
        },
        "required": ["title", "priority"],
        "additionalProperties": False
    },
    "strict": True
}]

工具參數驗證通過,不代表工具應該立即執行。執行器仍要檢查操作者權限、資源是否存在、請求是否重複,以及這個工具是否允許目前工作流程呼叫。

Structured Outputs 和 JSON mode 有什麼區別? JSON mode 的主要目標是讓回應可解析為 JSON,但它不等同於遵守你定義的完整欄位、枚舉和額外屬性規則。Structured Outputs 則把 JSON Schema 放進請求契約;只要你的端點和 Schema 位於官方支援範圍內,欄位結構控制會更明確。不過兩者都不能替你判斷業務內容是否正確。

第二次檢查:先處理狀態,再驗證語義

收到回應時,至少建立兩層驗證,不要直接把 output_text 寫入資料庫。

第一層是傳輸與模型狀態:

  • 檢查請求是否成功,以及回應是否真的包含預期輸出。
  • 檢查是否出現拒絕;安全拒絕不是一般 JSON 解析錯誤,不應無限重試同一個提示。
  • 檢查輸出是否因長度上限而中斷。被截斷的 JSON 即使只差一個括號,也不能送進下游。
  • 只有在錯誤屬於暫時性網路或服務問題時,才按你的重試政策重試,並使用請求識別碼避免重複寫入。

Responses API 的串流拒絕事件有專門的參考格式,可查看官方 refusal delta 文件,不要把拒絕文字當作正常資料欄位處理。

第二層是應用層驗證:

  • total 是否等於明細加總,或在允許的四捨五入範圍內。
  • currency 是否與帳戶、地區或原始文件一致。
  • 識別碼是否存在於你的資料庫,狀態轉換是否符合流程。
  • 日期、數量、權限與跨欄位依賴是否合理。
  • 工具參數是否符合最小權限與冪等要求。

strict: true 後為什麼仍然解析失敗? 常見原因包括:你讀取了錯誤的回應節點、程式把串流事件當成完整回應、請求因拒絕或截斷而沒有正常資料,或者你自己的 Schema/驗證器對 null、巢狀陣列與額外屬性的解讀不一致。先記錄原始狀態與完成原因,再判斷是傳輸問題、Schema 問題,還是業務規則問題。

第三步:按錯誤類型決定回退動作

把所有失敗都標成「解析失敗」,會讓重試系統把不可修復的問題反覆送出。建議建立以下分流:

  • Schema 不受支援:先縮減巢狀層級、格式關鍵字與不必要欄位,確認端點文件列出的支援範圍,再重新編譯與測試;不要只改提示詞。
  • 首次編譯延遲:將 Schema 編譯視為部署或版本切換事件,預先以測試請求暖機,並把首次延遲與一般請求分開記錄。
  • 長度中斷:縮短輸入與輸出欄位,分頁處理長清單,或拆成抽取與彙整兩次呼叫;不要嘗試修補不完整 JSON。
  • 安全拒絕:保留拒絕狀態與必要的稽核資訊,向使用者要求合法的替代輸入,或轉人工處理;不要把拒絕內容當成成功結果。
  • 業務校驗失敗:若資料仍可追查,送進失敗佇列並保留輸入、Schema 版本及驗證錯誤;若是提示不完整,可針對同一請求重新整理,但要限制次數。
  • 工具執行失敗:把工具回傳錯誤與模型輸出錯誤分開,避免模型因權限不足而連續重試危險操作。

OpenAI 結構化輸出遇到拒絕怎麼處理? 拒絕應是明確的分支,而不是塞入 summaryerror 或某個業務欄位。你的資料模型可以在應用層保存 acceptedrefusedtruncated 等處理狀態;只有 accepted 且通過業務驗證的結果,才進入資料庫或工具執行器。

上線前與長期維護:把 Schema 當成 API 契約

正式部署前,至少準備五組回歸樣例:

  1. 正常輸入,涵蓋每個必填欄位。
  2. 邊界值,例如空陣列、最長可接受文字與枚舉邊界。
  3. 合法空值,確認 null 與省略欄位不會被混淆。
  4. 超長輸入,驗證截斷、分段或拒絕的處理路徑。
  5. 安全拒絕樣例,確保拒絕不會誤寫入資料庫。

每次測試記錄模型識別、Responses API 或工具介面版本、Schema 版本、應用驗證器版本、輸入樣例識別與失敗分類。這些不是多餘的日誌:若日後只保留「解析失敗」四個字,你將無法判斷是模型變動、Schema 修改、SDK 升級,還是下游驗證規則造成回歸。

Schema 版本維護可採用相容性規則:

  • 新增可選欄位通常比改名或改型別安全,但仍要確認嚴格模式與驗證器行為。
  • 移除欄位、改變枚舉值或把可空欄位改成必填,應視為破壞性變更。
  • 先讓下游讀取器支援新舊版本,再以灰度方式切換產生端。
  • Schema 變更後重新檢查編譯快取、延遲、失敗佇列與資料庫遷移。
  • 將回歸測試固定在部署流程,不要等生產資料出現壞 JSON 才補測試。

你也應檢查資料保留與傳輸政策,因為結構化輸出本身不會自動改變資料治理要求;可對照官方端點資料控制說明決定哪些輸入能進入測試、日誌與人工覆核流程。

決策維度只使用 JSON mode使用 Structured Outputs生產環境建議
JSON 可解析性以可解析 JSON 為主要目標以指定 Schema 約束結構需要固定欄位時選嚴格 Schema
額外欄位需由應用層自行攔截可配合 additionalProperties 控制封閉資料契約採拒絕未知欄位
工具參數不等於工具權限驗證可約束參數形狀仍須加入權限、冪等與業務檢查
拒絕與截斷需自行辨識狀態仍必須自行分流不成功就不要寫入下游
維護成本初期較低,錯誤常在下游暴露前期需設計 Schema 與回歸樣例資料管道與工具執行器優先採用

如果你目前的方案是只靠 JSON mode 加提示詞,短期看似少了 Schema 設計工作,實際上會把欄位修補、重試、人工清洗和資料庫回滾成本推到更後段。若你把整套驗證都放在遠端 CI 或既有 Windows/Linux 測試機,還可能遇到 macOS 專屬 SDK、瀏覽器自動化環境不一致、併發測試排隊,以及測試機被其他工作佔用等問題;這不是 Structured Outputs 能單獨解決的問題。

對需要短期完成多模型、不同 Schema 版本和 macOS 工作流程回歸的團隊,租用 kvmboot 的 Mac 測試環境通常比臨時購置硬體更容易控制週期與環境切換。若你要長期承受穩定且高量的固定負載,或必須接觸實體 USB、專用周邊,購買自有 Mac 反而更合理;若只是批量驗證、短期整合與跨環境測試,可先查看kvmboot 的使用說明,再按測試批次評估Mac 環境方案

在部署前,你可以把不含業務資料的 Schema、正常/邊界/拒絕樣例和驗證欄位整理成一份驗收框架,交給團隊複製使用;若需要釐清批量測試的環境安排,再透過kvmboot 聯絡頁面確認。真正穩定的 OpenAI Structured Outputs,不是模型一次回傳漂亮 JSON,而是你能在每次請求後判斷「可接受、可重試,還是必須隔離」,並在 Schema 演進時持續證明這個判斷仍然成立。

用 kvmboot 雲端 Mac,將結構化輸出接入穩定工作流程

以獨享 M4 裸金屬 Mac 執行 JSON Schema 驗證、API 串接與自動化測試,減少共享環境造成的資源波動。

查看方案 · 首頁