Structured Output 和 Function Calling 常常被搞混,兩者到底差在哪裡,什麼時候該用哪一個?
最直觀的區分方式:Function Calling 回答的是「要不要呼叫某個外部工具、呼叫哪個工具、傳什麼參數」,Structured Output 回答的是「不管有沒有呼叫工具,這次的回傳結果要長什麼格式」。
舉例說明差異:一個 Agent 收到「幫我查一下 ETH 現在的價格,並判斷這是不是好的買入時機」這個指令。Function Calling 的角色是決定「要呼叫 get_eth_price() 這個工具去查價格」,並把呼叫的參數(例如要查哪個交易所的價格)用結構化格式傳出去;工具回傳價格數字後,Agent 接著要生成一個包含「當前價格」「買入建議」「信心分數」三個欄位的結論,這個結論輸出的格式規範,就是 Structured Output 在管的事。
實務上兩者幾乎總是一起用:Function Calling 需要用結構化格式描述要呼叫的工具和參數(這其實也是一種 Structured Output 的應用),工具執行完後的最終結論也常用 Structured Output 包裝成固定格式方便下游處理。可以把 Function Calling 理解成「Structured Output 的一個特殊應用場景」——當你需要模型輸出的結構化資料是「要呼叫哪個工具、帶什麼參數」時,就是 Function Calling;當你需要的結構化資料是任何其他形式的固定欄位(分析結論、分類標籤、風險評分)時,就是廣義的 Structured Output。
為什麼「在 Prompt 裡要求模型輸出 JSON 格式」和「用 API 的 Structured Output 功能強制格式」,成功率會差這麼多?
差異來自兩者的實作層級完全不同。
Prompt 層級:你在提示詞裡寫「請用以下 JSON 格式回答:{...}」,這只是一個「請求」,模型仍然是逐字生成文本,沒有任何機制阻止它偏離格式——它可能在 JSON 前後加上「好的,這是分析結果:」這類額外文字,可能漏掉某個欄位,也可能因為推理過程複雜而在生成到一半時「忘記」原本要求的格式。這些偏差在提示詞夠簡單清楚時發生率較低,但在複雜任務、長對話、或模型需要同時處理多個指令時,偏差率會明顯上升。
API 層級:多數主流 LLM API 提供的 Structured Output 功能,是在模型生成過程的底層做約束——並非事後檢查格式對不對,而是在生成每一個 token 的當下,直接限制模型只能生成符合 JSON Schema 語法的 token(這個技術通常叫做「約束解碼」,constrained decoding)。這意味著模型在技術層面「不可能」生成出格式錯誤的 JSON,因為格式錯誤的 token 選項在生成當下就被排除了。
實務影響:Prompt 層級的格式要求,在正式生產環境中通常需要額外寫「格式驗證失敗就重試」的容錯邏輯,因為即使成功率有 90%+,10% 的失敗率在高頻呼叫的系統裡仍然會頻繁觸發;API 層級的 Structured Output 幾乎不需要這層容錯,格式正確率接近 100%(唯一的例外情況通常是 Schema 本身設計得太複雜或有邏輯矛盾)。因此正式產品建議一律用 API 層級的強制約束,Prompt 層級的格式要求只適合快速原型或對可靠性要求不高的場景。
既然 Structured Output 能保證格式正確,為什麼還會有「格式對但內容是幻覺」這種問題?該怎麼處理?
這是 Structured Output 最容易被誤解的一點:格式正確性和內容正確性是兩個完全獨立的保證層級,Structured Output 只解決前者。
技術原因:約束解碼(constrained decoding)的機制,是在模型生成每個 token 時,限制它只能從「符合 JSON Schema 語法」的候選 token 裡選,但這個限制完全不干涉模型「選哪一個符合語法的 token」背後的判斷邏輯。舉個具體例子:如果 Schema 要求一個 confidence_score 欄位必須是 0 到 1 之間的數字,約束解碼會確保模型輸出的一定是這個範圍內的合法數字格式,但不會確保模型給出的那個數字是「經過真實推理算出來的」還是「隨便生成的一個看起來合理的數字」。同理,如果 Schema 要求一個 source_url 欄位,約束解碼只確保輸出的是一個合法格式的 URL 字串,不保證這個 URL 真實存在或內容相符。
處理方式需要在 Structured Output 之外疊加額外的驗證層:
對於可驗證的欄位(例如 URL、日期、ID),在下游程式碼裡做額外的真實性檢查(例如真的去 fetch 一次 URL 確認存在、對照資料庫確認 ID 有效)。
對於不易直接驗證的欄位(例如分析結論、信心分數),常見做法是要求模型在同一個 Structured Output 裡額外附上「推理依據」欄位(例如 reasoning 或 evidence),讓人工審查或另一個 Agent 可以交叉檢查這個結論是否有合理的支撐,而不是盲目相信格式正確的輸出。
對於高風險決策(例如涉及金融交易執行),常見做法是加入第二層驗證機制——用另一個獨立的模型呼叫或規則引擎,對第一次生成的結構化結果做合理性檢查(例如「這個建議的交易金額是否超出用戶設定的上限」),而不是把 Structured Output 的格式正確性,誤當成內容可信度的保證。
在多 Agent 系統裡,Orchestrator 要讀取多個 Sub-agent 的輸出並整合成最終決策,Structured Output 的 Schema 設計要注意什麼?
多 Agent 情境下的 Schema 設計,核心原則是「每個 Sub-agent 的輸出必須包含足夠的中繼資訊,讓 Orchestrator 不用重新理解 Sub-agent 的內部邏輯,就能做整合判斷」。具體要注意三點:
信心分數必須是可比較的統一量尺。如果 Sub-agent A 的信心分數是「高/中/低」的文字分類,Sub-agent B 的信心分數是「0-100 的數字」,Orchestrator 沒辦法直接比較兩者做整合決策(「高」該對應數字幾分?)。所有 Sub-agent 的 Schema 應該統一信心分數的量尺(例如統一用 0-1 的浮點數),讓 Orchestrator 可以直接做加權平均或取最低值這類整合運算。
必須包含來源可追溯欄位。除了結論本身,每個 Sub-agent 的輸出應該包含「這個結論是基於哪些輸入資料/哪次工具調用得出的」(例如一個 source_refs 欄位,記錄引用的 trace_id 或工具調用 ID)。這在 Orchestrator 發現多個 Sub-agent 給出矛盾結論時至關重要——沒有來源追溯,Orchestrator 沒辦法判斷該相信哪一個,只能隨機選或都不信;有來源追溯,Orchestrator 可以進一步查詢是哪個環節的資料出了問題。
必須明確區分「結論」和「不確定性/例外狀況」。Sub-agent 的 Schema 不應該只有「正常結論」的欄位,還要有明確的「無法判斷」或「執行失敗」狀態欄位(例如 status: success / uncertain / failed,加上對應的 failure_reason)。如果 Schema 沒有設計這個狀態欄位,Sub-agent 遇到無法處理的情況時,容易被迫「湊出一個看起來合理但實際上是猜測」的結論來符合 Schema 格式要求,這是 Structured Output 設計不良反而誘發幻覺的一個常見陷阱——寧可讓 Sub-agent 誠實回報「不確定」,也不要逼它一定要填出一個看似完整的答案。
一個新聞分析 Agent 的 Structured Output Schema 設計案例
某個追蹤加密貨幣新聞、判斷新聞對特定幣種價格影響的 Agent,其核心分析結論的 JSON Schema 設計如下:
{
"headline_summary": string, // 20字內濃縮摘要
"affected_assets": [string], // 受影響的幣種代號陣列
"sentiment": "positive" | "negative" | "neutral",
"confidence": number, // 0-1 浮點數
"reasoning": string, // 判斷依據的簡短說明
"source_verified": boolean, // 是否已交叉比對至少兩個獨立新聞源
"status": "success" | "insufficient_data"
}
這個 Schema 設計如何避免常見陷阱:confidence 欄位強制模型給出量化分數,而不是「這個新聞看起來蠻重要的」這種模糊文字,讓下游系統可以設定明確的閾值(例如信心低於 0.4 的分析結果不觸發自動通知,只記錄不採取行動)。source_verified 欄位直接對應「格式對但內容可能是幻覺」的防禦設計——如果這個新聞來源模型只在單一新聞網站看到、沒有其他來源佐證,模型必須誠實標記 source_verified: false,下游系統看到這個標記時,即使 confidence 分數很高,也會自動降級處理(例如只做記錄,不觸發實際交易建議)。status 欄位的存在避免了模型在資料不足時被迫「編造」一個分析結論——如果新聞內容本身模糊到無法判斷受影響幣種,模型可以誠實回報 status: insufficient_data,而不是硬湊一個 affected_assets 陣列。
實際運作中發現的問題:這個 Agent 上線初期,source_verified 欄位的準確率本身也需要驗證——工程團隊發現模型偶爾會把「同一篇新聞被轉載到多個網站」誤判為「多個獨立來源」,因此額外在下游加了一層域名去重邏輯,只有真正不同新聞機構(用不同的根域名判斷)的報導才算獨立來源,這說明即使是為了防禦幻覺而設計的驗證欄位,本身也需要下游做進一步的邏輯校驗,不能無條件信任。
Structured Output 的核心取捨是「約束嚴格度 vs 模型表達彈性」。Schema 設計得越嚴格(欄位固定、型別嚴格、不允許額外欄位),下游解析越可靠,但也可能限制模型在遇到 Schema 沒預期到的情況時的表達空間,逼它硬塞進不合適的欄位(例如上一節提到的「被迫編造結論」問題)。設計得越寬鬆(例如允許一個開放式的 additional_notes 欄位),彈性越高,但下游程式碼處理這些非結構化的補充內容時,又回到了脆弱解析的老問題。另一個取捨是「即時驗證成本」:越複雜的 Schema(巢狀結構、條件式必填欄位)通常對模型的生成難度越高,可能拉低格式合規率或增加生成延遲,越簡單的 Schema 則可能無法涵蓋所有真實情況,需要更頻繁修訂。建議:核心決策欄位(信心分數、狀態、金額)一律用嚴格 Schema,允許模型出錯的空間留在明確標示為「補充說明」的獨立欄位,兩者分開設計,而不是用一個 Schema 同時追求嚴謹和彈性。