工具設計的藝術

ACI:Agent-Computer Interface

HCI (人-機互動) 領域已經研究了幾十年,但 Agent 和計算機之間的互動(ACI)才剛剛開始。實戰經驗表明:工具設計的品質,直接決定了 Agent 的能力上限。

核心概念:工具是 Agent 和世界之間的契約

傳統軟體開發中,我們花大量精力設計使用者介面(HCI):按鈕放在哪裡、文案怎麼寫、互動怎麼回饋。但當 Agent 成為系統的使用者時,介面變成了工具定義。工具的名字、參數、描述,就是 Agent 的使用者介面。

HCI 人 → 系統

人類透過按鈕、表單、選單與系統互動。UI 設計的好壞直接影響使用者體驗。
使用者點選「查天氣」按鈕 → 系統呼叫 getWeather("NYC") → 返回結果給使用者
確定性:相同操作 → 相同結果

ACI Agent → 系統

Agent 透過工具定義(名稱、參數、描述)與系統互動。工具設計的好壞直接影響 Agent 表現。
使用者說:「要不要帶傘?」 → Agent 思考:需要呼叫天氣工具嗎? → 先問使用者在哪個城市? → 呼叫 get_weather(city="上海") → 綜合判斷後回答
非確定性:相同問題 → 不同呼叫路徑
"Plan to invest as much effort into your Agent-Computer Interface (ACI) as you would into a Human-Computer Interface (HCI)."
工具和傳統 API 的根本區別
使用者說「要不要帶傘」時,Agent 的決策過程
1
使用者在哪?
如果對話歷史中沒提到位置,Agent 可能先問「你在哪個城市?」,再決定是否呼叫工具。
2
需要呼叫天氣工具嗎?
如果上一輪剛查過天氣,Agent 可能直接用快取結果回答,跳過工具呼叫。
3
呼叫哪個工具?
是調 get_weather 還是 get_forecast?當前天氣 vs 未來預報,工具名和描述決定了 Agent 的選擇。
4
參數怎麼填?
city 參數應該填「Shanghai」還是「上海」?格式不清晰時 Agent 經常出錯。
傳統 API 是確定性的:開發者寫 getWeather("NYC"),每次執行路徑完全一樣。Agent 工具是非確定性的:模型需要理解什麼時候用、怎麼用,這完全取決於工具的設計品質。
工具設計四原則
PRINCIPLE 01

給模型足夠的 Token 空間想清楚

模型產生參數是一個 Token 接著一個 Token 寫出來的,一旦開始寫就很難回頭改。工具設計應該讓模型在寫複雜參數前,先寫簡單的方向性參數。
反例:第一個參數就要求寫 500 行程式碼補丁
正例:先寫 file_path、再寫 change_type、最後寫 content
PRINCIPLE 02

格式貼近模型的訓練資料

模型在訓練時見過大量自然語言和常見程式碼格式。工具參數格式越接近這些熟悉的模式,模型越不容易出錯。
反例:用自訂 DSL 描述檔案變更
正例:用標準 unified diff 格式,模型在訓練資料中見過無數次
PRINCIPLE 03

避免不必要的格式開銷

不要讓模型做數行數、JSON 轉義這類機械操作。模型不擅長精確計數,強迫它做只會增加出錯機率。
反例:要求 {"start_line": 15, "end_line": 23} 精確行號
正例:用唯一的上下文字串匹配目標位置
PRINCIPLE 04

Poka-yoke(防呆設計)

源自豐田生產系統的理念:透過改變設計,讓錯誤更難發生。與其期望模型不犯錯,不如讓工具本身就不容易用錯。
反例:參數接受相對路徑(模型經常搞錯當前目錄)
正例:只接受絕對路徑,從源頭消除歧義
真實案例:SWE-bench 中的一個改動

檔案路徑:相對路徑 vs 絕對路徑

BEFORE -- 相對路徑
{ "tool": "edit_file", "path": "src/utils/helper.py", "content": "..." }
Agent 頻繁搞錯當前工作目錄,導致編輯錯誤檔案或檔案找不到
AFTER -- 絕對路徑
{ "tool": "edit_file", "path": "/repo/src/utils/helper.py", "content": "..." }
消除路徑歧義,工具呼叫從頻繁出錯變成幾乎完美
這個改動的程式碼量極小:只是把參數從接受相對路徑改為要求絕對路徑。但效果巨大:一個參數設計的改變,讓整個 Agent 的可靠性大幅提升。這就是 Poka-yoke 的力量。
工具描述的學問

業界最佳實踐建議:像給一個聰明但沒有上下文的初級開發者寫文件一樣寫工具描述。這個開發者什麼都不知道,但理解力很強,你需要告訴他所有前提條件。

好的工具描述應該包含

示例用法:具體的輸入輸出樣例,讓模型一看就會
邊界情況說明:輸入是空的該怎麼處理?找不到結果要回傳什麼?
輸入格式要求:日期用 ISO 8601 還是時間戳?路徑用絕對還是相對?
和其他工具的區別:「用 search_code 搜程式碼,用 search_files 搜檔名,不要搞混」
何時不該用這個工具:「如果只需要檢查檔案是否存在,用 file_exists;read_file 留給需要讀取內容的場景」

工具描述對比

差的工具描述
{ "name": "search", "description": "Search for things" }
模型不知道搜什麼(程式碼?檔案?網頁?),參數格式不清楚,和其他搜尋工具分不清
好的工具描述
{ "name": "search_code", "description": "Search for code patterns across the repository using regex. Returns matching file paths and line numbers. Use search_files for filename matching instead. Example: search_code({ pattern: 'def process_', file_glob: '*.py' })" }
名字精確、描述清晰、有示例、有和其他工具的邊界說明
工具設計的投入應該和 Prompt 設計一樣多。工具名稱、參數結構、描述文案,都是 Agent 的使用者介面。一個參數的改動可能讓 Agent 從不可用變得可靠,正如 SWE-bench 中的絕對路徑案例所示。