Function Calling 完全指南:让 Claude 从"说话"变成"做事"
本文最后更新于 2026-05-11,文章内容可能已经过时。
Function Calling 完全指南:让 Claude 从"说话"变成"做事"
很多人学了一周 Function Calling,结果连 AI 有没有"真的执行"函数都搞不清楚。
这不怪你——大部分教程直接扔给你一堆代码,却没有解释清楚一件事:AI 在整个过程中,到底扮演了什么角色?
读完本文,你将能独立搭建一个可以调用外部工具的 AI 助手。我们从打破认知开始,到跑通第一个 Demo,再到处理并行多工具调用——循序渐进,每一步都有可以直接运行的代码。
---
第一章:你以为的 Function Calling vs 它实际在干什么
先问你一个问题:当你调用 Function Calling,AI 会"执行"你定义的函数吗?
不会。这是最常见的误解。AI 模型本身是一个语言模型,它不能联网、不能读文件、不能调用你本地的任何代码。它能做的,是返回一个结构化的"意图信号",告诉你它想调用哪个函数、参数是什么——然后执行权完全交回给你。
用流程图对比一下:
【普通对话链路】
用户输入 → Claude 生成文本 → 返回给用户
(AI 全程只产出文字)
【Function Calling 链路】
用户输入
↓
Claude 分析意图,判断"需要调用工具"
↓
返回结构化信号:{"name": "get_weather", "input": {"city": "北京"}}
↓
你的代码捕获这个信号,执行真实函数(调用天气 API)
↓
把执行结果用 tool_result 格式回传给 Claude
↓
Claude 读取结果,生成最终回答
↓
返回给用户
(AI 只负责"决策",执行权始终在你手里)
理解这一点,你才真正入门了工具调用。
核心心智模型:Claude 是一个"决策者",不是"执行者"。Function Calling 的本质,是给 AI 一套"我能做什么"的工具说明书,让它在对话中自主决定何时、如何使用这些工具。
---
第二章:环境搭建 + 最小可运行示例
环境准备
pip install anthropic
你需要一个 Claude API Key。如果还没有,或者被访问限制困扰,可以直接通过 [api.884819.xyz](https://api.884819.xyz) 获取——国内直连,按量计费,新用户注册即送体验 token,几分钟内就能跑起来本文的第一个 Demo。
20 行最小 Demo
import anthropic
client = anthropic.Anthropic(api_key="your_api_key")
定义工具
tools = [
{
"name": "get_weather",
"description": "获取指定城市的实时天气信息",
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如:北京、上海"
}
},
"required": ["city"]
}
}
]
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "北京今天天气怎么样?"}]
)
print(f"stop_reason: {response.stop_reason}")
print(f"content: {response.content}")
运行输出:
stop_reason: tool_use
content: [
TextBlock(text='我来帮您查询北京的天气。', type='text'),
ToolUseBlock(
id='toolu_01XYZ...',
name='get_weather',
input={'city': '北京'},
type='tool_use'
)
]
注意两个关键点:
1. stop_reason == "tool_use":这是 Claude 告诉你"我需要调用工具,请你去执行"的信号
2. ToolUseBlock:包含工具名称和参数,这就是你需要捕获并执行的"意图"
tools 参数的 JSON Schema 写法是新手最容易卡壳的地方。记住三要素:name(工具名)、description(功能描述,越清晰 AI 越准确)、input_schema(参数定义,遵循 JSON Schema 标准)。
---
第三章:3 个真实例子,从简单到复杂
例 1(简单):查实时天气 —— 单工具单轮调用
import anthropic
import json
client = anthropic.Anthropic(api_key="your_api_key")
tools = [
{
"name": "get_weather",
"description": "获取指定城市的实时天气",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"}
},
"required": ["city"]
}
}
]
def get_weather(city: str) -> dict:
"""模拟天气 API 调用"""
weather_data = {
"北京": {"temp": 22, "condition": "晴", "humidity": 45},
"上海": {"temp": 28, "condition": "多云", "humidity": 72},
}
return weather_data.get(city, {"temp": 20, "condition": "未知", "humidity": 50})
def run_weather_query(user_message: str):
messages = [{"role": "user", "content": user_message}]
# 第一轮:让 Claude 决策
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=tools,
messages=messages
)
if response.stop_reason == "tool_use":
# 提取工具调用信息
tool_use_block = next(b for b in response.content if b.type == "tool_use")
tool_name = tool_use_block.name
tool_input = tool_use_block.input
# 执行工具
result = get_weather(tool_input["city"])
# 把结果回传给 Claude
messages.append({"role": "assistant", "content": response.content})
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_use_block.id,
"content": json.dumps(result, ensure_ascii=False)
}]
})
# 第二轮:Claude 生成最终回答
final_response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=tools,
messages=messages
)
return final_response.content[0].text
return response.content[0].text
print(run_weather_query("北京今天天气怎么样?"))
运行输出:
北京今天天气晴朗,气温22°C,湿度45%,是个不错的天气!
恭喜,你已经掌握了 Function Calling 的基础闭环。
---
例 2(中等):联网搜索 + 摘要 —— 完整多轮链路
这个例子展示"AI 决策 → 工具执行 → 结果回传 → AI 再总结"的完整链路:
import anthropic
import json
client = anthropic.Anthropic(api_key="your_api_key")
tools = [
{
"name": "web_search",
"description": "搜索互联网获取最新信息,当需要实时数据或最新资讯时使用",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "搜索关键词"},
"max_results": {
"type": "integer",
"description": "返回结果数量,默认3",
"default": 3
}
},
"required": ["query"]
}
}
]
def web_search(query: str, max_results: int = 3) -> list:
"""模拟搜索 API"""
return [
{"title": f"关于'{query}'的最新报道", "snippet": f"这是关于{query}的详细信息...", "url": "https://example.com/1"},
{"title": f"{query}深度分析", "snippet": f"{query}的技术细节和应用场景...", "url": "https://example.com/2"},
][:max_results]
def run_search_and_summarize(user_message: str):
messages = [{"role": "user", "content": user_message}]
# 支持多轮工具调用
while True:
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=2048,
tools=tools,
messages=messages
)
if response.stop_reason == "end_turn":
# AI 已经完成回答
return response.content[0].text
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
# 处理所有工具调用
tool_results = []
for block in response.content:
if block.type == "tool_use":
if block.name == "web_search":
result = web_search(**block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result, ensure_ascii=False)
})
messages.append({"role": "user", "content": tool_results})
print(run_search_and_summarize("帮我搜索一下 Claude Function Calling 的最新进展,并给我一个简洁的摘要"))
你已经掌握了多轮工具调用的完整链路。
---
例 3(进阶):并行工具调用 —— 同时查多个城市
根据 Anthropic 官方文档,Claude 支持在单次响应中返回多个 tool_use block,实现并行工具调用。这在需要同时获取多份数据时可以显著减少往返次数:
import anthropic
import json
from concurrent.futures import ThreadPoolExecutor
client = anthropic.Anthropic(api_key="your_api_key")
tools = [
{
"name": "get_weather",
"description": "获取指定城市的实时天气",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"}
},
"required": ["city"]
}
}
]
def get_weather(city: str) -> dict:
weather_db = {
"北京": {"temp": 22, "condition": "晴"},
"上海": {"temp": 28, "condition": "多云"},
"广州": {"temp": 33, "condition": "阵雨"},
"成都": {"temp": 19, "condition": "阴"},
}
return weather_db.get(city, {"temp": 20, "condition": "未知"})
def run_parallel_weather(user_message: str):
messages = [{"role": "user", "content": user_message}]
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=tools,
messages=messages
)
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
# 提取所有工具调用
tool_use_blocks = [b for b in response.content if b.type == "tool_use"]
print(f"Claude 同时发起了 {len(tool_use_blocks)} 个工具调用")
# 并行执行(这里用线程池模拟)
def execute_tool(block):
result = get_weather(block.input["city"])
return {
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result, ensure_ascii=False)
}
with ThreadPoolExecutor() as executor:
tool_results = list(executor.map(execute_tool, tool_use_blocks))
messages.append({"role": "user", "content": tool_results})
final_response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=tools,
messages=messages
)
return final_response.content[0].text
result = run_parallel_weather("帮我同时查一下北京、上海、广州、成都今天的天气,做个对比")
print(result)
运行输出:
Claude 同时发起了 4 个工具调用
今日四城天气对比:
- 北京:22°C,晴,适合出行
- 上海:28°C,多云,较为闷热
- 广州:33°C,阵雨,记得带伞
- 成都:19°C,阴,气温舒适
你现在已经掌握了并行工具调用——这是构建高效 Agent 的关键技术。
---
第四章:3 个新手必踩的坑
坑 1:忘记回传 tool_result,对话直接卡死
错误代码:# ❌ 错误:拿到工具调用结果后,忘记回传
if response.stop_reason == "tool_use":
result = get_weather("北京")
# 直接打印,没有回传给 Claude
print(result)
报错现象: Claude 停在工具调用阶段,永远不生成最终回答,或者你的循环逻辑陷入死循环。
修复方案:
# ✅ 正确:必须把结果用 tool_result 格式回传
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_use_block.id, # 必须对应原始调用的 id
"content": json.dumps(result)
}]
})
这个坑我当年踩了两个小时,现在省给你。
---
坑 2:JSON Schema 写得不够精确,AI 乱填参数
错误代码:# ❌ 错误:description 太模糊,没有 required 字段
{
"name": "get_weather",
"description": "天气",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string"}
}
# 缺少 required!
}
}
报错现象: Claude 可能不传 city 参数,或者传入格式错误的值(比如传 "北京市朝阳区" 而不是 "北京")。
修复方案:
# ✅ 正确:description 清晰,required 完整,加上 enum 约束
{
"name": "get_weather",
"description": "获取指定城市的实时天气信息。city 参数必须是城市名,不含区县",
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如:北京、上海、广州"
}
},
"required": ["city"]
}
}
原则:description 写给 AI 看,越具体越好。你对工具的描述质量,直接决定 AI 调用的准确率。
---
坑 3:没处理 end_turn,循环逻辑写错
错误代码:# ❌ 错误:只处理了 tool_use,忘记处理 end_turn
while True:
response = client.messages.create(...)
if response.stop_reason == "tool_use":
# 处理工具调用
...
# 没有 end_turn 的退出条件 → 无限循环!
报错现象: 程序无限循环,API 调用次数暴增,账单飞涨。
修复方案:
# ✅ 正确:完整处理所有 stop_reason
while True:
response = client.messages.create(...)
if response.stop_reason == "end_turn":
return response.content[0].text # 正常结束
if response.stop_reason == "tool_use":
# 处理工具调用,继续循环
...
# 兜底处理其他情况
else:
break
---
第五章:何时用 Function Calling,何时不用
不是所有场景都需要工具调用。引入它会增加代码复杂度和 API 调用次数,用错地方反而是负担。
| 场景 | 是否用 Function Calling | 原因 | | 查实时天气/股价 | ✅ 用 | 需要实时数据,模型知识有截止日期 | | 操作数据库/文件系统 | ✅ 用 | 需要与外部系统交互 | | 生成结构化 JSON 输出 | ✅ 用 | 工具调用天然返回结构化数据 | | 写一篇文章/代码 | ❌ 不用 | 纯文本生成,模型直接完成 | | 回答知识性问题 | ❌ 不用 | 模型自身知识足够,无需外部数据 | | 简单的数学计算 | ❌ 不用(通常) | 模型直接推理,除非精度要求极高 | | 多步骤自动化任务 | ✅ 用 | 这就是 Agent 的核心场景 | 判断原则很简单:问自己一个问题——"这个任务需要 AI 知道它自己不知道的东西吗?" 如果答案是肯定的(实时数据、外部系统状态、用户私有数据),就用工具调用。---
结语
Function Calling 不是一个"高级功能",它是 AI 从"聊天机器人"进化到"自动化 Agent"的关键一步。
你刚刚学会的,是让 AI 从"说话"变成"做事"的核心技术。
文中所有代码在标准 Claude API 环境下均已测试通过。API 获取及用量管理:[api.884819.xyz](https://api.884819.xyz),国产模型完全免费,无月租,按量付费。
---
🔮 下一篇预告
>
工具调用你已经会了。
>
但如果工具不止一个、对话不止一轮、AI 需要自己决定"下一步做什么"——
那就不叫工具调用,叫 Agent。
>
下一篇,我们用 Claude 从零搭一个能自主完成任务的 AI Agent,看看它和今天这些例子,差在哪里。
>
关注 8848AI,不要错过。
---
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。#AI教程 #FunctionCalling #Claude #AI开发 #Python #AIAgent #8848AI #工具调用