Tool Use 和 Function Calling 有什麼區別?是同一個概念嗎?
這兩個術語在業界有時被混用,但嚴格說有細微差異:
Function Calling 是 OpenAI 在 2023 年 6 月引入的特定 API 功能,定義了 GPT 模型調用開發者定義函數的具體格式(JSON Schema 定義工具,模型輸出 JSON 格式的函數調用請求)。Function Calling 特指 OpenAI 的這個 API 機制,是一個廠商特定的實現。
Tool Use 是更廣義的概念,描述 AI 模型調用外部工具/服務的通用能力,不綁定特定的廠商或 API 格式。Anthropic 叫它「Tool Use」,Google 叫它「Function Calling」,但技術上做的事情幾乎一樣。
MCP(Model Context Protocol) 是在 Tool Use 之上的一層標準化協議,定義了 AI 和工具之間通信的統一格式,讓同一個工具可以被不同的 AI 模型使用,不需要為每個模型分別適配。
實際開發中:如果你在用 OpenAI SDK,你調用的是 Function Calling API;如果你在用 Anthropic SDK,你調用的是 Tool Use API;如果你在建構一個可以被多個模型使用的工具,你應該考慮用 MCP 格式。三個術語的底層技術本質相同,只是命名、格式和標準化程度不同。
怎麼設計好的工具 Schema?工具描述寫得好不好,對 Agent 的決策品質有多大影響?
工具的 Schema 設計直接決定了 LLM 能不能正確地選擇和調用工具。一個寫得好的工具描述,能讓 LLM 在沒有任何額外說明的情況下,準確知道「什麼時候該調用這個工具、傳什麼參數」。
好的工具 Schema 的五個要素:
工具名稱(name):清晰、動詞開頭,描述這個工具做什麼。好例子:get_aave_usdc_apy、withdraw_from_morpho。差例子:tool_1、execute(太模糊)。
工具描述(description):說明工具的用途、使用時機、和不應該使用的時機(負面說明同樣重要)。好例子:「查詢 Aave 協議上指定代幣的當前供應 APY。只用於讀取利率數據,不執行任何交易。適用於:需要比較不同協議利率時。不適用於:需要歷史 APY 數據時(用 get_historical_apy 工具)。」
參數定義(parameters):每個參數有清晰的類型、說明、和枚舉值(如果適用)。加上 examples 字段,讓 LLM 知道參數的預期格式。
返回值說明:在描述裡說明工具會返回什麼格式的數據,讓 LLM 知道如何解析返回值。
工具的邊界說明:明確說明「這個工具能做什麼、不能做什麼」,防止 LLM 對工具的能力做出超出實際的假設(例如以為查詢工具可以執行交易)。
工具描述的品質影響工具調用的正確率可以高達 20-30%——同樣的 LLM、同樣的任務,清晰的工具描述 vs 模糊的工具描述,工具調用格式錯誤率的差距可以非常大。
工具調用失敗時應該怎麼設計 Agent 的錯誤處理邏輯?
工具調用失敗是 Onchain Agent 日常運作中最常見的中斷事件,設計健壯的錯誤處理邏輯是生產環境部署的必要條件。
常見的工具調用失敗類型和對應的處理策略:
網路超時(HTTP 超時 / RPC 連接失敗):最常見的暫時性失敗,通常在幾秒到幾分鐘內自動恢復。處理策略:指數退避重試(第一次等 1 秒,第二次等 2 秒,第三次等 4 秒),最多重試 3 次。如果 3 次重試後仍然失敗,記錄錯誤日誌並通知 Orchestrator「子任務失敗,請決定下一步」,而不是讓 Agent 繼續嘗試。
API 返回錯誤(4xx / 5xx):需要區分錯誤類型。4xx(客戶端錯誤)通常是參數問題(404 - 資源不存在,401 - 認證失敗),重試不會解決問題,需要讓 LLM 重新分析問題。5xx(服務器錯誤)是服務器暫時問題,可以嘗試重試。
鏈上 revert(交易 revert):交易被廣播但在鏈上執行時 revert,常見原因:滑點超限、Gas 不足、授權過期。不能直接重試(同樣的參數大概率仍然 revert),需要 LLM 分析 revert 原因並決定是調整參數重試還是放棄操作。
後端驗證攔截(BLOCKED):Agent 嘗試的操作被後端安全驗證攔截,這通常不是「錯誤」而是「正確的安全攔截」。不應該讓 LLM 嘗試繞過這個攔截,應該記錄告警並通知人工審查。
在 Agent 的工具函數設計裡,所有的錯誤都應該返回結構化的錯誤對象(包含錯誤類型、錯誤描述、建議的後續動作),而不是讓原始異常傳播到 LLM Context 裡——原始異常信息可能包含敏感的系統信息,且往往格式對 LLM 不友好。
在 Onchain Agent 裡,讀取工具和寫入工具應該怎麼設計隔離?
讀取工具(Read Tools)和寫入工具(Write Tools)的隔離是 Onchain Agent 安全設計的核心原則之一:
讀取工具的特性和設計:不改變任何外部狀態,調用失敗可以重試任意次數,可以在任何時機調用(不需要額外確認)。設計原則:函數名稱以 get_、query_、fetch_ 開頭;返回純數據對象;永遠不應該觸發交易廣播;對返回數據的大小做限制(防止把 15,000 Token 的原始 JSON 塞進 Context)。
寫入工具的特性和設計:改變鏈上狀態、消耗 Gas、操作不可逆。設計原則:函數名稱以 execute_、send_、deposit_、withdraw_ 開頭(讓名稱明確告訴 LLM 這是一個有副作用的操作);在函數內部做參數的二次驗證(金額上限、地址白名單、操作類型許可);對高金額操作加入人工確認的 interrupt 點;記錄所有寫入工具的調用到安全日誌(不只是正常的 Debug 日誌)。
隔離的實作:在 Sub-agent 的設計層面,讀取 Sub-agent 只被賦予讀取工具,寫入 Sub-agent 只被賦予寫入工具,且兩個 Sub-agent 之間不能直接通信(只通過 Orchestrator 中轉)。這讓 Prompt Injection 污染讀取工具後,它能做的最壞操作只是返回錯誤數據,而無法直接觸發鏈上交易。
實際例子:一個 DeFi 利率優化 Agent 的工具設計
一個管理 $50,000 USDC 的 DeFi 利率優化 Agent 的完整工具集:
讀取工具(3個):
get_protocol_apy(protocol: str, token: str) -> {apy: float, tvl: float, updated_at: timestamp} — 查詢指定協議和代幣的當前 APY 和 TVL。只返回決策需要的最小字段(不是整個 API 返回)get_gas_price() -> {base_fee_gwei: float, priority_fee_gwei: float, estimated_usd: float} — 查詢當前 Gas 費用get_wallet_balance(address: str) -> {usdc: float, eth: float} — 查詢操作錢包的餘額寫入工具(2個,只有 Orchestrator 批准後才能調用):
withdraw_from_protocol(protocol: str, amount_usdc: float, approval_token: str) -> {tx_hash: str, status: str} — 從協議取出 USDC。後端驗證:amount_usdc ≤ 10,000(單次上限);protocol 在白名單;approval_token 有效(來自 Orchestrator 的確認)deposit_to_protocol(protocol: str, amount_usdc: float, approval_token: str) -> {tx_hash: str, status: str} — 向協議存入 USDC。同樣的後端驗證這個工具設計的安全性:即使 LLM 被 Prompt Injection 攻擊,也無法在沒有有效 approval_token 的情況下調用寫入工具。approval_token 是 Orchestrator 在人工確認(或自動驗證通過)後生成的一次性令牌。沒有 approval_token,寫入工具直接返回 BLOCKED。
工具數量多 → Agent 能做的事情更多、更靈活,但每次推理的 Context 成本更高(工具描述佔用更多 Token),且 LLM 在選擇工具時的「選擇困難」問題更嚴重(多個相似工具讓 LLM 更難判斷用哪個)。工具數量少 → Context 成本低、工具選擇清晰,但 Agent 的能力受限,複雜任務需要更多的工具組合調用(增加延遲和 Gas 費)。最佳實踐:一個 Agent 的工具集保持在 5-15 個之間;如果需要更多工具,通過 Sub-agent 的方式把工具分組(每個 Sub-agent 只持有它任務需要的最小工具集),而不是給單個 Agent 掛載幾十個工具。