Function Calling 深度指南:原理、实现与多模型对比实测
Function Calling(函数调用)是大模型应用开发中最核心的功能之一。它让 AI 不再只是一个"聊天机器人",而是能够调用外部工具、获取实时数据、执行具体操作的智能助手。
这篇文章我会从原理到实现,再到多模型对比,全方位讲清楚 Function Calling。测试用的是一个 OpenAI 兼容的聚合平台(97AIPRO),方便切换不同模型做对比。
一、Function Calling 是什么?
简单说,Function Calling 就是让大模型"学会使用工具"。
你给模型描述一组可用的函数(工具),模型会根据用户的问题,智能判断:
- 需不需要调用工具
- 调用哪个工具
- 传入什么参数
然后你在代码中执行这个函数,把结果返回给模型,模型再根据结果生成最终的自然语言回答。
整个流程是这样的:
用户提问 → 模型判断是否调用函数 → 是 → 返回函数名和参数
↓
代码执行函数
↓
结果返回给模型
↓
模型生成最终回答
二、典型应用场景
Function Calling 的应用场景非常广: - 实时数据查询:天气、股票、新闻、航班
- 计算与分析:数学运算、数据分析、统计
- 操作系统:发邮件、创建日历、操作数据库
- 第三方服务:地图导航、翻译、搜索
- 企业内部:查库存、查订单、审批流程
- Agent 系统:多步骤任务规划与执行
可以说,任何需要 AI 和外部世界交互的场景,都离不开 Function Calling。
三、基础实现
我们用 Python 来演示,基于 OpenAI 兼容接口(我用的是 97AIPRO,其他兼容平台也一样)。
3.1 定义函数
首先,你需要用 JSON Schema 格式描述你的函数:
tools = [
{
“type”: “function”,
“function”: {
“name”: “get_weather”,
“description”: “获取指定城市的天气信息”,
“parameters”: {
“type”: “object”,
“properties”: {
“city”: {
“type”: “string”,
“description”: “城市名称,如北京、上海、深圳”
},
“date”: {
“type”: “string”,
“description”: “日期,格式为 YYYY-MM-DD,默认为今天”
}
},
“required”: [“city”]
}
}
}
]
最佳实践:函数的 description 要写清楚"这个函数是做什么的、什么时候该用"。参数的 description 也要详细,这样模型才能正确理解和提取。
3.2 第一次调用:让模型判断
from openai import OpenAI
import json
client = OpenAI(
api_key=“your_api_key”,
base_url=“https://api.97aipro.com/v1”
)
messages = [
{“role”: “user”, “content”: “北京今天天气怎么样?”}
]
response = client.chat.completions.create(
model=“gpt-4o”,
messages=messages,
tools=tools,
tool_choice=“auto”
)
response_message = response.choices[0].message
3.3 检查是否需要调用函数
if response_message.tool_calls:
print(“模型决定调用函数:”)
for tool_call in response_message.tool_calls:
print(f"函数名:{tool_call.function.name}“)
print(f"参数:{tool_call.function.arguments}”)
else:
print(“模型直接回答:”, response_message.content)
运行结果大概是:
模型决定调用函数:
函数名:get_weather
参数:{“city”:“北京”,“date”:“2024-01-15”}
模型智能地识别出需要调用天气函数,并且正确提取了参数。
四、完整的函数调用流程
上面只是第一步,完整的流程需要多轮交互:
def get_weather(city, date=None):
“”“模拟获取天气的函数,实际项目中调用真实 API”“”
return f"{city}{date or ‘今天’}的天气:晴,温度 25°C,湿度 60%,微风"
第一步:用户提问
messages = [
{“role”: “user”, “content”: “北京今天天气怎么样?适合出门吗?”}
]
第二步:模型判断是否调用函数
response = client.chat.completions.create(
model=“gpt-4o”,
messages=messages,
tools=tools,
tool_choice=“auto”
)
response_message = response.choices[0].message
messages.append(response_message) # 把模型回复加入历史
第三步:执行函数
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 根据函数名分发执行
if function_name == "get_weather":
function_response = get_weather(**function_args)
else:
function_response = f"未知函数:{function_name}"
# 把函数结果加入对话历史
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response
})
第四步:把结果返回给模型,生成最终回答
second_response = client.chat.completions.create(
model=“gpt-4o”,
messages=messages
)
print(second_response.choices[0].message.content)
这样就完成了一次完整的函数调用流程。
五、多函数场景
实际项目中通常不止一个函数,我们来看看多函数的情况:
tools = [
{
“type”: “function”,
“function”: {
“name”: “get_weather”,
“description”: “获取指定城市的天气信息”,
“parameters”: {
“type”: “object”,
“properties”: {
“city”: {“type”: “string”, “description”: “城市名称”},
“date”: {“type”: “string”, “description”: “日期,YYYY-MM-DD”}
},
“required”: [“city”]
}
}
},
{
“type”: “function”,
“function”: {
“name”: “calculator”,
“description”: “执行数学计算,支持加减乘除和复杂表达式”,
“parameters”: {
“type”: “object”,
“properties”: {
“expression”: {“type”: “string”, “description”: “数学表达式,如 ‘123 * 456’”}
},
“required”: [“expression”]
}
}
},
{
“type”: “function”,
“function”: {
“name”: “search_news”,
“description”: “搜索最新新闻”,
“parameters”: {
“type”: “object”,
“properties”: {
“keyword”: {“type”: “string”, “description”: “搜索关键词”},
“count”: {“type”: “integer”, “description”: “返回结果数量,默认5”}
},
“required”: [“keyword”]
}
}
}
]
模型会根据用户的问题,智能选择最合适的函数。比如:
- “北京天气” → 调用 get_weather
- “12345 * 67890 等于多少” → 调用 calculator
- “今天有什么科技新闻” → 调用 search_news
经验分享:函数数量建议控制在 5-10 个以内。给的函数太多,模型容易混淆,选错函数的概率会增加。如果函数很多,建议先做一层分类,或者用 RAG 检索相关函数。
六、多模型对比实测
用聚合平台的好处就是切换模型方便。我分别用 GPT-4o 和 Claude 3.5 Sonnet 做了几个测试场景:
测试 1:简单函数调用
问题:“北京今天天气怎么样?”
模型
结果
GPT-4o
✅ 正确调用 get_weather,参数 city=北京
Claude 3.5 Sonnet
✅ 正确调用 get_weather,参数 city=北京
测试 2:多参数提取
问题:“帮我查一下 2024 年 1 月 20 号上海的天气”
模型
结果
GPT-4o
✅ 正确提取 city=上海, date=2024-01-20
Claude 3.5 Sonnet
✅ 正确提取 city=上海, date=2024-01-20
测试 3:多函数选择
问题:“帮我算一下 12345 * 67890 等于多少”
模型
结果
GPT-4o
✅ 正确选择 calculator 函数
Claude 3.5 Sonnet
✅ 正确选择 calculator 函数
测试 4:不需要调用的情况
问题:“你好,介绍一下你自己”
模型
结果
GPT-4o
✅ 直接回答,没有调用函数
Claude 3.5 Sonnet
✅ 直接回答,没有调用函数
测试 5:复杂推理 + 多轮调用
问题:“北京今天天气怎么样?如果下雨的话,帮我推荐几个室内活动”
模型
结果
GPT-4o
✅ 先调用天气,再根据结果推荐
Claude 3.5 Sonnet
✅ 先调用天气,再根据结果推荐
测试 6:参数格式校验
问题:“查一下 2024/1/15 北京天气”(日期格式不标准)
模型
结果
GPT-4o
✅ 自动转换为 YYYY-MM-DD 格式
Claude 3.5 Sonnet
✅ 自动转换为 YYYY-MM-DD 格式
结论:两个模型在 Function Calling 方面表现都很不错,基础场景完全够用。GPT-4o 在复杂场景下稍微稳定一些,Claude 3.5 Sonnet 也完全能满足大多数需求。大家可以根据价格和场景选择。
七、最佳实践
分享一些实际项目中总结的经验:
7.1 函数设计
- 函数名要清晰:见名知意,不要用缩写
- description 要详细:说清楚"做什么的、什么时候用、什么时候不用"
- 参数要明确:每个参数都要有 description,枚举值要列出来
- 返回值要结构化:尽量返回 JSON 或结构化数据,方便模型理解
7.2 错误处理 - 参数校验:不要完全信任模型传的参数,一定要做校验
- 异常捕获:函数执行可能失败,要做好异常处理
- 友好的错误信息:函数失败时返回清晰的错误描述,方便模型理解和重试
- 超时控制:给函数调用设置超时时间,避免卡住
7.3 性能优化 - 并行调用:如果多个函数之间没有依赖,可以并行执行
- 缓存结果:相同参数的调用可以缓存,减少重复计算
- 控制函数数量:不要一次给太多函数,影响模型判断准确率
- 流式输出:支持流式的话,用户体验更好
八、常见问题
Q: 模型会乱调用函数吗?
A: 一般不会,但偶尔会有。建议做好参数校验和异常处理,并且设置合理的函数描述,减少误调用概率。
Q: 支持同时调用多个函数吗?
A: 支持,GPT-4o 等模型支持 parallel tool calls,可以一次返回多个函数调用。
Q: 函数调用算 token 吗?
A: 算的,函数定义和参数都会算输入 token。所以函数描述尽量简洁但准确。
Q: 怎么调试 Function Calling?
A: 建议把每一步的输入输出都打日志,方便排查问题。也可以用平台的调试工具。
九、总结
Function Calling 是大模型从"能聊天"到"能做事"的关键一步,掌握它能让你的 AI 应用能力提升一个档次。
核心要点: - 理解原理:模型判断 → 执行函数 → 返回结果 → 生成回答
- 函数设计要清晰:好的描述是成功的一半
- 做好错误处理:不要完全信任模型的输出
- 多模型对比:不同模型各有优劣,根据场景选择
如果你需要做多模型对比测试,建议用 OpenAI 兼容的聚合平台,切换模型只改一行代码,测试效率高很多。我用的 97AIPRO 还不错,支持支付宝充值,国内访问也稳定,大家可以试试。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)