你让 Cursor “把全项目的 useAuth 都改成 useSession”,结果它只动了 3 个文件,但 grep -rn useAuth src/ 显示还剩 17 处。这不是模型偷懒,是它根本没”看见”剩下那 17 个文件——可能索引漏了、workspace 打开层级不对,或者你的 prompt 没把它指向正确目录。Cursor(以及 Windsurf、Cline 这类 IDE 集成 agent)只能修改”既在 codebase index 里、又在 chat context window 里”的文件,缺一个都漏。
最快的修法: 打开 chat,对每个要改的目录敲 @Folder、对关键文件敲 @File,然后在 prompt 末尾加一句”list every file path you changed”。@ 硬钉子会完全绕过 embedding 检索,是最可靠的一招。如果连 @Folder 都列不出文件,那问题出在索引上,直接跳到 Step 1。
先判断你属于哪一类
| 现象 | 最可能的原因 | 跳到 |
|---|---|---|
@Folder x 列不出文件,或比实际少很多 | 该目录被 .gitignore / .cursorignore 排除出索引 | Step 1 |
| 左下角 workspace 名是子目录,不是仓库根 | 打开层级不对 | Step 2 |
| 索引看着完整,但 agent 还是漏文件 | prompt 靠检索、没显式钉文件 | Step 3 |
| agent 凭空猜字段名 / 类型名 | 语义上必需的目录被 ignore 了 | Step 4 |
| 某个巨型文件(schema、i18n、迁移)像不存在一样 | 文件超过单文件索引大小上限 | Step 5 |
常见原因
按命中率从高到低排序。
1. 索引排除了关键目录
Cursor 的 codebase index 受四层规则影响:.gitignore、.cursorignore、.cursorindexingignore,以及 Cursor 内置的默认 ignore 列表(node_modules、lockfile、构建产物、二进制和媒体文件默认就跳过)。最常见的踩坑是把整个 src/packages/ 或 apps/web/ 写进 .gitignore(旧 monorepo 习惯),结果 Cursor 顺带也不索引了——因为它会”automatically ignores files in .gitignore and the default ignore list”。
如何判断:在 Cursor 里按 Cmd+Shift+P → “Cursor Settings” → Indexing(旧版本在 Features → Codebase Indexing),看已索引文件数。和 git ls-files | wc -l 对比,若差距超过 30%,说明大量文件被排除。
2. Workspace 打开的层级不对
你在 ~/projects/myapp/frontend/ 打开 Cursor,但后端代码、共享 types 在 ~/projects/myapp/backend/ 和 ~/projects/myapp/shared/。Cursor 只索引当前 workspace 根,看不到兄弟目录,agent 自然无法跨包重构。
如何判断:看 Cursor 左下角的 workspace 名。若显示的是子目录而不是 monorepo 根,就是这种情况。
3. Prompt 没显式钉文件
即使索引完整,Cursor 在长 chat 里也会按”相关性 + token 预算”挑文件塞进 context window。prompt 写得太抽象(“refactor the auth flow”),它会用 embedding 检索去找,但会漏掉那些命名不直观、注释不全的文件。
如何判断:展开 Cursor 回复下方的 context 折叠面板(“Context used”),它列出实际读过哪些文件。和你预期改动的文件清单对比。
4. 某条 ignore 规则挡住了 agent 仍需要的文件
像 src/generated/ 或 prisma/client/ 这种由 build 产生、但语义上很关键的类型定义,常被一并 ignore,于是 agent 改 query 时不知道字段名、类型名。
如何判断:grep -rn "from.*generated" src/,若代码大量从 generated 目录 import,但某条 ignore 规则把它排掉了,Cursor 就读不到。
5. 大文件被自动跳过
为了让检索更快,Cursor 会跳过超过单文件索引大小上限的文件(截至 2026 年 6 月,默认 1 MB / 1048576 字节)。如果你的 schema、迁移脚本或 i18n 字典是个超过上限的巨型单文件,agent 经常表现为”完全不知道这个文件存在”。
如何判断:find src -type f -size +1M,把列出来的文件贴回 chat 问 Cursor “do you see this file in your index?”
最短修复路径
按收益从高到低,前 3 步通常足够。
Step 1:核对 Codebase Index 范围
打开 Cursor → Cmd+Shift+P → “Cursor Settings” → Indexing(旧版本在 Features → Codebase Indexing)。看:
- 已索引文件数:和
git ls-files | wc -l对比 - Status:应是已完成 / 已同步的状态,不是 “Indexing” 也不是 “Stale”。语义检索要到约 80% 完成度才可用,所以进度条卡住就意味着上下文不全。
- Ignore 规则:面板会反映生效的
.gitignore+.cursorignore+.cursorindexingignore
索引大约每 5 分钟自动同步一次、只处理改动过的文件,所以大规模挪目录后它可能滞后。如果已索引数明显偏少,临时把可疑的 ignore 行注释掉,再触发重建:Cmd+Shift+P → Reindex Codebase,或点 Settings → Indexing 里的重建按钮。命令行也可以强制干净重建:
# 关掉 Cursor 后清掉 workspace 索引缓存
rm -rf ~/Library/Application\ Support/Cursor/User/workspaceStorage/*/cursorIndex
# 重启 Cursor,让它从零重建
Step 2:从 monorepo 根目录重开 workspace
如果你在子目录里打开,直接 File → Open Folder 重选根目录。或在终端:
cd ~/projects/myapp # monorepo 根
cursor . # 用根目录重启 Cursor
重开后,在 chat 里分别敲 @Folder frontend 和 @Folder backend 各验证一次,确认两边都能被引用到。若某个文件夹在选择器里没文件,说明它没被索引(回到 Step 1)。
Step 3:Prompt 里显式钉住文件 / 目录
不要写”修改 auth 相关逻辑”,改写成:
@File src/lib/auth.ts @File src/hooks/useAuth.ts @Folder src/components/auth
把 useAuth 替换为 useSession。只动我 @ 出来的文件 + 这些文件
的直接调用方。改完后列出所有被改的文件路径。
@File / @Folder / @Symbol 是硬钉子,比依赖 embedding 检索可靠得多。@Folder 的目标要尽量小:大约 10 个文件以内的文件夹能干净塞进去,钉一个巨型目录会冲爆 context 预算,Cursor 反而只会抽样读。需要全项目级别的提问时可以退而用 @Codebase,但精确重构还是显式钉文件最稳。Claude Code 用户对应的做法是在 CLAUDE.md 里写死 “always read these files first”。
Step 4:维护精简的 ignore 集合,同时让 generated 代码仍可引用
.cursorignore 语法和 .gitignore 一样,但只影响 Cursor。一个合理的 .cursorignore:
# 构建产物
dist/
build/
.next/
.astro/
out/
# 依赖
node_modules/
vendor/
# 缓存与日志
.cache/
.turbo/
*.log
coverage/
# 大型生成数据(按需)
**/*.snap
public/locales/*.json
要分清两个 ignore 文件的区别,它们行为不同:
.cursorignore会把文件挡在所有 AI 功能之外(semantic search、Tab、Agent、Inline Edit)外加索引。它适合放纯噪声。.cursorindexingignore只把文件排除出索引。这些文件不会出现在 codebase 搜索里,但仍能用@File引用到。偶尔需要钉、又不想撑大索引的大型 generated 目录,应该放这里。
不要把 src/generated/ 一类语义上必要的目录写进 .cursorignore(否则 agent 完全看不到它)。如果它大到不适合索引,就改放 .cursorindexingignore,需要时用 @File 钉进来。
Step 5:调高大小上限,或把文件拆开
如果某个单文件超过单文件索引上限(默认 1 MB),agent 会跳过它。两个选择。
在 settings.json 里调高上限(Cmd+Shift+P → “Preferences: Open User Settings (JSON)”):
{
"cursor.maxFileSize": 2097152
}
或把 i18n、schema、route 表按模块拆开,让每一块都能干净索引:
# 例:把较大的 src/i18n/zh.json 按 namespace 拆开
node scripts/split-i18n.mjs src/i18n/zh.json src/i18n/zh/
拆完更新 import,再 Reindex Codebase。
如何确认已修好
- Settings → Indexing 里,已索引文件数与
git ls-files | wc -l相差在 5% 以内,且状态为已同步。 - chat 里对每个相关目录敲
@Folder,都能列出你预期的文件(没有空选择器)。 - 用显式
@钉子 + “list every file you changed” 重跑一遍重构,打印出的清单应与预期一致。 - 在命令行验证没有遗漏:
grep -rn useAuth src/返回零结果(替换成你自己的符号)。较大的重构可以用git diff --stat核对每个该改的文件都改了。
预防建议
- 在仓库根放一份最小的
.cursorignore,只屏蔽构建产物和依赖,绝不屏蔽src/generated/、schema、迁移脚本。又大又必需的 generated 目录改放.cursorindexingignore。 - 大改动前先写一行 “files I expect to be touched: a.ts, b.ts, c.ts”,让 agent 反过来确认它能不能
@到全部。 - monorepo 始终从仓库根打开 Cursor,子包用
@Folder packages/foo限定,而不是单独打开子目录。 - 单文件接近 1 MB 索引上限时主动拆分;实在不可拆的(如自动生成的 schema)在 CLAUDE.md /
.cursorrules里点名说明,并用@File钉进来。 - 每次重大依赖升级或目录结构调整后,手动跑一次
Reindex Codebase,别等那 5 分钟左右的自动同步。
两个 ignore 文件的最新、确切行为,以及默认 ignore 列表,可查 Cursor 官方文档:Ignore files 与 Semantic & agentic search。
常见问题
为什么我让 Cursor 改的文件,它只改了一部分?
因为它只看见了一部分。文件必须既在 codebase index 里、又被拉进 chat 的 context window,才能被改。修法是把剩下的文件用 @File / @Folder 钉进来,并在 Settings → Indexing 里确认它们已被索引。
.cursorignore 和 .cursorindexingignore 有什么区别?
.cursorignore 把文件挡在所有 AI 功能(semantic search、Tab、Agent、Inline Edit)和索引之外。.cursorindexingignore 只把它排除出索引,你仍能用 @File 手动引用。需要偶尔引用的大型 generated 代码就用后者。
怎么强制 Cursor 重新索引?
Cmd+Shift+P(或 Ctrl+Shift+P)→ Reindex Codebase,或用 Cursor Settings → Indexing 里的重建按钮。要彻底重置就关掉 Cursor、删掉 workspace 索引缓存、再重启。
为什么一个大文件被忽略了?
Cursor 会跳过超过单文件索引上限的文件(截至 2026 年 6 月默认 1 MB)。在 settings.json 里调高 cursor.maxFileSize,或把文件按模块拆开后重新索引。
@Folder 有大小限制吗?
没有硬上限,但大文件夹会撑爆 context 预算,于是 Cursor 改为抽样读取。大约 10 个文件以内的文件夹效果最好;更大的目录就只钉关键的那几个 @File。