Composer 从来不读整个仓库,它只用嵌入检索递给它的那几十块片段干活。小仓库里 top-K 几乎覆盖全部;进到 1 万文件以上的 monorepo,同一个概念有十几个版本,检索只抽出 1-2 个,剩下的模型靠猜补。表现很一致:改了 A 模块,引用 A 的 B 模块原封不动;推荐的 import 路径根本不存在;packages/old-app 的旧写法渗进 packages/new-app。
这不是改一次设置就解决的事,而是要换一种给 Composer 喂上下文的方式。
一句话总结
- 写 prompt 之前先用
@Files手动挂 5-10 个相关文件,这一步就能解决大多数情况。 - 打开包目录(
apps/web),别开 monorepo 根——检索面和索引体积都能砍掉约一个量级。 - 把边界规则搬进
.cursor/rules/*.mdc。老的.cursorrules在 2026 年的 Agent 模式下会被静默忽略。 - 每条 prompt 只锁定一个包。“统一所有微服务的 logger” 这种说法必然漏包。
- Composer 2.5(默认 agent 模型,基于 Kimi K2.5)很强,但再强的模型喂错上下文照样瞎猜。赢在上下文,不在模型。
先搞清楚 Composer 跑的是哪个模型
不同模型对长上下文的处理差异很大,所以排查前先看一眼模型选择器。截至 2026 年 6 月,Cursor 给 agent 任务提供这几个:
| 模型 | 上下文窗口 | 大仓库表现 |
|---|---|---|
| Composer 2.5(默认 agent) | 大 agent 上下文,文件树级别改动 | 多文件重构快;SWE-Bench Multilingual 79.8%(2026 年 5 月 18 日发布) |
| Claude Sonnet 4.6 | 1M tokens | 稳定主力,长上下文撑得住 |
| Claude Opus 4.7 | 1M tokens | 横跨大段代码推理最强;SWE-Bench Multilingual 80.5% |
| GPT-5.5 | ~1M | agent 工具调用强 |
| Gemini 3.1 Pro | 1M tokens | 大上下文读取 |
窗口大不代表 Composer 会把整个 monorepo 塞进去。窗口只决定模型能装下多少检索到的上下文,进什么内容仍由检索说了算。这也正是下面这些招都在讲你挂了什么文件,而不是选哪个模型的原因。
常见原因
1. 检索只命中 top-N,覆盖率不够
Composer 把仓库切成大约 200-500 行的块再做嵌入。一句 “fix auth” 只取 top 10-20 最相关的块。10 万行的 auth 子系统里,这点信息量等于透过钥匙孔看屋子。
如何判断:让 Composer 答完后追问 List exactly which files you read。如果只列了 3-5 个、还漏掉你明知相关的文件,就是覆盖不够。
2. Monorepo 里多个同名模式互相干扰
packages/web/utils/fetch.ts 和 packages/admin/utils/fetch.ts 同名不同实现。相似度排序可能把 admin 版塞进 web 的 prompt,模型照抄。
如何判断:检查它给的代码里 import 路径有没有穿越包边界,比如 packages/web/... 下的文件 import 了 packages/admin/internal/...。
3. Working directory 设到了仓库根
Cursor 默认把 workspace 根当 working directory,于是所有文件都在搜索面里。收窄到 apps/web 后,检索面缩小约一个量级,质量立刻跳一档。官方说法很直接:直接打开 apps/web 而不是仓库根,索引体积能砍掉一个量级,agent 也更聚焦。
如何判断:看左下角的 workspace 路径。如果在 monorepo 里却指向仓库根,就是太宽。
4. 没有 MDC 规则给出”包边界”地图
没有规则,模型就不知道哪条路径属于哪个包、哪个是公开 API、哪个是内部,只能从文件路径瞎猜。注意格式已经变了:单个根目录 .cursorrules 在某些场景还能加载,但在 Agent 模式下会被静默忽略——而 Composer 正是跑在 Agent 模式里。现在的格式是 .cursor/rules/*.mdc。
如何判断:跑 ls -la .cursor/rules/。里面没有 .mdc 文件,就说明 agent 拿不到边界地图。
5. 一条 prompt 横跨多个包
“统一所有微服务的 logger” 没法保证检索覆盖到每个包。Composer 改它看得见的几个,剩下的静静漏掉。
如何判断:改完后跑 grep -r "old_logger" .,还有残留命中就是漏包了。
6. 索引过期或 .cursorignore 排得太狠
Cursor 每 5 分钟自动同步一次索引、只处理改动过的文件;但索引时被排除、或在索引暂停期间新增的目录,在检索里就根本不存在。.cursorignore 太激进(比如 **/*.test.ts)会把 Composer 本该参考的测试文件藏掉。还要注意:语义检索要到索引完成 80% 才上线,所以刚打开超大 monorepo 时,最初几条 prompt 跑的是不完整的索引。没调好的 monorepo 索引在打开后会把磁盘 IO 占满好几分钟;配上精简的 .cursorignore 调好后会快得多(有公开实测把 100 万文件的索引从约 12 分钟压到 3 分钟以内)。
如何判断:Cursor Settings → Indexing,看索引进度/状态;再打开 .cursorignore 核对它排除了什么。
动手前先确认
- 确认问题出在 Composer 还是 Cmd+K。Cmd+K 完全不走全仓检索,行为差很多。
- 复现前先 commit 或开 branch,免得一次 Apply 把未保存的改动覆盖掉。
- 记下 Cursor 版本和当前模型。Opus 4.7 和 Sonnet 4.6 都是 1M token 上下文;Composer 2.5 快,但和别的一样靠检索取料。
需要收集的信息
- 仓库的文件数和行数,以及是 monorepo 还是单包。
- 是否有
.cursor/rules/*.mdc和.cursorignore,以及上次完整索引的时间。 - 当前模型、是否在 Agent 模式、Composer 输入框里
@Files的截图。 - 模型对 “Which files did you actually read?” 的回答。
最短修复路径
按收益排序,前两步通常下一条 prompt 就见效。
Step 1:用 @Files 手挂 5-10 个最相关文件
最大的杠杆。任务前在 Composer 输入框里写:
@target-file.ts
@reference-pattern-1.ts
@reference-pattern-2.ts
@target-file.test.ts
@types/relevant.ts
然后加一句:“follow the pattern shown in reference-pattern-1.ts exactly”。手动挂的文件绕过检索排序,直接进上下文,这就是它在乱套的 prompt 上比任何招都管用的原因。
Step 2:把 working directory 设小
Cursor → File → Open Folder → 选 apps/web,别选 monorepo 根。Cursor 会把这个子目录当成项目根、只在它内部建索引,检索面和索引都缩到一个包以内,跨包污染基本消失。整个仓库大到没法好好索引时,这就是官方推荐的 monorepo 做法。
Step 3:给每个包写 MDC 规则
新建 packages/web/.cursor/rules/boundaries.mdc:
---
description: Web app package boundaries and conventions
globs: packages/web/**
alwaysApply: false
---
This is the customer-facing web app.
- Imports MUST stay inside packages/web/* or packages/shared/*.
- Never import from packages/admin/* or packages/internal-tools/*.
- Use the Logger from packages/shared/logger, not console.log.
- API calls go through src/api/client.ts; do not call fetch() directly.
globs 字段会在匹配文件进上下文时自动挂上这条规则,包与包之间就不再串味。四种激活模式要按需选:Always Apply(alwaysApply: true)、Auto Attached(写 globs)、Agent Requested(写 description、不写 globs)、Manual(@rule-name)。边界规则用 globs 的 Auto Attached 最合适。不想写 frontmatter 的话,在每个包目录放一份嵌套 AGENTS.md 也行。
Step 4:让 Composer 先回报上下文,再写代码
两步式 prompt:
Step 1: List exactly which files you've loaded into context and explain how each relates to the task. Do NOT write code yet.
Step 2: After I confirm, implement the change.
它列的文件不对就停手补 @Files,对了再放行。这一步花十秒钟,却能在它往错包写下 200 行之前抓住那次静默漏读。
Step 5:把跨包任务拆成单包子任务
别说”统一所有微服务”,改成:
Task scope: only packages/auth-service for now.
Goal: replace all usage of old_logger with the shared logger.
做完一个包就重开一个 Composer turn 再做下一个,避免上下文在包之间串。
Step 6:重跑索引并调 .cursorignore
先提交一份更紧的 .cursorignore,再重建索引,这样重建出来就是干净的。打开 Cursor Settings → Indexing & Docs → Clear Workspace Index,然后彻底重启 Cursor,让它重新索引(语义检索会在完成 80% 时恢复)。该排除的重目录:
node_modules/
.next/
dist/
build/
vendor/
target/
**/*.snap
正是这些排除项,把大型 monorepo 上动辄好几分钟的索引压成很快就能跑完。(.cursorignore 语法和 .gitignore 一样,每个开发者还能用各自的 ignore 把索引收窄到自己实际改动的目录。)
怎么确认已经修好
- 同一条 prompt 在 working dir 收窄前后各跑一遍,跨包污染应当消失。
- 让队友打开同一个 workspace 用同样的 prompt 复现,应当看到同样改善的行为。
- 跑
grep和 linter 实际验一遍,确认 import 路径不再穿越包边界。
如果还是没修好
- 把 prompt 缩到最小:只改一个函数、只
@一个文件、写死明确路径。 - 回滚最近一次 Cursor 升级或规则改动。
- 在 forum.cursor.com 搜 “monorepo composer context”,附上你的版本号和仓库规模数字。
- 抓 View → Output → Cursor 日志贴到 Bug Reports。
预防建议
- 每个包都放自己的
.cursor/rules/*.mdc,写清边界、约定、禁用 import。 - 每个包的 README 里写一节”改了 X 就要同步改 Y”,给模型做 anchoring。
- 把 5-10 个核心参考文件固定成 workspace 标签页,Composer 检索会优先打开的文件。
- 大重构交给 Claude Code 这类 CLI agent 做全仓扫描,Cursor 只做编辑器内的局部修改。别强求 Cursor 一个人硬扛——真要交接出去,也要把重构范围卡紧。
- 把”先列上下文再写代码”定为团队的标准 prompt 模板。
常见问题
换个 1M token 的模型能自动解决吗?
不能。Sonnet 4.6、Opus 4.7、Gemini 3.1 Pro 都是 1M token,但窗口只决定能装下多少检索到的上下文,进什么仍由检索说了算。模型再大,喂错上下文照样自信地瞎猜。挂对文件比窗口大小重要得多。
我的 .cursorrules 为什么不生效了?
截至 2026 年,单个根目录 .cursorrules 在 Agent 模式下会被静默忽略——而 Composer 正运行在 Agent 模式。把边界迁到带 globs 的 .cursor/rules/*.mdc,让它们按包自动挂载,或者每个包用嵌套 AGENTS.md。
大仓库里 Composer 2.5 比 Sonnet 强吗?
Composer 2.5 于 2026 年 5 月 18 日发布(基于 Moonshot 的开源 Kimi K2.5),在 SWE-Bench Multilingual 上拿到 79.8%,和 Opus 4.7 的 80.5% 基本打平,而且又快又便宜,支持文件树级别的多文件改动。但要在庞杂、含糊的代码库里做持续推理,Opus 4.7 仍是更稳的选择;而当你已经挂好了正确的文件、只需要快速多文件改动时,Composer 2.5 性价比很高。无论哪个,上下文纪律都比模型选择更关键。
怎么知道 Composer 漏读了某个文件?
直接问它:List exactly which files you read。如果它列的清单漏了你明知相关的文件,就是检索没命中——用 @Files 把那些文件挂上再重跑。别信一个从不说明出处的自信回答。
超大 monorepo 要不要干脆关掉索引?
不要——关掉 Composer 就彻底没了语义检索(也就是帮你自动找相关文件的代码库 @ 搜索和检索)。该做的是调 .cursorignore,排除 node_modules、dist、build、vendor、target,再打开子包目录、让 Cursor 只在它内部建索引。这样既保持索引快,又不会让 agent 变瞎。
相关阅读
标签: #排查 #Cursor #排查 #Composer 大项目