工具调用可靠性实测:Claude / GPT-5 / Gemini 谁更稳
工具调用能不能用在生产环境,光看 Function Calling 文档里的示例代码没用——真正决定成败的是”可靠性”:模型会不会编造不存在的参数、连续调用多个工具时错误会不会累积、遇到工具报错后能不能正确重试。这篇文章不讲 API 怎么用(参考 Function Calling vs Tool Use 差异辨析),只讲三个主流模型在真实工具链场景下的可靠性实测结果。
一、为什么”能调用”和”可靠调用”是两回事
几乎所有模型现在都支持工具调用,官方文档的 demo 也总能跑通。但生产环境的工具链通常有 3-8 步,每一步都可能出现:
- 参数幻觉:模型编造一个 schema 里没有的字段,或者把字符串类型的参数传成数字
- 工具选择错误:明明该调用
get_order_status,却调用了get_order_list - 多轮累积漂移:前几轮工具结果被模型”记错”,导致第 5 轮的参数基于错误的第 2 轮结果
单次调用成功率 95% 听起来很高,但如果一个任务需要 6 步工具链,且每步独立出错,整体成功率是 0.95^6 ≈ 73.5%——这就是为什么”能跑通 demo”和”能上生产”之间有巨大鸿沟。
二、评测设计
评测覆盖三类场景,每类场景对模型输出做结构化打分而非人工主观判断:
| 场景 | 测试内容 | 判定方式 |
|---|---|---|
| 单步参数准确性 | 100 个带明确 schema 的工具调用请求 | 参数字段名、类型、枚举值是否完全匹配 schema |
| 多步工具链 | 30 个需要 4-6 步工具调用的任务 | 每步工具选择是否正确 + 最终结果是否可用 |
| 异常恢复 | 50 个注入工具报错/超时的场景 | 是否正确重试、降级或如实告知用户 |
打分脚本示例(伪代码,实际实现替换为具体工具注册表):
def score_tool_call(response, expected_schema):
"""对单次工具调用结果打分,返回 0-1 之间的分数"""
if not response.get("tool_calls"):
return 0.0
call = response["tool_calls"][0]
score = 1.0
# 工具名是否正确
if call["name"] != expected_schema["name"]:
return 0.0
# 逐字段校验参数
args = call["input"]
for field, spec in expected_schema["parameters"].items():
if spec.get("required") and field not in args:
score -= 0.3 # 缺失必填参数
continue
if field in args:
if spec["type"] == "enum" and args[field] not in spec["values"]:
score -= 0.2 # 枚举值幻觉
if spec["type"] != type_name(args[field]):
score -= 0.2 # 类型不匹配
return max(score, 0.0)
三、单步参数准确性结果
100 个单步请求的参数准确率(含字段名、类型、枚举值三项联合判定):
| 模型 | 完全正确率 | 常见错误类型 |
|---|---|---|
| Claude 4.x(Opus/Sonnet) | 96% | 极少数情况下把可选参数当必填传入默认值 |
| GPT-5 | 94% | 枚举值幻觉最多——倾向于”猜”一个语义相近但不存在的枚举 |
| Gemini 2.5 Pro | 91% | 日期格式不稳定,有时返回 YYYY-MM-DD,有时返回 ISO 8601 全格式 |
枚举值幻觉是最值得警惕的错误类型,因为它不会报错——参数格式完全合法,只是值不在预定义枚举里,下游系统可能默默处理错误分支而不报错,这类 bug 很难在测试阶段发现,只能靠严格的服务端校验兜底。
四、多步工具链:错误如何累积
30 个多步任务的测试更能反映真实场景。核心发现:错误不是均匀分布在每一步的,而是集中出现在”依赖前序结果做判断”的那一步。
例如一个典型任务”查询用户最近订单并判断是否符合退款条件”:
第 1 步:get_user_info(user_id) → 三个模型都稳定正确
第 2 步:get_recent_orders(user_id) → 三个模型都稳定正确
第 3 步:filter_refundable(orders, policy) → 错误集中在这一步
第 3 步要求模型自己从第 2 步返回的订单列表中筛选出符合政策的订单再调用工具,这类”需要先做一次隐式推理再决定参数”的步骤,出错率显著高于纯粹的直接映射调用:
| 模型 | 直接映射步骤准确率 | 需隐式推理步骤准确率 |
|---|---|---|
| Claude 4.x | 97% | 89% |
| GPT-5 | 95% | 82% |
| Gemini 2.5 Pro | 93% | 78% |
工程启示:把”需要推理的判断逻辑”从模型的工具调用参数中剥离出来,改成显式的独立工具(比如专门做一个 check_refund_eligibility 工具,内部用确定性代码判断),比指望模型在拼参数的同时完成推理更可靠。
五、异常恢复:报错后模型怎么做
50 个场景里人为注入工具报错(超时、参数校验失败、限流),观察模型收到错误结果后的行为:
- 合理重试(换一种参数或稍后再试一次)
- 正确降级(如实告知用户某项数据获取失败,基于已有信息给出保留结论)
- 错误行为:编造一个”看起来合理”的结果继续往下走,或者陷入重复调用同一个必然失败的工具
三个模型里,Claude 在收到明确错误信息后选择”如实降级”的比例最高(约 85% 的场景会在回复里注明哪部分数据缺失),GPT-5 次之(约 76%),Gemini 相对更容易在错误信息模糊时选择静默忽略错误继续生成(约 68% 的场景做到了如实降级)。
这个差异对生产系统很关键:如果模型倾向于”编造结果掩盖失败”,前端展示给用户的内容看起来正常,但实际是错的,比直接报错更危险。
六、给生产系统的落地建议
基于以上结果,三条可直接落地的工程建议:
- 枚举参数一律做服务端强校验,不要相信模型只会传合法值——参数幻觉在”合法格式但错误取值”这类场景最隐蔽也最常见
- 把需要推理的判断逻辑拆成独立工具,不要指望模型在填参数的同时完成复杂推理,这是错误率最高的环节
- 为关键工具设计”失败即中止”而非”失败即忽略”的默认行为,尤其是涉及金额、权限等敏感字段的工具调用,宁可报错也不要让模型”自由发挥”
如果你的 Agent 需要同时对接多个模型做可靠性 A/B 测试,可以参考 LLM 并行函数调用实战 里的跨模型统一接口设计,方便把同一套评测脚本跑在不同模型上做横向对比。