前两周接了一个内部项目管理系统的改造,同事跟我吐槽:Cursor 这工具,写点工具函数效率确实高,一碰老代码就放飞自我,改完跑都跑不过。我说你让它改之前,它知道你这段业务是干嘛的吗?同事愣了一下:我直接把报错贴给它了啊。这个场景我见了太多次。很多人把 Cursor 当成一个"会说人话的搜索引擎",但 AI 能不能真正读懂你的代码,不取决于模型参数有多强,而取决于你喂给它的上下文、你下达指令的结构,以及你对它产出的验收方式。这套实践我从个人项目用到团队协作,核心就一件事:怎么让 AI 在你熟悉的项目里,像刚入职但悟性很高的实习生一样,先听明白再动手,而且交出来的活能过审。这篇博文不是 Cursor 的功能说明书,是一套可复用的辅助编码实践。
1. AI"读代码"的真实机制:它到底怎么理解你的仓库
1.1 先搞清楚 Cursor 的眼睛长在哪
很多人以为 Cursor 是把整个仓库都塞进模型脑子里再思考,实际上不是。它有一套检索增强机制:启动时会对仓库代码建索引,你提问时,系统会把你的问题和仓库里的代码块做相似度匹配,捞回来最相关的一批代码片段,拼进上下文窗口,再让模型基于这些片段回答。理解这一点非常关键——你以为它在"读整个项目",其实它只是在"抽读几页"。
这就像请了一个记忆力很好的实习生,你让他改一份合同,但只把合同第 3 页和第 7 页丢给他,其他页他自己翻不到,那改出来的内容当然前言不搭后语。Cursor 的"读"是检索式的,不是全景式的。仓库越大、文件越长,它能看到的比例就越低。很多"AI 改错代码"的翻车现场,根源不是模型笨,是它压根没看到那个最关键的文件。
我自己的一个习惯是:向 Cursor 提问前,先想一下"它可能需要知道哪几个文件"。如果我对项目还不熟,就先在对话里敲一句"请根据 @Codebase 梳理一下 xxx 功能的调用链路",让它先把检索到的信息亮出来,确认它看到了什么,再让它动手改。这一步能过滤掉大半的"瞎改"。
1.2 为什么"贴个报错让它修"越改越乱
报错信息是最末端的结果,不是问题的根源。一段报错只能告诉 AI"哪里炸了",不能告诉它"这里的预期行为是什么、数据流从哪进来、谁在调用这个函数"。直接把报错丢给 AI,等于让医生只看体温计度数就开药,不问病史、不做检查。
我见过最典型的操作:同事贴了一行 TypeError,Cursor 给了一个"防御性判断"补丁,结果程序不报错了,但功能逻辑也变了——因为 AI 不知道那个字段在上游已经被改成另一种结构。它只能基于报错信息做"最小表面修复",而不是"根源修复"。
真正有效的做法是:报错信息 + 出错函数完整代码 + 调用方的上下文。至少要告诉它"这段代码的输入是什么、输出应该是什么"。AI 不缺修 bug 的能力,缺的是判断"哪个 fix 才是符合业务预期"的信息。你给的信息越接近"需求文档",它越不会乱来。
1.3 判断 AI 是真懂了还是装懂的三条标准
我踩过不少坑之后,总结出三条判断标准,只要有一条不满足,就绝不直接采用 AI 的代码:
- 复述一致性:让它先用自己的话复述一遍这段代码的业务职责和改动意图。如果复述出来和你的预期对不上,后面写出来的代码大概率也是歪的。
- 检索覆盖度:问它"你改了哪些文件,为什么改这几个",尤其要留意有没有遗漏掉那些不在检索结果里但实际相关的文件。AI 常常只改你 @ 给它的文件,没有主动去翻被调用方。
- 边界条件敏感度:让它主动说明"哪些情况我不会处理"。如果 AI 自信满满说"没问题、完美",反而要提高警惕——一个正常人写代码都知道边界条件一抓一大把,AI 表现得过于乐观,通常说明它的上下文里就没有那些边界信息。
这三条标准后来被我固化成提示词的一部分,见第三节的模板。有了它们,AI 输出的质量稳定了不止一个档次。
2. 让 Cursor"补课":搭建项目级上下文的具体步骤
2.1 三个文件解决 80% 的"失忆"问题
Cursor 对单个文件的跟踪能力不弱,但对项目整体脉络的理解,完全取决于你有没有把"项目说明书"摆在它面前。我接手任何项目,第一件事就是在仓库根目录维护三个文件:README.md、.cursorrules、AGENTS.md(如果你用 Agent 模式)。
README.md负责写清楚项目是什么、技术栈、启动方式、目录结构、部署注意点。这个文件很多团队有,但内容早就过时了。Cursor 建索引时会读它,你给它的信息越准确,它后面理解项目的能力越强。
.cursorrules是 Cursor 的规则文件,相当于给它一份"项目级行为准则"。你可以在这里约定代码风格、禁止事项、命名规范、目录约定。这个文件不是摆设,它会被加载进每次对话的上下文,相当于你给 AI 立了一个"入职培训手册"。
AGENTS.md是我后来加上的。Cursor 的 Agent 模式(能自主多文件操作的那个)会优先读取它。我会把"哪些目录不能动""测试命令怎么写""提交前必须跑什么检查"这些操作级别的东西写进去。有了它,Agent 模式翻车的概率会低很多。
2.2 .cursorrules 示例模板(可直接抄)
下面这份是我个人项目里正在用的模板,你们可以直接复制改改。重点是具体的、可执行的条目,不要写废话:
# 项目技术栈 - 后端:Python 3.11 + FastAPI - 前端:React 18 + TypeScript + Vite - 数据库:PostgreSQL 15 + SQLAlchemy 2.0 # 代码风格 - 所有 Python 代码必须加类型注解 - TypeScript 组件使用函数式组件和 Hooks,不用 class 组件 - 禁止在业务代码里使用 any 类型 - 字符串统一使用单引号 # 目录约定 - 业务逻辑放在 app/services/,不要在路由里写复杂逻辑 - 数据库模型放在 app/models/ - 新功能的 API 路由统一注册在 app/api/v1/ # 禁止事项 - 不要修改 migrations/ 下已经生成的迁移文件 - 不要引入新的第三方依赖,除非明确要求 - 不要改动 tests/ 下已有测试的断言逻辑 # 开发约定 - 提交前必须跑:pytest && npm run lint - 数据库连接串统一从环境变量读取,不准硬编码 - 所有对外接口需要写 OpenAPI 描述这些规则不是一次写死的,我会在项目演进中不断往里面加条目。比如有次 AI 连续两次把新代码塞进了一个被废弃的老模块,我在.cursorrules里加了一条"所有新增功能一律放在 app/services/v2/ 下,老模块只做兼容层调用",问题就再没出现过。
2.3 引用文件的高级姿势:@、# 与 @Codebase 的取舍
新手容易犯的错是把所有相关文件手动粘贴进聊天框,既有长度限制,又容易贴错版本。Cursor 提供了引用机制:在对话框输入@可以选择文件、文件夹、文档,输入#可以引用具体代码符号(函数名、类名)。
我的经验是分场景用:
- 改动范围明确(比如改一个函数逻辑):用
@文件名精确引用那个文件,再加#函数名定位符号,信息密度最高。 - 需要全局理解(比如排查一个跨模块问题):用
@Codebase让它检索整个仓库,但一定要接着追问一句"你找到的相关文件有哪些",确认它没有因为检索限制漏掉关键位置。 - 涉及大量文件(比如跨模块重构):用
@文件夹把相关目录整体框进来,同时用.cursorrules里"禁止事项"来约束它不要碰不该碰的文件。
还有个小提醒:你在 Cursor 里写的 prompt 和.cursorrules内容对 AI 不是秘密,它会在回答里隐式复述你的规则,也会随着上下文传给后续对话。所以不要把密钥、密码、token 写进这些文件。网上流传的"提示词泄露"说白了就是这一层,规则文件是给 AI 读的,本身没有保密性可言。
3. 一套能直接抄的编码任务提示词模板
3.1 分解"剪短点"式的模糊指令
很多人给 Cursor 下指令,是"帮我写个导出功能""给这个页面加个筛选",有点像进了理发店只说"剪短点"。理发师的理解是"剪短 3 厘米",你想要的是"保留鬓角、打薄后脑勺"。AI 也一样,它非常擅长顺着模糊指令编出一个看起来合理的方案,但那个方案大概率不是你要的。
问题不是 AI 蠢,而是 AI 没有"追问权"。正常实习生会反问"导出格式是 CSV 还是 Excel?字段有哪些?要不要带权限过滤?",但 Cursor 默认不会把这些追问全部抛给你——它会挑一个概率最高的方案直接开工。所以你必须把任务描述得让它没有"自由发挥"的空间。
3.2 五要素任务模板(含代码块模板)
我把编码任务拆成五个要素,每次给 Cursor 下任务都按这个结构来:
- 背景与目标:这段代码在项目里的作用,要实现什么业务目标。
- 输入与现状:相关文件路径、函数名、数据结构、数据流入口。
- 约束与边界:不要改哪些文件,是否允许加依赖,兼容性要求,性能底线。
- 输出格式:改哪些文件、是否允许重构、是否要附带测试。
- 验收标准:怎么证明改对了,比如跑什么命令、看什么行为。
把这五要素写成一份可复用的 prompt 模板,大概长这样:
你是这个项目的资深开发者。请完成以下任务: 【背景与目标】 (写清楚这个功能为什么存在,最终要达成什么效果) 【输入与现状】 - 相关文件:@文件路径 - 关键函数:#函数名 - 当前逻辑:(简述现有实现,或让 AI 先自己梳理后复述) 【约束与边界】 - 必须保留: - 禁止改动: - 不允许引入新的依赖:(是/否) - 兼容性要求:(浏览器版本/Node版本/数据库版本) 【输出要求】 - 需要修改的文件: - 是否需要新增文件: - 是否需要配套测试: - 代码风格要求:(如无可省略) 【验收标准】 - 手动验证步骤: - 自动化验证命令:在让 AI 动手前,我还固定加一句:"请先复述你对任务的理解,列出你将要修改的文件清单,等我确认后再开始写代码。"这句话非常重要。它等于强制 AI 先出"施工方案",你审核后它再动手。实操里,AI 列出的文件清单经常和预期有出入,你在这一步就能纠偏,省得后面反复返工。
3.3 同一个改动的弱提示与强提示对比
举个例子。假设要给一个任务列表加"按标签筛选"的功能。
弱提示是这样的:
帮我给任务列表加一个按标签筛选的功能。Cursor 可能给你生成一个全新的筛选组件,把列表请求参数改了,但完全没考虑你现有的标签体系是从哪个接口来的,也没有处理"无标签任务"这种边界。等你看完代码,发现它定义的数据结构和后端接口对不上,还要花大量时间去改。
强提示是这样的:
【背景与目标】任务列表页目前按状态筛选,希望增加按标签筛选,标签数据来自 @services/tag.ts 的 getTagList,任务项中的标签字段是 tagIds: string[]。 【输入与现状】列表页文件 @pages/TaskList.tsx,现有筛选状态在 @stores/taskFilter.ts 中管理,接口请求在 @api/task.ts 的 fetchTasks(filters)。 【约束与边界】不要改动 @api/task.ts 的响应结构,不要新增第三方依赖,tagIds 为空时表示筛选全部任务。 【输出要求】修改 @pages/TaskList.tsx、@stores/taskFilter.ts,并补充对应的单元测试。 【验收标准】npm run test 通过;筛选后 URL 上要有对应的 query 参数,方便刷新后保持状态。给足上下文后,Cursor 写出来的代码基本就是"项目内生长的代码",风格一致、调用链正确、边界清晰。同一个功能,弱提示可能要来回改三轮,强提示一次通过的几率非常高。我现在对新任务的第一版 prompt 就会认真写五要素,写完通常发现自己对需求的思考也清晰了一大半。
4. 实测中的三个坑与边界:什么时候别信 AI 的"自信"
4.1 翻车记录:一次定时任务时区调整,AI 漏了一行
我必须坦白讲,即使上下文喂得很足,AI 依然会在一些隐蔽细节上翻车。最深刻的一次是我让它修改一个定时任务的时区处理逻辑。任务很简单:原来按 UTC 每天凌晨 2 点跑,改成按东八区凌晨 2 点跑。
我按五要素模板写得很清楚,甚至把涉及时区转换的工具函数@utils/time.ts和定时任务注册文件@jobs/cleanup.ts都 @ 进去了。Cursor 迅速改了注册时间,加了转换逻辑,测试也写了,看起来完美。但上线后第一天,任务没有按预期触发。
排查了一下午,最后发现根因在配置文件里:定时调度的 cron 表达式是从环境变量读的,部署环境的TZ变量没设,系统默认还是 UTC。Cursor 只改了代码逻辑,它不会主动去查你的部署配置。类似这种"看起来跟代码无关但严重影响运行结果"的坑,AI 很难主动发现,因为它的上下文边界里就没有环境配置这一项。
那次之后,我对涉及时间、时区、环境变量的改动多了一个强制步骤:明确在提示词里加一条"请检查影响此逻辑的所有配置项和环境变量,并列出可能影响运行结果的部署配置"。
4.2 让 AI 自己当验收员:反向提问与自检清单
不信任 AI 的最好办法,是让它自己证明自己。我养成一个习惯:AI 产出代码后,不急着跑,先让它做几件事:
- 列出所有修改点,解释每个修改的原因。
- 指出这次改动会影响哪些下游调用方。
- 主动列出它没有处理的边界情况。
听起来像是在面试 AI,实际非常有用。有一次让它重写一个数据导出的函数,它列出的"未处理边界"里写着"当导出数据量超过 10 万条时,原方案的 Excel 库会内存溢出,建议分批导出"。我根本没提这个需求,它是在审视代码时主动发现的。把这个机制装进工作流后,AI 承担了很大一部分"代码审查兜底"的工作。
反向提问同样好用。比如不是"帮我修 bug",而是"这段代码在什么情况下会出错,什么情况下性能退化?"或者"如果要改掉这个函数的第三个参数,哪些地方需要同步改?"这种问题能逼着它把隐式依赖翻出来。相当于把 AI 从"写代码的"切换成"帮我检查代码的"。
4.3 Tab 补全、Chat 和 Agent 模式的分工,以及额度使用的个人习惯
Cursor 的三个主力功能我现在是分开用的,不会什么事情都开 Agent:
- Tab 补全:单行、几行的机械改动,或者重复性代码生成,用它最高效,基本不占额外思考额度,也不打断心流。
- Chat 模式(Ctrl/Command + L):改单个文件、解释一段代码、排查一个问题,用 Chat 最合适。它会在当前文件和你 @ 的上下文里回答,不会擅自改其他文件。
- Agent 模式(Ctrl/Command + I 或独立窗口):跨文件重构、新功能搭建、需要自己翻项目的时候,才交给 Agent。它虽然能自主操作多个文件,但消耗的额度也快得多。
网上经常有人问 Cursor Pro 有多少额度、Agent 用多了怎么办,我的个人感受是:如果 Tab 和 Chat 能解决的问题就别开 Agent,省钱只是其次,关键是 Agent 一旦跑偏,你去纠正它的时间成本比手写还高。额度不是用来"省"的,是用来避免"把时间浪费在让 AI 理解问题上"的。真正贵的从来不是额度,是你被 AI 带偏之后擦屁股的时间。
另外,以下场景我会主动关掉 AI,自己手写:
- 涉及事务、并发、锁这类一致性敏感的代码。AI 写这类代码常常"表面正确",但并发场景下很难靠看代码判断对错。
- 需要大量项目历史决策背景的重构。AI 没有经历过那些讨论,它只会按当前代码反推意图,容易丢掉"当初为什么这么设计"的约束。
- 性能优化。AI 更擅长写出"能跑的代码",而不是"跑得快的代码",性能瓶颈定位还是得靠人。
5. 把整套方法串起来:一次完整的小需求实战
5.1 场景:给内部任务系统加筛选功能
有一回我给团队内部的任务管理系统加"按负责人筛选"的功能。这个需求不大不小,正好能用上前面所有方法。我当时没有急着让 Cursor 改代码,而是先花了十分钟完善.cursorrules里关于这个模块的约定,然后打开对话,把任务按模板敲了进去。
任务背景写得很短:任务列表目前只按状态筛选,希望增加负责人筛选,负责人数据来自用户接口;现状则是列出了列表页、筛选项组件、状态管理、接口定义四个文件路径。约束写了三条:不要动接口响应结构,负责人字段在响应里叫assigneeId,筛选条件为空时不做过滤。
5.2 五个步骤的完整执行链路
第一步,我让 Cursor 先复述对任务的理解和修改文件清单,它列出来的文件里多了一个我没提到的筛选条件类型定义文件,正好是需要的,我确认后让它开工。
第二步,改代码。它按模板把筛选项组件、状态管理、请求参数三处都改了,还主动在 URL query 里加了同步,说"方便刷新后保持筛选状态",这正是我预期内的细节。
第三步,让它自己列边界条件。它写了一句"当负责人的值为空字符串或 null 时不传给后端,避免无效筛选参数",完全覆盖了我担心的情况。
第四步,让它补测试。因为现有测试基础薄弱,我没要求写完整单测,只让它补了一个筛选函数的核心用例。
第五步,手动验收。跑起来后实测发现一个小问题:筛选项的下拉框在数据量大的时候需要支持搜索,我原来的 prompt 里漏了这个需求。这就是第五要素"验收标准"没写全的典型例子。我在对话里补了一句"下拉框需要支持输入搜索,因为用户可能有几十个",Cursor 基于现有组件库很快就改完了。
5.3 迭代循环:AI 生成→我审查→追加上下文→再生成
整套流程跑下来,真正有效的其实是那个循环:AI 生成一版 → 我审查代码和边界 → 发现问题/遗漏 → 追加上下文和约束 → 再让 AI 改。这不是简单的 prompt 优化,而是把 AI 当成了一个可以在循环里持续改进的协作对象。
我给团队分享这套方法时,很多人问"为什么我让 AI 干个活要写那么长 prompt,不累吗"。我的回答是:写 prompt 本身就是在逼你想清楚需求。以前你开发前要在脑子里过一遍"输入是什么、输出是什么、边界在哪、怎么验证",现在只是把这个过程外化成了文字。等到你对项目和 AI 的配合方式足够熟悉,这些模板会内化成一种肌肉记忆,敲起来并不慢,但省下来的返工时间远超那几分钟。
一点个人体会
我用了大半年 Cursor,最大的感受是:别把它当成"自动写代码机器",它更像一个"特别需要你把话说清楚的同事"。AI 的阅读理解能力取决于你提供的上下文边界,它的输出质量取决于你定义的任务清晰度,它的可信度取决于你有没有设计验收闭环。这三句话几乎可以解释我遇到过的所有"AI 不靠谱"的场景。
最后分享一个实用小技巧:每次让 AI 干活前,逼自己用五要素写一遍任务,写完你会发现自己对需求的思考清晰了不止一倍——哪怕最后不交给 AI,这个习惯本身就值回时间。