Mindket

Claude 工具调用:用 Python 定义工具并处理调用

黑色横幅,标题是“Claude API 实战”,下面是“调用、工具、缓存与智能体循环”。

Claude 工具调用,是让模型请你的代码去运行一个函数。你用名称、描述和 JSON Schema 来描述每个工具。Claude 想用某个工具时,响应会以 stop_reason 为 tool_use 结束。你运行函数,再在下一条用户消息里发回 tool_result。模型自己从不运行任何东西。

本节内容

  • 用名称、足够长的描述和 JSON Schema 来描述每个工具。
  • 每个 tool_use 块都要回一个带相同 id 的 tool_result。
  • 并行结果要一起发,失败要用 is_error 上报。
  • 知道哪些 tool_choice 取值会被当前模型拒绝。
全部课程
本页目录
  1. 开始之前
  2. 跑通 tool_use 与 tool_result 往返
  3. 写出 Claude 能用好的工具定义
  4. 用 tool_choice 引导调用
  5. 一次响应里的多个工具调用
  6. 上报错误,让 Claude 能恢复
  7. Anthropic 和 Alex Albert 在 X 上谈工具设计
  8. 常见错误
  9. 自己试一试
  10. 接下来
  11. 自测一下
  12. 常见问题
  13. 资料来源

开始之前

请先学完第 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)
  1. 用 name、description 和 input_schema 定义工具,再把列表作为 tools 传入。
  2. 发送用户消息。Claude 回复的 stop_reason 是 tool_use,并带有一个或多个 tool_use 块,每个块有 id、name 和 input。
  3. 把 response.content 完整、不加修改地追加到历史里,作为助手消息。使用工具时,文档要求每个 thinking 块都原样传回。
  4. 对每个 tool_use 块运行你的函数,并构造一个 tool_result 块,其 tool_use_id 与它的 id 相同。
  5. 把所有结果放进一条用户消息里,再调用一次 API。这时 Claude 会写出最终回答。

写出 Claude 能用好的工具定义

描述决定了大部分效果。文档把它称作影响工具表现的最重要因素,要求至少写三四句话:这个工具做什么、什么时候用、每个参数是什么意思,以及它返回什么。

少而宽的工具,比多而窄的工具效果更好,所以把相关操作合并成一个带 action 参数的工具。几个工具并排时,名称按服务加前缀,比如 github_list_prs。函数只返回信息量高的数据,因为它返回的一切,都会变成下一次调用的输入 token。

工具字段出自定义工具页面,2026-11-05 阅读。
字段是否必需要知道的事
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 限制在每个回合最多调用一次工具。

Claude 发布说明里的工具调用变化
  1. 工具调用结束 beta

    在 Claude API、Bedrock 和 Vertex AI 上都不再需要 beta 请求头。

  2. 新增 disable_parallel_tool_use

    写在 tool_choice 里,让 Claude 每个回合最多调用一个工具。

  3. tool_choice 新增 none

    可以禁止 Claude 调用任何工具。

  4. 工具辅助函数和工具运行器进入 beta

    Python 和 TypeScript SDK 可以替你跑循环。

  5. 工具使用示例不再需要 beta 请求头

    工具搜索、记忆、代码执行和网页抓取工具也一样。

  6. Fable 5.1 拒绝强制 tool_choice

    在 Fable 5.1 和 Mythos 5.1 上,any 和 tool 会返回错误。

  7. Opus 5.5 同样拒绝

    另外,工具可以写进对话中途的系统消息里,目前是 beta。

  8. Sonnet 5.5 也一样

    强制调用工具同样返回错误。

来源:Claude Docs: Release notes (2026年11月5日 查阅)

出自定义工具页面,2026-11-05 阅读。
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 请求头。先把描述写好,再给带嵌套输入的工具加两三个示例。

代码执行、网页抓取、记忆、程序化工具调用、工具搜索和工具使用示例,现在都已正式可用。

Alex Albert, 在 Anthropic 做研究,引文为译文 · X (2026年11月5日 查阅)
Anthropic(@AnthropicAI)2025 年 9 月 11 日在 X 上发帖,介绍 Anthropic 工程博客的新文章:为 LLM 智能体写好工具,并给开发者分享让工具更好用的建议。
Anthropic 在 X 上,2025 年 9 月 11 日
Alex Albert(@alexalbert__)2026 年 2 月 17 日在 X 上发帖:代码执行、网页抓取、记忆、程序化工具调用、工具搜索和工具使用示例现已正式可用。
Alex Albert 在 X 上,2026 年 2 月 17 日

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 课程里连接服务器的那一课。

自测一下

  1. 响应以 stop_reason "tool_use" 结束,接下来该发送什么?

    查看答案

    C. 一条用户消息,里面的 tool_result 块带着对应的 tool_use id Claude 从不运行工具,所以由你的代码运行,并在用户消息里回复,每个 tool_use id 对应一个 tool_result。

  2. Claude 在一个响应里返回了两个 tool_use 块,结果该怎么发?

    查看答案

    A. 放进一条用户消息,里面有两个 tool_result 块 分开的用户消息会教会 Claude 不再做并行调用,所以所有结果都放进同一条消息。

  3. 工具在你的代码里抛出了异常,tool_result 应该带什么?

    查看答案

    D. is_error 为 true,加一条说明怎样修正调用的消息 有指导意义的错误信息,会告诉 Claude 哪里出了错、接下来该试什么,它就不用瞎猜了。

  4. 在 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 课会讲。

资料来源

  1. Anthropic Docs: Tool use with Claude (2026年11月5日 查阅)https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview
  2. Anthropic Docs: Define tools (2026年11月5日 查阅)https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools
  3. Anthropic Docs: Handle tool calls (2026年11月4日 查阅)https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls
  4. Anthropic Docs: Parallel tool use (2026年11月4日 查阅)https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use
  5. Anthropic Docs: How tool use works (2026年11月4日 查阅)https://platform.claude.com/docs/en/agents-and-tools/tool-use/how-tool-use-works
  6. Anthropic Docs: Tool runner (2026年11月4日 查阅)https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-runner
  7. Anthropic Docs: Stop reasons and fallback (2026年11月4日 查阅)https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons
  8. Anthropic Docs: Prompt caching (2026年11月4日 查阅)https://platform.claude.com/docs/en/build-with-claude/prompt-caching
  9. Anthropic Docs: Claude API errors (2026年11月4日 查阅)https://platform.claude.com/docs/en/api/errors
  10. Claude Docs: Release notes (2026年11月5日 查阅)https://platform.claude.com/docs/en/release-notes/overview
  11. Anthropic Engineering: Writing effective tools for agents (2026年11月5日 查阅)https://www.anthropic.com/engineering/writing-tools-for-agents
  12. X: Anthropic shares its guide to writing tools for agents (2026年11月5日 查阅)https://x.com/AnthropicAI/status/1966236220868247701
  13. X: Alex Albert on tool use examples and tool search becoming generally available (2026年11月5日 查阅)https://x.com/alexalbert__/status/2023834875678298535

分享本节课

浏览会用工具的 AI 智能体

看看 Mindket 上的成品智能体怎样描述自己的工具和设置,再把你自己的也上架。

浏览 AI 智能体

本节课的 Markdown 版本 · Claude API 实战课:从零构建 AI 智能体 · 全部课程