大模型 Function Calling怎么选?Claude/GPT/Gemini 工具调用避坑指南(2026)
Function Calling(函数调用)是让大模型能够调用外部工具的核心能力,也是开发 AI Agent 的基础。简单说,就是你告诉模型"你有哪些工具可以用",模型根据用户的问题决定调哪个工具、传什么参数。
听起来很简单?实际开发中坑不少。我上周就遇到一个:同一套工具定义,GPT-5.4 调用正常,Claude 4.6 偶尔漏参数,Gemini 2.5 直接把 JSON 搞坏。排查两天发现各家对参数格式的处理逻辑不一样。
这篇文章把三家的 Function Calling 能力做了系统实测,告诉你:该怎么选、怎么用、怎么避坑。
什么是 Function Calling?
先用一个例子说明白。假设你在做一个购物助手,用户说"帮我搜一下 500 块以下的蓝牙耳机"。
没有 Function Calling 的模型:只能回复一段文字,告诉你去哪里搜。
有 Function Calling 的模型:直接输出一个结构化的调用请求:
{
"name": "search_products",
"arguments": {
"query": "蓝牙耳机",
"price_range": { "min": 0, "max": 500 },
"sort_by": "rating"
}
}
你的后端拿到这个 JSON,调用真正的商品搜索 API,把结果返回给模型,模型再组织成自然语言回复用户。
整个流程:用户说话 → 模型决策调哪个工具 → 输出结构化参数 → 后端执行 → 结果返回模型 → 模型回复用户。
工具定义怎么写?
使用 Function Calling 的第一步是定义工具。三家模型都支持 JSON Schema 格式,这里给一个完整的例子:
{
"tools": [
{
"name": "search_products",
"description": "搜索商品信息,支持按类目、价格区间和排序方式筛选",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词,比如'蓝牙耳机'、'机械键盘'"
},
"category": {
"type": "string",
"enum": ["electronics", "clothing", "food"],
"description": "商品类目:electronics=电子产品,clothing=服装,food=食品"
},
"price_range": {
"type": "object",
"description": "价格范围,包含最低价和最高价,单位为人民币元",
"properties": {
"min": { "type": "number", "description": "最低价(元)" },
"max": { "type": "number", "description": "最高价(元)" }
}
},
"sort_by": {
"type": "string",
"enum": ["price", "rating", "sales"],
"description": "排序方式:price=按价格,rating=按评分,sales=按销量"
}
},
"required": ["query"]
}
},
{
"name": "create_order",
"description": "创建订单,需要商品ID、数量和收货地址",
"parameters": {
"type": "object",
"properties": {
"product_id": { "type": "string", "description": "商品唯一ID" },
"quantity": { "type": "integer", "minimum": 1, "description": "购买数量" },
"shipping_address": {
"type": "object",
"description": "收货地址,必须包含城市和街道",
"properties": {
"city": { "type": "string", "description": "城市" },
"street": { "type": "string", "description": "详细街道地址" },
"zip": { "type": "string", "description": "邮编(选填)" }
},
"required": ["city", "street"]
}
},
"required": ["product_id", "quantity", "shipping_address"]
}
},
{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"location": { "type": "string", "description": "城市名称,如'北京'、'上海'" },
"date": { "type": "string", "format": "date", "description": "日期,格式 YYYY-MM-DD" }
},
"required": ["location"]
}
}
]
}
关键技巧:
description写得越详细,模型调用越准确。别只写"价格范围",要写清楚"包含最低价和最高价,单位为人民币元"。这一个改动就能把参数错误率降低 60%+。
三家模型实测对比
我设计了 900 个测试用例,覆盖 6 个维度,每个模型跑 3 轮取平均值。
测试维度说明
| 维度 | 测试什么 | 用例数 | 举例 |
|---|---|---|---|
| 基础调用 | 意图明确,参数齐全 | 200 | “搜索蓝牙耳机” |
| 参数推理 | 用户没说全,模型需要补全 | 200 | “搜便宜的耳机”(没指定类目) |
| 多工具编排 | 一个请求要调多个工具 | 150 | “查北京天气,顺便搜户外外套” |
| 嵌套对象 | 参数里有 object/array | 150 | 带 shipping_address 的订单 |
| 拒绝调用 | 用户意图不匹配任何工具 | 100 | “给我讲个笑话”(不该调工具) |
| 错误恢复 | 工具返回错误后怎么处理 | 100 | 首次调用参数错,能否自行修正 |
结果汇总
| 模型 | 基础调用 | 参数推理 | 多工具编排 | 嵌套对象 | 拒绝调用 | 错误恢复 | 综合得分 |
|---|---|---|---|---|---|---|---|
| Claude Opus 4.6 | 99.5% | 94.2% | 91.3% | 96.7% | 97.0% | 88.3% | 94.5% |
| GPT-5.4 | 99.0% | 96.1% | 93.7% | 91.2% | 95.0% | 92.7% | 94.6% |
| Gemini 2.5 Pro | 98.5% | 90.8% | 86.4% | 84.3% | 93.0% | 85.0% | 89.7% |
结论:Claude 和 GPT 第一梯队,几乎打平但各有偏科。Gemini 简单场景够用,复杂场景差距明显。
各家的坑和解决方案
Claude 4.6:稳但偶尔"懒"
优点:嵌套对象处理最稳(96.7%),拒绝调用最准(不该调的坚决不调)。
坑:tool_choice: "auto" 模式下,约 3% 的情况会在该调工具时选择纯文本回复。多工具场景更容易触发。
解决方案:
# 关键业务流程,强制模型必须调用工具
response = client.messages.create(
model="claude-opus-4-6-20260325",
messages=messages,
tools=tools,
tool_choice={"type": "any"} # 强制调用工具
)
另一个小问题:多工具场景下,Claude 有 8.7% 概率串行调用(先调 A 等结果再调 B),虽然最终结果正确但多一轮交互。加个 system prompt 提示能缓解:
当用户请求涉及多个工具调用且工具之间没有数据依赖时,请并行调用以提高效率。
GPT-5.4:编排强但格式偶尔翻车
优点:多工具编排最强(93.7%),能稳定地并行调用多个工具,参数推理能力也最好。
坑:嵌套 object 参数偶尔被序列化成字符串,概率约 8.8%:
// ❌ 错误输出
{ "price_range": "{\"min\": 100, \"max\": 500}" }
// ✅ 正确应该是
{ "price_range": { "min": 100, "max": 500 } }
解决方案:在 schema 的 description 里显式写明结构(参考上面的工具定义示例),错误率从 8.8% 降到 2.1%。
Gemini 2.5 Pro:便宜但要多写防御代码
坑 1:嵌套对象 15.7% 的 JSON 格式错误(多逗号、少括号)。
坑 2:有时在调用工具之前先输出一段"分析文字",导致解析困难。
解决方案:必须加一个容错解析层:
import json
import re
def safe_parse_arguments(raw_args):
"""处理各种模型输出的参数格式差异"""
if isinstance(raw_args, str):
try:
return json.loads(raw_args)
except json.JSONDecodeError:
# 修复常见格式问题:尾部多余逗号
cleaned = re.sub(r',\s*}', '}', raw_args)
cleaned = re.sub(r',\s*]', ']', cleaned)
return json.loads(cleaned)
return raw_args
选哪个?一张表说清楚
| 你的场景 | 推荐模型 | 原因 |
|---|---|---|
| 客服机器人 | Claude 4.6 | 不该调工具时坚决不调,安全性最高 |
| 数据处理流水线 | GPT-5.4 | 并行调用省时间,编排能力最强 |
| 简单单工具调用 | 三家都行 | 基础调用差距不大,选最便宜的 |
| 参数结构复杂 | Claude 4.6 | 嵌套对象格式正确率最高 |
| 预算有限 | Gemini 2.5 | 单价低,但要算上重试成本 |
实际花了多少钱?
900 个测试用例 × 3 轮的实际消耗:
| 模型 | 总费用 | 含重试的费用 | 重试成本占比 |
|---|---|---|---|
| Claude Opus 4.6 | $41.7 | $43.2 | 3.6% |
| GPT-5.4 | $38.5 | $39.8 | 3.4% |
| Gemini 2.5 Pro | $22.3 | $26.1 | 17.0% |
Gemini 单价最低,但重试成本占比高达 17%——因为格式错误需要重新调用。实际场景如果工具调用频繁,这个差距会更大。
4 个马上能用的优化技巧
1. Schema description 写详细
最简单有效的优化。把所有参数的 description 写清楚,包括类型、单位、示例值。对所有模型都有效。
2. 加错误重试机制
MAX_RETRIES = 2
async def call_with_retry(client, messages, tools):
for attempt in range(MAX_RETRIES + 1):
response = await client.chat(messages, tools=tools)
tool_calls = parse_tool_calls(response)
if validate_tool_calls(tool_calls, tools):
return tool_calls
# 把错误反馈给模型让它修正
messages.append({
"role": "tool",
"content": f"参数格式错误: {get_validation_error(tool_calls)},请修正"
})
raise ToolCallError("重试次数耗尽")
3. 多工具场景加 prompt 提示
规则:
- 工具之间无数据依赖 → 并行调用
- 后一个工具需要前一个结果 → 串行调用并说明原因
4. 统一多模型调用接口
如果你需要在项目中对比或切换不同模型,维护三套 SDK 很麻烦。可以用 API 聚合方案统一 endpoint,比如我测试时用的 ofox,一个地址切换三家模型,省去了分别配置的工作量。代码里只需要改 model 参数:
from openai import OpenAI
client = OpenAI(
api_key="your-key",
base_url="https://api.ofox.ai/v1" # 统一入口
)
# 切换模型只需改这一行
response = client.chat.completions.create(
model="claude-opus-4-6-20260325", # 或 "gpt-5.4" 或 "gemini-2.5-pro"
messages=messages,
tools=tools
)
常见问题
Function Calling 和 Prompt 让模型输出 JSON 有什么区别?
Function Calling 是模型原生支持的结构化输出能力,有专门的训练和优化,格式正确率远高于"请你输出 JSON"。而且 Function Calling 支持 tool_choice 参数控制模型是否必须调用工具,灵活度更高。
工具定义太多会影响性能吗?
会。工具定义会占用 context window,工具越多模型选择越困难。实测超过 15 个工具后准确率开始下降。建议按场景分组,每次只传相关的工具子集。
本地部署的开源模型支持 Function Calling 吗?
部分支持。Qwen2.5(72B+)和 Llama 3.3(70B+)都有 Function Calling 能力,但准确率和商用模型还有差距,尤其是多工具编排和嵌套对象场景。如果是生产环境,建议还是用商用 API。
最后更新:2026-03-25
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)