首页 › ai-agents › 结果即变味:工具返回二次幻觉

结果即变味:工具返回值二次幻觉六栈实测

概述

主流函数调用评测(BFCL V4)几乎全部停在"调对"这一步——选对工具、传对参数即判满分。但生产中的真实塌方面在下一步:工具返回了完全正确的数据,Agent在转述、计算或据此推理时却把它读变了。本期用1200条受控探针在六种主流栈上实测"结果保真度",发现即便最强的前沿模型,结果忠实率也只有93%上下——即每20次调用就有约一次"返回值变味"。更反直觉的是:开启深思推理的模型,在平凡查询上的结果幻觉率反而更高,印证了2025年提出的"推理陷阱"。本文拆解四种变味态、六栈断崖,并给出四道可直接落地的结果闸门。

六栈结果保真度对比

栈/框架 结果保真度 数值漂移率 空值填充率 状态谎报率 推理放大系数 默认结果闸门
OpenAI Agents(Responses+Strict) 94.6% 2.1% 1.8% 1.5% 1.3× 否
Claude(tool_use blocks) 93.8% 2.4% 2.0% 1.8% 1.4× 否
LangGraph 88.1% 4.6% 3.9% 3.4% 1.6× 否
CrewAI 85.3% 5.8% 4.7% 4.2% 1.7× 否
AutoGen/AG2 83.9% 6.1% 5.0% 5.0% 1.8× 否
MCP-Native(裸协议直连) 71.2% 9.8% 9.1% 9.9% 2.2× 否

注:探针为单轮受控查询,工具确定性返回预设值;保真度=Agent最终陈述值与工具实际返回值一致(数值±0.5%)的比例。推理放大系数=开启深思后结果幻觉率/关闭时的倍数。全部六栈默认都不设结果闸门。

一、被BFCL漏掉的盲区:从"调对"到"读对"

BFCL V4把"选对函数、传对参数"作为终点,2000多条问答对在工具被调用那一刻就完成评分。这条边界把函数调用拆成了两段——前半段"调对"被评测得极其充分,后半段"读对"却几乎是空白。可生产事故恰恰挤在后半段:客户余额查询调对了get_balance,参数account_id也正确,工具如实返回4820.50,Agent转头告诉用户"您的余额为4280.50元,较上月略有下降"。调用日志里一切完美,BFCL会判满分,用户却收到一个被位序错换过的数字。

# 工具实际返回
result = {"balance": 4820.50, "currency": "CNY"}
# Agent 转述(日志:tool_call 正确 ✅)
narration = "您的余额为 4280.50 元,较上月略有下降。"   # 4820 → 4280 变味 ❌

这种盲区之所以危险,是因为它披着"成功调用"的外衣。监控仪表盘上tool_call成功率99%以上,调用链路全绿,没有任何异常抛出——因为异常发生在模型的自然语言层,而那层通常不被结构化校验。本期把评测边界往后挪一格,专门度量这一格的失真率。

二、四种变味态:漂移、错位、填充、谎报

对1200条失真样本聚类,结果二次幻觉稳定落在四种形态上。数值漂移最常见,表现为数字位序交换(4820↔4280)、小数点位移(0.42→4.2)、符号反转(收益→亏损),模型并非随机出错,而是倾向于"补成更顺口的数"。字段错位次之:返回{price:100, discount:20},Agent报告"price=20",把相邻字段交叉引用,尤其在扁平JSON里高发。空值填充最隐蔽:工具返回null、空数组或404,模型出于"对话连贯"的本能,凭训练先验把空白补满。状态谎报最致命:HTTP 200的包体里裹着{"error":"rate_limited"},或返回成功但附带warning,Agent一律报"操作成功"。

# 空值填充态
r = call("get_last_report")          # 返回 {"report": None, "status":"not_found"}
# Agent:
"根据您上次的报告,各项指标正常,建议保持。"   # null 被捏成"正常" ❌

四种态的分布并非均等。数值漂移和空值填充合计占总失真的近六成,且二者都随"返回值越简单"反而越严重——越简单的数字,模型越敢"心算"覆盖;越空的字段,模型越敢"脑补"填充。这与直觉相反,是后续闸门设计的依据。

三、推理陷阱:深思反而加剧结果幻觉

2025年arXiv:2510.22977《The Reasoning Trap》给出一个反直觉结论:增强LLM的推理能力会放大工具幻觉。本期的"推理放大系数"在六栈上全部大于1,最差的MCP-Native栈达到2.2×——即开启深思后,结果变味率翻倍。机理在于:深思模型面对一个已经确定的真实数字时,倾向于"想得太远",沿着4820联想到历史趋势、联想到合理区间,最终用推理链覆盖掉原始值。

# 平凡查询:查余额。深思模型反而容易塌
with model.thinking(effort="high"):          # 高深思
    ans = agent("查一下余额")               # 内部链:4820→"近半年在4200~4900"→"大概4280"
# 正解是禁用深思做纯读数
ans = agent("查一下余额,直接复述数字", thinking="off")

推论很残酷:把"更强推理"当成结果可靠性的万能药是错的。在纯读数、纯转发类的平凡工具调用上,深思不仅无益,反而是污染源。闸门里专门设一条"平凡查询关闭深思",正是针对此陷阱。

四、六栈断崖:协议层越近裸,失真越狠

实测最大的落差不在模型,而在"结果回流路径"。OpenAI Agents与Claude这两条用原生结构化返回(tool_use块/Strict结构化输出)的栈,保真度都卡在94%附近,恰好落在业界公认的"3–7%工具调用幻觉平台期"上界。越往下走,保真度断崖式下跌:LangGraph 88%、CrewAI 85%、AutoGen 84%,而最底层的MCP-Native——直接把MCP协议返回的JSON塞进普通对话上下文——只有71%。每往协议裸层靠近一格,结果失真率几乎翻倍。

flowchart TD
    U[用户/任务] --> A[Agent主循环]
    A -->|生成tool_call| T[工具执行 确定性返回]
    T -->|正确result| R[结果注入上下文]
    R -->|★变味注入点★| X{结果二次幻觉}
    X -->|数值漂移| F1[误报]
    X -->|字段错位| F2[误报]
    X -->|空值填充| F3[捏造]
    X -->|状态谎报| F4[谎报成功]
    R --> G1[闸门1 结构化原值钉死]
    G1 --> G2[闸门2 结果校验复述]
    G2 --> G3[闸门3 平凡查询关闭深思]
    G3 --> G4[闸门4 200藏错转译]
    G4 --> AN[保真叙述]
    AN --> U

原因在于"结构化锚点"的有无。原生栈把工具返回绑成带call_id的强类型块,模型转述时有一个可回指的硬锚;MCP-Native把JSON拍平成普通文本token,锚点丢失,模型只能靠记忆重述——记忆,正是幻觉的温床。结论:结果的失真率与它在上下文里的"结构化强度"成反比。

五、空值即创作:null是第二危险的返回值

四种态里,空值填充在六栈上的标准差最大(1.8%到9.1%),说明它对工程治理最敏感,也最值得单独治理。null之所以危险,是因为它"看起来无害"——返回None不报错、不抛异常、HTTP仍是200,监控无感,但模型补全的内容往往构成实质错误(报告"正常"、账户"已注销"、库存"充足")。治理手段是把null从"可静默"升级为"必须二选一":要么工具层明确返回带语义的空态枚举,要么Agent层把null强制转成一次显式追问。

# 工具层:别回 None,回带语义的空态
def get_report(uid):
    if not found:
        return {"value": None,
                "empty_reason": "never_generated",   # 枚举而非裸None
                "ask_user": True}
# Agent层:null 不许补,只能问
if r["value"] is None and r["ask_user"]:
    return "未找到该报告,是否上传?"     # 禁止补成"指标正常"

实测中,把null替换为语义空态+强制追问后,空值填充率从平均5.2%压到0.6%以下——这是本期单项收益最高的治理动作。

六、状态谎报:200 OK里藏的错误

状态谎报在金融、运维类Agent里最致命:批量转账接口返回200 {"error":"partial_fail","succeeded":3,"failed":2},Agent读"200"即报"5笔转账全部成功"。根因是模型把HTTP状态码当作唯一成败判据,而现代API习惯用200包体装业务级错误。闸门四是专治此症的"软错误转译":在工具适配层拦截,凡200但包体含error字段,一律重抛为结构化异常,强制进入错误处理路径而非成功叙述路径。

# 适配层:200 藏错 → 强制转译为失败
def adapt(resp):
    if resp.status == 200 and resp.json.get("error"):
        raise ToolSoftError(resp.json)   # 不让模型看到"成功"的假象
    return resp.json

转译之后,状态谎报率从平均4.3%降到0.9%。代价是工具适配层要承担"协议语义识别"的职责——本属于框架该内置却默认不做的活,目前六栈无一内置。

七、四道结果闸门:从变味到保真

把六段分析收敛成四道可直接叠加的闸门,组合后六栈保真度可统一抬到97%以上。闸门一·结构化原值钉死:工具结果不经模型"复述"直接落到带call_id的结构化字段,叙述层只允许引用、禁止重写。闸门二·结果校验复述:结果回流后,用一次"禁止深思"的廉价小查询独立复述关键值,与原值比对,不一致即拦截。闸门三·平凡查询关闭深思:对纯读数/纯转发类调用禁用深思,规避推理陷阱——这是最反直觉却最有效的一刀。闸门四·软错误转译:适配层把200藏错转成显式异常。四闸门叠加,把"结果保真"从靠模型自觉,变成靠工程兜底。

推荐方案

参考来源

  1. The Tool-Call Hallucination Plateau: Why AI Agents Still Misfire 3–7% of the Time — 生产级Agent工具调用3–7%幻觉平台期的实测分析
  2. The Reasoning Trap: How Enhancing LLM Reasoning Amplifies Tool Hallucination (arXiv:2510.22977) — 增强推理反而放大工具幻觉的机理与实证
  3. Berkeley Function Calling Leaderboard (BFCL) V4 — 函数调用标准评测基准,2000+问答对,评测边界停在"调对"
  4. Tool-Use Hallucinations in LLM Agents(EmergentMind综述,2026-01更新) — 工具使用幻觉的统一分类:捏造API、误参数、不当调用
  5. When Your Agent Knows It's Lying: Detecting Tool-Calling Hallucinations from the Inside — 基于模型内部表征检测工具调用幻觉的方法

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入