AI 写烂代码,往往不是因为它完全不会写,而是因为它太愿意“帮你多想一点”。软件工程里,最可怕的热心肠通常会长出一堆抽象层。

很多开发者第一次用 AI 写代码,会经历一个奇怪的情绪曲线。
第一天:太强了,它五分钟写完我半小时的活。
第三天:怎么开始乱改文件了?
第七天:它为什么给我加了一个抽象工厂?我只是想改个按钮文案。
这不是个别模型的问题。AI 编程工具的本质,是在已有上下文里生成“看起来合理”的下一步。它可以很快,但它默认不知道你的仓库审美、团队习惯、历史包袱和上线风险。
你不给它立规矩,它就会用训练数据里的平均工程风格来帮你。平均风格有时能救命,有时像把全网技术博客搅碎后糊到你的项目里。
为什么 AI 容易写丑代码
第一,它倾向于完成显性的需求,而不是保护隐性的系统约束。
你说“支持导出 Excel”,它会去找最快能跑的办法。至于项目里已有导出服务、权限模型、异步任务队列、审计日志,它未必主动尊重。尤其当上下文太长、文件太多时,它更容易抓住局部线索下手。
第二,它经常把“通用”误解成“高级”。
很多丑代码不是写得太简单,而是写得太会装。接口、适配器、基类、策略模式、配置层,一套招呼下来,当前问题解决没解决另说,维护成本已经先到账。
第三,它缺少真正的代码所有权。
人类工程师知道自己下周还要修这个坑,所以会克制。AI 没有这个心理负担。它写完会礼貌地说“已完成”,然后把未来留给你。
这也是为什么 DORA 2025 把 AI 描述为组织能力的放大器:团队本来有清晰架构和质量流程,AI 会放大效率;团队本来就混乱,AI 也会放大混乱。Stack Overflow 2025 调查里,开发者对 AI 输出准确性的信任并不高,这不是保守,而是被现实教育过。

给 AI 一份项目宪法
与其每次骂它“别过度设计”,不如把约束写进项目规则。可以放在 CLAUDE.md、AGENTS.md、.cursorrules 或团队内部模板里。
下面这段可以直接复制:
## Implementation Rules
- Make the smallest change that solves the requirement.
- Read existing code before editing.
- Follow repository patterns.
- Do not design for hypothetical future requirements.
- Do not add factories, adapters, interfaces, base classes, or new config layers unless required.
- Keep changes within the current module whenever possible.
- Do not refactor unrelated code.
- Tests should verify observable behavior.
- Before editing, state files and reasons.
- Before finishing, remove dead code and unnecessary indirection.注意,这不是为了让 AI 变得胆小,而是让它先学会克制。工程质量的底线通常不是“多高级”,而是“别人能不能接着改”。
每次改代码前,先让它交计划
AI 最容易失控的时刻,是你直接说“开始改”。更稳的做法是先让它交一份小计划:
请先不要修改文件。先阅读相关代码,然后输出:
1. 你认为需求涉及哪些模块;
2. 计划修改哪些文件;
3. 每个文件为什么需要改;
4. 哪些地方不应该改;
5. 验证方式是什么。
等我确认后再执行。这个步骤能过滤掉很多灾难。你会提前发现它误解了模块归属,或者准备重构一个根本不该碰的公共组件。
如果任务很小,不一定每次都人工确认,但计划仍然有价值。因为计划会把模型的“脑内路线”暴露出来,方便你及时刹车。
反过度设计清单
AI 写代码最大的问题之一,是它特别擅长把简单需求写成小型框架。可以在每次任务结束前,让它按下面清单自查:

请做一次反过度设计检查:
- 有没有为了未来需求新增抽象?
- 有没有新建接口、工厂、基类、适配层,但当前只有一个实现?
- 有没有把本来局部的逻辑提升成全局配置?
- 有没有修改无关文件?
- 有没有为了通过测试而改变测试意图?
- 有没有保留临时变量、日志、死代码或重复工具函数?
- 这个改动能否用更少文件、更少概念完成?这里有个简单判断:如果 AI 解释某个抽象时频繁使用“未来可以”“方便扩展”“更灵活”,但当前需求没有第二个真实场景,基本可以先删。
测试不是装饰品
很多 AI 生成的代码看起来顺滑,但一跑就露馅。更麻烦的是,它还会写一些只验证自己实现细节的测试。
好的约束应该要求它做三件事:
- 写行为测试,不写自我证明;
- 跑现有测试,而不是只跑新增测试;
- 如果不能跑,说明原因和手动验证路径。
你可以直接这样要求:
测试要求:
1. 优先覆盖用户可观察行为;
2. 不要为了实现细节写脆弱测试;
3. 必须说明运行了哪些命令;
4. 如果测试失败,先分析原因,不要直接改测试;
5. 如果无法运行测试,给出原因和最小人工验证步骤。这一步很重要。模型的解释有时像销售话术,测试结果才像收银小票。
让 AI 写代码,别让它管理复杂度
真正成熟的 AI 编程工作流,不是让模型一次性吞掉整个项目,而是把复杂度拆成一张张小工单。
适合 AI 直接做的任务:
- 补测试;
- 改局部 bug;
- 迁移重复格式;
- 生成小型工具函数;
- 根据清晰接口补实现;
- 做代码阅读和风险扫描。
不适合直接甩给 AI 的任务:
- 大范围架构重塑;
- 多模块状态归属调整;
- 权限、安全、交易、支付等高风险逻辑;
- 没有验收标准的“帮我优化一下”;
- 团队自己也没想明白的需求。
AI 是很好的放大器,但它放大的不一定是能力,也可能是混乱。你给它清晰边界,它会快得很可怕;你给它一团浆糊,它也能很快把浆糊摊满整个仓库。
最后一道人工闸门
提交前让 AI 做一次总结不够。你应该让它提供证据:
请给出最终交付说明:
1. 实际修改了哪些文件;
2. 每个修改解决了什么问题;
3. 运行了哪些验证命令,结果是什么;
4. 仍然存在什么风险;
5. 哪些地方你刻意没有修改。最后一项尤其重要。一个成熟工程师知道“不改什么”同样是判断力。AI 也必须被训练成这样。
当你开始用规则、计划、测试和审查来约束 AI,它就不再像一个兴奋过头的实习生,而更像一个执行力很强但需要清晰边界的队友。
它可以很快,但方向盘要在工程体系手里。
夜雨聆风