我用 7 条铁律管住 Cursor:让 AI 写代码不再「自由发挥」

这是一份我写给自己的 Cursor 全局规则(code-rules.mdc),每次对话都强制生效。它不是流程模板,而是一组「写代码时的底线」------无论走不走工作流,都得守。

为什么需要一套「底线规则」?

用过 AI 编程工具的人大概都有体会:AI 写代码容易「用力过猛」。

  • 你让它改一个小 bug,它顺手帮你重构了半个文件;
  • 你让它加个功能,它在项目里留下一堆临时脚本和调试日志;
  • 你让它修个报错,它把异常 catch 掉返回个默认值,bug 看着没了,根因还在;
  • 你让它写注释,它把 let a = 1 解释成「声明变量 a 并赋值为 1」。

这些问题单看都不大,但叠在一起,代码库会迅速变得难以审查、难以维护。尤其是当你用 Cursor 这类工具频繁让 AI 动代码时,每一条 diff 都需要人来 review,AI 的「自由发挥」会直接拖垮 CR(Code Review)效率。

所以我写了这份 code-rules.mdc,核心目标只有一个:让 AI 的每次改动都尽量小、准、可读、可审。

下面逐条拆解。

规则总览

# 规则 一句话
1 禁止临时文件 不在项目内留调试脚本、日志、草稿
2 抽函数要克制 别为了「好看」就包一层 function
3 用简体中文 给人看的都用中文,给机器看的不动
4 动手前先读 不凭记忆编造接口,复用本仓写法
5 改完自检 改了相关代码才跑检查,不空转
6 定位根因 禁止空 catch、默认值藏错误
7 回复先给结论 短句、完整句,不复述工具过程

1. 禁止在项目内创建临时文件

禁止在项目内创建临时文件(调试脚本、日志、备份、草稿、未请求的文档)。用户要求的正式文件除外。

这是最常见也最恼人的问题。AI 为了「验证一下」,会在项目里建个 test-temp.jsdebug.logbackup-old.js,然后忘了删。这些文件进入 git,污染 diff,还会被后续的 linter、构建工具误抓。

底线:项目里只放正式文件。要验证就说明,别偷偷建文件。

2. 抽函数是为了 CR 更小,不是为了「好看」

抽函数是为了让 CR 的 diff 更小、更好读,不是凡是新逻辑都新建 function。

  • 一行或两三行直接改原处;再包一层 function 会让 diff 更大。
  • 仅当改的是已合入主干的函数,且新逻辑是一整段流程、会明显拉长或打乱原函数时,才抽成独立 function。
  • 新增文件、新增函数按正常结构写。

这条是反直觉的,值得多说两句。

很多团队的习惯是「新逻辑就抽函数,函数越短越好」。但在 AI + CR 的场景下,这条会反噬:

  • AI 把原本 3 行的改动包成一个新函数 → diff 里多了「函数定义 + 函数调用 + 原处替换」,行数反而更多;
  • CR 的时候,reviewer 要跳转去看新函数实现,上下文被打断。

所以这里的取舍是:抽函数的唯一判据是「原函数会不会被打乱」。如果新逻辑只是一两行,直接写在原处,diff 最小、最好读。只有当新逻辑是一整段流程、塞进去会让原函数变得又长又乱时,才抽出去。

3. 给人读的用简体中文

给人读的用简体中文(说明、注释、提交说明、文档正文)。 代码、API、文件名、YAML key、OpenSpec 名称保持原规范。不翻译第三方 skill/命令模板,不改未触及的旧注释。

原则很简单:人读的归人,机器读的归机器

  • 注释、提交说明、文档正文 → 简体中文;
  • 变量名、API 字段、YAML key、文件名 → 保持原规范,不硬翻。

同时强调「不改未触及的旧注释」------别让 AI 顺手把别人的英文注释也翻译了,那是不相关的 diff。

4. 动手前先读,不凭记忆编造

动手前先读现有实现和同类写法。禁止凭记忆编造接口、字段、路由、配置;找不到就明确说找不到。 优先复用本仓库已有写法。只做需求所需的最小改动:不提前抽象、不顺手重构、不补没要的文档/防御代码。 注释格式跟本仓。新增和改到的代码默认要写;一行赋值/透传、名字已能说明用途的可不写。禁止复述代码。

这条管的是 AI 最危险的失败模式:幻觉

AI 会「猜」接口名、字段名、路由路径,然后写得有模有样,编译还不一定报错------因为 TS 类型可能 any 逃逸。等上线才发现 getUserInfo 其实叫 fetchUser,已经晚了。

底线

  • 动手前先读现有实现,找不到就说找不到,不许编;
  • 复用本仓已有写法,不引入新的风格;
  • 最小改动:不提前抽象、不顺手重构、不加没要的防御代码;
  • 注释默认要写,但「禁止复述代码」------let a = 1 不需要注释说「声明变量 a」。

5. 改完自检,但别每次小改都跑全量

改完自检:符合需求、无多余文件、无无关 diff。 改了相关代码才跑本仓已有检查(eslint / stylelint / typecheck 以当前 package.json 为准),不要每次小改都跑,也不要只改不验。

两个要点:

  1. 改了相关代码才跑检查 ------改个 README 不用跑 eslint,改了 .ts 才跑 typecheck;
  2. 不要只改不验------动了该测的代码就必须验,不能图省事跳过。

判据是「相关性」,不是「频率」。

6. 修问题先定位根因,禁止藏错误

修问题先定位根因。禁止空 catch、默认值、提前 return 把错误藏掉。 不要为每段逻辑套 try/catch;能由现有请求封装/全局错误处理接住的,业务里不要再套一层。仅在本层确有恢复、降级或需要转换成用户可理解错误时才 catch。

这条直指 AI 修 bug 的典型「偷懒」姿势:

ts 复制代码
// ❌ 错误示范:把异常藏掉,根因还在
try {
  const data = await fetchUser(id)
} catch (e) {
  return null
}

报错没了,bug 也没了吗?不,bug 还在,只是你看不见了。

底线

  • 先定位根因,再修;
  • 禁止空 catch、默认值、提前 return 这些「藏错误」手段;
  • 能由全局错误处理接住的,业务层不要再套一层 try/catch;
  • 只有本层确有恢复/降级/转译成用户可理解错误时,才 catch。

7. 回复先给结论

回复先给结论,再给必要依据。用短句、完整句;项目术语第一次出现时用一句话解释。不要复述工具过程。

这条管的是 AI 的回复可读性。

AI 喜欢这么回:「我先用了 Get-Content 读取文件,然后发现......接着我执行了......最终......」。这些工具过程对人是噪音。

底线:先说结论(改了什么、结果如何),再给必要依据(为什么这么改)、短句、完整句。项目术语第一次出现要解释。不复述工具过程。


这套规则的定位

这份规则刻意写得「克制」------它不是流程规范,不规定你怎么拆任务、怎么做设计,它只管一件事:AI 动代码时的底线行为

  • 走工作流(lwc-* skill)时:阶段流程、验证清单、CR 维度以对应 skill 为准,写代码行为仍守本文件;
  • 不走工作流时:本规则是唯一约束。

换句话说,它是「无论你用什么流程,都得守的最低门槛」。

📌 关于 lwc-* 工作流(一套 AI 前端开发工作流 skill)的详细介绍,会在下一篇文章中展开,欢迎关注。

配置方式

在 Cursor 中,把规则文件放在 .cursor/rules/ 目录下,文件名 code-rules.mdc,设置 alwaysApply: true,即可让规则每次对话都生效:

yaml 复制代码
---
name: code-rules
description: 写代码时的全局底线;小任务不走工作流时仍全部生效
alwaysApply: true
---

alwaysApply: true 是关键------它保证规则在所有对话中都加载,不需要手动 @ 引用。

写在最后

AI 编程工具的效率红利,前提是 diff 可审、代码可控。一旦放任 AI「自由发挥」,节省的编码时间会被翻倍的 review 成本吃掉,甚至埋下隐患(藏掉的异常、编造的接口)。

这 7 条规则本质都在回答同一个问题:怎么让 AI 的每次改动都尽量小、准、可读、可审。

如果你也在用 Cursor 或类似工具高频让 AI 动代码,不妨参考这套底线,按自己团队的实际情况调整。规则不用多,能守住底线就够。

下面附上完整的规则文件原文,可以直接复制到你的 .cursor/rules/code-rules.mdc 中使用。

完整规则文件原文

yaml 复制代码
---
name: code-rules
description: 写代码时的全局底线;小任务不走工作流时仍全部生效
alwaysApply: true
---

本规则每次对话都生效,走 `lwc-*` 时也不关闭。
走工作流时:阶段流程、验证清单、CR 维度以对应 skill 为准;写代码行为仍守本文件。
不走工作流时,本规则是唯一约束。

1. 禁止在项目内创建临时文件(调试脚本、日志、备份、草稿、未请求的文档)。用户要求的或实现所需的正式文件除外。
2. 抽函数是为了让 CR 的 diff 更小、更好读,不是凡是新逻辑都新建 function。
   - 一行或两三行直接改原处;再包一层 function 会让 diff 更大。
   - 仅当改的是已合入主干的函数,且新逻辑是一整段流程、会明显拉长或打乱原函数时,才抽成独立 function。
   - 新增文件、新增函数按正常结构写。不要为遵守本条去全量对比主干。
3. 给人读的用简体中文(说明、注释、提交说明、文档正文)。
   代码、API、文件名、YAML key、OpenSpec 名称保持原规范。不翻译第三方 skill/命令模板,不改未触及的旧注释。
4. 动手前先读现有实现和同类写法。禁止凭记忆编造接口、字段、路由、配置;找不到就明确说找不到。
   优先复用本仓库已有写法。只做需求所需的最小改动:不提前抽象、不顺手重构、不补没要的文档/防御代码。能一行说清的不要拆成一段;不为「看起来完整」加空转代码。
   注释格式跟本仓。新增和改到的代码默认要写;一行赋值/透传、名字已能说明用途的可不写。禁止复述代码。
5. 改完自检:符合需求、无多余文件、无无关 diff。
   改了相关代码才跑本仓已有检查(eslint / stylelint / typecheck 以当前 `package.json` 为准),不要每次小改都跑,也不要只改不验。
6. 修问题先定位根因。禁止空 catch、默认值、提前 return 把错误藏掉。
   不要为每段逻辑套 try/catch;能由现有请求封装/全局错误处理接管的,业务里不要再套一层。仅在本层确有恢复、降级或需要转换成用户可理解错误时才 catch。
7. 回复先给结论,再给必要依据。用短句、完整句;项目术语第一次出现时用一句话解释。不要复述工具过程。
相关推荐
可以想象21 分钟前
Agent 层比模型层更重要?从本周 AI 两件大事说起
aigc·ai编程
梨想橙汁27 分钟前
JS 核心语法:运算符流程控制、函数、数组与对象实战详解
前端·javascript
七牛开发者27 分钟前
拆解 dsh:Turn 与 Step 如何组织 Agent 主循环
前端·javascript·人工智能
梨想橙汁28 分钟前
JavaScript 零基础入门:引入方式、变量与数据类型,吃透原始与引用类型
前端·javascript
不可能片场32 分钟前
puppeteer 调试实录:CDP 双层响应让取值永远 None
前端·electron
咖啡无伴侣33 分钟前
2. 从零搭建企业级 Monorepo 工程化模板:ESLint 10 (基础骨架)+ Prettier 配置与避坑指南
前端·架构
光影少年37 分钟前
react navite实现全局弹窗、Toast 组件
前端·react native·react.js
ServBay39 分钟前
Claude Fable 5.1正式上线:Claude 最强,还降价?
aigc·ai编程·claude
WebInfra41 分钟前
Rslib 1.0 正式发布:面向多场景的 JavaScript 库开发工具
前端·javascript·github