AI 凭空引用了不存在的文件:3 个原因 + 修复路径

Agent 写了 `src/utils/superhelper.ts` 这种从未存在的导入——常见但易修。

Build 报 Cannot find module './utils/superhelper',你在项目里 grep 一圈完全没这个文件——Claude Code 或 Cursor 凭空写了一条 import,引用了它”觉得应该存在”的 utility。这类幻觉是 LLM 最常见的失败模式之一:它根据训练数据 + 类似项目的常见命名,“补全”了一个看起来很合理的路径,但实际并没创建对应文件。好消息是这种问题易修——错误信息会精确告诉你是哪一行,修法只有两种(实现它或换掉它)。这篇拆原因、给修复模板、写预防规则。

常见原因

按命中率从高到低排序。

1. Agent 自己混淆了 plan 和 code

它在思考阶段说”我会用一个 formatDate 工具”,结果在 code 阶段直接 import { formatDate } from './utils/formatDate'——它把自己计划里的名字当成了已存在的代码。

// agent 写的
import { formatDate } from '@/utils/formatDate';
// 但项目里实际是
import dayjs from 'dayjs';

如何判断:看 agent 的 reasoning trace,它有没有提过 “create” / “implement”。如果没有”创建”动作只有 import,就是混淆了。

2. 它默认这种 utility 在项目里”应该”存在

LLM 见过太多项目里有 src/utils/cn.tssrc/lib/utils.tssrc/helpers/format.ts,于是默认你的项目也有。typescript template、Next.js / shadcn 默认有 lib/utils.ts,但你的项目可能没用 shadcn。

如何判断:搜常见模板路径——src/lib/utilssrc/utils/cn@/lib/db——看是不是你压根没建过的”标配”路径。

3. 训练数据里见过的开源库 / 包名

它写 import { useDebounce } from 'react-use',但你装的是 usehooks-ts 没装 react-use。错误是 Cannot find module 'react-use'。这其实是包幻觉,不是文件幻觉,但根因相同。

如何判断:检查 package.json 是否真有这个依赖;npm list <package> 没结果就是包幻觉。

4. Agent 在 monorepo 里走错 workspace

你的 monorepo 里 packages/ui/src/Button.tsx 存在,但 agent 在 packages/app 里写 import { Button } from '../ui/Button',路径算错。文件存在但路径不通。

如何判断:错误信息里的路径是相对路径而且层级看着可疑(../../../ui/),就检查 tsconfig 的 paths 设置和实际目录层级。

5. 大小写错误(macOS 本地 OK,CI 挂)

import './Button' 但文件叫 button.tsx,macOS 本地能解析,Linux build 挂。严格来说不是幻觉,但症状类似。

如何判断git ls-files | grep -i button 看实际文件名大小写。

6. Agent 引用了它”准备创建”但忘了创建的文件

它在 plan 里说”我会创建 src/api/posts.ts”,但实际只 import 没创建——可能是上下文限制提前结束,或者它跳过了那一步。

如何判断:grep 所有 agent 这轮的 Write 工具调用,看 path 列表里有没有缺失的那个文件。

最短修复路径

按收益排序。绝大多数能在 5 分钟内修完。

Step 1:用 tsc --noEmit 一次列出所有幻觉 import

npx tsc --noEmit 2>&1 | grep -E "TS2307|TS2305|Cannot find"

你会得到类似:

src/components/Form.tsx:5:23 - error TS2307: Cannot find module '@/utils/superhelper'
src/pages/posts.tsx:8:30 - error TS2307: Cannot find module '@/lib/db'
src/hooks/useAuth.ts:3:15 - error TS2305: Module '@/utils' has no exported member 'verifyToken'

每一条对应一个待修。

Step 2:判断这个 utility 该不该存在

打开报错的那个文件,看它怎么用这个 import:

import { superhelper } from '@/utils/superhelper';

// ...
const result = superhelper(data, { format: 'json' });

问自己两个问题:

  1. 这个功能项目里已经有等价物吗?(如 lodashdayjs、你自己写过的 helper)
  2. 如果没有,值得为它建一个新文件吗?
情况修法
项目里已有等价物换 import,不建新文件
是个小功能(< 20 行)直接 inline 写在调用处
是个能被多处复用的工具真的建出来
是个包幻觉npm install 装真包,或换成已装的等价包

Step 3:用 grep 找替代

确认是不是已有等价物:

# 按功能名搜
grep -rn "formatDate\|format_date\|dateFormat" src/

# 按签名搜
grep -rn "export function.*Date.*string" src/

# 找已装的相关包
grep -E "(date|format|debounce|throttle)" package.json

如果有现成的,把幻觉 import 替换掉即可。

Step 4:让 agent 自己修,给精确 prompt

不要手动修每一个——把列表喂回 agent:

build 失败。以下 import 引用了不存在的文件:

[贴 tsc --noEmit 的输出]

修复规则(严格遵守):
1. 不要创建新文件,除非该 utility 真的不存在等价物
2. 修每个 import 前先 grep 项目,确认是否有现成实现
3. 如果是 npm 包不存在,告诉我包名,让我决定是装还是换
4. 修完跑 `tsc --noEmit` 必须全绿
5. 不要改 tsconfig 的 paths

Step 5:对于真的需要创建的文件,让 agent 单独提议

如果有 utility 确实需要新建:

你要创建 src/utils/X.ts,先输出:
1. 完整文件内容(含类型)
2. 使用它的所有调用点
3. 为什么不用现成的 lodash / dayjs / 内置 API

等我批准再创建。

强制人工 review,避免它再创造一堆只用一次的”辅助文件”。

预防建议

  • 在 CLAUDE.md / AGENTS.md / .cursorrules 写:“导入前必须先 grepfind 确认目标存在;不能编造路径”
  • 让 agent 完工前自动跑 tsc --noEmit——把它写进”完成标准”
  • pre-commit hook 跑 tsc --noEmit,TS2307 / TS2305 直接拦
  • 项目根放一个 docs/utils.md 列出常用 helper 和它们的实际路径,喂给 agent 当上下文
  • 给 agent 装 file-search 工具时确保它会用——很多 agent 默认不会主动 search 文件结构
  • 强制小 commit:每次 npm install 单独提一个 commit,方便回看”这一周到底装了什么”
  • 对 monorepo,在 root tsconfig 用 paths 别名而不是相对路径,幻觉率明显下降

相关阅读

标签: #AI 编程 #排查 #排查