Appearance
怎麼寫工具描述,讓 AI 不會亂用工具?
先理解問題
你做了一個 AI 助手,給它 10 個工具。AI 要讀檔案時,它應該用你的 Read 工具,而不是跑一個 cat file.txt 的 shell 命令。但 AI 在訓練過程中看過幾百萬次 cat,它的直覺就是用 cat。
工具描述(Tool Description) 就是你給 AI 的「工具說明書」。寫得好,AI 選對工具、用對參數;寫得差,AI 亂選工具、浪費 token、甚至做出危險操作。
Claude Code 有 40 多個工具,每個都有精心撰寫的描述。讓我們看看它們用了哪些寫法,以及為什麼有效。
寫法一:「假設你可以,放心嘗試」
FileReadTool(讀檔案工具)的描述開頭:
Reads a file from the local filesystem.
You can access any file directly by using this tool.
Assume this tool is able to read all files on the machine.
If the User provides a path to a file assume that path is valid.
It is okay to read a file that does not exist; an error will be returned.翻譯:
- 「你可以直接讀任何檔案」
- 「假設這個工具能讀所有檔案」
- 「如果使用者給了一個路徑,就假設它是有效的」
- 「讀一個不存在的檔案沒關係,會返回錯誤」
為什麼要寫「假設你可以」?
因為 AI 天生「謹慎過度」。如果你不明確鼓勵它嘗試,它可能會先問:「你確定這個檔案存在嗎?」或「我不確定我有權限讀這個目錄。」
這種多餘的確認浪費了使用者的時間和 token。與其讓 AI 猶豫不決,不如告訴它:「放心讀,讀不到就報錯,報錯也沒關係。」
「失敗也沒關係」的哲學
最後一句「It is okay to read a file that does not exist」特別重要。它建立了一個行為模式:嘗試 → 失敗 → 報錯 → 調整,而不是先驗證 → 確認存在 → 才嘗試。
前者通常只需要 1 次工具呼叫(讀了報錯),後者可能需要 3 次(先 ls 看看存不存在 → 再確認路徑 → 才讀)。
實戰思考
想想你自己的工具。使用者說「讀 config.yaml」,你的 AI 是直接嘗試讀取,還是先問「你確定有這個檔案嗎?」如果是後者,試試在工具描述中加入「放心嘗試」的語言。
寫法二:「逐一列舉,不要用抽象描述」
FileReadTool 的描述接著列舉它支援的所有格式:
- This tool allows Claude Code to read images (eg PNG, JPG, etc).
- This tool can read PDF files (.pdf). For large PDFs (more than
10 pages), you MUST provide the pages parameter. Maximum 20 pages.
- This tool can read Jupyter notebooks (.ipynb files).
- This tool can only read files, not directories. To read a directory,
use an ls command via the Bash tool.為什麼不寫「支援多種格式」?
因為如果你只寫「支援多種格式」,AI 不知道 PDF 是不是「多種格式」之一。它可能不會嘗試用 Read 讀 PDF,而是用 Bash 跑 pdftotext——一個更慢、更不可靠的方法。
具體列舉消除了 AI 的猜測。它清楚知道:PNG 可以、PDF 可以(但大檔案要分頁)、ipynb 可以、目錄不行(用別的工具)。
最後一條:「不能做什麼」+「改用什麼」
This tool can only read files, not directories.
To read a directory, use an ls command via the Bash tool.這不只是說「不能讀目錄」——它還告訴 AI 遇到目錄時該怎麼辦。這防止 AI 卡住(「我不能讀目錄,但使用者要我看目錄下有什麼,我該怎麼辦?」)。
實戰思考
把你的工具描述中所有「不能做 X」的地方檢查一遍。有沒有告訴 AI「不能做 X 時,應該改用 Y」?如果沒有,AI 遇到這些情況可能會卡住或做出意想不到的行為。
寫法三:「搶佔式禁止」——對抗 AI 的訓練慣性
GrepTool(搜尋工具)的描述:
ALWAYS use Grep for search tasks.
NEVER invoke `grep` or `rg` as a Bash command.
The Grep tool has been optimized for correct permissions and access.為什麼要用全大寫的 ALWAYS 和 NEVER?
因為 AI 在訓練資料中看過太多用命令列 grep 的範例了。它有一種「肌肉記憶」想要在 Bash 中打 grep pattern file。
一般強度的指令——比如「建議使用 Grep 工具」——可能會被這個「肌肉記憶」壓過。全大寫的 ALWAYS/NEVER 相當於提高了這條指令的「音量」,讓它能蓋過訓練資料的慣性。
給理由,不只是給規定
注意最後一句:「The Grep tool has been optimized for correct permissions and access.」(Grep 工具已經被最佳化為具有正確的權限和存取方式。)
這給了 AI 一個它能理解的理由。
心理學上有一個著名的實驗叫做「影印機實驗」(Ellen Langer, 1978)。在排隊影印的隊伍中,光說「我可以先印嗎?」只有 60% 的人會讓步。但如果加一句理由——「我可以先印嗎,因為我趕時間」——成功率跳升到 94%。甚至連無意義的理由——「我可以先印嗎,因為我需要影印東西」——也有 93% 的成功率。
有理由,不管理由好不好,遵循率都會大幅提升。
AI 也展現類似的行為:「不要用命令列的 grep」的遵循率低於「不要用命令列的 grep,因為我們的 Grep 工具有正確的權限管理」。加了理由後,AI 更傾向遵從指令,即使理由本身很簡單。
實戰思考
盤點你的 AI 應用中「AI 老是做錯的行為」。這些行為很可能是被訓練資料的慣性驅動的。試試「ALWAYS/NEVER + 理由」的組合。比如:
- 「ALWAYS use our
searchProducts()API. NEVER construct SQL queries directly. Our API handles pagination, caching, and access control automatically.」
寫法四:「告訴 AI 什麼會失敗,以及怎麼修」
FileEditTool(檔案編輯工具)的描述:
The edit will FAIL if `old_string` is not unique in the file.
Either provide a larger string with more surrounding context
to make it unique or use `replace_all` to change every instance.「失敗預防」比「使用說明」更有用
大多數工具描述只寫「怎麼用」。但 Claude Code 的做法是同時寫「什麼會導致失敗」和「怎麼從失敗中恢復」。
對比兩種寫法:
- ❌ 「old_string 必須在檔案中是唯一的」——只說了規則
- ✅ 「如果 old_string 不唯一,編輯會失敗。可以加更多上下文讓它唯一,或用 replace_all」——說了規則 + 失敗後怎麼辦
想像你教新員工用一台影印機。你可以有兩種教法:
教法 A(只教規則):「紙張必須放正,不能歪。」——新員工放歪了,影印機卡紙。他不知道怎麼辦,找你來幫忙。
教法 B(教規則 + 教失敗恢復):「紙張必須放正。如果卡紙了,打開側面板,慢慢把紙抽出來,不要用力拉。」——新員工放歪了,卡紙了,但他自己就能解決。
第二種教法讓 AI 在第一次失敗後知道怎麼自救,而不是重複犯同樣的錯誤或卡住不動。在 AI Agent 的場景中,「自救能力」特別重要——因為 AI 是自主執行的,如果它遇到問題只會「放棄」或「重試同樣的錯誤操作」,使用者體驗會非常差。
具體數字的力量
給 Anthropic 內部員工的版本還多了一句:
Use the smallest old_string that's clearly unique —
usually 2-4 adjacent lines is sufficient.
Avoid including 10+ lines of context when less uniquely identifies the target.「2-4 行」和「10+ 行」是具體的數字。AI 之前的行為是為了「確保唯一」而包含大量的上下文——有時候放了 20 行——浪費了大量 token。具體數字把 AI 的行為錨定在合理範圍內。
實戰思考
回顧你的工具出過的錯誤。每個錯誤都問自己:「如果工具描述中提前說了『這種情況會失敗,遇到時應該這樣做』,AI 能自己修復嗎?」把答案寫進工具描述。
寫法五:「元提示詞」——教 AI 怎麼寫提示詞
AgentTool(代理工具)是最特別的一個,因為它是一個「啟動新 AI 的工具」。所以它的描述需要教 Claude 怎麼給新 AI 寫提示詞——這是「提示詞的提示詞」。
Brief the agent like a smart colleague who just walked into the room —
it hasn't seen this conversation, doesn't know what you've tried,
doesn't understand why this task matters.翻譯:「把代理當成一個剛走進房間的聰明同事——它沒有看過這次對話、不知道你嘗試過什麼、不理解這個任務為什麼重要。」
為什麼用「同事」這個比喻?
因為 AI 理解這個比喻。它立刻知道要提供什麼層次的上下文——不是寫一本使用手冊,而是像跟同事交接工作一樣,把關鍵背景和目前進度交代清楚。
反面範例的力量
Never delegate understanding. Don't write "based on your findings,
fix the bug" or "based on the research, implement it."
Those phrases push synthesis onto the agent instead of doing it yourself.翻譯:「不要把『理解』的工作推給代理。不要寫『根據你的發現,修復這個 bug』。這種寫法是把思考的工作甩鍋給代理。」
為什麼給反面範例? 因為說「寫好一點」太模糊了。但如果你說「不要寫『根據你的發現』這種話」,AI 就能精確地避免這個錯誤模式。
兩個字的行為規範
Don't peek. (不要偷看。)
Don't race. (不要搶跑。)兩個字概括了兩條複雜的規則:
- Don't peek:代理在背景運行時,不要去讀它的輸出檔案。等它完成再看。
- Don't race:代理還沒完成時,不要猜測或編造它的結果。
為什麼兩個字比一段話有效? 因為它們像口號——好記、好執行。AI 在決策時可以快速匹配到「這算不算 peek?」「這算不算 race?」
實戰思考
如果你的 AI 應用有「多步驟」或「多代理」的功能,想想你的代理之間怎麼交接。寫一套像「Don't peek / Don't race」這樣簡短有力的規則,然後附上具體的反面範例。
寫法六:把動態內容移出工具描述
AgentTool 的描述中有一個快取最佳化的技巧:
代理列表(「有哪些代理可以用」)原本寫在工具描述裡:
Available agent types:
- general-purpose: 通用代理...
- Explore: 快速探索程式碼...
- Plan: 架構規劃...但問題是:每當 MCP 伺服器連線/斷線,代理列表就會改變。工具描述改了,整個工具 schema 的快取就失效了。
原始碼的註解記錄了影響:
typescript
// 動態 agent 列表佔了整個 fleet cache_creation tokens 的 ~10.2%10.2% 的快取建立 token!在每天處理數十億 token 的規模下,這是巨大的浪費。
解法:把代理列表移到「附件訊息」中,工具描述改成靜態的一句話:
Available agent types are listed in <system-reminder> messages.這樣工具描述永遠不變,快取永遠命中。
實戰思考
檢查你的工具描述中有沒有「會隨時改變的內容」。比如「可用的模型列表」、「支援的語言」、「連線中的服務」。把它們移到系統訊息或附件中,讓工具描述保持靜態。
寫法七:「兩層描述」——短描述選工具,長描述教用法
每個工具有兩個文字介面:
- 短描述(description):一句話,出現在工具列表中
- 長描述(prompt):完整使用指南
例如 FileReadTool:
- 短描述 =
"Read a file from the local filesystem." - 長描述 = 50 行的完整使用指南
為什麼分兩層? 因為 API 的 tools 參數會包含所有工具的 schema(包含 description)。如果 40 個工具每個都有 50 行描述,光是工具 schema 就要幾千個 token。短描述讓 AI 快速判斷「要不要用這個工具」,長描述在 AI 決定使用後才需要。
7 種寫法的決策流程圖
當你要為一個新工具寫描述時,可以用這個流程圖來決定使用哪些寫法:
整體回顧:7 種寫法的速查表
| 寫法 | 適用場景 | 範例 |
|---|---|---|
| 假設你可以 | AI 太謹慎、老是先確認 | 「Assume this tool can read all files」 |
| 逐一列舉 | 支援多種格式/模式 | 「PNG ✓、PDF ✓(限 20 頁)、目錄 ✗」 |
| 搶佔式禁止 | AI 有訓練慣性用舊方法 | 「ALWAYS use Grep. NEVER use grep in Bash.」 |
| 失敗預防 | 工具有常見的失敗模式 | 「will FAIL if not unique → 加更多上下文」 |
| 元提示詞 | 多代理/多步驟系統 | 「Brief like a colleague who just walked in」 |
| 動態內容外移 | 描述中有會變的部分 | 把代理列表移到附件訊息 |
| 兩層描述 | 工具數量多 | 短描述選工具,長描述教用法 |