开始之前
请先学完第 1 课:这一课沿用了它的客户端、密钥和遍历内容块的循环。工具调用走的是同一个 Messages 接口,只是请求里多了一个 tools 列表。
工具调用总览把工具分成两类,但模型自己都不运行。客户端工具,也就是你定义的那些,由你的代码运行函数并回报结果。网页搜索、网页抓取和代码执行这类服务端工具,则在 Anthropic 那边运行,所以响应到达时,结果可能已经在里面了。这一课讲的是客户端工具。
跑通 tool_use 与 tool_result 往返
一次请求,一个工具,两次调用。下面的代码定义了 get_weather,提出一个需要它的问题,并处理一次往返。第 4 课会把同样的步骤包进循环里。天气函数是为本课写的占位实现,请换成真正的查询。
第二次请求能否被接受,取决于两条规则。带结果的用户消息必须紧跟在含有 tool_use 块的助手消息之后,而且 tool_result 块必须排在它内容的最前面,位于任何文字之前。违反任何一条,API 都会返回 400。
import json
import anthropic
client = anthropic.Anthropic()
tools = [
{
"name": "get_weather",
"description": (
"Get the current weather for a city. Use it when the user asks about "
"weather, temperature or whether to bring an umbrella. It returns the "
"temperature in Celsius and a short condition. It does not forecast."
),
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "A city name, for example Lisbon"},
},
"required": ["city"],
},
}
]
def get_weather(city: str) -> str:
# Stand-in for a real weather API call.
return json.dumps({"city": city, "temp_c": 18, "condition": "light rain"})
messages = [{"role": "user", "content": "Do I need an umbrella in Lisbon today?"}]
response = client.messages.create(
model="claude-opus-5-5", max_tokens=1024, tools=tools, messages=messages
)
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
results = []
for block in response.content:
if block.type == "tool_use":
results.append(
{
"type": "tool_result",
"tool_use_id": block.id,
"content": get_weather(**block.input),
}
)
messages.append({"role": "user", "content": results})
response = client.messages.create(
model="claude-opus-5-5", max_tokens=1024, tools=tools, messages=messages
)
for block in response.content:
if block.type == "text":
print(block.text)- 用
name、description和input_schema定义工具,再把列表作为tools传入。 - 发送用户消息。Claude 回复的
stop_reason是tool_use,并带有一个或多个tool_use块,每个块有id、name和input。 - 把
response.content完整、不加修改地追加到历史里,作为助手消息。使用工具时,文档要求每个 thinking 块都原样传回。 - 对每个
tool_use块运行你的函数,并构造一个tool_result块,其tool_use_id与它的 id 相同。 - 把所有结果放进一条用户消息里,再调用一次 API。这时 Claude 会写出最终回答。
写出 Claude 能用好的工具定义
描述决定了大部分效果。文档把它称作影响工具表现的最重要因素,要求至少写三四句话:这个工具做什么、什么时候用、每个参数是什么意思,以及它返回什么。
少而宽的工具,比多而窄的工具效果更好,所以把相关操作合并成一个带 action 参数的工具。几个工具并排时,名称按服务加前缀,比如 github_list_prs。函数只返回信息量高的数据,因为它返回的一切,都会变成下一次调用的输入 token。
| 字段 | 是否必需 | 要知道的事 |
|---|---|---|
name | 是 | 必须匹配 ^[a-zA-Z0-9_-]{1,128}$ |
description | 强烈建议 | 纯文本,至少三四句话 |
input_schema | 是 | 带 properties 和 required 的 JSON Schema 对象 |
input_examples | 否 | 示例输入,必须能通过 schema 校验,简单工具每个约 20 到 50 个 token,嵌套结构约 100 到 200 个 |
strict | 否 | 设为 true,让 Claude 的输入符合 schema |
cache_control | 否 | 放在工具列表上的缓存断点,第 3 课会讲 |
用 tool_choice 引导调用
默认情况下,Claude 自己判断请求需不需要工具。tool_choice 可以改写这一点,在当前的模型上,它的四个取值表现各不相同。从发布说明可以看到,九月以来,强制调用的取值被一个模型接一个模型地关掉了。
并行调用也由同一个字段控制。在 auto 下,把 disable_parallel_tool_use 设为 true,就把 Claude 限制在每个回合最多调用一次工具。
工具调用结束 beta
在 Claude API、Bedrock 和 Vertex AI 上都不再需要 beta 请求头。
新增
disable_parallel_tool_use写在
tool_choice里,让 Claude 每个回合最多调用一个工具。tool_choice新增none可以禁止 Claude 调用任何工具。
工具辅助函数和工具运行器进入 beta
Python 和 TypeScript SDK 可以替你跑循环。
工具使用示例不再需要 beta 请求头
工具搜索、记忆、代码执行和网页抓取工具也一样。
Fable 5.1 拒绝强制
tool_choice在 Fable 5.1 和 Mythos 5.1 上,
any和tool会返回错误。Opus 5.5 同样拒绝
另外,工具可以写进对话中途的系统消息里,目前是 beta。
Sonnet 5.5 也一样
强制调用工具同样返回错误。
来源:Claude Docs: Release notes (2026年11月5日 查阅)
| tool_choice | 行为 | 注意 |
|---|---|---|
{"type": "auto"} | Claude 自己决定要不要调用工具 | 传入工具时的默认值 |
{"type": "any"} | Claude 必须调用你的某一个工具 | 下面方框里的模型会返回 400 |
{"type": "tool", "name": "get_weather"} | Claude 必须调用指定的工具 | 同样返回 400,而且强制调用会跳过思考 |
{"type": "none"} | Claude 不能调用工具 | 没有传入工具时的默认值 |
一次响应里的多个工具调用
问两座城市的天气,Claude 可以在同一个响应里返回两个 tool_use 块。你的代码决定是一个接一个地运行,还是同时运行。关键在于回复:把每个 tool_result 都放进同一条用户消息里。
把每个结果分成单独的用户消息发送,一开始也能用,但并行工具调用页面提醒说,这样会教会 Claude 不再做并行调用。每个结果仍然需要自己那次调用的 id,API 靠 id 来配对,不看位置。
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "{\"temp_c\": 18}" },
{ "type": "tool_result", "tool_use_id": "toolu_02", "content": "{\"temp_c\": 24}" }
]
}上报错误,让 Claude 能恢复
工具有两种失败方式:你的函数抛出异常,或者 Claude 发来的输入不合规。两种都用 tool_result 上报,把 is_error 设为 true,并附上说明怎样修正调用的消息。对于参数无效或缺失的调用,文档说 Claude 会先带着修正重试两三次,再向用户道歉。像下面这样的消息给了它修正的依据,一个光秃秃的“Error”则没有。
你决定不运行的调用,也需要一个 tool_result,带上 is_error 和原因。漏掉一个,下一次请求就会失败,错误信息说的是发现了 tool_use id,但后面没有紧跟 tool_result 块。
把工具返回的一切都当作不可信内容。处理工具调用页面提醒,网页或文件里可能带着专门用来引导模型的文字,文档把这叫作间接提示词注入(indirect prompt injection)。所以工具能碰什么,要在你自己的代码里强制限制,不要只写在提示词里。
{
"type": "tool_result",
"tool_use_id": "toolu_01",
"is_error": true,
"content": "City not found. Pass a city name such as Lisbon, not a country."
}Anthropic 和 Alex Albert 在 X 上谈工具设计
Anthropic 在 2025-09-11 在 X 上发帖,推荐了工程博客上的为智能体写好工具一文。文章认为,工具越多,效果不一定越好。它举的例子是:只返回匹配行的 search_logs,比把日志全部返回的 read_logs 更好用。定义工具页面至今仍把这篇文章列为命名和返回内容的延伸阅读,所以 get_weather 也照此办理,只返回两个字段,而不是整个天气 API 的响应。
Alex Albert 在 Anthropic 做研究,他在 2026-02-17 发帖说,工具使用示例、工具搜索和程序化工具调用都已正式可用。工具使用示例就是工具字段表里的 input_examples,现在不需要 beta 请求头。先把描述写好,再给带嵌套输入的工具加两三个示例。
代码执行、网页抓取、记忆、程序化工具调用、工具搜索和工具使用示例,现在都已正式可用。
X 官方嵌入卡片的截图,拍摄于 2026-11-05,时间为 UTC。点击截图可到 X 上打开原帖。两张卡片都省略了原帖结尾的链接。
常见错误
- 把每个 tool_result 放进单独的用户消息,这会减少并行调用。
- 在同一条消息里,把文字放在 tool_result 块的前面。
- 在结果后面紧跟着加一个文本块,这可能让 Claude 用空回复结束回合。
- 只用文本块重建助手消息,结果丢掉了 API 要求传回的 thinking 块。
- 描述只写一行,然后纳闷 Claude 为什么选错了工具。
- 在会拒绝它的模型上,用 tool_choice 强制调用工具。
- 明明 Claude 只要两个字段,却返回整行数据库记录。
自己试一试
- 再加一个工具
get_time,提一个两个工具都要用的问题。返回了几个tool_use块,你是不是在一条用户消息里回复的? - 让
get_weather在城市是“Atlantis”时抛出异常,并返回本课的错误 JSON。Claude 是换一个城市重试,还是告诉用户? - 把描述删到只剩一句话,比较哪些问题仍然会触发这个工具。
- 把
disable_parallel_tool_use设为true,再问一遍两座城市的问题。
接下来
这一课的循环只跑一轮就停了,而每多一轮,都要重新发送同样的工具列表和系统提示词。第 3 课会把它们缓存起来。如果你更想接入现成的工具,不想自己写 schema,可以看 MCP 课程里连接服务器的那一课。
自测一下
响应以 stop_reason "tool_use" 结束,接下来该发送什么?
查看答案
C. 一条用户消息,里面的 tool_result 块带着对应的 tool_use id Claude 从不运行工具,所以由你的代码运行,并在用户消息里回复,每个 tool_use id 对应一个 tool_result。
Claude 在一个响应里返回了两个 tool_use 块,结果该怎么发?
查看答案
A. 放进一条用户消息,里面有两个 tool_result 块 分开的用户消息会教会 Claude 不再做并行调用,所以所有结果都放进同一条消息。
工具在你的代码里抛出了异常,tool_result 应该带什么?
查看答案
D. is_error 为 true,加一条说明怎样修正调用的消息 有指导意义的错误信息,会告诉 Claude 哪里出了错、接下来该试什么,它就不用瞎猜了。
在 Opus 5.5 上,tool_choice 设为 type "tool" 的请求返回了 400,文档建议怎么办?
查看答案
B. 用 auto,并在工具上设 strict 为 true,或者用结构化输出 这些模型拒绝强制的 tool_choice,所以文档指向 auto 加 strict,或者结构化输出。
常见问题
该用工具运行器,还是自己写循环?
工具运行器在 Python 和 TypeScript SDK 里还是 beta,它替你运行循环,并把工具抛出的异常变成 is_error 结果。需要人工审批、自定义日志或有条件执行时,文档建议手写循环。
漏掉 tool_result 会得到什么错误?
一个 invalid_request_error,内容是发现了 tool_use id,但后面没有紧跟 tool_result 块。检查结果是不是在紧接着的那条用户消息里,以及每个 tool_use id 是否都有对应的结果。
为什么 API 要我把 thinking 块传回去?
使用工具时,文档要求助手回合里的每个 thinking 和 redacted_thinking 块都按收到时的样子传回,连空的也不例外。编辑、重排或过滤它们会让请求失败,所以请追加完整的响应内容。
工具定义要花 token 吗?
要。工具定义、tool_use 块和 tool_result 块都计入 token。在 Opus 5.5 上,文档还列出一段 286 个 token 的工具调用系统提示词,tool_choice 为 auto 或 none 时会加上它。
工具定义可以缓存吗?
可以。缓存顺序是工具、系统提示词、消息,缓存断点 cache_control 可以放在最后一个工具上。改动任何一个工具定义,都会让整个缓存失效,第 3 课会讲。
资料来源
- Anthropic Docs: Tool use with Claude https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview
- Anthropic Docs: Define tools https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools
- Anthropic Docs: Handle tool calls https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls
- Anthropic Docs: Parallel tool use https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use
- Anthropic Docs: How tool use works https://platform.claude.com/docs/en/agents-and-tools/tool-use/how-tool-use-works
- Anthropic Docs: Tool runner https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-runner
- Anthropic Docs: Stop reasons and fallback https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons
- Anthropic Docs: Prompt caching https://platform.claude.com/docs/en/build-with-claude/prompt-caching
- Anthropic Docs: Claude API errors https://platform.claude.com/docs/en/api/errors
- Claude Docs: Release notes https://platform.claude.com/docs/en/release-notes/overview
- Anthropic Engineering: Writing effective tools for agents https://www.anthropic.com/engineering/writing-tools-for-agents
- X: Anthropic shares its guide to writing tools for agents https://x.com/AnthropicAI/status/1966236220868247701
- X: Alex Albert on tool use examples and tool search becoming generally available https://x.com/alexalbert__/status/2023834875678298535


