什麼是工具使用?
您現有的工作流程依賴許多不同的技術——專案管理軟體、資料庫、檔案。Claude 無法自行檢查這些東西。相反地,它依賴工具,這些工具讓 Claude 能夠存取外部資料和執行動作。
什麼是工具
簡單來說,工具是您定義並公開給 Claude 的函式。您描述它的功能以及它接受的輸入,而 Claude 決定何時呼叫它。
這裡有個關鍵要內化的概念:Claude 不會執行工具——您的程式碼才會執行。流程如下:
- Claude 請求呼叫工具。
- 您的程式碼執行該函式。
- 結果回傳給 Claude,然後它繼續進行。
工具如何定義
工具是JSON 結構(schema),包含三個部分:名稱、描述和輸入結構。您在請求主體中以 tools 陣列的形式將它們傳遞給 Claude。
描述是 Claude 用來決定是否呼叫該工具的依據。如果您寫的描述含糊不清,就會得到不佳的工具使用結果。這是代理程式(agent)誤判或無法抓取可用工具的首要原因。請具體明確。
以下是工具定義的樣子:
{
"name": "lookup_building_code",
"description": "Look up a specific building code section by its identifier. Returns the full text of that code section.",
"input_schema": {
"type": "object",
"properties": {
"section": {
"type": "string",
"description": "The building code section to look up"
}
},
"required": ["section"]
}
}那麼當我們使用這個工具時會發生什麼事呢?假設我們向代理程式發送一份合規報告。在第一輪,Claude 會回傳 stop_reason: "tool_use"——這就是我們的信號。以下是該回應的樣子:

我們的迴圈會以 Claude 請求的參數呼叫 lookup_building_code,然後將結果作為工具結果回傳——這是一則使用者訊息,包含一個與工具呼叫 id 綁定的 tool_result 區塊:

然後 Claude 會繼續進行。此時,我們可以持續呼叫工具並將結果回傳給 Claude,直到它獲得所需的資訊為止。
多個工具:讓 Claude 自行選擇
一個工具很有用,但有趣的部分在於給 Claude 多個工具,並觀察它選擇使用哪一個、以什麼順序使用。
想像這個情境:您正在為前往丹佛(Denver)的三天旅行打包行李,您想知道今天的天氣以及接下來幾天的預報。因此我們宣告兩個工具,而不是一個:
const tools = [
{
name: "get_weather",
description: "Get today's current weather for a city.",
input_schema: {
type: "object",
properties: {
city: { type: "string", description: "The city to check" }
},
required: ["city"]
}
},
{
name: "get_forecast",
description: "Get the weather forecast for the next few days for a city.",
input_schema: {
type: "object",
properties: {
city: { type: "string", description: "The city to check" }
},
required: ["city"]
}
}
];這個迴圈與我們之前看過的代理程式迴圈完全相同。唯一新增的部分是一個 runTool 函式,它使用 switch 陳述式根據工具名稱進行分派——這段程式碼正是您的程式碼實際執行的地方:
function runTool(name, input) {
switch (name) {
case "get_weather":
return getWeather(input.city);
case "get_forecast":
return getForecast(input.city);
}
}
while (true) {
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages,
tools,
});
if (response.stop_reason !== "tool_use") {
// Claude 已完成——這是最終答案
break;
}
messages.push({ role: "assistant", content: response.content });
const toolResults = response.content
.filter((block) => block.type === "tool_use")
.map((block) => ({
type: "tool_result",
tool_use_id: block.id,
content: runTool(block.name, block.input),
}));
messages.push({ role: "user", content: toolResults });
}這就是整個模式。想要第三個工具?把它加入陣列,在 switch 中加入一個 case,就完成了。
執行這段程式碼,您會看到 Claude 呼叫 get_weather,然後呼叫 get_forecast——有時在同一輪,有時一個接著一個。然後它會回答:打包分層衣物,今天預期會有小雪,整週會逐漸回暖。
現在請注意 Claude 如何 做出選擇。它讀取了描述,將您的提示對應到「今天的天氣」和「接下來幾天」,並為每個情況選擇了正確的工具。這就是為什麼您的工具描述真的很重要。
工具執行器:跳過樣板程式碼
您可能已經發現我們剛寫的程式碼有兩個警訊:
- 對於兩個簡單的查詢來說,這是大量的程式碼。
- 在實際的程式碼庫中,您不會想為每個函式手寫 JSON 結構。這就像把您的程式碼寫兩次一樣。
這就是工具執行器(tool runner)發揮作用的地方。它以 beta 版形式內建於 Claude SDK 中:TypeScript、Python、Ruby、C#、Go、Java 和 PHP。您只需定義每個工具一次,執行器會在內部處理整個工具使用/工具結果的迴圈。
在 TypeScript 中,執行器推薦使用的輔助函式 betaZodTool(),以 Zod(一個用於宣告和驗證資料形狀的 TypeScript 函式庫)撰寫的簡短結構來描述每個工具。這個輔助函式需要 Zod 3.25.0 或更新版本,全新安裝即可取得:
npm install zod您的程式碼會縮減為:描述工具、傳送提示、等待結果。以下是透過工具執行器連接的相同雙工具天氣示範:
import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
import { z } from "zod";
// 將我們手動執行的相同兩個查詢包裝起來,各搭配一個簡短的 Zod schema
const weatherTool = betaZodTool({
name: "get_weather",
description: "Get today's current weather for a city.",
inputSchema: z.object({
city: z.string().describe("The city to check"),
}),
run: async ({ city }) => getWeather(city),
});
const forecastTool = betaZodTool({
name: "get_forecast",
description: "Get the weather forecast for the next few days for a city.",
inputSchema: z.object({
city: z.string().describe("The city to check"),
}),
run: async ({ city }) => getForecast(city),
});
const runner = client.beta.messages.toolRunner({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [
{
role: "user",
content:
"I'm packing for a three-day trip to Denver. What's the weather today and over the next few days?",
},
],
tools: [weatherTool, forecastTool],
});
// 等待 runner 執行完畢,在所有工具來回呼叫都結束後取得最終訊息
const finalMessage = await runner;相同的情境,程式碼卻少了許多:
- 沒有 while 迴圈,沒有 stop reason 的 switch 判斷,也不需要手動將工具結果推回訊息中——執行器會處理所有這些事情。
- 沒有手寫的 JSON 結構,每個工具只需一個簡短的 Zod 結構,它同時也會驗證 Claude 傳送的輸入。
- 每個
run函式都包裝了我們剛才手動執行的相同查詢。 - 等待執行器(awaiting the runner)會在一切都完成後回傳最終的助理訊息。
執行它,您會得到相同的答案。
真正的工具會包裝您現有的程式碼
在實際情況中,您的工具不會是硬編碼的天氣資料。它們會包裝您應用程式中已經存在的實際函式。
以合規審查代理程式為例:它的工具是圍繞著程式碼庫中已存在的 lookup_building_code 和 search_building_code 函式的薄包裝層。使用工具執行器,您將這些函式各自包裝在一個帶有自己 Zod 結構的簡短工具定義中,代理程式就會在它撰寫的每個發現中引用具體的法規條文:

回顧
- 工具讓 Claude 能夠存取您的系統。工具是您定義並公開的函式;Claude 決定何時呼叫它,而您的程式碼負責執行它。
- 工具是 JSON 結構,包含名稱、描述和輸入結構,以
tools陣列的形式在請求中傳遞。 - 撰寫具體的描述。含糊的描述是代理程式誤判的首要原因。
stop_reason: "tool_use"是您執行工具並將結果作為工具結果回傳的信號。- 對於多個工具,根據工具名稱進行分派。新增工具意味著在陣列中新增項目,並新增一個 case。
- SDK 的工具執行器(在各個 Claude SDK 中以 beta 版提供)會處理整個迴圈,在 TypeScript 中,每個工具都是帶有 Zod 結構的簡短定義。或者您也可以自行執行這個迴圈。
- 您可以自行執行,也可以委派這個迴圈。在這個範圍的另一端,受管理的代理程式(managed agents)會將整個代理程式委派給 Anthropic。