在接入 Claude API 时,很多开发者会搜索 Claude API Function Calling,希望实现类似 OpenAI Function Calling 的能力:让大模型根据用户问题自动决定是否调用某个函数,并传入结构化参数。

不过需要先明确一点:在 Anthropic Claude 官方文档中,这项能力通常被称为 Tool Use,也就是“工具使用”或“工具调用”,而不是 Function Calling。

从开发视角来看,下面这些说法基本指的是同一类能力:

  • Claude Function Calling
  • Claude API Tool Use
  • Claude 工具调用
  • Claude API 工具调用配置
  • Claude 调用外部函数

但严格来说,Claude 并不会直接执行你的后端函数。它的职责是:

判断是否需要调用工具,并生成一份结构化的工具调用请求。

真正的函数执行、数据库查询、接口请求、权限校验、业务系统写入,仍然需要由你的服务端代码完成。


1. Claude Tool Use 的核心工作流程

Claude 工具调用的完整链路可以概括为:

用户提问
  ↓
Claude 判断是否需要工具
  ↓
返回 tool_use 调用请求
  ↓
后端解析 tool_use 并执行真实函数
  ↓
后端将执行结果通过 tool_result 回传给 Claude
  ↓
Claude 基于工具结果生成最终回答

也就是说,Claude 只负责“提出调用意图”,而不是“实际执行动作”。

例如用户问:

帮我查一下订单 OD20240601001 发货了吗?

Claude 可能返回一个工具调用请求:

{
  "type": "tool_use",
  "id": "toolu_01ABC",
  "name": "get_order_status",
  "input": {
    "order_id": "OD20240601001"
  }
}

随后你的后端根据 name 找到对应函数,查询订单系统,再把结果返回给 Claude。


2. 什么场景适合使用 Claude Function Calling

Claude Tool Use 并不是所有场景都必须使用。它更适合那些需要外部数据、实时信息或业务系统能力的任务。

2.1 适合使用工具调用的场景

常见场景包括:

  • 查询实时数据
    例如天气、汇率、股票价格、物流进度、库存状态等。

  • 调用内部业务系统
    例如 CRM、ERP、订单系统、支付系统、客服工单系统等。

  • 获取用户相关数据
    例如账户余额、会员等级、订单列表、售后记录等。

  • 执行结构化任务
    例如从自然语言中抽取参数、补全表单、分类、规则判断等。

  • 构建 Agent 多步骤流程
    例如先搜索商品,再查询库存,再生成购买建议。

2.2 不一定需要工具调用的场景

以下任务通常可以直接让 Claude 回答:

  • 普通知识问答
  • 文案生成
  • 文章总结
  • 内容改写
  • 固定 FAQ
  • 代码解释
  • 不依赖实时数据的推理任务

如果一个任务本身不依赖外部系统,强行加入工具调用会带来额外成本:

  • 请求轮次变多;
  • token 消耗增加;
  • 后端逻辑变复杂;
  • 调试链路变长;
  • 出错点更多。

因此,工具调用应该用于“模型自己无法可靠完成”的任务,而不是所有任务都挂工具。


3. Claude Tool Use 中几个关键字段

在 Claude Messages API 中,与工具调用关系最密切的字段主要有以下几个。

字段 作用
tools 声明当前可供 Claude 使用的工具列表
input_schema 定义工具参数结构和约束
tool_use Claude 返回的工具调用请求
tool_result 后端执行工具后回传给 Claude 的结果
tool_choice 控制 Claude 自动选择工具、强制调用工具或不调用工具
stop_reason 判断 Claude 是否因为需要调用工具而暂停输出

理解这几个字段,是实现 Claude Function Calling 的基础。


4. 第一步:定义工具 tools

定义工具时,并不是把真实函数上传给 Claude,而是给 Claude 一份“工具说明书”。

Claude 会根据工具的以下信息判断是否调用工具:

  • name:工具名称;
  • description:工具用途描述;
  • input_schema:工具参数结构。

一个典型工具定义如下:

{
  "name": "get_order_status",
  "description": "根据订单 ID 查询订单的支付状态、发货状态和预计送达时间。只有当用户明确询问订单状态、物流进度或订单是否发货时才使用。",
  "input_schema": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "订单编号,例如 OD20240601001"
      }
    },
    "required": ["order_id"]
  }
}

这里需要注意:description 不只是说明工具能做什么,更重要的是告诉 Claude 什么时候应该使用它


5. 第二步:发送用户消息和工具列表

首次请求 Claude 时,需要同时传入:

  • 用户问题;
  • 工具列表 tools
  • 模型参数;
  • 其他上下文信息。

示例请求结构如下:

{
  "model": "claude-3-5-sonnet-20241022",
  "max_tokens": 1024,
  "tools": [
    {
      "name": "get_order_status",
      "description": "根据订单 ID 查询订单的支付状态、发货状态和预计送达时间。只有当用户明确询问订单状态、物流进度或订单是否发货时才使用。",
      "input_schema": {
        "type": "object",
        "properties": {
          "order_id": {
            "type": "string",
            "description": "订单编号,例如 OD20240601001"
          }
        },
        "required": ["order_id"]
      }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": "帮我查一下订单 OD20240601001 发货了吗?"
    }
  ]
}

Claude 收到请求后,会判断当前问题是否需要调用工具。


6. 第三步:解析 Claude 返回的 tool_use

如果 Claude 认为需要使用工具,响应内容中通常会包含 tool_use

示例:

{
  "type": "tool_use",
  "id": "toolu_01ABC",
  "name": "get_order_status",
  "input": {
    "order_id": "OD20240601001"
  }
}

此时响应中的 stop_reason 通常是:

"stop_reason": "tool_use"

这表示:

Claude 暂停生成最终自然语言回答,等待你执行工具并返回结果。

开发者需要在后端做几件事:

  1. 遍历 Claude 返回的 content
  2. 找到 typetool_use 的内容块;
  3. 读取 name
  4. 根据 name 分发到对应后端函数;
  5. 校验 input 参数;
  6. 执行业务逻辑。

7. 第四步:后端执行真实函数

拿到 tool_use 后,需要由后端执行真正的函数。

例如:

async function getOrderStatus(orderId) {
  // 示例:这里可以查询数据库、调用订单系统或第三方接口
  return {
    order_id: orderId,
    payment_status: "paid",
    shipping_status: "shipped",
    estimated_delivery: "2024-06-05"
  };
}

工具分发逻辑可以类似这样:

async function executeTool(toolUse) {
  const { name, input } = toolUse;

  if (name === "get_order_status") {
    if (!input.order_id) {
      throw new Error("order_id is required");
    }

    return await getOrderStatus(input.order_id);
  }

  throw new Error(`Unknown tool: ${name}`);
}

这里有一个非常重要的原则:

永远不要无条件信任模型生成的工具参数。

尤其是涉及以下场景时,后端必须做严格校验:

  • 数据库查询;
  • 订单取消;
  • 支付退款;
  • 文件读写;
  • 邮件发送;
  • 权限变更;
  • 用户隐私数据查询;
  • 内部系统写操作。

Claude 生成的参数应该被视为“用户输入”,而不是可信指令。


8. 第五步:通过 tool_result 回传执行结果

工具执行完后,需要将结果包装成 tool_result,再发送给 Claude。

其中最关键的字段是:

"tool_use_id": "toolu_01ABC"

这个 ID 必须与上一轮 Claude 返回的 tool_use.id 完全一致。

示例:

{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01ABC",
      "content": "{\"order_id\":\"OD20240601001\",\"payment_status\":\"paid\",\"shipping_status\":\"shipped\",\"estimated_delivery\":\"2024-06-05\"}"
    }
  ]
}

注意:

  • tool_use_id 不能自己随便生成;
  • 必须对应上一轮的 tool_use.id
  • 如果有多个工具调用,需要分别回传对应结果;
  • 工具执行失败时,也应该返回可解释的错误信息。

请添加图片描述

9. 第六步:Claude 生成最终回答

Claude 收到 tool_result 后,会结合工具返回的数据生成自然语言回答。

例如最终回复可能是:

订单 OD20240601001 已支付,目前已经发货,预计将在 2024-06-05 送达。

从用户视角看,这就是一次完整的“模型调用函数并回答”的流程。

但从系统实现看,实际经历了两次 Claude API 请求:

  1. 第一次:用户问题 + tools,Claude 返回 tool_use
  2. 第二次:回传 tool_result,Claude 返回最终回答。

10. tools.name:工具名要短、明确、可路由

工具名建议使用英文小写和下划线,例如:

get_order_status
search_products
cancel_order
create_ticket
query_user_profile

不建议使用过于泛化的名称:

get_data
query
do_action
handle_request
process

原因有两个:

第一,Claude 需要通过工具名理解大致用途。

第二,后端通常会根据工具名做函数分发。

例如:

const toolHandlers = {
  get_order_status,
  search_products,
  cancel_order
};

如果工具名过于抽象,后续调试和排查都会很麻烦。


11. tools.description:重点写清楚“什么时候用”

很多开发者在写工具描述时,只写工具能做什么,例如:

查询订单。

这种描述太短,Claude 很难准确判断调用边界。

更推荐的写法是:

根据订单 ID 查询订单的支付状态、发货状态和预计送达时间。只有当用户明确询问订单状态、物流进度、是否发货或预计送达时间时才使用。

好的 description 应该包含三类信息:

  1. 这个工具能做什么;
  2. 用户表达什么意图时应该使用;
  3. 什么情况下不应该使用。

例如:

{
  "name": "search_products",
  "description": "根据关键词搜索商品列表,返回商品名称、价格、库存和商品 ID。只有当用户想查找、比较或购买商品时才使用。不要用于查询订单状态。"
}

当你有多个职责相近的工具时,描述边界尤其重要。

例如:

  • get_order_status:查询订单状态;
  • search_products:搜索商品;
  • cancel_order:取消订单;
  • create_refund_request:创建退款申请。

如果描述写得模糊,模型很容易误选工具。


12. input_schema:用 JSON Schema 约束参数

input_schema 用来告诉 Claude 工具需要哪些参数,以及每个参数的类型和含义。

一个基本 schema 通常包括:

  • type
  • properties
  • required
  • 字段级 description

示例:

{
  "type": "object",
  "properties": {
    "order_id": {
      "type": "string",
      "description": "订单编号,例如 OD20240601001"
    }
  },
  "required": ["order_id"]
}

如果某个字段只有固定取值,建议使用 enum

例如:

{
  "type": "object",
  "properties": {
    "status_type": {
      "type": "string",
      "enum": ["payment", "shipping", "refund"],
      "description": "要查询的状态类型。payment 表示支付状态,shipping 表示物流状态,refund 表示退款状态。"
    }
  },
  "required": ["status_type"]
}

如果不使用 enum,模型可能生成各种不稳定的值,例如:

物流状态
发货情况
delivery
shipping_status
快递

这些值对人类来说意思接近,但对后端代码来说可能完全无法匹配。

因此,能枚举的字段尽量枚举,能限制格式的字段尽量限制格式。


13. tool_choice:自动调用、强制调用与禁用工具

tool_choice 用来控制 Claude 是否使用工具,以及使用哪个工具。

常见策略有三种:

13.1 自动选择工具

让 Claude 自己判断是否需要调用工具。

适合大多数对话场景,例如:

  • 用户可能问普通问题;
  • 也可能查询订单;
  • 也可能搜索商品。

这种情况下可以传入 tools,但不强制指定具体工具。

13.2 强制调用某个工具

适合必须结构化输出或必须走业务系统的场景。

例如,你希望 Claude 一定调用 get_order_status

{
  "tool_choice": {
    "type": "tool",
    "name": "get_order_status"
  }
}

适合场景:

  • 表单信息抽取;
  • 固定接口查询;
  • 参数解析;
  • 必须经过后端校验的业务流程。

13.3 禁止工具调用

适合纯文本生成任务,例如:

  • 写文章;
  • 总结内容;
  • 翻译文本;
  • 生成标题;
  • 普通知识问答。

最简单的方式是:不要传 tools

如果你使用的 SDK 或 API 版本支持显式禁用工具,也可以根据 Anthropic 官方文档进行配置。由于 API 字段可能随版本变化,建议以最新官方文档为准。


14. temperature 和 max_tokens 如何设置

在工具调用场景中,一般建议降低 temperature

原因是工具调用更关注:

  • 参数稳定;
  • 工具选择准确;
  • 输出结构可控;
  • 行为可预测。

通常可以设置为:

{
  "temperature": 0,
  "max_tokens": 1024
}

当然,并不是所有场景都必须设置为 0。

如果你的任务需要一定创造性,例如工具结果返回后生成营销文案,可以适当提高 temperature。

但对于订单查询、支付、退款、库存、权限这类业务场景,建议优先使用低温度配置。


15. 多工具调用时的处理方式

在复杂场景中,Claude 可能一次返回多个 tool_use

例如用户问:

帮我查一下订单 OD20240601001 的物流状态,再看看有没有同款商品还在售。

Claude 可能同时请求两个工具:

  • get_order_status
  • search_products

后端需要分别执行每个工具,并分别返回对应的 tool_result

关键点是:

每个 tool_result 都要对应正确的 tool_use_id

伪代码示例:

const toolResults = [];

for (const block of response.content) {
  if (block.type === "tool_use") {
    const result = await executeTool(block);

    toolResults.push({
      type: "tool_result",
      tool_use_id: block.id,
      content: JSON.stringify(result)
    });
  }
}

然后把所有工具结果一起回传给 Claude。


16. 工具执行失败时怎么处理

真实业务系统中,工具调用失败很常见,例如:

  • 订单不存在;
  • 用户未登录;
  • 权限不足;
  • 第三方接口超时;
  • 参数格式错误;
  • 数据库异常。

不要直接让程序崩溃,也不要返回空字符串。

更推荐返回结构化错误信息,例如:

{
  "success": false,
  "error_code": "ORDER_NOT_FOUND",
  "message": "未找到订单 OD20240601001"
}

再通过 tool_result 回传给 Claude。

Claude 可以根据错误信息生成更友好的回复:

没有查询到订单 OD20240601001。请确认订单编号是否正确,或提供下单手机号后四位继续查询。

这样可以显著提升用户体验。


17. 常见坑位与排查建议

17.1 把 Claude 当成真正的函数执行器

Claude 不会真正执行函数。它只会返回工具调用请求。

错误理解:

Claude 会自动调用我的后端函数。

正确理解:

Claude 会告诉你它想调用哪个工具,真正执行动作的是你的服务端。

17.2 忘记处理 stop_reason = tool_use

如果返回结果中 stop_reasontool_use,说明 Claude 正在等待工具结果。

此时不能直接把这一轮响应当最终回复展示给用户,而应该执行工具并继续下一轮请求。


17.3 tool_use_id 对不上

tool_result.tool_use_id 必须等于上一轮 tool_use.id

如果 ID 不匹配,Claude 无法判断工具结果属于哪次调用。


17.4 工具描述太模糊

例如:

查询数据。

这类描述会导致 Claude 不知道什么时候调用,也不知道和其他工具的边界。

应该写清楚:

  • 工具用途;
  • 调用条件;
  • 不适用场景;
  • 参数含义。

17.5 input_schema 太宽松

如果 schema 没有限制,模型可能生成难以处理的参数。

例如后端只接受:

payment
shipping
refund

但模型可能返回:

物流状态
快递
delivery

解决方式是使用 enum 或更清晰的字段描述。


17.6 后端不做参数校验

这是非常危险的做法。

工具调用中的参数来自模型推断,本质上仍然是不可信输入。

必须做:

  • 必填校验;
  • 类型校验;
  • 格式校验;
  • 权限校验;
  • 业务规则校验;
  • 风险操作二次确认。

17.7 工具过多且边界重叠

如果一次传入过多工具,并且描述相似,Claude 选错工具的概率会上升。

建议:

  • 只传当前场景需要的工具;
  • 拆分工具职责;
  • 避免多个工具功能重叠;
  • 在 description 中写清楚边界。

18. 推荐的后端接入结构

一个相对清晰的 Claude Tool Use 后端结构可以分为几层:

Controller
  ↓
Claude Client
  ↓
Tool Use Parser
  ↓
Tool Router
  ↓
Tool Handler
  ↓
Business Service

职责划分如下:

模块 职责
Controller 接收用户请求
Claude Client 调用 Claude Messages API
Tool Use Parser 解析 Claude 返回的 tool_use
Tool Router 根据工具名分发处理器
Tool Handler 校验参数并调用业务服务
Business Service 执行真实业务逻辑
Tool Result Builder 构造 tool_result 并回传 Claude

这样设计的好处是:

  • 工具扩展更方便;
  • 业务逻辑更清晰;
  • 更容易做日志追踪;
  • 更容易做权限控制;
  • 更容易处理异常。

19. 最佳实践总结

实现 Claude Function Calling / Tool Use 时,可以遵循以下实践:

  1. 工具名使用清晰的英文动词短语
    例如 get_order_statussearch_products

  2. description 写清楚调用时机
    不只写“能做什么”,还要写“什么时候用”。

  3. input_schema 尽量严格
    必填字段、字段类型、枚举值都要明确。

  4. 后端必须做参数校验
    不要信任模型生成的参数。

  5. 高风险操作要二次确认
    例如退款、取消订单、删除数据、修改权限。

  6. 处理好 stop_reason = tool_use
    它表示 Claude 正在等待工具结果。

  7. 正确维护 tool_use_id
    tool_result 必须和 tool_use 一一对应。

  8. 不要给 Claude 传过多无关工具
    只传当前任务需要的工具,减少误调用。

  9. 工具执行结果尽量结构化
    建议返回 JSON,方便 Claude 理解。

  10. 做好日志和链路追踪
    记录用户输入、tool_use、tool_result、最终回答,方便排查问题。


20. 小结

Claude API 的 Function Calling 本质上是 Anthropic 的 Tool Use 能力。

它并不会直接执行函数,而是通过 tool_use 告诉后端:

  • 想调用哪个工具;
  • 需要哪些参数;
  • 当前为什么需要暂停等待工具结果。

后端执行真实函数后,再通过 tool_result 把结果回传给 Claude,Claude 才会生成最终自然语言回答。

如果要稳定落地 Claude 工具调用,重点不在于“让模型调用函数”这个概念本身,而在于:

  • 工具定义是否清晰;
  • 参数 schema 是否严格;
  • 后端分发是否可靠;
  • 权限和参数校验是否完善;
  • 异常情况是否可控。

对于订单查询、业务系统接入、实时数据检索、Agent 工作流等场景,Claude Tool Use 是非常实用的能力。只要把工具边界、参数约束和后端安全控制做好,就可以构建出稳定可靠的 Claude API 工具调用系统。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐