作者:互联网 时间: 2026-07-01 09:37:07
完整链路大致如下:
用户提问↓Claude 判断是否需要工具↓返回 tool_use↓后端解析并执行真实函数↓回传 tool_result↓Claude 基于结果生成最终回答
也就是说,Claude 负责「决策和参数生成」,你的服务端负责「执行和安全控制」。
工具调用并不是所有场景都需要。它更适合处理模型无法仅靠自身知识稳定完成的任务。
典型适用场景:
不太适合的场景:
如果一个任务 Claude 直接回答即可,强行挂工具只会带来额外请求轮次、更高 token 成本和更复杂的工程逻辑。
在 Claude Messages API 中,和工具调用相关的字段主要有:
| 字段 | 作用 |
|---|---|
tools | 声明当前有哪些工具可用 |
input_schema | 定义工具参数结构和约束 |
tool_use | Claude 返回的工具调用请求 |
tool_result | 后端执行工具后返回给 Claude 的结果 |
tool_choice | 控制是否调用工具,以及调用哪个工具 |
理解这几个字段,基本就能掌握 Claude Tool Use 的主流程。
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"]}}
这里的 get_order_status 只是一个声明。真正的 get_order_status 函数,需要你在后端自己实现。
首次请求时,需要把用户消息和 tools 一起传给 Claude。
伪代码结构如下:
{ "model": "claude-3-5-sonnet-latest", "max_tokens": 1024, "tools": [ { "name": "get_order_status", "description": "根据订单 ID 查询订单的支付状态、发货状态和预计送达时间。只有当用户明确询问订单状态、物流进度或订单是否发货时才使用。", "input_schema": {"type": "object","properties": { "order_id": {"type": "string","description": "订单编号"} },"required": ["order_id"]} }], "messages": [ { "role": "user", "content": "帮我查一下订单 OD20240601001 发货了吗?" }]}
Claude 会根据用户问题自行判断是否需要调用工具。
tool_use如果 Claude 判断需要调用工具,响应中会出现类似结构:
{ "type": "tool_use", "id": "toolu_01ABC", "name": "get_order_status", "input": {"order_id": "OD20240601001"}}
此时常见的 stop_reason 是:
"tool_use"
它表示:Claude 暂停生成最终回答,等待你执行工具并回传结果。
接下来进入你的服务端逻辑:
tool_use.nametool_use.input伪代码示例:
async function handleToolUse(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}`);}
重点:不要信任模型生成的参数。
即使你在 input_schema 中定义了参数格式,后端也必须再次校验,尤其是以下高风险操作:
模型负责生成参数,不负责保证参数绝对安全。
tool_result 回传结果工具执行完成后,需要把结果包装成 tool_result 再发回 Claude。
关键点:tool_use_id 必须等于上一轮 Claude 返回的 tool_use.id。
示例:
{ "role": "user", "content": [ { "type": "tool_result", "tool_use_id": "toolu_01ABC", "content": "{"status":"shipped","estimated_delivery":"2024-06-05"}" }]}
如果 tool_use_id 对不上,Claude 就无法知道这个结果对应哪一次工具调用。
Claude 收到 tool_result 后,会基于真实工具结果生成自然语言回答。
例如:
你的订单 OD20240601001 已发货,预计将在 2024-06-05 送达。
所以用户最终看到的回答,并不是工具直接返回的原始数据,而是 Claude 基于工具结果组织后的表达。
tools.name:短、明确、方便路由推荐使用英文小写 + 下划线:
get_order_statussearch_productscancel_ordercreate_ticket
不推荐:
get_dataquerydo_actionprocess
原因很简单:工具名不仅给 Claude 看,后端通常也会根据它做分发。名字越抽象,越容易误调用,也越难排查。
tools.description:重点写清楚「什么时候用」很多人只写工具能做什么,但这还不够。对 Claude 来说,更重要的是判断「什么时候该用」。
不推荐:
查询订单。
推荐:
根据订单 ID 查询订单的支付状态、发货状态和预计送达时间。只有当用户明确询问订单状态、物流进度或订单是否发货时才使用。
如果多个工具能力接近,一定要在 description 里写清楚边界。
例如:
search_products:当用户想查找可购买商品、价格、库存时使用。get_order_status:当用户已经提供订单 ID,并询问订单支付、发货、物流状态时使用。
否则模型很容易把「查商品」和「查订单」混在一起。
input_schema:用 JSON Schema 约束参数一个合格的 input_schema 至少应该包含:
typepropertiesrequireddescription示例:
{"type": "object","properties": {"order_id": {"type": "string","description": "订单编号,例如 OD20240601001"},"status_type": {"type": "string","enum": ["payment", "shipping", "refund"],"description": "要查询的状态类型"}},"required": ["order_id", "status_type"]}
如果字段只有固定取值,建议使用 enum。
否则模型可能生成各种近义值:
物流状态发货情况deliveryshipping_status
这些对人类来说差别不大,但对后端来说可能完全匹配不上。
tool_choice:控制是否调用工具tool_choice 用来控制 Claude 的工具调用策略。
常见模式有三种:
让 Claude 自己判断是否调用工具。
适合大多数对话式场景。
{"tool_choice": {"type": "auto"}}
适合必须走结构化流程的场景,比如表单抽取、订单查询、工单创建。
{"tool_choice": {"type": "tool","name": "get_order_status"}}
如果是纯文本生成、总结、改写,不需要传 tools 即可。
如果 SDK 或 API 版本支持显式禁用,也可以按官方最新文档配置。Anthropic API 字段可能随版本演进,生产环境建议以官方文档为准。
temperature 和 max_tokens工具调用场景下,建议降低随机性:
{"temperature": 0,"max_tokens": 1024}
尤其是参数抽取、查询类任务,temperature 不宜过高。否则可能出现:
max_tokens 也要留足空间,否则可能出现工具调用内容被截断的问题。
当业务中存在多个工具时,建议遵循两个原则:
示例:
[{"name": "search_products","description": "根据关键词搜索商品信息,包括商品名称、价格和库存。仅当用户想查找或比较商品时使用。","input_schema": {"type": "object","properties": {"keyword": {"type": "string","description": "商品搜索关键词"}},"required": ["keyword"]}},{"name": "get_order_status","description": "根据订单 ID 查询订单状态。仅当用户提供订单 ID 并询问支付、发货、物流或退款状态时使用。","input_schema": {"type": "object","properties": {"order_id": {"type": "string","description": "订单编号"}},"required": ["order_id"]}}]
不要把一个工具设计成万能入口:
handle_user_requestprocess_businessquery_data
这种设计短期省事,长期会带来三个问题:
错误示例:
用于查询业务信息。
这类描述会导致 Claude 在很多无关问题上也尝试调用工具。
建议写成:
仅当用户明确提供订单 ID,并询问订单支付、发货、物流或退款状态时使用。
不要让 Claude 自己判断用户有没有权限取消订单、退款或查看数据。
权限判断必须放在后端:
用户身份校验↓权限校验↓参数校验↓执行工具
模型可以帮你理解意图,但不能替代权限系统。
tool_result 不要塞太多无关数据工具结果越大,Claude 消耗的 token 越多,也越容易抓不住重点。
推荐返回精简结构:
{"order_id": "OD20240601001","shipping_status": "shipped","estimated_delivery": "2024-06-05"}
不推荐直接返回完整数据库记录,尤其是包含内部字段、日志、用户隐私信息的结果。
在复杂任务中,Claude 可能连续发起多次工具调用。
例如:
用户:帮我查一下这款手机有没有货,如果有货就告诉我最近的门店。
可能流程是:
search_products↓check_inventory↓find_nearest_store↓最终回答
因此后端代码不要假设「每次对话只会有一次 tool_use」。
生产环境必须处理异常情况:
建议统一封装错误结果,再返回给 Claude:
{"error": true,"message": "未查询到该订单,请确认订单编号是否正确。"}
这样 Claude 可以基于错误信息给用户一个可读的回复,而不是直接中断流程。
可以把 Claude Tool Use 接入理解成下面这段伪代码:
async function chatWithTools(userMessage) {const firstResponse = await claude.messages.create({model: "claude-3-5-sonnet-latest",max_tokens: 1024,temperature: 0,tools,messages: [{role: "user",content: userMessage}]});const toolUse = firstResponse.content.find(item => item.type === "tool_use");if (!toolUse) {return firstResponse.content;}const toolResult = await handleToolUse(toolUse);const finalResponse = await claude.messages.create({model: "claude-3-5-sonnet-latest",max_tokens: 1024,messages: [{role: "user",content: userMessage},{role: "assistant",content: firstResponse.content},{role: "user",content: [{type: "tool_result",tool_use_id: toolUse.id,content: JSON.stringify(toolResult)}]}]});return finalResponse.content;}
真实项目中还需要补充:
tool_use 的并发或串行处理如果你准备在业务中接入 Claude Tool Use,可以按这个顺序推进:
description 写清楚使用条件和边界input_schema 尽量严格,能用 enum 就用 enum尤其是涉及写操作时,不建议让模型一步完成。
例如取消订单可以拆成两步:
第一步:Claude 识别用户想取消订单,调用查询工具确认订单状态第二步:向用户确认是否取消第三步:用户确认后,后端再执行取消动作
这样可以降低误操作风险。
Claude API 的 Function Calling,本质上是 Anthropic 的 Tool Use 机制。
它的核心不是「让模型执行函数」,而是:
让模型判断调用哪个工具、生成结构化参数;让后端执行真实逻辑、返回工具结果;再让模型基于结果生成最终回答。
接入时重点关注五件事:
只要把这些边界处理好,Claude Tool Use 就可以稳定连接业务系统,把大模型从「只会回答」扩展到「能参与真实业务流程」。