給 Agent 一雙手:Tool Use 與 Function Calling 的實作課
語言模型在 2023 年 6 月之前,是「只有大腦、沒有手」的存在:它能寫出呼叫天氣 API 的程式碼,卻不能自己按下執行鍵。OpenAI 隨著 GPT-4-0613 推出的 function calling 改變了這件事——模型改為輸出「函式名稱+結構化參數」,由應用程式執行後把結果餵回去。三年後的今天,這套機制長成了所有 Agent 的神經末梢:查資料庫、寫檔案、呼叫幾十個 MCP 伺服器,本質都是同一條迴路——模型決策 → 工具執行 → 結果回流。今天這篇,把這雙手的鍛造術拆開來看。
一、三代演進:從「猜 JSON」到「保證合規」
第一代 function calling(2023/6)只解決了一半問題:模型會輸出 JSON 參數,但「是合法 JSON」不等於「符合 schema」——缺必填欄位、型別寫錯照樣發生,開發者得自己寫驗證層善後。接著的 JSON Mode 保證輸出是合法 JSON,但 schema 依從性依然不保證。
真正的轉折是 2024 年 8 月的 Structured Outputs:用約束解碼(constrained decoding)在 token 生成階段就擋掉不合規的輸出,必填欄位、型別、列舉值全部強制。2026 年生產環境的共識很明確:一律開 strict: true,JSON Mode 視為 legacy。
介面也在演進:OpenAI 從 Chat Completions(message.tool_calls[] 加上 role: "tool" 的回傳訊息)走到 Responses API(回應 output 陣列裡的 function_call 項目,結果以 function_call_output 接回)。概念不變,信封換了。
二、兩大家族的信封長什麼樣
如圖一,概念相同,OpenAI 與 Anthropic 的 wire format 有幾個實作上必須知道的差異:
- OpenAI:
arguments是 JSON 字串,呼叫端要自己json.loads解析一次;tool_choice控制是否強制呼叫;並行工具呼叫在 GPT-4o / 4.1 / 5 系列預設開啟——模型可以在單一回合一次丟出多個獨立呼叫,應用端用asyncio.gather並行執行,省掉好幾輪來回。 - Anthropic Messages API:content block 架構。assistant 的輸出是型別化 block 陣列,
tool_use只是其中一種——它的input已經是結構化物件,不用二次解析;工具結果放在 user 角色訊息裡的tool_resultblock;以stop_reason: "tool_use"表示「這一回合要動手了」。同樣支援 strict 模式,也能用disable_parallel_tool_use強制一回合只做一件事。
三、工具設計的五個實作要點(2026 版)
工具定義的三個欄位 name、description、input_schema 裡,description 是最重要的欄位——它是模型決定「什麼時候用這把工具」的唯一依據。Anthropic 在 2026 年 7 月的部落格文章 The new rules of context engineering 給了一個反直覺的結論:對新一代模型,範例反而會限制探索;把參數設計成表達力好的列舉(例如狀態欄位只允許 pending / in_progress / completed),比寫一段 worked example 更能引導正確用法。規則讓位給判斷力,範例讓位給介面設計。
其餘四點是工程紀律:
- 數量節流:同時暴露的工具維持在 5–15 個;再多就用 ToolSearch 做延遲載入(Claude Code 的做法:先搜尋,用的時候才載入完整定義——progressive disclosure,context 保持乾淨)。
- 錯誤要餵回去:工具執行失敗時,把錯誤訊息包裝成 tool result 回傳,讓模型有機會自我修正;直接丟例外中斷迴路是最浪費的死法。
- 並行與嚴格的取捨:2025 年起 OpenAI 已支援 strict 模式+並行呼叫並存(非微調模型);微調模型若求穩,可關掉並行保 schema 可靠度。
- 定義保持 byte-identical:跨回合不要改工具定義的位元組內容,prompt caching 才能命中,又省錢又省延遲。
# OpenAI:並行工具呼叫的典型處理
import asyncio, json
resp = client.chat.completions.create(
model="gpt-5", messages=messages, tools=tools) # 並行預設開啟
calls = resp.choices[0].message.tool_calls or []
if calls:
results = await asyncio.gather(*[
run_tool(c.function.name, json.loads(c.function.arguments))
for c in calls]) # 一次發出,並行執行
messages += [to_tool_msg(c, r) # 結果接回對話
for c, r in zip(calls, results)]
四、怎麼驗收這雙手:BFCL
模型會不會用工具,不能憑感覺,要量。UC Berkeley 的 BFCL(Berkeley Function Calling Leaderboard,ICML 2025) 是這個領域的事實標準,分四層(如圖二):singleturn(單輪呼叫,含並行與多候選干擾項)、crowdsourced(2,251 筆從六萬多筆社群貢獻精選的真實場景)、multiturn(8 個 API 套件、1,000 個查詢,考驗持續的上下文管理與動態決策)、agentic(長程多步驟真實任務)。
看分數要看分項,不要只看總分。BFCL 有三條評分 track:AST(語法正確)、executable(真的跑得起來)、irrelevance(該不呼叫時不亂呼叫)——AST 高分但 executable 低分的模型,會產出「看起來合理但跑不起來」的呼叫;irrelevance 低分的模型則有亂開槍傾向。τ-bench 補上另一塊:在航空與零售的多輪模擬環境裡,連 GPT-4o 在 retail 的 pass@8(八次獨立執行全過)都不到 25%——多輪工具 Agent 是不確定性的放大器。
最後一句實話:公開基準只能告訴你「這個模型會不會用工具」,production 的 gate 永遠是自家私有評測集——按工具、參數邊界案例、錯誤碼分層,每週把線上失敗的 trace 升格進去。
結語
Tool use 是 Agent 的雙手,但「長出手」不等於「會用手」。2026 年的實作共識可以收成一句話:schema 用 strict、描述寫清楚、數量做節流、錯誤餵回去、評測看分項。這五件事做到,Agent 才算從聊天機器人變成能動手做事的同事。
參考來源
- Patil et al., The Berkeley Function Calling Leaderboard: From Tool Use to Agentic Evaluation of Large Language Models, UC Berkeley, ICML 2025. 評測榜:https://gorilla.cs.berkeley.edu/leaderboard.html
- Anthropic, The new rules of context engineering for Claude 5 generation models, 2026-07-24(要點整理:developersdigest.tech)
- FutureAGI, Evaluating Tool-Calling Agents 2026. futureagi.com
- OpenAI function calling:strict 模式與並行呼叫相容性整理 kommunicate.io
沒有留言:
張貼留言