Claude Tool Use 工具调用怎么用?完整代码实战
Claude Tool Use(工具调用,也叫函数调用)的用法是:你在请求里用 JSON Schema 描述若干工具,模型判断该不该调用、生成结构化参数(tool_use 块),你的代码执行真实函数后,把结果作为 tool_result 回传,模型再据此给出最终回答。整个流程都走标准的 Messages API(POST /v1/messages),不需要额外接口。下面用官方 SDK 把这条链路跑通。
一、工具调用的核心机制
很多人误以为 Claude 会"自己去执行"函数。事实并非如此:模型只负责决策和生成参数,真正的执行始终在你的代码里。一次完整的工具调用是这样一个循环:
- 你发请求,
tools字段里带上工具定义; - 模型返回
stop_reason: "tool_use",并在content里给出tool_use块(含工具名、唯一id和参数input); - 你执行对应函数,把结果包成
tool_result块(用同一个tool_use_id关联),作为一条user消息回传; - 模型读取结果,继续推理,直到
stop_reason变为end_turn输出最终答案。
如果你还不熟悉 Messages API 的基本调用,建议先看 Claude API 怎么调用?从注册到第一次请求完整教程 和 Claude Messages API 全部参数说明(含代码示例)。
二、定义一个工具
工具定义包含三部分:name(工具名)、description(描述,模型靠它判断何时调用)、input_schema(参数的 JSON Schema)。描述要写清楚"什么时候该用",而不只是"它做什么"——这对新版 Opus 模型尤其重要,触发条件写明确能显著提升调用准确率。
{
"name": "get_weather",
"description": "查询指定城市的当前天气。当用户询问天气、温度、是否下雨时调用此工具。",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名,例如 北京、上海"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位"}
},
"required": ["city"]
}
}
三、Python 完整实战(anthropic 官方 SDK)
先安装 SDK:pip install anthropic,并把密钥放进环境变量 ANTHROPIC_API_KEY。下面是一个手写循环的完整示例,主力模型用 Claude Opus 4.8(claude-opus-4-8),你也可以按需换成 Sonnet 4.6 或 Haiku 4.5。
from anthropic import Anthropic
client = Anthropic()
tools = [{
"name": "get_weather",
"description": "查询指定城市的当前天气。当用户询问天气、温度时调用。",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string", "description": "城市名"}},
"required": ["city"],
},
}]
def get_weather(city: str) -> str:
# 真实场景下这里调用气象 API;此处用假数据演示
return f"{city} 当前晴,气温 26°C"
messages = [{"role": "user", "content": "北京今天天气怎么样?"}]
while True:
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
tools=tools,
messages=messages,
)
# 把模型这一轮的完整 content 追加进历史(必须保留 tool_use 块)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason != "tool_use":
# 没有再请求工具,输出最终文本
print("".join(b.text for b in resp.content if b.type == "text"))
break
# 处理本轮所有 tool_use 块,结果统一放进一条 user 消息
tool_results = []
for block in resp.content:
if block.type == "tool_use":
result = get_weather(**block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result,
})
messages.append({"role": "user", "content": tool_results})
三个关键点:第一,每一轮都要把 resp.content 原样追加回 messages,否则会丢掉 tool_use 块导致下一轮报错;第二,tool_result 的 tool_use_id 必须和对应 tool_use 的 id 一致;第三,模型一轮可能请求多个工具(并行调用),要全部执行完再回传。关于多轮上下文的拼接细节,可参考 Claude API 多轮对话怎么实现?上下文管理详解。
四、Node.js 实战(@anthropic-ai/sdk)
安装:npm install @anthropic-ai/sdk。逻辑与 Python 完全一致,注意用 JSON.parse 风格处理参数(SDK 已帮你解析为对象,不要对序列化字符串做字符串匹配)。
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const tools = [{
name: "get_weather",
description: "查询指定城市的当前天气。当用户询问天气时调用。",
input_schema: {
type: "object",
properties: { city: { type: "string", description: "城市名" } },
required: ["city"],
},
}];
function getWeather(city) {
return `${city} 当前晴,气温 26°C`;
}
let messages = [{ role: "user", content: "上海现在多少度?" }];
while (true) {
const resp = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 1024,
tools,
messages,
});
messages.push({ role: "assistant", content: resp.content });
if (resp.stop_reason !== "tool_use") {
console.log(resp.content.filter(b => b.type === "text").map(b => b.text).join(""));
break;
}
const toolResults = [];
for (const block of resp.content) {
if (block.type === "tool_use") {
const result = getWeather(block.input.city);
toolResults.push({ type: "tool_result", tool_use_id: block.id, content: result });
}
}
messages.push({ role: "user", content: toolResults });
}
更多 Node 调用细节(含流式)见 Claude API Node.js 调用示例:从安装到流式输出。
五、tool_choice:控制模型何时调用
默认情况下模型自行决定是否用工具。你可以用 tool_choice 强制控制:
| 取值 | 行为 |
|---|---|
{"type": "auto"} | 模型自行决定(默认) |
{"type": "any"} | 必须调用至少一个工具 |
{"type": "tool", "name": "get_weather"} | 必须调用指定工具 |
{"type": "none"} | 禁止调用工具 |
如果想限制模型一次只调用一个工具,可在 tool_choice 里加 "disable_parallel_tool_use": true。需要做分类、抽取这类"必须产出结构化结果"的任务时,{"type": "any"} 配合一个带 enum 的工具非常好用。
六、错误处理与避坑
- 工具执行失败:在
tool_result里加"is_error": true并写明错误信息,模型会据此换方案或追问,而不是直接崩。 - 别截断历史:丢失
tool_use块会导致 400 错误(消息结构不合法)。 - 参数一律 JSON 解析:当前模型在
input的转义上可能不同,永远用json.loads/JSON.parse而非裸字符串匹配。 - 遇到 401/429:认证或限流问题分别参考 Claude API 报错 401 怎么解决?认证失败排查指南 与 Claude API 429 限流报错怎么办?3 种重试方案。
当输出较长或 max_tokens 较大时建议开启流式输出,避免请求超时,具体见 Claude API 流式输出 Python 实现教程(SSE 详解)。如果你的工具最终是为了让模型调用你自己的服务端接口,Claude 函数调用示例:让模型调用你的 API 有更贴近业务的完整案例。Tool Use 也是 MCP(模型上下文协议)的底层基础,想进一步了解可看 MCP 是什么?一篇讲清 Claude 模型上下文协议。
常见问题
Tool Use 会额外收费吗?
工具调用本身不是独立计费项,但工具定义、模型生成的 tool_use 块、你回传的 tool_result 都会算进输入/输出 token。也就是说一次工具调用通常意味着多轮往返,token 消耗会比单次问答高。具体价格以 Anthropic 官网为准,省钱思路可参考 Claude API 怎么省钱?5 个降低 Token 成本的方法。
所有 Claude 模型都支持工具调用吗?
当前主力模型 Claude Opus 4.8、Sonnet 4.6、Haiku 4.5 均支持 Tool Use。复杂的多步代理任务推荐用 Opus 4.8,对延迟和成本敏感的场景可选 Haiku 4.5。选型对比见 Claude 模型怎么选?Opus / Sonnet / Haiku 选型指南。
一次能定义多少个工具?模型会用错吗?
单次请求可以定义多个工具,但工具过多会增加模型选错的概率。建议保持工具集聚焦、命名具体(如 get_user_orders 优于 orders),并在 description 里写清触发条件。工具数量很大时,可以考虑工具搜索(tool search)机制按需加载,避免把所有 schema 一次性塞进上下文。