为什么你的 AI 编码智能体会产生文件路径幻觉
> 当 AI 编码智能体没有仓库的真实地图时,就会编造文件路径。本文说明这为何发生,以及扎根依据如何带来更少的幻觉编辑。
破绽不是一个写错的函数体。而是一次自信满满的编辑,针对一个不存在的文件,或者一个存在但并非实现该行为的文件。
你要求修复会话过期问题。智能体打开了 src/auth/session.ts。这条路径看起来合理。但它也是错的。真正的处理函数在 apps/api/src/middleware/expiry.ts 里,两次重构之前被重命名过。智能体没有对你撒谎。它是用训练先验加上上下文窗口里已经有的内容,补全了一个路径形状的字符串。
这是真实仓库中常见的失败模式。模型会写代码。失误在于选错了写代码的地方。
为什么智能体会编造路径
编码智能体是一个带工具的下一个 token 预测模型。当你说“修一下会话过期”时,它必须先指定一个文件,才能读取或修补任何东西。如果它还没有一张有依据的地图,它就会从以下来源构造一条路径:
- 它在其他仓库里见过的命名约定。
src/auth/session.ts是一种常见形态。 - 已经出现在对话里的文件,那可能是你上周粘贴过的文件,而不是现在真正重要的文件。
- 它碰巧运行过的目录列表,在大型代码树上是不完整的。
- 指令文件。
CLAUDE.md和AGENTS.md告诉智能体该如何表现。它们不是符号、调用方或当前路径的活索引。
这些来源没有一个是今天这个仓库的地图。模型填补空白的方式,和它填补任何空白的方式一样:用一个高概率的延续。这个延续常常看起来像一条真实的路径。有时那个文件确实存在,而且就在正确文件旁边。有时它曾经存在于上个月已合并的一个分支上。有时它从来就不存在。
如果智能体从未搜索过正确的字符串,grep 在这里救不了你。智能体猜了一条路径,然后读了那条路径返回的内容,然后编辑了它。第一个错误的步骤是路径,不是补丁。
读文件也不等于找到正确的文件。Claude Code、Cursor、Codex 以及类似的工具,可以打开你指向的任何东西。问题在于,它们能否在编辑之前,可靠地找到正确的文件、重要的符号、依赖关系、测试,以及影响范围。没有地图的文件访问,依然是从猜测开始的。
错误文件的编辑是一个检索问题
把编造出来的路径当作一次检索失败来处理,而不是当作性格缺陷。
如果智能体在被允许编辑之前必须返回 path/file.ext:line,会发生两件事。第一,你可以打开这条引用,在十秒内拒绝这次工作。第二,智能体必须去查询某个真正了解这棵代码树的东西。
这就是代码库上下文层的工作。仅靠语义搜索是不够的。一个“听起来像会话过期”的片段,依然可能落在一个已废弃的包里。当你知道字符串时,你还需要精确文本;当你知道名字时,你需要符号查找;当你知道形状时,你需要结构化搜索;当你需要调用方和影响范围时,你需要依赖关系图。
Maguyva 就是为兼容 MCP 的编码智能体提供的这一层。它不是编辑器。Claude Code、Cursor、Codex CLI、VS Code、Windsurf 以及其他 MCP 客户端,都留在它们原本的位置。智能体在触碰任何一行代码之前,先查询一张排序过的地图。
这个主张刻意保持谦逊:更少的幻觉编辑。Maguyva 并不会剥夺模型猜测的能力。它改变的是默认的第一步,从“编造一条看似合理的路径”变成“请求排序过、带引用的位置”。
一份有依据的答案是什么样子
对“会话过期在哪里处理”这个问题,一个有用的答案不是一段话。而是一份简短的位置清单:
apps/api/src/middleware/expiry.ts:48- 处理函数apps/web/src/lib/auth-client.ts:112- 调用方apps/api/tests/expiry.test.ts:20- 如果这次改动出错就会失败的测试
你可以打开这些行。如果错了,你就停下。如果对了,智能体就可以编辑。重点在于验证,而不是一句口号。
Maguyva 提供 11 个面向客户的 MCP 工具,涵盖搜索、符号、依赖分析、文件检索、仓库上下文和确定性实用工作流。四种检索模式(语义、结构、图/依赖和文本)融合成排序结果;符号查找是一个独立的 MCP 工具(find_symbol)。有依据的答案会带着文件路径和行号返回,方便你对照眼前的代码树来评判。
文档 描述了最短路径:先免费开始,索引一个你已经了解的仓库,连接客户端,然后问一个你能核实的问题。
一个改变第一次编辑的循环
你不需要一套新的工作流信条。你需要的是在第一次落笔之前多加一步。
- 问一个你已经能评判的问题。“哪段代码处理登录和会话过期”比“修一下认证”更好。
- 要求引用。文件路径和行号,而不是“认证模块”的一段摘要。
- 打开被引用的文件。跟着符号走。确认你即将触碰的依赖关系。
- 只有到那时,才让智能体去打补丁。
如果第二步没有返回任何有用的东西,智能体就没有资格临时编造一条路径。它要么再搜索一次,要么由你来指路。正是这一道关卡,产生了更少的幻觉编辑。模型还是同一个模型。变了的是地图。
指令文件依然重要。保留它们。用它们来记录约定、审查规则,以及不该触碰的东西。不要要求它们充当索引。一个列出三个重要目录的 CLAUDE.md,在一次包拆分之后的那一周就会过时。而一张可查询的地图,会随着仓库的更新而更新。
一个相关的失败是“几乎对”的文件:当行为其实在 auth-client.ts 里时,智能体却打开了 auth.ts;或者补丁打在了一个生成的文件上,而不是源文件;或者因为名字匹配,编辑了 packages/legacy 里的那份拷贝。引用不会让这些错误变得不可能发生。它们只是让这些错误在 diff 落地之前变得可见。
一张地图不会为你修复的东西
对自己得到的东西保持清醒。一张有依据的地图不会让每一次编辑都变得正确——你的智能体依然可能在完全正确的文件里写出一个糟糕的补丁。如果你的代码库依赖动态派发、反射或猴子补丁,一些符号查找返回的结果会比你希望的更单薄,因为运行时的间接性对任何静态索引都会造成这种效果。而如果你在期待一个百分比——“幻觉路径减少了 X%”——你在这里找不到,因为除了你自己,没有人能为你的仓库诚实地测出这个数字。
你可以期待的东西范围更窄,也更有用:智能体不再用一条猜测出来的路径来开始它的编辑。这第一步会扎根于一张真实的地图,而更少的幻觉编辑正是由此而来。引用之后的一切——阅读 diff、判断补丁——依然是你的工作,和以往一样。
这个测试几乎不花你什么成本:索引一个你已经了解的仓库,问一个你能核实的问题。从一条曾经让你吃过亏的路径开始。如果引用错了,你会立刻看出来。如果对了,你智能体的下一次编辑就有了一个更好的落脚点。
// it doesn't know the file. it knows how to find it.
相关阅读
更多来自 Maguyva 开发日志的内容
在没有本地索引器的情况下,给 AI 智能体大型仓库的上下文_
如何在不在笔记本电脑上运行本地索引器的情况下,从云端为编码智能体提供一张大型仓库的可查询地图。
会随行的上下文_
Cursor 的索引器在 Cursor 里非常出色。Maguyva 是同一个智能体可以从其他编辑器、CLI 和 CI 中查询的托管 MCP 地图。
先地图,后审查_
在编码智能体动笔之前,先让它扎根于一张仓库地图。之后再让 Greptile 审查这个拉取请求。这是互补的搭档,不是替代关系。