Claude学院

Claude Tool Use 工具调用怎么用?完整代码实战

Claude Tool Use(工具调用,也叫函数调用)的用法是:你在请求里用 JSON Schema 描述若干工具,模型判断该不该调用、生成结构化参数(tool_use 块),你的代码执行真实函数后,把结果作为 tool_result 回传,模型再据此给出最终回答。整个流程都走标准的 Messages API(POST /v1/messages),不需要额外接口。下面用官方 SDK 把这条链路跑通。

一、工具调用的核心机制

很多人误以为 Claude 会"自己去执行"函数。事实并非如此:模型只负责决策和生成参数,真正的执行始终在你的代码里。一次完整的工具调用是这样一个循环:

  1. 你发请求,tools 字段里带上工具定义;
  2. 模型返回 stop_reason: "tool_use",并在 content 里给出 tool_use 块(含工具名、唯一 id 和参数 input);
  3. 你执行对应函数,把结果包成 tool_result 块(用同一个 tool_use_id 关联),作为一条 user 消息回传;
  4. 模型读取结果,继续推理,直到 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_resulttool_use_id 必须和对应 tool_useid 一致;第三,模型一轮可能请求多个工具(并行调用),要全部执行完再回传。关于多轮上下文的拼接细节,可参考 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 的工具非常好用。

六、错误处理与避坑

当输出较长或 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 一次性塞进上下文。

Claude API 开发