Cursor 辅助编码:用规则文件与上下文体系让 AI 读懂代码

Cursor 辅助编码:用规则文件与上下文体系让 AI 读懂代码 接手一个三十万行的老项目第一次让 Cursor 帮忙改一个接口它给我返回了一堆看起来十分合理、但项目里根本不存在的工具函数。那一刻我就明白问题不在于模型不够聪明而在于它压根不知道我这个项目的“规矩”长什么样。后来我用差不多两个月时间把自己的辅助编码流程从“随手问两句”改造成一套固定套路Cursor 才真正从“会写代码的实习生”变成了“熟悉项目的同事”。这套东西的核心其实就一句话让 AI 读懂你的代码比让它写代码更重要。这篇内容就是把这套可复用的实践完整拆开讲清楚它是什么、解决什么问题、每一步为什么这么做。不管你是刚装上 Cursor 想试试水的新手还是已经用了一段时间但总觉得它“答非所问”的老手都能从里面挑到能直接抄作业的部分。文中涉及的具体文件格式和菜单位置版本迭代比较快请以你手头版本为准。Cursor 中文怎么设置其实是个很小的细节但它侧面说明了同一件事工具本身不复杂难的是把工具嵌进你自己的工程习惯里。界面语言在设置里的通用选项里切换重启生效真正需要花心思的是规则文件怎么组织、上下文怎么给、会话怎么收尾。我见过太多人把精力全花在前者结果 AI 每次生成的东西还是要自己重写一遍。1. 为什么“让 AI 读懂代码”比“让 AI 写代码”更难1.1 模型看到的世界和你看到的世界不是同一个你在编辑器里打开一个函数脑子里自动带上了三层背景这个模块在业务里承担什么职责、上层调用方对它的隐性约定、团队近几年踩过的历史坑。模型没有这些。它拿到的是零散的文件片段加上一个简短的提问然后基于海量公开代码的统计规律猜一个“最可能正确”的答案。猜得准不准取决于你给它的碎片能不能拼出一张完整的图。我做过一个很直观的对比。同一个“给用户列表加分页”的需求第一次我直接说“帮我加分页”它生成的代码里用了项目里根本不存在的一个分页组件参数命名也和我团队的风格完全相反。第二次我先把相关的三个文件丢进上下文再补上一句“沿用现有列表组件的参数风格”它给出来的东西几乎可以直接提交。区别不在提示词写得多漂亮而在于它这次“看见”了我项目里真实存在的东西。这也是为什么很多人觉得 AI 编程时好时坏。写得顺的那些场景恰好是模型见过的通用模式写得崩的那些场景往往是你项目里的私有约定。1.2 上下文腐烂一个几乎人人都会遇到的症状我给它起了个名字叫上下文腐烂。具体表现是会话开得越长AI 的表现反而越差。开头两轮还挺准到第十轮开始引用你已经删掉的旧函数到第二十轮干脆自己编一套接口出来。原因不难理解会话上下文是有长度上限的早期内容会被压缩甚至丢弃中间几轮产生的临时方案又混在里面模型逐渐分不清哪条是最终结论。我当时的做法特别粗暴就是不停地开新会话。但新会话又有新问题每次都要重新解释一遍项目结构重复劳动。这两头堵的状态就是我下决心做这套可复用实践的直接原因。我需要的是一套机制让新会话能在几秒钟内恢复到“已经懂项目”的状态同时让单个会话活不过它的有效期。1.3 这套实践要解决的三件事把目标拆清楚后面所有设计才有依据。我给自己定的是三件事。第一件是知识固化。项目里那些不成文的约定比如错误处理统一走哪个包装函数、日志字段怎么命名、新接口必须加哪个鉴权注解这些东西以前只存在老员工的脑子里现在要变成 AI 每次都能读到的固定文本。第二件是上下文精准投放。不是把所有代码都塞进去而是根据任务类型决定这次该带上哪几个文件、哪几段文档。投多了会稀释重点投少了会缺信息这里面有取舍。第三件是流程可复制。同一个需求换个人、换台机器、过两个月跑出来的结果应该是接近的。也就是说提示词、检查项、提交前动作都得有固定模板而不是靠临场发挥。这三件事合起来才叫“可复用”。只把界面调成中文、只装个插件那不叫实践那叫配置。2. 三层上下文体系把项目“喂”给 Cursor 的整体设计2.1 规则层一次写清长期生效规则层解决的是“永远成立的事”。比如代码风格、目录约定、禁止使用的写法、必须走的封装。这部分内容的特点是变动频率极低写完可能几个月都不用动所以它适合做成固定文件常驻在模型的上下文里。我早期用的是项目根目录下的单一规则文件把所有约定堆在一个文本里。用了一阵子发现两个问题一是文件越长模型越容易忽略中间的段落二是前后端混在一个文件里改前端规则时容易误伤后端。后来我改成了一个规则目录按领域拆成多个小文件每个文件只负责一类约束。这样维护起来清楚模型读取时也更聚焦。规则文件里我一般写五类内容项目整体技术栈和目录结构说明、代码风格约定、错误处理和日志规范、测试要求、明确禁止的行为。第五类特别重要比如“不要引入新的第三方依赖”“不要修改自动生成的代码”这类负向约束能挡掉相当一部分跑偏的生成结果。2.2 索引层让“整个代码库”变成可检索的对象规则层管的是约定索引层管的是事实。代码库里真实存在的函数、组件、类型定义模型不可能全靠记忆所以需要把它变成一个可以按需检索的索引。我的用法比较克制。日常小改动我只用文件级引用明确告诉它“就看这几个文件”。只有当任务是“找到所有调用某个方法的地方”或者“这个功能在别的模块里有没有类似实现”时我才会动用全库检索。原因是全库检索返回的内容质量参差不齐噪声多容易把无关代码混进上下文反而干扰判断。这里有个我踩过的坑值得说一下。有一次我让它在全库范围里找“用户相关的工具函数”它返回了七八个文件其中三个是废弃目录里的老代码。我一时没注意结果新写的功能把老废弃代码里的实现方式抄了过来上线前才被发现。从那以后我在规则文件里专门加了一句废弃目录下的代码不作为参考。2.3 会话层单次任务的临时上下文会话层是最容易被忽视的一层但它直接决定了单次任务的质量上限。我的原则是一个会话只做一件事做完就关。重构一个模块是一个会话写一组单元测试是另一个会话两者绝不混在一起。会话内部还有个小技巧任务进行到一半需要插入别的事情时不要在当前会话里接着聊直接新开。因为一旦开始聊别的之前累积的上下文就被污染了再回到原任务时模型对“我们刚才在干什么”的理解会变形。另外我在每个会话的开头会习惯性写一句任务边界比如“本次只修改 A 模块的接口层不动数据层”。这句话的作用是给模型一个明确的活动范围减少它自作主张跨模块改动的概率。2.4 三层之间的配合关系简单说一下这三层怎么协同。规则层是底座常在后台生效索引层是按需调取的资料库会话层是当下的工作台。理想的单次流程是这样的规则层先把项目的底线约束住会话开头我描述任务并用索引层拉进来相关的两三个文件模型在约束范围内给出方案我审查后再让它落地。三层缺一层都会出问题。只有规则层没有索引层模型知道规矩但不知道现状容易写出“风格正确但函数不存在”的代码。只有索引层没有规则层模型能看到代码但不懂约定写出来的东西每次都不一样。只有会话层那就是大多数人的现状每次都在从零开始解释。3. 规则文件怎么写把团队约定翻译成模型能执行的约束3.1 该写什么、不该写什么规则文件最容易犯的错是写成项目说明书。我见过有人把整个架构图、全部表结构、所有接口文档都塞进去结果文件长得吓人效果反而更差。原因很简单模型处理长文本时会稀释注意力真正关键的约束被淹没在信息海里。我的判断标准是这条内容如果不写模型有较大可能性做错那就写如果模型本来就会做对那就不写。举个例子“用 named export 而不是 default export”值得写因为两种写法都常见模型可能随机选一个“函数要有返回值”就不用写这不属于约定。按这个标准筛下来一个领域的规则文件通常控制在几百字到一千字出头就够了。还有一个思路上的转变。规则文件不是给新人看的入职文档它是给模型看的行为约束。所以语气上要直接、命令式少讲背景。比如写“所有对外接口必须走统一的错误包装函数禁止直接抛出原始异常”比写“为了让错误处理更优雅我们建议……”要有效得多。3.2 一个可以照着改的规则模板下面是我现在用的一个后端领域的规则文件骨架格式是带元信息的 Markdown前几行是配置项后面是规则正文。具体字段名以你当前版本的支持情况为准不同版本有差异。--- description: 后端接口与业务逻辑层编码规则 globs: [src/api/**, src/service/**] alwaysApply: false --- ## 技术栈 - 语言TypeScript严格模式开启 - 框架内部封装的 Web 框架路由装饰器命名为 Route - 数据访问统一走 repository 层禁止在 service 层直连数据库 ## 目录约定 - 接口定义src/api/ - 业务逻辑src/service/ - 数据访问src/repository/ - 公共类型src/types/ - 废弃代码legacy/不作为参考禁止引用 ## 代码风格 - 导出方式命名导出不使用默认导出 - 命名变量与函数用小驼峰类型与接口用大驼峰常量用全大写下划线 - 单个函数不超过 60 行超出必须拆分 ## 错误处理 - 所有对外接口必须用 wrapError() 包装返回值 - 禁止直接 throw 原始 Error必须使用内部定义的业务异常类 - 日志字段固定为 traceId、userId、action、duration ## 测试要求 - 新增 service 方法必须补单元测试放在同名 __tests__ 目录 - 测试用例命名格式should_预期行为_when_条件 ## 禁止事项 - 不引入新的第三方依赖如确需引入先问人 - 不修改自动生成的类型声明文件 - 不在循环里做数据库查询 - 不跨层调用api 层不得直接引用 repository 层这个模板里有几个点我觉得挺关键。globs 字段决定了这个规则在什么路径下生效这样后端规则不会污染前端文件。alwaysApply 设为 false是因为这类规则只在相关文件被引用时才需要加载常驻反而占上下文。禁止事项单独成段因为负向约束在实践中的命中率意外地高。3.3 规则文件里的危险写法有几种写法我试过效果不好列出来避坑。第一种是把“建议”当规则写。比如“建议使用早返回减少嵌套”这属于风格偏好模型有时候遵守有时候不遵守写在规则里只会制造不确定性。要么改成硬约束“必须”要么干脆删掉。第二种是写互相冲突的条目。我有一阵同时写了“函数保持短小”和“禁止过度抽象”结果模型在两个极端之间摇摆。规则内部要自洽这需要定期通读一遍。第三种是把具体实现写进规则。比如把某个工具函数的完整代码贴进去想着“这样它就能直接用了”。问题是这段代码会过期规则文件里躺着一份三年前的实现反而误导模型。规则写“存在这个函数、叫什么名字、怎么调用”就够了实现细节让它自己去读源码。注意规则文件每次修改后建议开个新会话验证一下效果观察三到五个任务确认约束真的生效了再定下来。频繁改规则比不改规则更糟。4. 实操从零跑通一套可复用的辅助编码流程4.1 准备阶段环境与项目适配先把工具本身调顺手。安装完成后界面语言按自己的习惯切换中文的话在设置里的通用选项里找改完重启生效。快捷键可以按自己习惯映射一套尤其是唤起对话面板和切换模式的快捷键用得频率极高。项目侧的准备有三件事。第一件是确认项目能被正确索引大型项目首次索引需要一些时间索引不完整会直接影响全库检索的质量。第二件是梳理出规则文件覆盖的领域划分我一般按前端、后端、脚本工具、测试分成三到四组每组一个文件。第三件是准备一份“项目术语表”把业务里那些黑话和它们的代码对应关系写清楚比如“渠道”对应的是哪个实体、“激活”在代码里叫什么这份表放在规则目录里能显著减少模型用错概念的情况。4.2 任务拆解把大需求切成可验证的小块这一步是整套流程里最花时间、也最影响结果的一步。我的做法是任何超过半天工作量的需求先在纸上或文档里拆成若干个小任务每个小任务的验收标准要写得能判断真假。拆解的标准有三条。第一一个任务最好只涉及两到三个文件。第二一个任务的产出要能被一个测试或者一次手动操作验证。第三任务之间的依赖关系要明确避免并行做两个会互相影响的改动。举个例子“给订单模块加分页”这个需求我会拆成定义分页请求和响应的类型、在 repository 层加带分页参数的查询方法、在 service 层组装分页结果、在接口层暴露参数、补测试。每个小任务单独开会话去处理做完一个验证一个。这样出问题时定位范围很小回退成本也低。这里有个反直觉的经验拆得细不等于效率低。我以前觉得来回开会话很烦喜欢一口气把整个需求丢进去。结果是生成的东西一多半要重写返工时间远超拆解时间。后来老老实实拆整体反而快了。4.3 单次任务的执行动作一个标准任务我走五步。第一步新开会话用一句话写清任务边界和验收标准。第二步把相关文件引用进来通常两到三个必要的话加上术语表。第三步让模型先给方案再写代码方案不对就直接停省得后面白改。第四步代码落地后我自己过一遍重点看它有没有偷偷改动不该动的文件。第五步跑测试通过后提交。第三步的“先方案后代码”我认为是被低估的习惯。直接让它写代码你审核的是结果先让它说方案你审核的是思路。思路错了改代码是徒劳的。我现在的做法是明确说“先不要改文件用文字说明你打算改哪几个文件、每个文件改什么”等确认后再让它动手。第四步有个必查项就是看改动范围。我会习惯性地查看本次会话到底碰了哪些文件有没有顺手改掉一些我没让它动的东西。这个动作花不了半分钟但挡住过好几次意外。4.4 提示词模板与参数取舍我不追求花哨的提示词常用的就三个模板改改内容就能用。实现类模板任务在 src/service/order.ts 中新增按状态分页查询订单的方法 约束沿用 repository 层已有的查询风格分页参数复用 PaginationQuery 类型 产出只改 order.ts补一个单测到 __tests__/order.test.ts 先说明改动方案我确认后再写排查类模板现象调用 /api/order/list 时传入 page2 返回结果与 page1 相同 相关文件src/api/order.ts、src/service/order.ts、src/repository/order.ts 请先列出可能的原因按可能性排序每个原因说明怎么验证先不要改代码重构类模板任务把 src/service/user.ts 里的三个重复校验逻辑抽成公共方法 约束公共方法放 src/service/common/validators.ts不改变现有对外行为 产出改动清单 每处调用的替换说明测试必须全部通过关于参数我的取舍是涉及具体代码修改的任务把发散程度调低让它老老实实按已有风格写涉及方案讨论、找 bug 原因的任务可以适当放开让思路广一点。这个差别看起来小实际影响挺大。用高发散度去写业务代码跑偏概率明显上升。5. 常见问题与排查技巧实录5.1 回答对着干它总引用不存在的函数这是出现频率最高的问题基本可以定位到三个原因。一是上下文里没有包含定义那些函数的文件模型只能靠猜。二是规则文件里没有写清目录结构它不知道去哪个目录找。三是项目里有重名函数它挑错了那个。排查顺序我一般是这样先看这次引用了哪些文件把缺失的定义文件补进去再看规则文件里的目录约定是否清晰最后搜一下项目里有没有同名函数造成歧义。多数情况第一步就解决了。长期解法是在规则文件里维护一份核心函数清单把那些被高频引用的工具函数、包装函数、类型定义列出来写清所在文件和用途。这份清单不用长二三十条就能覆盖八成场景。5.2 改了 A 忘了 B跨文件改动不完整典型场景是改了一个函数的签名但没同步更新所有调用方。这不是模型独有的问题人也会犯但模型的犯错方式更隐蔽因为它改动完还会给你一段看起来很完整的说明。我的应对办法是在任务描述里直接点明“这个函数有 N 个调用方都要改”并给出查找方式。另一个办法是改完后单独开一个会话专门问“还有哪些地方引用了这个方法有没有漏改的”。这个交叉验证看着多余实际上很值。定期做一次全库的静态检查也是个好习惯把类型检查、格式检查、单元测试跑一遍能兜住大部分这类遗漏。我把这套检查固定成提交前的动作养成肌肉记忆后基本能防住。5.3 问题排查速查表我把这两年遇到的高频问题整理成了下面这张表遇到时按现象找能省不少翻记录的时间。现象最可能的原因优先动作引用不存在的函数或组件上下文缺少定义文件补引用相关文件后重试代码风格每次都不一样规则文件缺失或未生效检查路径匹配规则是否覆盖当前文件会话越往后越乱上下文腐烂新开会话只带当前任务必需文件反复改同一个文件改不对任务粒度过大拆成更小的子任务逐个验证生成结果里混入废弃写法索引到了废弃目录在规则里明确排除废弃路径改了签名但调用方没动跨文件依赖未声明显式列出调用方数量与位置生成的测试跑不过测试依赖的 mock 不匹配把现有测试文件一并引用进去建议引入新的第三方库缺少依赖约束在禁止事项里写明5.4 我踩过的三个具体坑第一个坑是把规则文件当成一次性工作。我最初写完规则就没再管过结果项目重构后目录全变了规则里的路径还是老的模型按老路径找文件自然找不到。现在我固定在每次大改动之后花十分钟同步规则文件把它当成代码的一部分来维护。第二个坑是过度依赖自动生成。有段时间我几乎不自己写代码了什么都让 AI 生成结果发现自己对项目的理解在退化评审别人代码时抓不住重点。后来我调整了比例核心逻辑自己写样板代码和重复劳动交给 AI这个平衡点我觉得更健康。第三个坑是提示词写太长。我曾经写过一个两百多字的提示词把各种约束都堆进去结果模型反而抓不住重点。现在的做法是提示词控制在三到五行详细的约束交给规则文件去承载各司其职。6. 怎么判断这套实践真的在起作用6.1 三个可以量化的观察指标光凭感觉说“好用多了”不够我给自己定了三个可观察的指标。第一个是首次通过率也就是 AI 生成的结果第一次就能用、不需要返工的比例。我刚做这套实践时大概三成稳定之后能到七成左右。这个指标的提升主要来自规则文件和上下文投放的改善。第二个是单任务会话轮次。同样的任务类型以前平均要来回七八轮现在通常两到三轮就能收尾。轮次下降意味着沟通成本在降低也意味着上下文腐烂的机会变少。第三个是回退率就是提交后因为 AI 引入的问题需要回滚的比例。这个指标我盯得最紧它直接反映质量。在把测试要求写进规则文件之后这个数字明显下来了。这三个指标不用搞什么仪表盘我自己就是每周翻一遍提交记录大致估个数趋势能看出来就够了。6.2 规则库的沉淀与版本管理规则文件我建议直接进版本库和代码一起管理。好处有三点改动有记录能回溯是哪次调整导致了效果变化团队成员可以共享同一套规则避免各写各的新人接手时能看到约定是怎么演化过来的。我还在规则目录里放了一个变更记录文件每次改规则时写一行说明改了什么、为什么改。这个习惯看起来有点较真但几个月后回头看能省掉大量“当时为什么这么写”的困惑。对于多人协作的场景规则文件的修改最好走一次简单评审哪怕只是拉个人看一眼。规则文件影响所有人的日常输出改错了影响面比改一个函数大得多。6.3 可复用到底体现在哪里回到标题里的“可复用”我理解的复用体现在三个层面。层面一是跨任务复用。同一套规则、同一套提示词模板在完全不同的需求上都能用不用每次重新设计沟通方式。层面二是跨人复用。规则文件和模板都是文本可以复制给别人新人上手时直接把目录拷过去起点就是别人摸索了两个月的成果。层面三是跨时间复用。半年后我自己回来做类似的任务翻出这套东西就能直接进入状态不用重新回忆当初是怎么做的。这一点对长期维护的老项目尤其重要。最后分享一个我最近常用的做法给每个项目单独维护一份“AI 使用笔记”记录这个项目里哪些提示词有效、哪些坑反复出现、规则文件改过哪几次。这份笔记不对外就是给自己的备忘录。积累几次之后你会发现真正省时间的不是模型变强了而是你不再重复解释同一件事了。