ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Claude Code是如何彻底解决大模型工具调用的幻觉问题?

2026/9/2 9:10:27 拓冰建站 浏览量
Claude Code是如何彻底解决大模型工具调用的幻觉问题? 随着Claude code源码被逆向我们可以更好的借鉴这个产品优秀的设计思路来解决我们开发agent的各种问题。不管大语言模型LLM有多聪明它们本质上是“文字接龙”的高手。当它们被赋予了使用工具的操作权限比如读写文件、运行命令时常常会犯一些让人头疼的毛病也就是所谓的“幻觉”比如捏造工具调用了一个根本不存在的工具。胡填参数少传了必填参数或者把数字填成了字符串。急于作答还没确认工具是否执行成功就自信满满地说“我已经搞定了”。健忘症丢失上下文前面执行过的工具结果聊着聊着就忘了。claude-code项目作为一个强大的 Agent智能体为了解决这些问题在架构设计上花了很多心思。简单来说项目并没有指望大模型“不犯错”或者“变聪明”而是搭建了一套“发现错误 - 结构化报错 - 引导模型自己修正”的闭环防御系统。下面我们结合代码用通俗易懂的方式来拆解这套机制。一、核心原理工具调用是怎么跑起来的首先在claude-code中大模型和本地工具库是怎么沟通的呢请看下面的流程图核心对话循环1. 组装提示词和系统设定2. 模型说需要用工具: tool_use3. 验证并运行工具4. 告诉模型执行结果: tool_result模型输出回答文本用户输入查询引擎 Query Engine核心调度循环 Query Loop调用大模型 API工具执行器 StreamingToolExecutor具体工具如 文件编辑、执行命令这里面的核心机制在src/query.ts中的queryLoop查询循环。这个循环是一个while(true)死循环把以前的聊天记录、可用的工具列表打包发给大模型。大模型如果不确定答案就会回复一个特殊指令{type: tool_use, name: 读文件, input: {...}}我需要用工具。本地代码拦截到这个指令去执行真正的动作。本地代码把执行结果打包成{type: tool_result, content: 文件内容是...}再次发给大模型。大模型看到结果后再决定是继续用其他工具还是给出最终回答。二、怎样防止大模型产生“幻觉”十层防弹衣为了防止模型“胡作非为”claude-code在每个关键环节都安检相当于给系统穿了“十层防弹衣”。 1防“胡言乱语”系统提示词约束在项目启动时src/constants/prompts.ts代码会给大模型发一段非常严格的“纪律要求”要求严谨“在没看懂代码前不要乱提修改建议。”要求诚实“如实报告结果如果测试失败了就说失败千万别说谎掩盖。没运行过的事情就直说别暗示你成功了。”这是从心理学层面Prompt 工程预防它产生幻觉。 2防“凭空捏造”不存在的工具检测有时候模型会自己“发明”一个工具并尝试调用。面对这种情况代码没有崩溃见src/services/tools/toolExecution.ts。它会拦截“等一下你用的这个工具的名字不存在”然后系统会把这个错误信息当做一次工具执行结果反馈给模型[错误没有找到你调用的这个工具请看下现有的工具列表重新选择]模型收到这个错误后一般会自己“哦不好意思应该是用 XXX 吧”然后自动修正。 3防“张冠李戴”Zod 参数严格校验找到了对的工具但模型乱填参数怎么办比如本该填数组的地方它传了字符串。claude-code所有的工具定义都使用了Zod一个很强大的类型校验库。在执行工具前Zod 会先扫一眼参数校验失败立刻终止并生成一份清晰的错误报告比如“参数file_path是必填的但你没填”扔给模型让它重发。这也保证了真正的工具逻辑代码永远拿到的都是安全的、格式绝对正确的数据。 4防“纸上谈兵”业务逻辑深度验证参数格式对了就一定安全吗不一定。每个工具自己还有一个validateInput函数进行深度体检比如在FileEditTool文件编辑工具中你要修改的文件实际上存在吗文件会不会太大超过 1GB把内存撑爆你是不是试图在没读取过这个文件的情况下就要盲写修改它如果有以上问题同样会报错打回让模型重新走正规流程。 5防“看太多眼花”ToolSearch 延迟加载法大模型有两点不好一是读的内容太多会分心二是内容太多很贵烧钱。项目里有 50 多种内部工具和外部工具。如果一开始就把所有工具的详细说明书塞给大模型它很容易晕甚至产生幻觉乱用。所以通过ToolSearchTool实现了**“延迟加载”**一开始只告诉模型有这些工具的“名字”但不教它怎么用隐藏具体参数要求。当模型想用某个复杂工具时它发现自己不知道参数它就得先用ToolSearch这个工具去查目标工具的说明书。查完学会了再回过头去调用真实工具。这个妙招不仅省钱还大大降低了模型混淆工具参数引发的幻觉问题。 6防“做事有头无尾”强制 result 协议闭合底层 API 规定模型只要发出了tool_use工具调用请求客户端就必须必须给它反馈tool_result工具执行结果。如果遇到网络突然断开、或者用户强行按CtrlC中断了代码那模型岂不是在苦苦等待结果代码里有一个专门收尾的医生yieldMissingToolResultBlocks如果遇到意外医生会挨个给刚才没执行完的工具补一张死亡证明[系统错误用户中断了]发送给模型。这样永远保证了对话系统的连续性。 7防“滔滔不绝被斩断”输出截断自动恢复大模型每次说话的字数是有上限的比如 8000 个 Token。如果模型写代码写到一半被系统强行掐断达到上限max_output_tokens错误就会引发严重的上下文错乱。claude-code很聪明它并不会把这个错误抛给用户而是偷偷瞒着用户向模型发一条紧急消息“你刚才的输出达到了字数上限被截断了不要道歉不要总结直接从上一句话断掉的地方接上继续说。”系统最多会自动抢救 3 次完美解决模型长回答中断的 Bug。 8防“自我感觉良好”Stop Hooks 后验检查解决“急于作答 (Premature Answer)”的终极武器叫Stop Hooks。大模型有时候改了一行代码觉得没问题了就准备对用户说“我完成任务了”。此时Stop Hooks发挥作用。系统在模型报告完成之前会自动运行一堆检查脚本比如项目自动编译跑一遍、单元测试跑一遍。只有测试通过了模型才能真正对用户撒花。如果测试报错了Blocking Errors报错信息会被硬塞回给大模型“别急着走你写的代码跑不通附上报错赶紧再改改” 9防“左手打右手”并发安全分区模型聪明的时候会一次性发好几个工具调用的请求。但是不同的工具能不能一起跑读数据只读随便并行大家互不干涉。写数据/删文件不能并行万一 A 工具刚写进去的内容被 B 工具删了呢。系统通过isConcurrencySafe()标记把工具进行分类。一旦发现冲突就老老实实排队串行执行避免因并发导致的系统状态混乱这种混乱反馈给模型会让它彻底抓狂。 10防“遗忘”历史自动压缩对话越长前面发生的事情模型越容易忘遗忘型幻觉。系统包含一套超轻量的自动记忆压缩机制 (autocompact)。当历史字数超过安全阈值时程序会将前面的旧聊天“折叠”成一句话摘要并清除掉旧的、没必要长久记忆的冗长工具结果内容。配合提示词“请随时总结你看到的重要信息因为原本的冗长日志可能会被清除”引导模型养成做短笔记的好习惯。三、这个“死循环”是如何退出的虽然核心的queryLoop是一个while(true)的“死循环”但它并不是真正的无限执行下去。它有几个精确设计的“退出通道”当检测到以下 5 种情况时循环就会终止并把控制权交还给用户1. 自然退出大模型觉得“办完了”正常流程每次大模型回复后程序都会检查模型本次有没有生成调用工具的代码块如果没有调用工具意味着模型分析发现它已经收集到了足够的信息开始用“纯文本”直接给出最终的答案了。代码中有一个标志位needsFollowUp会变成false。循环检测到之后运行结算逻辑如 Stop Hooks 检查然后通过return { reason: completed }完美谢幕。2. 人工阻断式退出用户的 CtrlC如果大模型在使用工具时“一意孤行”或者调用耗时太久用户按下了ESC或CtrlC。底层的AbortController就会发出中断信号。系统捕获后会停止所有请求给模型留下一句“被用户强制中断”的记录并通过return { reason: aborted_streaming }紧急抛出退出。3. 被“督导”拦下式退出Stop Hooks 的一票否决权即使模型自己觉得完成了触发了后验检查脚本Stop Hooks。如果测试脚本报错且某个特定的高级 Hook 认为“这个任务偏离了方向已经无法挽回”它可以发出一个特殊信号preventContinuation: true。系统看到这个信号后就会认输通过return { reason: stop_hook_prevented }强行退出并告知用户。4. 彻底崩坏的边缘退出达到 Token 的物理极限即便有自动抢救功能截断自动接力、聊天历史压缩等抢救也是有极限的输出超限如果模型连续 3 次被截断且没能把话接下去。输入框爆满如果上下文怎么压缩都还是超过最高承载量Prompt Too Long导致彻底发不出去请求。这个时候系统只能无奈地通过return { reason: prompt_too_long }或image_error报错退出。5. 钱烧完了系统强杀退出预算耗尽为了防止进入死胡同导致疯狂调用 API 产生巨额账单系统会统计这一轮循环消耗的Token 预算 (task_budget)。如果消耗达到了预设的安全阈值循环机制也会被强行掐断输出提示“Token 预算使用达到上限”后退出。一句话总结只要大模型还在要求“我要用工具”、只要任务预算充裕、且测试没有通过这个死循环就会一直自动转下去帮你打工直到它真正得出了答案闭嘴、被人为叫停、或是把所有容错方法都试完后循环才会终止。四、最终总结看完以上机制总结一下claude-code防止 LLM 乱来的核心哲学“不相信模型拥抱失败构建反馈闭环。” (Fail-closed with feedback)它假设大模型就是一个“虽然聪明但毛手毛脚的员工”。系统不祈祷员工永远不犯错而是建立了一套极其完善的规章制度Schema校验并在员工犯错的每一种可能性记不住、乱写、瞎猜、做到一半跑路上都安装了监控和引导只要你犯错系统就会拦截并且把错误原因翻译成员工听得懂的话报错反馈丢给你让你自己修。这套体系保障了claude-code在实际应用中无比强大和稳定。