適用於誰
- 搜「如何讓大模型穩定輸出 json」「llm 結構化輸出」「讓模型輸出結構化 json」的人;
- 程序裏解析模型返回的 JSON 時,隔三差五遇到多了一段解釋、少了一個字段、括號沒閉合的人。
本文根據 OpenAI 和 Anthropic 的官方文檔整理,資料核對於 2026-10-11。Gemini 的做法見站內《Gemini 結構化輸出怎麼用》。
結論先說
- 有三個可靠程度不同的層級:只靠提示詞要求 < JSON 模式 < 結構化輸出。
- 能用結構化輸出就用它。它用你提供的 JSON Schema 約束生成過程,保證結果符合 Schema。OpenAI 的原話是建議「只要可能,就用結構化輸出而不是 JSON 模式」。
- JSON 模式只保證「是合法 JSON」,不保證字段對。
- 結構化輸出也有兩種情況會不符合 Schema:模型出於安全原因拒答,以及輸出被長度上限截斷。這兩種都要在代碼裏判斷。
- Claude 的舊辦法「預填充」已經不能用了。官方文檔說明,從 Claude 4.6 系列起,在最後一條 assistant 消息裏預填內容會返回 400 錯誤,要改用結構化輸出。
三個層級的區別
| 只靠提示詞 | JSON 模式(OpenAI) | 結構化輸出 | |
|---|---|---|---|
| 輸出是合法 JSON | 大多數時候 | 是 | 是 |
| 符合你指定的字段和類型 | 不保證 | 不保證 | 是 |
| 需要自己校驗和重試 | 需要 | 需要 | 一般不需要(拒答和截斷除外) |
| 適用 | 聊天介面、不支持該功能的模型 | 較舊的模型 | 支持的模型,優先選擇 |
OpenAI 列出的結構化輸出的三個好處:類型可靠,不用再校驗和重試格式錯誤的回答;拒答可以被程序識別;提示詞更簡單,不需要用很重的措辭去強調格式。
Anthropic 的說法類似:不用結構化輸出時,即使提示詞寫得很仔細,仍可能遇到 JSON 語法錯誤、缺少必填字段、數據類型不一致;結構化輸出通過約束解碼來保證結果符合 Schema。
步驟
OpenAI:結構化輸出
用官方 SDK 時,最省事的方式是用 Pydantic(Python)或 Zod(JavaScript)定義結構,交給 parse 方法:
python
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
class Invoice(BaseModel):
seller: str
total: float
items: list[str]
response = client.responses.parse(
model="模型名", # 換成官方模型列表裏支持結構化輸出的模型
input=[
{"role": "developer", "content": "從用戶提供的文本里提取發票資料。"},
{"role": "user", "content": "……發票文字……"},
],
text_format=Invoice,
)
print(response.output_parsed)
官方文檔裏的幾條規則:
- 結構化輸出有兩種形式:用在函數調用裏,或者用作回答的格式。要把模型接到你的工具、函數、數據上,用函數調用;只是想讓模型按固定結構回答用戶,用回答格式;
- 支持的是 JSON Schema 的一個子集。支持的類型有字符串、數字、布爾、整數、對象、數組、枚舉和 anyOf;字符串可以加
pattern和若干預定義的format(如date-time、email、uuid); - 官方給 Schema 設計的建議:鍵名清楚直觀;給重要的鍵寫清楚標題和描述;用評測來確定哪種結構最適合你的場景。
JSON 模式是更基礎的版本,把格式設為 json_object 即可開啟。兩條官方的重要提醒:
- 必須在對話裏明確要求模型輸出 JSON(比如寫在系統消息裏)。不寫的話,模型可能一直輸出空白字符直到用完 token 上限;
- 它只保證能解析,不保證符合任何特定結構,需要你自己用校驗庫檢查並重試。
Claude:結構化輸出
Anthropic 文檔描述的流程是三步:定義 Schema → 放進請求的 output_config.format(type 為 json_schema)→ 從返回的文本內容塊裏讀取符合 Schema 的 JSON。用 SDK 時,推薦的方式是把 Pydantic 模型傳給 client.messages.parse():
python
from anthropic import Anthropic
from pydantic import BaseModel
client = Anthropic()
class ContactInfo(BaseModel):
name: str
email: str
plan_interest: str
response = client.messages.parse(
model="模型名", # 換成官方文檔列出的支持模型
max_tokens=1024,
messages=[{"role": "user", "content": "……電郵正文……"}],
output_format=ContactInfo,
)
print(response.parsed_output)
Claude 這邊同樣有兩種形式:JSON 輸出(output_config.format)和嚴格工具調用(工具定義裏加 strict: true),可以一起用。
官方列出的 Schema 限制,寫 Schema 時最容易踩的幾條:
- 對象的
additionalProperties必須設為false; - 不支持數值範圍約束(
minimum、maximum、multipleOf)和字符串長度約束(minLength、maxLength); - 不支持遞歸的 Schema;數組的
minItems只支持 0 和 1; - 用了不支持的特性會直接返回 400 錯誤,並說明原因。
範圍和長度這類約束,寫進字段的描述裏讓模型遵守,再在代碼裏校驗。
兩家都要處理的例外
即使開了結構化輸出,下面兩種情況的返回仍可能不符合 Schema:
| 情況 | OpenAI 怎麼判斷 | Claude 怎麼判斷 |
|---|---|---|
| 模型出於安全原因拒答 | 輸出內容的類型為 refusal | stop_reason 為 refusal(HTTP 狀態碼仍是 200) |
| 輸出被長度上限截斷 | 響應狀態為 incomplete,原因是 max_output_tokens | stop_reason 為 max_tokens |
處理辦法:拒答時按業務邏輯提示用戶;截斷時調高輸出上限後重試。
Claude 文檔還有兩個細節值得知道:一是不保證枚舉值的大小寫完全一致,比較時最好先統一大小寫;二是不要在 Schema 裏設一個讓模型「寫出思考過程」的字段,可能觸發拒答,官方建議改成要一段簡短的說明。
不能用結構化輸出時:提示詞寫法
在聊天介面裏,或者用的模型不支持這個功能時,只能靠提示詞。盡量做到這幾點:
- 給出完整的示例,而不是隻描述。把期望的 JSON 原樣貼出來,字段名、類型、嵌套關係一目了然;
- 明確邊界:「只輸出 JSON,不要任何解釋,不要用代碼塊包裹」。Anthropic 文檔給出的消除開場白的寫法是:直接回答,不要以「以下是……」「根據……」這類話開頭;
- 規定缺失值怎麼填:找不到的字段填
null,不要編造,也不要省略鍵; - 用標籤包住輸出:讓模型把 JSON 放在
<json>標籤裏,程序只取標籤內的內容; - 代碼裏做兜底:解析失敗時把報錯訊息連同原輸出發回去讓模型修正,最多重試兩三次。
示例:
從下面的招聘資訊中提取字段,嚴格按示例的 JSON 結構輸出。
只輸出 JSON,不要解釋,不要用代碼塊。找不到的字段填 null。
示例:
{"company": "某某科技", "position": "數據分析師", "city": "杭州",
"salary_min": 15000, "salary_max": 25000, "remote": false}
招聘資訊:
<posting>
[粘貼內容]
</posting>
常見問題
Q:結構化輸出會讓回答質素變差嗎?
官方文檔沒有給出這樣的結論。需要注意的是字段順序:兩家文檔都說明輸出會按 Schema 裏定義的順序生成字段(Claude 另註明必填字段排在可選字段之前)。所以把「依據」這類字段排在「結論」字段前面,通常更合理。
Q:字段很多、嵌套很深可以嗎?
兩家都對 Schema 的複雜度有上限,具體數字以官方文檔為準。能拆成兩次調用的,不要硬塞進一個巨大的 Schema。
Q:為什麼以前在 Claude 上用的「預填一個左花括號」不靈了?
Anthropic 文檔說明:從 Claude 4.6 系列模型起,不再支持在最後一條 assistant 消息裏預填充,帶預填充的請求會返回 400 錯誤。官方給的遷移方向就是結構化輸出,或者先直接要求模型按結構輸出,新模型在這方面已經相當可靠。
Q:國產模型、本地模型怎麼辦?
看各自的文檔是否提供 JSON 模式或結構化輸出參數。兼容 OpenAI 接口的服務不一定完整支持,以實際返回為準;不支持時用上面的提示詞寫法加代碼校驗。
參考資料
- OpenAI 文檔:Structured model outputs — https://developers.openai.com/api/docs/guides/structured-outputs
- Anthropic 文檔:Structured outputs — https://platform.claude.com/docs/en/build-with-claude/structured-outputs
- Anthropic 文檔:Prompting best practices(Migrating away from prefilled responses)— https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices
0 條評論
還沒有評論,來搶沙發~