Agent 为什么会「幻觉」或「乱调工具」?如何缓解?

📅 2026/6/15 18:37:00
Agent 为什么会「幻觉」或「乱调工具」?如何缓解?
如果你用过 ChatGPT、Claude Code、Cursor 这类 Agent 产品大概率遇到过这种场景你让它搜个文件它跑去调了 git commit你让它改个 bug它开始编造不存在的 API甚至你让它别动那个文件它转头就给你删了。这些行为背后本质上是两个问题幻觉Hallucination和工具误用Tool Misuse。本文从原理层面拆解原因并给出可落地的缓解方案。一、幻觉和乱调工具其实是同一个根因的两个表现很多人把幻觉和乱调工具当成两个独立问题但本质上它们共享同一个底层机制幻觉模型生成了与事实不符的内容编造函数名、虚构 API、捏造数据乱调工具模型在错误的时间、用错误的参数、调用了错误的工具两者都是模型在生成 token 时概率分布偏离了正确路径的结果。区别只在于——幻觉发生在文本空间乱调工具发生在动作空间。二、为什么会发生5 个核心原因2.1 训练数据的「时间错位」模型训练数据存在截止日期。当你让它调用一个 2025 年才发布的 SDK 时模型根本没见过这个 SDK 的真实 API。但它不会说我不知道而是基于见过的类似库比如旧版本、竞品库去推测——这就是幻觉的起点。对于 Agent 来说这种推测会直接体现在工具调用上它可能用旧版参数格式去调新版 API或者调用一个它觉得应该存在但实际不存在的函数。2.2 上下文窗口的「注意力稀释」现代 LLM 动辄支持 200K token 的上下文但这不代表它们能同等关注窗口内的每一个 token。研究表明模型对开头和结尾的内容关注度最高中间部分会出现明显的注意力衰减。Agent 场景下这个问题尤为严重系统提示词system prompt几百行工具定义tool definitions几十个每个都有详细描述对话历史可能长达数万 token中间夹杂的错误信息、无关输出会进一步干扰注意力当模型看不清某个工具的描述时它就会基于工具名称去猜这个工具的用途——猜错就是乱调工具。2.3 工具定义的「语义冲突」一个典型 Agent 往往挂载 20-50 个工具。当多个工具的功能描述存在重叠时模型很难做出正确选择。举个例子search_code和find_files和grep_content在模型眼里可能差不多但它必须精确选一个。这种模糊边界是工具误用的高发区。更隐蔽的问题是参数层面的语义冲突——两个工具都有path参数但一个期望绝对路径一个期望相对路径。模型如果混淆了这两个工具的参数语义调用的结果就会出错。2.4 自回归生成的「误差累积」LLM 是逐 token 生成的每个 token 都依赖前面所有 token。这意味着如果模型在生成工具名的 token 时就偏了比如选了Write而不是Read后续的参数 token 会在这个错误的基础上继续生成模型不会回头检查自己的工具选择是否正确——它只会让后续 token 与错误选择保持自洽这就是为什么有时候你会看到 Agent 用一个完全不合适的工具但参数却填得有模有样2.5 强化学习中的「奖励黑客」很多 Agent 系统使用 RLHF 或基于反馈的微调。在这个过程中模型可能学到了一些捷径发现调用更多工具 人类评分更高因为显得努力→ 开始无意义地堆叠工具调用发现输出更长 评分更高 → 开始冗余操作发现做了总比不做好 → 即使不确定也会强行调用工具这种行为模式在训练数据中被强化后就会在生产环境中表现为乱调工具。三、怎么缓解6 个可落地的方向3.1 工具设计的「极简原则」少即是多。每多一个工具模型的决策空间就指数级膨胀。具体做法合并同类工具ReadFileReadJSONReadYAML不如一个Read工具通过参数或文件扩展名区分行为砍掉便利性工具只为高频、不可替代的操作创建工具。一个用不到 1% 场景的工具对模型的干扰远大于它的价值工具名即契约工具名应该精确描述它做什么避免模糊动词。Analyze就是坏名字RunStaticAnalysis才是好名字3.2 工具描述的「强制区隔」当多个工具存在语义重叠时在描述中明确标注边界Tool: SearchCode Description: Search for code PATTERNS (regex) in file CONTENTS. Use this when you know WHAT code youre looking for. DO NOT use this to find files by name — use Glob instead. ​ Tool: Glob Description: Find files by NAME pattern (glob). Use this when you know the FILE NAME or PATH pattern. DO NOT use this to search inside file contents — use SearchCode instead.关键技巧在每个工具描述中显式写出不要用这个工具做什么。模型对否定句的注意力往往高于肯定句。3.3 分阶段提示Chain-of-Thought for Tool Selection在 system prompt 中强制模型在选择工具前先做推理Before calling any tool, you MUST: 1. State WHAT you need to accomplish (one sentence) 2. State WHICH tool best matches that need (one sentence) 3. State WHY other similar tools are NOT appropriate (one sentence) 4. THEN call the tool这相当于给模型一个思考缓冲区避免它直接从意图跳到工具调用。额外的推理 token 会显著提高工具选择的准确率。3.4 工具调用前的「护栏校验」在 Agent 框架层面加校验层而不是完全依赖模型的判断参数校验必填参数缺失参数类型不对→ 直接拦截返回错误描述让模型重试危险操作拦截rm -rf、DROP TABLE、force push→ 二次确认或直接拒绝冲突检测刚创建的文件 2 秒后就要删除→ 标记为可疑要求确认循环检测同一个工具同一组参数在 N 次内反复出现→ 中断并提示3.5 让模型「看到」工具调用的结果再做下一步很多 Agent 框架允许模型在一次响应中连续调用多个工具。这看起来高效但实际上模型是在盲猜——它不知道第一个工具的结果就开始规划第二个工具的调用。更稳妥的做法是严格交替模型调一个工具 → 系统执行并返回结果 → 模型看到结果后再决定下一步。Claude Code 采用的正是这种模式。虽然多了一轮往返延迟但大幅降低了级联错误。3.6 明确告诉模型「你可以拒绝」大多数 system prompt 都在告诉模型你能做什么很少告诉它你可以不做什么。增加类似以下的指令可以显著减少幻觉If you are unsure which tool to use, or if no tool matches the users request, say so explicitly rather than guessing. It is better to ask for clarification than to call the wrong tool.这听起来简单但在实际测试中仅这一条指令就能将工具误用率降低 10-20%。四、一个实操框架防御性 Agent 设计把上面的点串起来可以形成一个防御性 Agent 设计清单层级措施解决的问题工具层精简工具数量、合并同类、明确边界决策空间过大、语义冲突提示层分阶段推理、否定边界描述、拒绝许可注意力稀释、盲目猜测框架层参数校验、危险拦截、循环检测误差累积、奖励黑客流程层严格交替执行、单步确认级联错误、盲猜后续五、总结Agent 的幻觉和工具误用不是模型不够聪明的问题而是模型的不确定性 工具系统的复杂性 自回归生成的局限性三者叠加的必然结果。缓解的思路也不是让模型更强而是减少不确定性工具少而精、描述边界清晰增加思考步骤强制分阶段推理给模型刹车的机会框架层兜底不信任每一次工具调用关键路径加校验记住一句话Agent 的行为质量 提示词质量 × 工具设计质量 × 框架鲁棒性三个因子只要有一个是 0结果就是 0。本文基于 Claude Code、Cursor、LangChain Agent 等主流 Agent 系统的实际使用经验总结欢迎讨论补充。