Function Calling 的正確理解是:模型只依照工具 Schema 產生結構化呼叫請求,不會直接替你執行任意 API。如果你正在查 Function Calling JSON API,建議先用一個只讀工具跑通「宣告 → 模型呼叫 → 程式執行 → 結果回傳 → 最終回答」閉環,再決定是否加入多模型適配層。
本週建議動作:先選一個不會修改資料的查詢工具,分別記錄 OpenAI、Google Gemini 與 Claude API 的原始回應;若未來需要共用工具或切換模型,再建立內部事件契約。
這篇適合三類讀者:第一次建構工具型 AI 的後端開發者、多模型平台工程師,以及需要審核憑據與高風險動作的安全負責人。若你只想了解模型排名,本文不是選型榜單;本文處理的是「誰宣告、誰執行、誰批准、誰驗證」。
先看共同資料流,再看三家的結構差異
Function Calling 可以拆成五個責任節點:
- 模型接入開發者宣告工具名稱、用途、輸入欄位與 Schema。
- 模型根據使用者意圖,產生工具名稱與 JSON 引數。
- 供應商適配層解析不同 API 的回應格式,轉換成內部事件。
- 工具執行器負責認證、網路請求、逾時、重試、冪等與結果封裝。
- 安全與業務層決定是否允許動作,最後再把工具結果交回模型。
這條流程中最容易犯的錯,是把模型輸出的 JSON 當成已經完成的 API 結果。事實上,OpenAI 文件也提醒,模型產生的引數不一定永遠是有效 JSON,或可能包含 Schema 沒有定義的欄位;你的程式仍要驗證後才能執行。(OpenAI 官方 API 文件)
Function Calling 會直接執行 API 嗎?
不會。對自訂工具而言,模型只提出「應該呼叫哪個工具,以及要傳哪些引數」。真正的 HTTP 呼叫、資料庫查詢或 macOS 指令,都必須由你的應用程式或執行環境完成。Google Gemini 的官方流程同樣把「執行函式」列為開發者責任。(Google Gemini 官方 Function Calling 文件)
三家平台的核心欄位不是同一套
| 平台 | 工具宣告重點 | 模型呼叫資料 | 結果如何對回原呼叫 |
|---|---|---|---|
| OpenAI | tools 內的 function,包含 name、description、parameters;可用 strict 要求符合受支援的 Schema 子集 |
tool_calls 陣列;常見欄位包括 id、function.name、function.arguments |
依 tool_call_id 對應工具結果;實作時應保留原始訊息結構 (OpenAI 官方 API 文件) |
| Google Gemini | function declaration 以 name、description、parameters 描述,格式採支援的 OpenAPI Schema 子集 |
舊式 Generate Content API 常見 functionCall part;新式流程可見 function_call step,並可能帶有呼叫 id |
回傳 function response 時保留對應識別資訊;混合內建工具時不能假設呼叫位於 parts 陣列最後 (Google Gemini 官方 Function Calling 文件) |
| Claude | tools 位於請求頂層,輸入欄位使用 input_schema |
回應包含 tool_use content block,主要欄位是 id、name、input,並以 stop_reason: tool_use 表示意圖 |
用 tool_use_id 放入後續 tool_result,而且結果區塊必須緊接在對應工具使用之後 (Claude 官方 Tool Use 文件) |
三家模型的工具呼叫 JSON 格式一樣嗎?
不一樣。三家都使用 JSON 表達工具引數,但外層訊息角色、呼叫區塊名稱、識別欄位與結果回傳方式不同。你可以統一「內部語意」,不能直接假設三家的請求或回應 JSON 可以互換。
第一層對比:模型宣告工具,還是執行器真正負責工具
工具宣告不是 API 文件的全文複製。你應該只提供模型判斷所需的資訊:
- 工具名稱:保持穩定,避免同義工具同時出現。
- 工具描述:說明何時使用、何時禁止使用。
- 輸入 Schema:列出型別、必填欄位、列舉值與格式限制。
- 呼叫策略:允許自動選擇、強制工具、禁止工具,或限制平行呼叫。
- 業務前置條件:例如只能查詢目前登入使用者可存取的資源。
JSON Schema 的價值,不只是讓 JSON 看起來整齊。它把模型可產生的輸入範圍縮小,讓執行器可以在進入外部 API 前做機械式驗證。OpenAI 的 strict 可要求工具呼叫遵循指定 Schema,但文件同時指出嚴格模式只支援 JSON Schema 的部分能力;Google Gemini 也使用 OpenAPI Schema 的支援子集。(OpenAI Structured Outputs 官方文件) (Google Gemini 官方 Function Calling 文件)
Function Calling 為什麼需要 JSON Schema?
因為自然語言無法直接作為可靠的函式輸入。Schema 能清楚區分字串、數字、布林值、陣列、必填欄位與允許值。不過 Schema 只處理「形狀」,不能確認使用者是否擁有資源,也不能替你完成授權。
例如,order_id 符合字串格式,不代表它屬於目前登入者。action: "delete" 符合列舉值,也不代表刪除動作已獲得批准。
第二層對比:適配層統一事件,但不要抹平原始回應
多模型專案最值得投資的部分,通常不是再包一層相似 SDK,而是定義內部事件。可以採用以下概念模型:
{
"event_type": "tool_call_requested",
"provider": "openai",
"conversation_id": "internal-session-id",
"call_id": "provider-call-id",
"tool_name": "get_order_status",
"arguments": {
"order_id": "A-1001"
},
"raw_response_ref": "stored-response-id"
}
這個事件不是三家平台的通用請求格式,而是你自己的內部契約。供應商適配層應把不同欄位映射到 call_id、tool_name 與 arguments,同時保留原始回應、模型版本、SDK 版本與 API 入口。
原因很實際:
- 後續排查時,你需要知道原始回應究竟是
tool_calls、functionCall還是tool_use。 - 平行工具呼叫可能改變事件順序,不能只取最後一個文字區塊。
- 某些平台有額外狀態或上下文欄位,過度正規化會讓重播與除錯失去依據。
- 供應商更新格式後,你可以只修改適配器,不必重寫工具執行器。
如果你的專案還在驗證單一模型,直接使用官方 SDK 通常較快。若已有多個模型、共享工具目錄、集中審計或供應商故障切換,就應建立內部契約。你也可以先閱讀 AI Coding Agent 選型方向,再判斷是否需要把工具層抽成獨立服務。
第三層對比:模型提出請求,執行器承擔真實風險
工具執行器不是一個簡單的 eval(function_name, args)。最少要處理以下邊界:
- 名稱白名單:模型只能呼叫註冊工具,不能自行拼接程式或命令。
- Schema 驗證:先驗證型別、必填欄位、字串長度與列舉值。
- 認證隔離:API 金鑰放在伺服器端的密鑰管理系統,不放入提示詞、對話內容或模型可讀檔案。
- 逾時與重試:外部 API 失敗時要區分可重試錯誤與不可重試錯誤。
- 冪等設計:建立訂單、寄信、付款等動作要有去重鍵,避免模型重試造成重複操作。
- 結果封裝:回傳可讀的錯誤代碼與必要內容,不要把整個內部堆疊追蹤交給模型。
- 資源所有權:以目前使用者的身分重新檢查資料權限。
模型生成錯誤引數時應該怎麼處理?
不要直接重試同一個請求。先把錯誤分成三類:
- JSON 無法解析:記錄原始輸出,要求模型重新產生。
- Schema 不合規:回傳欄位錯誤,限制重試次數。
- 業務規則不允許:停止執行,要求使用者補充或確認。
如果是高風險工具,應在執行前建立人工批准狀態。Schema 合規只代表輸入格式正確,不代表這個動作符合使用者授權、業務規則或資源所有權。
工具權限的條件分支
- 若工具只讀取公開或已授權資料,則可考慮自動執行,但仍保留稽核記錄。
- 若工具讀取私人資料,則必須先驗證登入身分與資源歸屬。
- 若工具會寫入資料,則加入預覽、確認或可回滾機制。
- 若工具具破壞性,例如刪除、停機或撤銷權限,則預設人工批准。
- 若工具可連線開放網路,則限制網域、方法、頻寬與傳出資料,否則回退到受控代理服務。
- 若工具需要長期執行、持續自動化或存取本機環境,則不要把整個伺服器權限交給模型,應使用隔離執行節點。
第四層對比:用同一業務樣例測試三家,而不是只測成功案例
測試時,三家平台應使用同一個只讀工具,例如「查詢訂單狀態」。但你要分別記錄平台、模型、SDK、API 入口與介面日期,不能只保存最後顯示給使用者的文字。
建議照以下步驟執行:
- 定義相同語意的工具:名稱可按平台規則調整,但輸入欄位與業務意思保持一致。
- 準備正常案例:使用合法訂單編號,確認模型能產生正確工具名稱與引數。
- 加入缺失欄位:故意省略訂單編號,觀察模型是追問、猜測,還是產生不完整呼叫。
- 加入錯誤資料:測試不存在的訂單、無權限訂單與格式錯誤輸入。
- 測試平行呼叫:準備兩個互不依賴的只讀查詢,確認事件解析不依賴固定順序。
- 模擬工具失敗:讓執行器回傳逾時、認證失敗與業務錯誤,觀察模型是否誤報成功。
- 測試歷史遺失:移除部分工具呼叫或結果,確認適配層能拒絕不完整狀態,而不是繼續執行。
- 驗證最終回答:工具回傳錯誤時,模型不得把錯誤結果包裝成已完成的動作。
| 測試項目 | 你要觀察的結果 | 不合格時的處理 |
|---|---|---|
| 引數缺失 | 模型是否追問或產生可識別的驗證錯誤 | 不執行外部 API,回傳欄位錯誤 |
| 多個工具呼叫 | 是否正確保存每個呼叫識別碼與順序 | 以事件佇列重組,不依賴文字位置 |
| 工具逾時 | 是否明確表示工具未完成 | 停止重試或套用冪等策略 |
| 權限不足 | 是否阻止跨使用者讀取 | 在執行器重新驗證所有權 |
| 歷史不完整 | 是否拒絕缺少結果的狀態 | 標記工作階段失效並要求重新開始 |
| 最終回答錯誤 | 是否把失敗說成成功 | 以工具執行狀態作為回覆依據 |
Claude API 的工具流程特別值得留意:tool_use 後,工具結果要用 tool_result 回傳,並透過 tool_use_id 對應;結果區塊的位置也有明確要求。這類訊息歷史規則若在適配層被忽略,通常會在多輪或失敗重試時才暴露。(Claude 官方 Tool Use 文件)
最後決策:直接用官方 SDK,還是建立多模型適配層?
你可以用以下分支做架構決定:
- 若目前只有一個模型、工具數量少、沒有供應商切換需求,則先用官方 SDK,將執行器和權限檢查獨立出來。
- 若同一套工具要服務 OpenAI、Google Gemini 與 Claude API,則建立內部工具目錄與事件契約,並保留每家平台的原始訊息。
- 若需要平行呼叫、長對話、重試或工作階段恢復,則加入事件佇列、狀態儲存與重播機制,不要只靠一次 API 回應。
- 若工具會修改資料或觸發付款、刪除、部署,則把批准流程放在模型之外。
- 若工具需要 macOS 指令、Xcode、iOS 模擬器或 Apple 自動化,則再評估獨立的遠端 Mac 執行節點,而不是把本機權限直接暴露給模型。
這也是 Function Calling 與 MCP 等工具協議需要分開理解的原因:前者主要描述模型如何提出結構化工具請求,後者更偏向工具與 AI 應用之間的連線與發現方式。若你正在設計共享工具層,可延伸閱讀 MCP 與 AI Agent 工具整合方向。
如果你目前用的是單一雲端執行環境,常見問題是權限邊界不清、長時間任務難以維持,以及涉及 Xcode 或 Apple 自動化時缺少原生 macOS 工具鏈。這些限制不一定能靠更複雜的提示詞解決。當你的 Agent 工具需要固定的 macOS、Xcode 或持續自動化環境時,租用 Hashvps 的遠端 Mac 資源會比把高權限工具塞進一般伺服器更容易隔離、測試與回收;若只是長期穩定重負載、必須接觸實體裝置,或已有固定本機設備,則自購 Mac 可能更合適。
為 AI 工具串接提供穩定的遠端 Mac 與算力
使用 Hashvps 遠端 Mac,快速建立適合 API 整合、Function Calling 與自動化測試的開發環境。
透過 Hashvps Mac 租賃,彈性取得獨立資源,方便驗證不同模型、工具流程及 JSON Schema。