Claude API 工具调用实战指南:Function Calling 怎么配、怎么用
如果你在搜 Claude API Function Calling,大概率是想实现类似 OpenAI Function Calling 的能力:让模型判断要不要调用某个函数,并把参数结构化返回给后端。
先说结论:在 Claude 官方体系里,更常用的叫法是 Tool Use,也就是工具调用。它不是让 Claude 直接执行你的函数,而是让 Claude 生成一份“调用请求”,真正执行动作的仍然是你的服务端。
典型流程如下:
用户提问 → Claude 判断是否需要工具 → 返回 tool_use → 后端执行真实函数 / 查询数据库 / 请求业务 API → 后端把结果作为 tool_result 回传 → Claude 基于结果生成最终回复
简单理解:
Claude 负责“决定调用哪个工具、参数是什么”;
你的后端负责“真正执行工具,并把结果返回给 Claude”。
这篇主要按实战视角讲:该怎么配置、什么场景适合用、后端要注意什么、哪些坑容易踩。
一、Claude 工具调用适合什么场景?
不是所有 AI 应用都需要工具调用。判断标准很简单:这个问题是否依赖外部实时数据或业务系统?
适合用工具调用的场景
比如下面这些,就很适合接 Claude Tool Use:
查询订单状态、物流状态、退款进度;
查询天气、库存、汇率、股票等实时数据;
调用 CRM、ERP、工单系统、支付系统;
从用户输入中抽取结构化参数;
根据规则判断是否满足某个业务条件;
串联多个工具,做简单 Agent 流程。
例如用户问:
帮我查一下订单 OD20240601001 发货了吗?
这类问题,Claude 自己不可能知道真实订单状态,必须调用你的订单系统。
不太适合用工具调用的场景
下面这些通常直接让 Claude 回答就行:
普通知识问答;
文案生成;
文章总结;
翻译润色;
FAQ 固定问答;
不依赖实时数据的解释类问题。
硬接工具调用的结果往往是:
请求轮次变多;
token 成本增加;
代码复杂度上升;
问题排查更麻烦。
所以我的建议是:只有当模型必须访问外部数据或系统时,再上工具调用。
二、Claude Tool Use 里几个核心字段
在 Claude Messages API 里,和工具调用关系最密切的字段主要有这些:
字段 作用 tools 告诉 Claude 当前有哪些工具可用 input_schema 定义工具参数结构和类型 tool_use Claude 返回的工具调用请求 tool_result 后端执行工具后返回给 Claude 的结果 tool_choice 控制模型自动调用、强制调用或不调用工具
实际开发时,最常打交道的是:
你传入 tools;
Claude 返回 tool_use;
你执行函数;
你再传回 tool_result。
三、完整调用流程
下面用一个“查询订单状态”的例子说明。
1. 定义工具 tools
注意,这一步不是把真实函数上传给 Claude,而是给 Claude 一份“工具说明书”。
示例:
{ "name": "get_order_status", "description": "根据订单 ID 查询订单的支付状态、发货状态和预计送达时间。只有当用户明确询问订单状态、物流进度或订单是否发货时才使用。", "input_schema": { "type": "object", "properties": { "order_id": { "type": "string", "description": "订单编号,例如 OD20240601001" } }, "required": ["order_id"] } }
这里最关键的是三个部分:
name:工具名,后端一般会根据它分发函数;
description:告诉 Claude 这个工具什么时候该用;
input_schema:约束参数格式。
2. 把用户问题和 tools 一起发给 Claude
用户输入:
帮我查一下订单 OD20240601001 发货了吗?
请求中同时带上工具列表。Claude 会自己判断:这个问题是否需要调用工具。
如果它认为需要,就不会直接给最终答案,而是返回一个 tool_use。
3. 解析 Claude 返回的 tool_use
Claude 返回内容可能类似这样:
{ "type": "tool_use", "id": "toolu_01ABC", "name": "get_order_status", "input": { "order_id": "OD20240601001" } }
这说明 Claude 想调用:
get_order_status(order_id="OD20240601001")
这时常见的 stop_reason 是:
"tool_use"
意思是:Claude 暂停生成最终回答,等待你执行工具并返回结果。
4. 后端执行真实函数
你的服务端需要做几件事:
根据 name 找到对应函数;
校验 input 参数;
判断用户是否有权限查询;
调用数据库或业务 API;
得到真实结果。
伪代码大概是这样:
if (toolUse.name === "get_order_status") { const { order_id } = toolUse.input; // 参数校验 if (!/^ODd+$/.test(order_id)) { throw new Error("Invalid order_id"); } // 权限校验 // 确认当前用户是否有权查询该订单 const result = await getOrderStatusFromDB(order_id); }
这里有个非常重要的点:
不要无条件相信 Claude 生成的参数。
尤其是涉及下面这些操作时,一定要做后端校验:
数据库读写;
支付、退款;
文件系统操作;
邮件、短信发送;
用户权限变更;
删除、取消、提交类动作。
Claude 生成的是“建议调用参数”,不是可信指令。
5. 用 tool_result 把结果回传给 Claude
工具执行完成后,需要把结果包装成 tool_result 发回 Claude。
关键是:tool_use_id 必须和上一轮 Claude 返回的 tool_use.id 对上。
示例:
{ "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,否则 Claude 不知道这份结果对应哪次工具调用。
6. Claude 生成最终回答
Claude 收到 tool_result 后,会基于真实结果生成自然语言回复,例如:
你的订单 OD20240601001 已支付并已发货,预计 2024-06-05 送达。
这才是用户最终看到的答案。
四、tools 怎么写更稳定?
工具调用好不好用,很多时候取决于 tools 写得够不够清楚。
1. 工具名要具体,不要太泛
推荐:
get_order_status search_products cancel_order create_support_ticket
不推荐:
get_data query do_action handle_request
原因很简单:工具名太泛,模型容易选错,后端路由也不好维护。
如果你有多个工具,工具名最好能一眼看出用途。
2. description 不只写“能做什么”,更要写“什么时候用”
很多人会这样写:
查询订单。
这个描述太模糊了。
更推荐这样写:
根据订单 ID 查询订单的支付状态、发货状态和预计送达时间。只有当用户明确询问订单状态、物流进度或订单是否发货时才使用。
如果工具之间职责相近,更要把边界写清楚。
比如:
get_order_status:只用于查询订单支付和发货状态。 get_refund_status:只用于查询退款申请状态和退款到账时间。
否则用户问“我的订单处理到哪了”,模型可能不知道该选订单工具还是退款工具。
3. input_schema 要尽量约束参数
input_schema 建议至少包含:
type
properties
required
字段级 description
示例:
{ "type": "object", "properties": { "order_id": { "type": "string", "description": "订单编号,例如 OD20240601001" }, "status_type": { "type": "string", "enum": ["payment", "shipping", "refund"], "description": "要查询的状态类型" } }, "required": ["order_id", "status_type"] }
如果字段只有固定选项,建议一定加 enum。
不加的话,模型可能生成:
物流状态 发货情况 delivery shipping_status
这些对人来说差不多,但后端可能完全匹配不上。
五、tool_choice 怎么用?
tool_choice 主要控制 Claude 是否调用工具,以及调用哪个工具。
常见有三种用法。
1. 自动选择工具
适合大多数客服、问答、业务助手场景。
模型会根据用户问题判断要不要调用工具。
适合:
用户可能问业务数据,也可能普通聊天;
多个工具可选;
不确定是否必须调用工具。
2. 强制调用某个工具
适合你明确知道这个任务必须走工具的情况。
比如:
表单信息抽取;
固定结构化解析;
必须查数据库才能回答;
必须走风控规则判断。
示例:
{ "tool_choice": { "type": "tool", "name": "get_order_status" } }
这种方式可以减少模型“偷懒直接回答”的情况。
3. 不调用工具
如果只是总结、改写、写文案,其实不传 tools 就可以。
比如:
“帮我总结这段文字”
“帮我写一段商品介绍”
“把这句话改得更礼貌”
这类任务不需要工具,直接调用模型更省事。
六、temperature 和 max_tokens 怎么设置?
工具调用场景里,我一般建议:
temperature:0 ~ 0.3
原因是工具调用更看重稳定性,不需要太多随机发挥。
如果你希望模型稳定抽取参数、稳定选择工具,就不要把温度调太高。
max_tokens 则要根据场景设置:
只是返回工具调用:可以设小一点;
最终回答比较长:需要适当放大;
多轮工具调用:要预留足够 token。
实战里,建议不要一开始就把 max_tokens 设得特别小,否则可能出现工具参数或最终回复被截断的问题。

七、实战中最容易踩的坑
下面这些是接 Claude Tool Use 时比较常见的问题。
坑 1:以为 Claude 会直接执行函数
Claude 不会直接访问你的数据库,也不会直接调用你代码里的函数。
它只会返回类似:
{ "name": "get_order_status", "input": { "order_id": "OD20240601001" } }
真正执行必须由后端完成。
坑 2:工具描述太模糊,导致选错工具
比如你定义了两个工具:
query_order query_refund
描述都写成:
查询信息。
这种情况下,模型选错并不奇怪。
建议把使用条件写清楚:
query_order:当用户询问订单是否支付、是否发货、物流进度时使用。 query_refund:当用户询问退款申请、退款审核、退款到账时间时使用。
坑 3:没有做参数校验
不要因为参数是 Claude 给的,就直接传给数据库或内部接口。
至少要校验:
字段是否存在;
类型是否正确;
格式是否合法;
是否在允许枚举中;
当前用户是否有权限操作该资源。
尤其是写操作,比如取消订单、发起退款、修改地址,一定要谨慎。
坑 4:tool_use_id 对不上
回传 tool_result 时,tool_use_id 必须使用 Claude 返回的那个 tool_use.id。
错误示例:
{ "tool_use_id": "my_custom_id_123" }
正确做法:
{ "tool_use_id": "toolu_01ABC" }
这个 ID 是模型识别上下文的重要依据,不能乱填。
坑 5:把敏感权限交给模型决定
Claude 可以帮你判断意图,但不能替代权限系统。
比如用户说:
帮我取消这个订单。
Claude 可以提议调用 cancel_order,但后端仍然必须确认:
这个订单是不是当前用户的;
订单当前状态是否允许取消;
是否需要二次确认;
是否存在风控限制。
我的建议是:
读操作可以相对宽松,写操作必须加权限校验和确认流程。
坑 6:工具太多,模型选择不稳定
如果一次传给 Claude 几十个工具,模型选择错误的概率会变高,token 成本也会上升。
建议:
按业务场景拆分工具集;
当前页面只传当前场景需要的工具;
工具描述保持明确;
相似工具尽量合并或明确边界。
例如订单详情页只传:
get_order_status get_logistics_info apply_refund
不要把商品搜索、优惠券、会员积分、客服工单全塞进去。
八、推荐的后端处理结构
实战里可以按这个思路组织代码:
1. 接收用户输入 2. 调用 Claude,传入 messages + tools 3. 判断返回内容是否包含 tool_use 4. 如果有 tool_use: 4.1 根据 name 路由到对应函数 4.2 校验 input 4.3 校验权限 4.4 执行业务逻辑 4.5 生成 tool_result 4.6 再次调用 Claude 5. 返回 Claude 最终自然语言回答
简单伪代码:
const response = await callClaude({ messages, tools }); const toolUse = findToolUse(response); if (toolUse) { const result = await executeTool(toolUse.name, toolUse.input, currentUser); const finalResponse = await callClaude({ messages: [ ...messages, responseMessage, { role: "user", content: [ { type: "tool_result", tool_use_id: toolUse.id, content: JSON.stringify(result) } ] } ], tools }); return finalResponse; } return response;
核心点就两个:
tool_use 是 Claude 发出的调用请求;
tool_result 是你执行后返回给 Claude 的结果。
九、我的配置建议
如果是第一次接 Claude 工具调用,可以按下面这个配置思路起步:
工具定义
工具名用英文小写加下划线;
一个工具只做一类明确任务;
description 写清楚使用条件;
参数尽量用 JSON Schema 约束;
固定值一定用 enum。
模型参数
temperature 设为 0 ~ 0.3;
max_tokens 不要过小;
工具调用链路先保证稳定,再考虑文案表现。
安全策略
后端必须校验参数;
后端必须校验权限;
高风险操作增加二次确认;
不让模型直接决定写操作;
对工具调用做好日志记录,方便排查。
十、总结
Claude API 的 Function Calling,本质上就是官方所说的 Tool Use 工具调用。
它的关键不是“让模型执行函数”,而是让模型:
理解用户意图 → 判断是否需要工具 → 生成结构化调用参数 → 等待后端执行结果 → 基于真实结果回答用户
如果你的应用需要连接订单、库存、物流、CRM、ERP、数据库等外部系统,Claude 工具调用非常实用。
但如果只是写作、总结、翻译、普通问答,就没必要强行接工具。
最后给一个实战建议:
工具调用的稳定性,主要取决于三件事:工具描述是否清楚、参数 schema 是否严格、后端校验是否完善。做好这三点,Claude Tool Use 才能真正稳定落地。
