简

從訂單排查案例理解工具粒度、命名、參數與返回值的設計,再通過真實任務、調用記錄和獨立測試改進工具質量。

Tool Design:怎樣讓 Agent 選對工具、用對接口?
27 分鐘
5301 字

Agent Loop講清了工具請求怎樣進入執行循環,Computer Environment解釋了動作在哪裏發生。這一篇接着看循環中的接口:同一份軟件能力,怎樣交給模型,才容易被選對、用對,併產生有用的反饋?

讀 Anthropic 的 《Writing effective tools for agents — with agents》,我更關注兩件相互連接的事:工具如何設計,以及設計是否真的有效。原文將原型、任務評估和持續修改放在一起,而不是把一份工具説明寫完就當作結束。

  • 能力怎麼劃分: 從用户任務出發,確定值得暴露的工具與操作邊界。
  • 接口怎麼表達: 讓名稱、參數和返回值共同解釋工具的用途。
  • 質量怎麼判斷: 通過任務結果與調用記錄,找出設計中需要修改的地方。

下面用一個假設的訂單排查任務貫穿這些問題:客服想查清一位客户最近兩週的訂單裏,是否存在重複扣款,並列出需要跟進的訂單。工具、數據和測試任務都是圍繞這個場景設計的示例。

一、API 能被調用,不等於 Agent 容易用對h2

假設訂單系統已經提供三個 API:查訂單、查支付流水、查退款記錄。後端程序可以按照寫好的邏輯調用它們:訂單 ID 從哪裏來,支付狀態如何解釋,哪些字段要繼續傳給下一個接口,都由代碼明確安排。

換成 Agent,模型需要先從任務中判斷該選哪個工具,再組織參數,並根據結果決定是否繼續。於是,接口除了要滿足程序執行,還多了一層要求:它必須讓調用者理解,自己提供的能力適合解決什麼問題。

比如一個工具叫 query,只有 id 和 type 兩個參數。開發者知道 type=2 表示支付流水,但模型看到的只是兩個缺少業務含義的字段。即使參數類型完全合法,也可能查錯對象。

我會把這裏的質量分成兩個層面:

層面要檢查的問題
實現正確性給定合法參數,工具是否查詢了正確資源,返回了正確數據?
使用有效性給定用户任務,Agent 是否選對工具、填對參數,並正確使用返回結果?

前者仍然需要普通的軟件測試;後者要把模型放進調用過程才能觀察。接口單元測試通過,不能替代 Agent 使用測試。

這也不意味着傳統 API 必須全部重做。已有 API 可以繼續作為底層能力,Agent Tool 則在上面重新組織名稱、參數、數據和操作邊界。需要改變的是對模型暴露的使用方式,不一定是業務系統本身。

二、工具粒度:圍繞任務組織能力,而不是照着端點逐個包裝h2

訂單排查至少需要兩種動作:先找到相關訂單,再檢查某筆訂單的付款與退款情況。如果只給一個 list_all_orders,Agent 就得先接收大量無關訂單,再逐條篩選;如果把每張表都拆成一個工具,它又需要自己拼接內部數據關係。

針對這個場景,我會先提供兩項能力:

orders_search
按客户、时间范围等条件查找订单,返回摘要与可继续查询的 ID
orders_get_payment_context
按订单 ID 返回付款、退款及关联关系,供重复扣款排查使用

第二個工具可以在內部調用多個 API,但從 Agent 的視角看,它完成的是一個連貫的取證步驟。支付流水和退款記錄經常需要一起解釋,把它們放在同一份結果中,可以減少模型反覆獲取、關聯數據的工作。

反過來,我不會把它繼續擴大成 handle_customer_problem,讓工具同時排查、決定補償並執行退款。這幾件事不是同一個操作邊界:查詢證據與改變訂單狀態,應當在接口上明確區分。

因此,工具粒度不是“越細越靈活”,也不是“越粗越省調用”。我更看重三個判斷:

  • 結果是否連貫: 合併後的操作,是否共同服務於一個明確任務步驟?
  • 輸入是否可獲得: Agent 能否從用户信息或前一個結果中拿到所需參數?
  • 行為是否可預期: 調用工具之前,是否清楚它只讀取信息,還是會修改狀態?

如果一次查詢就能得到完整付款證據,沒必要強迫模型拼接多份流水;如果一次調用悄悄完成了退款,就把本該獨立判斷的動作藏進了查詢。

工具的價值不是多包一層函數,而是把底層軟件能力整理成模型可以理解和組合的任務步驟。

三、Tool Definition:名稱、説明與 Schema 要表達同一個接口h2

工具定義不是隻有 JSON Schema。名稱影響模型如何區分能力,説明解釋適用場景,Schema 則給參數建立結構約束。三者如果説的是不同的事,模型就需要在矛盾信息裏猜測。

名稱先交代資源,再交代動作h3

search、get_data、process 很難與其他工具區分。訂單工具採用 orders_search、orders_get_payment_context,至少讓模型先看到資源範圍,再看到操作。

如果還有客服工單搜索,可以叫 tickets_search。這種 Namespace 不是為了名字整齊,而是讓“搜訂單”和“搜工單”在選擇時就有區別。名稱規則是否有效,仍要通過調用記錄判斷;沒有必要先假設某種前綴或後綴對所有模型都最優。

説明寫清用途,也寫清不做什麼h3

“搜索訂單”解釋得太少。我會把這個示例工具的説明寫成:

按客户 ID 和創建時間範圍查詢訂單,適用於訂單定位和售後排查。時間範圍為左閉右開,使用帶時區的時間戳。返回訂單摘要、穩定的訂單 ID 和下一頁游標;不返回完整支付流水,也不會退款或修改訂單。排查扣款明細時,使用返回的訂單 ID 調用 orders_get_payment_context。

這段説明既解釋當前工具,也交代下一步怎樣接上其他能力。它不是替模型寫死整個任務流程,而是讓能力邊界可見。

Schema 約束形狀,字段語義還要明確h3

下面使用 Anthropic 自定義工具的 name、description、input_schema 結構。日期、分頁和默認值是這個示例自己的約定,不是平台統一規定:

{
"name": "orders_search",
"description": "按客户与创建时间查询订单摘要,不修改订单。支付明细请用返回的 order_id 调用 orders_get_payment_context。时间范围为左闭右开,须含时区。",
"input_schema": {
"type": "object",
"properties": {
"customer_id": { "type": "string", "minLength": 1, "description": "客户系统的稳定 ID,不是姓名或订单 ID" },
"created_from": { "type": "string", "format": "date-time", "description": "包含此时间,必须带时区" },
"created_before": { "type": "string", "format": "date-time", "description": "不包含此时间,必须晚于 created_from" },
"page_size": { "type": "integer", "minimum": 1, "maximum": 50, "description": "每页条数;省略时工具实现使用 20" },
"cursor": { "type": "string", "minLength": 1, "description": "原样传入上一页 next_cursor;首轮省略,翻页保持其他查询条件不变" }
},
"required": ["customer_id", "created_from", "created_before"],
"additionalProperties": false
}
}

required 表示必填,additionalProperties: false 拒絕未聲明字段。字段出現在 properties 中,並不自動成為必填項;這點在 JSON Schema 的對象説明中有明確區分。

但結構合法仍不等於業務正確。一個合法字符串可能是不存在的客户 ID;兩個合法時間戳也可能前後顛倒。format 是否被嚴格校驗還取決於校驗器配置,工具實現仍應驗證時間格式、時區、範圍順序和游標與查詢條件的匹配關係。

默認值也需要代碼落實。“省略時使用 20”不是寫在説明裏就會自動發生。這裏工具實現負責補默認值、檢查輸入,再調用底層 API。

假設任務明確指定查詢區間,一次調用可以是:

{
"customer_id": "cus_demo_42",
"created_from": "2026-09-28T00:00:00+08:00",
"created_before": "2026-10-12T00:00:00+08:00",
"page_size": 20
}

如果用户只説“最近兩週”,運行時還需要提供當前日期及業務時區,讓這個相對範圍能夠被解釋。參數要求明確,輸入信息也要足夠,不能把缺少依據的問題全歸給模型。

四、Tool Result:讓下一步判斷有依據,也有繼續查詢的入口h2

工具返回值可以看作下一輪判斷的材料。訂單搜索不需要把數據庫整行原樣返回,但也不能只剩一句“找到了一些訂單”。

下面是一頁示例結果。payment_status 描述付款狀態,不直接宣稱存在重複扣款;是否重複,需要繼續核對支付流水。

{
"orders": [
{
"order_id": "ord_demo_104",
"order_number": "DEMO-104",
"created_at": "2026-10-03T10:20:00+08:00",
"amount_minor": 12900,
"currency": "CNY",
"payment_status": "paid"
}
],
"next_cursor": "cursor_demo_page2",
"has_more": true
}

這裏每個字段都有作用:訂單號方便向用户解釋,order_id 供後續工具調用,金額與幣種幫助核對交易,分頁信息説明這一頁不是全部結果。示例約定 amount_minor 使用最小貨幣單位,12900 對應人民幣 129 元;這個約定需要在工具輸出説明中寫清。

減少返回內容,不等於刪除下一步所需的標識。 只返回易讀的訂單號,卻讓後續工具要求另一種未提供的內部 ID,調用鏈就會斷開。同樣,只返回“不透明 ID”而沒有可解釋的業務信息,模型也難以組織可靠回答。

分頁、篩選與截斷解決的是不同問題h3

在這個示例裏,客户與時間條件先縮小查詢範圍;分頁再控制每次返回多少訂單。只有一筆訂單出現疑點時,可以進一步查詢它的付款上下文,而不是給每筆訂單附上完整流水。

如果結果因長度限制被截斷,需要明確告訴 Agent:哪些內容沒有返回,以及怎樣繼續獲取。無聲地丟掉後半部分,再讓模型回答“全部檢查完了”,就是接口製造的信息缺口。

這裏也不追求返回越短越好。只有一個總數,可能節省了當前調用的 token,卻迫使模型不斷補查。應當比較完成整個任務所需的調用和信息,而不是隻看某一份響應的長度。

錯誤結果也應該支持下一步行動h3

假設 Agent 把查詢結束時間寫在開始時間之前,只有 INVALID_ARGUMENT 不夠定位問題。這個示例可以返回:

{
"error": {
"code": "INVALID_TIME_RANGE",
"field": "created_before",
"message": "created_before 必须晚于 created_from;两个时间都必须包含时区。",
"hint": "保留查询目标,修正时间范围后重试。"
}
}

這是工具的業務錯誤示例,不是某個協議的完整錯誤包。若通過 MCP 暴露,還需要按協議區分工具執行錯誤與協議錯誤;MCP Tools 規範定義了對應機制。

錯誤反饋應指向可以修正的地方,但不能暗示所有錯誤都值得重試。時間範圍寫錯可以修改參數;服務不可用可能需要等待或報告;沒有訪問條件也不能靠反覆換參數繞過去。

“沒有匹配訂單”則是一次成功查詢的空結果,不應混同為執行失敗。這會影響 Agent 是向用户説明查無記錄,還是繼續修正一條失敗請求。

五、Tool Evaluation:把設計判斷放進完整任務裏檢驗h2

接口寫清楚以後,仍有一個不能靠閲讀説明回答的問題:Agent 實際使用時,會不會按照預期理解它?

我會先把工具實現跑通,確認查詢、參數校驗和分頁本身正確,再給 Agent 自然表達的任務。前者檢查軟件行為,後者檢查工具定義與模型之間的配合。

測試任務要有目標,不要提前把解法塞給模型h3

“調用 orders_search,再調用付款工具”更像操作指令,不能充分檢驗模型是否理解兩項能力的區別。對於這個場景,可以準備這樣的任務與檢查點:

任務可以核對的結果
查客户在指定兩週內有沒有重複扣款,列出需跟進訂單與測試數據中的有效支付、退款關係核對,既不能漏報,也不能把失敗支付算成重複扣款
同一範圍跨多頁,疑似訂單在最後一頁最終檢查覆蓋全部目標訂單,而不是隻回答第一頁
用户只提供客户姓名,存在重名客户先澄清或使用已提供的客户定位能力,不編造 customer_id
支付查詢返回服務暫時不可用説明核對受阻,不把失敗響應解釋成“沒有重複扣款”

測試數據需要預先確定。比如同一訂單的兩筆扣款中,一筆已全額退款,是否仍列為“需要跟進”,就要按任務中的業務口徑定義。否則模型和檢查器可能討論的是兩個不同問題。

檢查器也不應只接受某一句固定文案。這裏真正要核對的是訂單集合、證據和結論是否一致。先查全部訂單再逐筆取證,或先利用已有篩選縮小範圍,都可能得到正確結果,不必強制只有一條調用路徑。

調用記錄解釋哪裏出了問題h3

只看最終回答,會漏掉工具設計的問題。一條結論即使碰巧正確,過程也可能反覆查詢、漏掉分頁,或者用了不屬於目標客户的數據。

可以記錄工具名、輸入參數、返回內容、錯誤、耗時、調用次數,以及整個任務的 token 消耗。把這些記錄與預期結果對照,才能區分不同原因:

調用中的現象優先檢查的設計點
經常選擇工單搜索,而不是訂單搜索名稱、資源範圍和適用場景是否容易混淆
反覆提交姓名作為 customer_id字段含義與客户定位能力是否明確
同一頁被重複讀取游標、翻頁條件和結束信號是否清楚
每筆訂單都先查大量無關字段返回值是否遺漏關鍵證據,或工具粒度不合適
查到記錄卻無法繼續獲取支付明細前後工具需要的 ID 是否連貫

這些是排查方向,不是看到一種現象就能斷定一種原因。比如調用次數增加,可能是分頁太小,也可能是數據規模本來更大;需要結合任務和返回記錄判斷。

模型對工具的反饋可以幫助歸納問題,但它的解釋不能替代實際記錄。模型説“數據不夠”,要繼續檢查到底缺了哪個字段;説“已經查完”,則要看最後是否仍有 has_more。

圖 1 · 用任務結果與調用記錄,推動工具設計迭代
工具設計、執行與評估的閉環 準備工具原型,執行任務集,檢查結果與調用軌跡,修改工具設計,再更新原型重測。獨立任務用於複核效果。 準備工具原型接口定義與可運行實現執行任務集固定條件,記錄調用檢查結果與調用軌跡定位誤選、誤用與冗餘 修改工具設計用獨立任務複核效果 交給 Agent核對證據形成改動更新並重測 比較任務正確性,也比較完成任務所需的代價
迭代依據是任務證據,不是模型對工具的主觀評分。窄屏可在圖內左右滑動查看。

修改後重測,也要檢查是否只適應了熟悉題目h3

如果調用記錄顯示模型一直混淆客户 ID 與訂單 ID,可以先改字段名稱與説明,再保持任務、數據和模型設置一致,比較修改前後的表現。一次改動同時換模型、換數據、改接口,就很難判斷改善來自哪裏。

模型的調用行為可能波動,同樣的條件也值得重複運行。比較一組任務的完成情況、常見錯誤與調用代價,比用單次成功宣稱“設計已經改好”更有依據。

用於修改工具的任務之外,還要保留一組獨立任務:換客户、換時間表達、改變分頁數量,加入空結果與服務錯誤。它們檢驗的是設計能否遷移,而不是是否記住了一批熟悉問題。

評估也可以請 Agent 輔助分析:把失敗記錄、工具定義和預期結果放在一起,讓它歸類問題、提出修改建議,再由測試驗證。這裏的 Agent 是幫助發現和修改問題的協作者,不是工具質量的最終裁判。

我更看重的結論是:工具質量不是説明寫得像不像文檔,而是 Agent 能否藉助這份接口,穩定地完成有明確檢查標準的任務。 名稱、Schema、輸出和錯誤處理,最終都要回到這個標準上。

幾個關鍵問題,串起接口設計與質量驗證h2

參數已經符合 Schema,為什麼仍可能用錯工具?

Schema 主要約束輸入結構。客户 ID 寫成另一個存在的客户 ID,可能通過校驗,卻不符合用户目標;選中一個不相關的工具,也不會因為參數合法就變成正確選擇。需要把任務理解、工具選擇與輸入校驗分開檢查。

減少工具數量,就一定能提高完成率嗎?

不一定。合併經常一起取用的信息,可以減少關聯工作;把不相干的查詢和寫入擠進一個萬能工具,則會擴大使用歧義。應該比較任務步驟是否更清楚,而不是單純減少工具數。

返回值越短,是否代表工具越高效?

不是。少了關鍵 ID、分頁信號或付款證據,模型可能需要更多調用,甚至得出錯誤結論。高效應當按整個任務衡量:在結果可靠的前提下,減少無關信息和可避免的往返。

為什麼評估不能只檢查最終回答?

最終回答説明結果是否正確,調用記錄則解釋工具怎樣被使用。漏掉最後一頁卻碰巧得出正確結論,與完整核對後的正確結論,不是同樣可靠的使用過程。兩者一起看,才容易定位接口問題。

怎樣區分工具改好了,還是隻適應了測試題?

保留沒有用於修改設計的獨立任務,並維持可比較的運行條件。改進若只發生在熟悉任務上,遇到換名、跨頁或錯誤場景就失效,還不足以説明工具具有更好的通用可用性。

這一篇關注的是接口質量:讓一個能力的用途、輸入和反饋都清楚。工具庫擴大後,怎樣按需發現工具、組織頻繁調用和處理大量中間結果,是另一層機制問題;它不能替代這裏的設計,也不只是把工具數量繼續往上加。

參考資料h2