AI 改代码的分寸:默认只加,不删不改

让 AI 帮你改代码,最难的不是让它写出来,而是控制它改到哪里为止。
最常见的翻车方式是这样的:你让它加一个小功能,回来一看,它顺手重构了三个文件、删了"看起来没用"的工具函数、还调整了两处命名。功能也许是对的,但你不敢合并——因为你不知道它还动了什么。
问题不在能力,在于没有定义改动的默认边界。
一种很有效的做法是给 AI 一条非常具体的默认约束:
只加,不删,不改。 新增代码可以;要删除或修改既有代码,先停下来说明原因,等确认。
为什么是"只加"?因为它有三个好处:
可回滚。 只新增的代码,撤销就是删文件,风险可控。而修改和删除会破坏既有行为,且往往牵一发动全身。
可评审。 diff 里全是新增,评审时一眼能看完。如果既有代码被改动,评审者必须逐行确认"这里为什么改",成本高一个量级。
可预期。 AI 不会因为"顺手优化"而扩大改动范围。任务边界和改动边界重合,这是协作里最省心的一种状态。
当然,"只加"是默认,不是绝对。真正需要改的时候,规则是"先说明,再动手"——把决策权交回给人。
光说"不删不改"还不够具体,实践中把它拆成一张清单:
| 类型 | 默认 | 理由 |
|---|---|---|
| 新增文件 / 新增函数 | ✅ 可直接做 | 可回滚、可评审 |
| 修改既有函数实现 | ⚠️ 先说明 | 改变既有行为 |
| 删除代码 / 文件 | ⚠️ 先说明 | 可能有用例或调用方在依赖 |
| 改接口签名 / 数据结构 | ⚠️ 先说明 | 影响面超出当前任务 |
| 改数据库迁移文件 | ⚠️ 先说明 | 不可逆,且影响历史数据 |
| 修改或删除测试用例 | ❌ 不做 | 测试是验收标准,不是待修的障碍 |
| 增删依赖 | ⚠️ 先说明 | 影响构建与供应链 |
| 改 CI / 部署配置 | ⚠️ 先说明 | 影响所有人的流水线 |
测试单独说一句:测试失败时,正确的动作是如实报告失败,而不是"顺手改一下让它通过"。让测试变绿很简单,但那是把验收标准改成了适应实现——等于自己给自己打分。
这类边界不是拍脑袋定的,而且确实会生效。两方面依据:
一是 GitHub 团队分析过 2500 多份项目说明文件,提炼出的六要素模板里,明确包含一条"写清楚不可修改的边界"(explicit never modify boundaries)——它被当成高质量文件的共同特征。
二是实证研究显示,智能体对文件里的指令执行得非常到位:文件里提到某个包管理器,它就真的会去用(研究测到的差异是每任务 1.6 次 vs 不到 0.01 次);文件里要求跑全量测试,它就真跑,哪怕这次只是改一行。它听话,所以边界写清楚是真的管用;但也正因为听话,多余的边界会变成实实在在的成本。
有一类动作做错了没法撤销,必须走"先列清单、再等确认"的流程:
以推送为例,把它写成一条硬规则:
看起来啰嗦,但这条规则来自一次真实教训:一句"你可以提交了",结果被顺手推到了公开仓库,而那批提交其实还没整理好。
规律是:凡是"说一句就能做"的高危动作,都要拆成两步。 提交和推送分开,删除和确认分开,打 tag 和推送 tag 分开。
这些约束要写进项目文档(即项目根目录的 AGENTS.md),而且要写成祈使句的 don'ts,尽量靠前放:
写作要点跟项目文档那篇一致:有触发条件、有明确动作、有例外处理。"注意不要乱改"这种话,AI 读完不会有行为变化。
误区一:把"只加不删不改"理解成"不能重构"
不是不能重构,而是重构要作为独立任务提出来。AI 可以在结果里说"这里有个重复逻辑,建议单独开一次重构",但不要在加功能的时候顺手做。
误区二:认为这个规则会降低效率
实测相反。改动范围小 → 评审快 → 合并快。而一次大范围改动被卡在评审里来回讨论,才是最慢的。
误区三:只约束 AI,不约束流程
如果 CI 允许直接推主干、允许改测试就合并,那规则写在文档里也会被绕过。文档约束 + 流水线约束要配套:保护分支、必过检查、测试覆盖率门槛。
AI 写代码的速度已经不是瓶颈了,可控性才是。
一条"默认只加,不删不改",看起来是给 AI 上枷锁,实际上是给它划出一条可以放心跑的赛道——在赛道内它完全自主,出赛道才需要人拍板。边界清楚了,反而更快。
今天就能做的一件事:打开你的项目文档,加一节"边界",把上面那七条 don'ts 粘进去,然后观察下一轮 AI 的改动范围有没有变小。
#智能体 #AI编程 #代码评审 #工程规范 #技术实践