上一篇的 <output_format> 只寫了「三段摘要,每段附原文依據」。給人看,這樣就夠;但如果接手的是程式,這一格得寫得更硬。
叫 Claude「請固定用嚴格格式回答」聽起來很合理,對程式來說卻還是不夠。它可能少一個欄位、把數字寫成字串,或臨時多補一句解釋。人看得懂,程式當場就卡住。
自由文字像請人把檢查結果寫在白紙上;JSON Schema 則是先印好表格,規定每一格該填什麼。
以資安掃描的 Finding 為例,印好的表格長這樣:
{
"type": "object",
"properties": {
"title": { "type": "string" },
"severity": { "type": "string", "enum": ["low", "medium", "high", "critical"] },
"line": { "type": "integer" }
},
"required": ["title", "severity", "line"]
}
填好、而且通過驗證的那一張,則是這樣:
{
"title": "SQL Injection",
"severity": "high",
"line": 42
}
type 規定 title 必須是字串、line 必須是整數;enum 讓 severity 只能從四個選項裡挑,模型自己發明的 "Severe" 會被擋下;required 保證三個欄位一個都不能少。
但 Schema 寫在哪裡,差別很大。貼進 Prompt 裡,它仍然只是一句叮嚀。Claude API 的 Structured Outputs 則是把 JSON Schema 編譯成 grammar,直接約束模型的輸出:在請求中用 output_config.format 指定 type: "json_schema",或在工具呼叫時加上 strict: true,兩者也可以併用。Python 與 TypeScript 的 SDK 還能直接用 Pydantic 或 Zod 定義,不必手寫原始 Schema。叮嚀變成約束,差的就是這一步。代價是 Schema 不能無限複雜,結構太龐大會在編譯階段被擋下,直接回 400。
不過有一件事 Schema 管不到:它保證的是格式,不是正確性。你完全可能拿到一份格式完美、內容錯誤的 JSON。severity 一定會落在那四個選項裡,但這個漏洞到底算不算 high,Schema 一個字都管不上。這就回到 Day 02——模型仍然在做機率接龍,Schema 只是規定了它能往哪些方向接。
所以我現在會把驗收拆成兩層:形狀交給 Schema 擋,內容自己抽樣去看。