Claude Tool Use 怎么用?从零到生产的完整教程(2026)

Claude Tool Use 怎么用?从零到生产的完整教程(2026)上周接了个需求 做一个能查天气 查数据库 还能发邮件的 AI 助手 一开始想着用 LangChain 套一层 后来发现 Claude 原生的 Tool Use 也叫 Function Calling 已经很成熟了 根本不需要额外框架 但官方文档写得有点绕 我踩了不少坑才把整条链路跑通 把摸索出来的东西全写下来 让你少走弯路 Claude Tool Use 是 Anthropic

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



上周接了个需求,做一个能查天气、查数据库、还能发邮件的 AI 助手。一开始想着用 LangChain 套一层,后来发现 Claude 原生的 Tool Use(也叫 Function Calling)已经很成熟了,根本不需要额外框架。但官方文档写得有点绕,我踩了不少坑才把整条链路跑通。把摸索出来的东西全写下来,让你少走弯路。

Claude Tool Use 是 Anthropic 提供的原生函数调用能力,允许你在对话中定义工具(函数),Claude 会自动判断何时调用哪个工具、提取参数,你执行函数后把结果返回给它,它再生成最终回答。目前 Claude Sonnet 4.6 和 Opus 4.6 都支持,Sonnet 性价比最高,Opus 复杂推理更强。

维度 说明 支持模型 Claude Opus 4.6、Sonnet 4.6、Haiku 4.6 协议格式 Anthropic 原生格式 / OpenAI 兼容格式均可 核心流程 定义工具 → 发送请求 → Claude 返回工具调用 → 你执行函数 → 结果回传 → Claude 生成回答 并行调用 支持,一次可调用多个工具 嵌套调用 支持,工具结果可触发新一轮工具调用 踩坑重灾区 tool_result 的 content 必须是字符串、工具描述写得烂会导致调用率暴跌
sequenceDiagram participant U as 你的代码 participant A as Claude API participant T as 本地工具函数 U->>A: 发送消息 + 工具定义 A->>U: 返回 tool_use(要调用哪个工具、参数是什么) U->>T: 执行本地函数 T->>U: 返回执行结果 U->>A: 把 tool_result 回传 A->>U: Claude 生成最终回答 

这个流程是整个 Tool Use 的骨架,后面的代码全是围绕这个转的。

pip install openai httpx 

这里用的是 OpenAI SDK。因为很多聚合平台都兼容 OpenAI 协议,Claude 的 Tool Use 在 OpenAI 兼容模式下也能正常工作,切换模型零成本。

先来最简单的场景——让 Claude 调用一个查天气的函数。

import json from openai import OpenAI client = OpenAI( api_key="your-api-key", base_url="https://api.ofox.ai/v1" # 聚合接口,一个 Key 调 Claude/GPT/Gemini ) # 1. 定义工具 tools = [ , "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位,默认摄氏度" } }, "required": ["city"] } } } ] # 2. 你的本地函数(实际项目中这里调真实 API) def get_weather(city: str, unit: str = "celsius") -> dict: # 模拟数据,实际替换成真实天气 API fake_data = { "北京": {"temp": 22, "humidity": 45, "condition": "晴"}, "上海": {"temp": 26, "humidity": 72, "condition": "多云"}, "深圳": {"temp": 31, "humidity": 80, "condition": "雷阵雨"}, } data = fake_data.get(city, {"temp": 20, "humidity": 50, "condition": "未知"}) if unit == "fahrenheit": data["temp"] = data["temp"] * 9 / 5 + 32 data["city"] = city data["unit"] = unit return data # 3. 发送请求 messages = [ {"role": "user", "content": "深圳今天天气怎么样?适合跑步吗?"} ] response = client.chat.completions.create( model="claude-sonnet-4.6", messages=messages, tools=tools, tool_choice="auto" # 让 Claude 自己决定要不要调工具 ) # 4. 处理工具调用 assistant_message = response.choices[0].message if assistant_message.tool_calls: # Claude 决定调用工具 messages.append(assistant_message) # 先把 assistant 消息加进去 for tool_call in assistant_message.tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments) print(f"Claude 要调用: {func_name}({func_args})") # 执行本地函数 if func_name == "get_weather": result = get_weather(func_args) # 把结果回传(注意:content 必须是字符串!) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False) }) # 5. 让 Claude 根据工具结果生成最终回答 final_response = client.chat.completions.create( model="claude-sonnet-4.6", messages=messages, tools=tools ) print(final_response.choices[0].message.content) else: # Claude 觉得不需要调工具,直接回答了 print(assistant_message.content) 

实测输出:

Claude 要调用: get_weather({'city': '深圳'}) 深圳今天31°C,湿度80%,有雷阵雨。不太建议户外跑步哦, 湿度太高容易中暑,雷阵雨也不安全。建议等晚上凉快点再去, 或者去室内跑步机上练练。 

Claude 不是机械地把数据复述一遍,它会结合天气数据给出建议。这就是 Tool Use 比硬编码模板强的地方。

真实项目很少只有一个工具。下面这个例子定义了三个工具,并且实现了自动循环——Claude 可能调完一个工具还想调另一个,代码自动处理。

import json from openai import OpenAI client = OpenAI( api_key="your-api-key", base_url="https://api.ofox.ai/v1" ) # 定义多个工具 tools = [ { "type": "function", "function": { "name": "search_products", "description": "根据关键词搜索商品,返回商品列表(名称、价格、库存)", "parameters": { "type": "object", "properties": { "keyword": {"type": "string", "description": "搜索关键词"}, "max_results": {"type": "integer", "description": "最多返回几条,默认5"} }, "required": ["keyword"] } } }, }, "required": ["product_id"] } } }, { "type": "function", "function": { "name": "create_order", "description": "创建订单。注意:仅在用户明确表示要购买时才调用", "parameters": { "type": "object", "properties": { "product_id": {"type": "string"}, "quantity": {"type": "integer", "description": "购买数量,默认1"} }, "required": ["product_id"] } } } ] # 模拟业务函数 def search_products(keyword, max_results=5): return [ {"id": "P001", "name": f"机械键盘-{keyword}款", "price": 359, "stock": 42}, {"id": "P002", "name": f"薄膜键盘-{keyword}入门", "price": 89, "stock": 156}, ] def get_product_reviews(product_id): reviews = { "P001": {"score": 4.7, "count": 2341, "summary": "手感好,Cherry轴,就是有点吵"}, "P002": {"score": 4.1, "count": 892, "summary": "便宜够用,适合办公"}, } return reviews.get(product_id, {"score": 0, "summary": "暂无评价"}) def create_order(product_id, quantity=1): return {"order_id": "ORD", "status": "created", "product_id": product_id, "quantity": quantity} # 函数路由 FUNC_MAP = def chat_with_tools(user_input: str): messages = [ {"role": "system", "content": "你是一个电商购物助手,帮用户搜索商品、查看评价、下单购买。"}, {"role": "user", "content": user_input} ] max_rounds = 5 # 防止死循环 for round_num in range(max_rounds): response = client.chat.completions.create( model="claude-sonnet-4.6", messages=messages, tools=tools, tool_choice="auto" ) msg = response.choices[0].message # 没有工具调用,说明 Claude 准备好回答了 if not msg.tool_calls: return msg.content # 有工具调用,执行并回传 messages.append(msg) for tool_call in msg.tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments) print(f" [Round {round_num + 1}] 调用 {func_name}({func_args})") result = FUNC_MAP[func_name](func_args) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False) }) return "工具调用轮次超限,请简化问题" # 测试 answer = chat_with_tools("我想买个键盘打代码用,帮我看看有啥推荐的,评价好的那种") print(answer) 

跑起来后,Claude 会先调 search_products,看到结果后自动调 get_product_reviews 查评价,再综合两次结果给出推荐。两轮工具调用,全自动。

这部分是我花时间最多的地方。

content 字段必须是字符串,不能直接传 dict。

# ❌ 错误写法 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": {"temp": 22} # 这会报 422 错误 }) # ✅ 正确写法 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps({"temp": 22}, ensure_ascii=False) }) 

这个坑比较隐蔽。我一开始给 get_weather 的 description 写的是 "获取天气",三个字。结果 Claude 经常不调这个工具,直接瞎编一个天气回答。

description 要写清楚三件事:这个函数干什么、输入什么、返回什么。参数的 description 也一样,别偷懒。

# ❌ 太简单 "description": "获取天气" # ✅ 写清楚 "description": "获取指定城市的当前天气信息,返回温度(数字)、湿度(百分比)、天气状况(文字描述)" 

这个 bug 特别坑,报错信息还不明显。Claude 返回工具调用后,必须先把那条 assistant 消息原封不动加回 messages,再加 tool result,顺序不能乱。

# ❌ 漏掉了 assistant message messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result_str }) # ✅ 先加 assistant,再加 tool result messages.append(assistant_message) # 这一步不能少! messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result_str }) 

Claude 有时候一次返回多个 tool_calls(比如同时查两个城市的天气)。每个 tool_result 的 tool_call_id 必须和对应的 tool_call 匹配,搞混了就 400 错误。用上面 for tool_call in msg.tool_calls 的写法就不会出问题。

这个参数控制 Claude 调不调工具、怎么调:

值 行为 适用场景 “auto” Claude 自己决定(推荐) 大多数场景 “none” 禁止调工具 纯聊天轮次 “required” 强制必须调工具 你确定这轮一定要调工具 {“type”: “function”, “function”: {“name”: “xxx”}} 强制调指定工具 流程编排、测试

90% 的时候用 “auto” 就够了。只有在做严格的多步骤流程编排时才需要强制指定。

Claude Tool Use 的核心就是那个请求-调用-回传的循环,搞懂这个剩下的都是细节。重点记四条:description 要写详细、content 必须是字符串、assistant message 不能漏、循环要设上限防死循环

我现在用的方案是通过 ofox.ai 的聚合接口调 Claude,它是一个 AI 模型聚合平台,一个 API Key 可以调 Claude Opus 4.6、GPT-5、Gemini 3 等 50+ 模型,低延迟直连,支持支付宝付款。换模型不用改代码,Claude 的 Tool Use 和 GPT-5 的 Function Calling 用同一套代码就能跑,方便对比效果。

代码我放 Gist 上了,直接 copy 就能跑。有问题评论区见。

小讯
上一篇 2026-04-23 11:42
下一篇 2026-04-23 11:40

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/277106.html