Claude API Function Calling 实战指南:Tool Use 配置、流程与常见坑
在接入 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 暂停生成最终自然语言回答,等待你执行工具并返回结果。
开发者需要在后端做几件事:
- 遍历 Claude 返回的
content; - 找到
type为tool_use的内容块; - 读取
name; - 根据
name分发到对应后端函数; - 校验
input参数; - 执行业务逻辑。
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 请求:
- 第一次:用户问题 + tools,Claude 返回
tool_use; - 第二次:回传
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 应该包含三类信息:
- 这个工具能做什么;
- 用户表达什么意图时应该使用;
- 什么情况下不应该使用。
例如:
{
"name": "search_products",
"description": "根据关键词搜索商品列表,返回商品名称、价格、库存和商品 ID。只有当用户想查找、比较或购买商品时才使用。不要用于查询订单状态。"
}
当你有多个职责相近的工具时,描述边界尤其重要。
例如:
get_order_status:查询订单状态;search_products:搜索商品;cancel_order:取消订单;create_refund_request:创建退款申请。
如果描述写得模糊,模型很容易误选工具。
12. input_schema:用 JSON Schema 约束参数
input_schema 用来告诉 Claude 工具需要哪些参数,以及每个参数的类型和含义。
一个基本 schema 通常包括:
typepropertiesrequired- 字段级
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_statussearch_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_reason 是 tool_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 时,可以遵循以下实践:
-
工具名使用清晰的英文动词短语
例如get_order_status、search_products。 -
description 写清楚调用时机
不只写“能做什么”,还要写“什么时候用”。 -
input_schema 尽量严格
必填字段、字段类型、枚举值都要明确。 -
后端必须做参数校验
不要信任模型生成的参数。 -
高风险操作要二次确认
例如退款、取消订单、删除数据、修改权限。 -
处理好
stop_reason = tool_use
它表示 Claude 正在等待工具结果。 -
正确维护
tool_use_id
tool_result 必须和 tool_use 一一对应。 -
不要给 Claude 传过多无关工具
只传当前任务需要的工具,减少误调用。 -
工具执行结果尽量结构化
建议返回 JSON,方便 Claude 理解。 -
做好日志和链路追踪
记录用户输入、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 工具调用系统。
更多推荐

所有评论(0)