2026 年維護 OpenAI Agent 的團隊,最容易踩的坑不是「模型會不會說話」,而是舊程式仍把 json_object 當成結構化輸出,或在 Chat Completions 上沿用非嚴格 Function Calling。新專案官方建議從 gpt-5.6 起步;Function Calling 與 Structured Outputs 底層都是約束解碼,但入口、預設 strict 行為和 JSON Schema 子集並不相同。
核對日期為 2026 年 8 月 18 日,欄位與行為以 OpenAI Function Calling 指南、Structured Outputs 指南 為準。本文不虛構延遲、價格或成功率;公開文件沒寫死的地方會標明「需用現網回放確認」。
如果你正在把 OpenAI 相容後端切到其它模型,結構化輸出和工具迴圈必須單獨驗收,不能只換 Base URL。可對照站內的 OpenAI API 遷移 Kimi K3 怎麼驗收?2026 清單。
先看結論:三件事同時變了
很多儲存庫還停在 2024 年的心智模型:提示詞裡寫「請回傳 JSON」、再靠正規表示式從程式碼區塊挖出來。2026 年的生產鏈路上,這條路會被 Schema 違約、缺欄位、enum 幻覺 直接打穿解析器。
真正要改的是三層,而不是再換一個更大的模型名稱:
- 交貨契約
- 最終給使用者或下游服務的物件,用 Structured Outputs(Responses 裡是
text.format,Chat Completions 裡是response_format.json_schema)。 - 執行契約
- 模型要呼叫你的工具時,參數必須貼合工具自己的 JSON Schema;這就是 Function Calling,底層與 Structured Outputs 同一套約束解碼。
- 相容契約
- 舊的 JSON Mode(
json_object)只保證「看起來像 JSON」,不保證欄位、型別、enum 與 Schema 一致。官方已把它定位成 Structured Outputs 的前身,新專案不要再用它當主路徑。
另外還有一條容易漏掉的產品線變化:新程式應走 Responses API。Chat Completions 仍可用,但 strict 的預設策略不同——Responses 會盡量把 Schema 正規化成嚴格模式,失敗才回退;Chat Completions 預設仍是非嚴格、盡力而為。
模型與 API 主路:gpt-5.6 + Responses
Structured Outputs 從 GPT-4o 一代開始可用;官方對新專案的建議是直接用 gpt-5.6。更舊的 gpt-4-turbo 及更早快照,文件仍指向 JSON Mode,而不是完整的 json_schema 嚴格輸出。
選型時先分清兩套入口
| 你要的結果 | 該用的入口 | 2026 年注意點 |
|---|---|---|
| 給使用者/下游一個固定物件 | Responses:text.format;或 Chat Completions:response_format: json_schema |
打開 strict: true;SDK 可用 Pydantic / Zod + parse() |
| 讓模型呼叫你的函式、查庫、改狀態 | tools 裡的 function tool |
工具參數 Schema 同樣走 strict;並行呼叫、多工具迴圈要自己寫執行器 |
| 工具面太大,不想一次塞進上下文 | tool_search 延遲載入 |
僅 gpt-5.4 及更新模型支援;工具定義會計入輸入 token |
| 參數不是 JSON,而是自由文字或特定文法 | custom tools + 可選 CFG | 適合 DSL、查詢語言;不要硬套 function JSON Schema |
SDK 側更值得養成的習慣:不要手寫一份容易漏 additionalProperties 的 Schema,而是用官方 helper 從型別產生。Python 走 client.responses.parse(..., text_format=YourModel);JavaScript 走 zodTextFormat。手寫 Schema 時,strict: true 不滿足約束會直接 請求被拒,而不是「模型隨便輸出再讓你重試」。
和 Gemini 路線對比時,不要把「相容 OpenAI SDK」理解成 Schema 行為也一樣。Google 的能力升級路徑見 Gemini 3.5 Pro 有什麼新功能?10 個你需要知道的 AI 能力升級;跨廠商拷貝同一份 JSON Schema 時,巢狀物件的 additionalProperties 規則經常是第一個炸點。
JSON Mode、Structured Outputs、Function Calling
生產事故裡最常見的混淆是:日誌裡確實是 JSON,於是以為 Structured Outputs 已經生效。下表按官方語意拆開:
| 能力 | 保證合法 JSON | 保證貼合 Schema | 典型啟用方式 | 適用模型 |
|---|---|---|---|---|
| JSON Mode | 是 | 否 | text.format.type = json_object |
含部分 GPT-5 相容檔;老快照常用 |
| Structured Outputs | 是 | 是(受支援的 Schema 子集) | json_schema + strict: true |
gpt-4o-2024-08-06 / gpt-4o-mini 及之後,新專案用 gpt-5.6 |
| Function Calling + strict | 工具參數是合法 JSON | 工具參數貼合 parameters Schema | tools 裡 strict: true |
支援 tools 的模型;建議始終開 strict |
什麼時候不該用 Function Calling
如果模型不需要碰你的系統(不查庫存、不改工單、不跑指令稿),只是要把回答拆成卡片、步驟、評分,那就用 Structured Outputs。反過來,只要輸出是「請幫我執行這個副作用」,就必須走 tools,而不是把函式參數偽裝成最終回答 Schema。
拒答不再是「壞 JSON」
安全拒答時,模型不會硬塞進你的 Schema。Responses / Chat Completions 會給出獨立的 refusal 欄位。解析層要把拒答當成一等公民:先看 refusal,再 output_parsed,不要把空物件當成功。
Strict JSON Schema 的硬規則
開啟 strict 之後,OpenAI 接受的是 JSON Schema 的子集,不是任意 Draft 2020-12 文件。請求級最常撞牆的三條:
properties裡出現的每個欄位,都必須出現在required陣列。- 每個
object(含巢狀)都必須additionalProperties: false。 - 根物件不能是
anyOf;可選語意用「必填 + 允許 null」表達,例如["string", "null"]。
也就是說:把欄位從 required 裡拿掉,假裝它是可選 這條舊技巧在 strict 下會直接 400。正確寫法是欄位仍 required,型別寫成可空聯合,應用層把 null 當成「未提供」。
下面這段是生產裡常見的「擷取工單」物件,注意巢狀 object 也寫了 additionalProperties:
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class Ticket(BaseModel):
title: str
priority: str
assignee: str | None
tags: list[str]
response = client.responses.parse(
model="gpt-5.6",
input=[
{"role": "system", "content": "從使用者描述中擷取工單欄位。"},
{"role": "user", "content": "登入頁 500,指派給 Noah,優先順序高,標籤 auth 與 api。"},
],
text_format=Ticket,
)
ticket = response.output_parsed
print(ticket.title, ticket.priority, ticket.assignee)
偵錯時若請求被拒,優先看錯誤訊息裡缺的是哪條約束,而不是先降模型。Playground 產生的 Schema 預設已開 strict,把它原樣拷進儲存庫通常比「從舊 json_object 提示詞改造」更快。
跨廠商時再核對一次:同一份「每個 object 都 false」的 Schema,在部分相容閘道或其他模型上可能變成 HTTP 400。這時應做依供應商變換,而不是維護三份業務 Schema。
Function Calling 2026:strict、tool_search、custom tools
官方現在把 Function Calling 與 tool calling 當作同一件事:用 JSON Schema 描述可呼叫函式,再用應用側執行器跑副作用。2026 年文件裡新增或被強調的幾條,會直接改你的 Agent 迴圈。
strict 的預設值不要靠猜
- 建議始終顯式
strict: true。 - Responses:省略 strict 時,伺服器端會嘗試正規化 Schema;正規化失敗則回退非嚴格,回應裡的 tool 會顯示
strict: false。 - Chat Completions:省略時預設非嚴格。
- 微調模型若一輪呼叫多個函式,文件寫明該輪可能關閉 strict。
工具定義會計入上下文並按輸入 token 計費。描述寫太長、一次掛 40 個工具,會同時打高帳單和降低選工具準確率。工具很多時,用 tool_search 把低頻工具延遲載入——僅 gpt-5.4 及更新模型支援,迴圈裡還可能先出現 tool_search_call / tool_search_output,再進入真正的 function_call。
custom tools:別把 DSL 塞進 JSON 物件
function tools 適合結構化參數;custom tools 適合自由文字輸入輸出,並可附加上下文無關文法(CFG)約束。SQL 片段、內部查詢語言、需要詞彙終端互斥的格式,用 CFG 比「string 欄位裡再寫一堆 prompt」穩。若 CFG 報 unexpected tokens,先查終結符是否重疊,而不是先怪模型。
tools = [{
"type": "function",
"name": "get_order",
"description": "依訂單編號查詢狀態。僅在使用者提供明確訂單編號時呼叫。",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string"},
"locale": {"type": ["string", "null"]},
},
"required": ["order_id", "locale"],
"additionalProperties": False,
},
}]
執行迴圈沒有變:看到 finish_reason / item type 為工具呼叫 → 跑本地函式 → 把結果以 tool 角色回傳 → 再請求。變的是參數不再需要你用 json.loads 碰運氣。仍必須保存完整 assistant 訊息(含 tool_calls),否則第二輪會丟呼叫 ID。
並行工具呼叫時,順序以呼叫 ID 為準
一次回應可能帶多個 tool call。回傳時按 call_id 對齊,不要按陣列下標假設順序。灰度日誌至少記錄:工具名、參數雜湊、耗時、是否 strict、是否發生 schema 回退。
舊專案遷移清單
把「能跑」和「可交貨」拆開驗收。建議保留舊後端開關,先在獨立環境回放真實流量。
- 模型:新鏈路指定
gpt-5.6(或帳號已開通的同等檔),不要讓閘道靜默對應到舊快照。 - 輸出:把
json_object換成json_schema+strict: true,或 Responses 的text.format。 - 工具:每個 function 補齊
required與巢狀additionalProperties: false;可選欄位改可空聯合。 - 解析:接入
parse()與refusal分支;串流場景確認增量 JSON 與最終 parsed 物件一致。 - 工具面:超過十幾項就評估
tool_search;先縮短 description,再考慮延遲載入。 - 對照:用同一組固定任務對比舊 JSON Mode 與新 Schema 路徑的重試率、缺欄位率、人工返工。
通過標準不是「回傳 200」,而是:解析器零正規表示式兜底、工具參數型別穩定、拒答可觀測、回滾開關演練過。需要長時間掛著 SDK、回放腳本和瀏覽器工作階段時,本機筆電休眠會打斷對照實驗——這正是後面雲端 Mac mini 的切入點。
FAQ
JSON Mode 和 Structured Outputs 可以混用嗎?
不要在同一條鏈路上混。JSON Mode 只保證合法 JSON;Structured Outputs 才保證 Schema。混用會讓監控分不清「解析失敗」是模型問題還是契約問題。新程式只用 json_schema / text.format。
新專案還要寫 Chat Completions 嗎?
能用 Responses 就用 Responses。官方範例、parse helper 和 strict 正規化都優先走這條。存量 Chat Completions 可以繼續,但必須顯式設定 strict,並接受預設非嚴格這一差異。
為什麼我的 Schema 一開 strict 就 400?
最常見是漏了 required、巢狀 object 沒寫 additionalProperties:false、根型別用了 anyOf,或把可選做成「不出現在 required」。把錯誤訊息裡的約束補全後再發;不要靠關閉 strict 掩蓋 Schema 錯誤,除非你明確要非嚴格回退。
Function Calling 一定要 strict 嗎?
官方建議始終開啟。不開啟時參數是盡力而為,你的執行器還得防缺欄位和型別漂移。Responses 省略 strict 還可能被伺服器端改寫,日誌裡要記下最終 strict 值。
tool_search 什麼時候值得上?
工具定義已經明顯擠佔上下文、或大部分工具在單次任務裡根本用不到時。需要 gpt-5.4 及以上。上線前要回放「先搜尋工具再呼叫」的兩段軌跡,舊執行器如果只認 function_call 會直接中斷。
Schema 保證了,還要校驗業務值嗎?
要。約束解碼不驗證外鍵、權限和冪等。enum 合法不等於列舉值對你的庫存有意義。把 Schema 校驗和業務校驗分成兩層日誌,故障時才分得清。
gpt-5.6 和更早的 GPT-5.x 在結構化輸出上差在哪?
文件把 gpt-5.6 標為新專案預設。能力是否在你的帳號、區域、批次處理與微調路徑上完全對齊,必須以當前模型清單和一次最小 parse 請求為準,不要用部落格裡的別名去猜閘道對應。
和 Claude / Grok 的 JSON Schema 能共用一份嗎?
契約方言接近 Draft 2020-12,但子集不同。OpenAI strict 要求每個 object 都 additionalProperties:false;有的供應商會拒絕巢狀層的該欄位。保持一份業務 Schema,依供應商做變換層。
延伸閱讀
在雲端 Mac mini 上,Schema 驗收可以 24/7 掛著跑
Function Calling 和 Structured Outputs 的迴歸,本質是長時間在線的對照實驗:兩套 SDK、固定回放集、工具沙箱、串流前端,還要避免筆電合蓋休眠。Apple Silicon 統一記憶體適合同時跑本地代理與瀏覽器偵錯;macOS 上 Homebrew、Docker、SSH 開箱即用;M4 Mac mini 待機功耗大約 4W,適合把驗收環境掛過夜。
如果你需要一台不搶家庭頻寬、能 SSH 常駐的 Mac 來跑 Agent 回放,Nuvcloud 雲端 Mac mini M4 是目前把「開發機」和「對照實驗機」拆開的低摩擦選項——立即了解方案套餐,讓 strict Schema 的灰度不必綁在自己的筆電上。