等级 L2 · 每天 30 分钟 · 场景:写代码→二、让 AI 写业务代码,改代码→三、改存量代码
一句话:AI 写不好业务代码,八成不是模型的问题,是你知道而它不知道的东西没告诉它。这篇讲怎么把上下文给足、怎么小步推进、以及哪些代码根本不该交出去。
学习地图
| 你的问题 | 看哪一节 |
|---|---|
| 「写出来的代码不能用」 | 一、给上下文 |
| 「新功能怎么让 AI 写」 | 二、让 AI 写业务代码 |
| 「改老代码它总是越改越乱」 | 三、改存量代码 |
| 「哪些活不该交给它」 | 四、什么不该让 AI 写 |
| 「生成完怎么审」 | 五、review 的重点 |
一、给上下文
同一个需求,两种给法的差距比换模型大得多。
❌ 写一个订单超时自动取消的功能
✅ 订单超时自动取消。
现状:Spring Boot 3 + MySQL,订单表 t_order 已按月分表(分片键 create_time)。
项目里已有 XXL-JOB,定时任务统一放 job 包下。
规则:待支付状态超过 30 分钟自动取消,取消要回滚库存。
约束:单次扫描不能锁表;任务可能重复触发,必须幂等。
不引入新中间件。
参考:库存回滚逻辑看 InventoryService.rollback,事务边界照它的写法。
输出:先给实现思路和涉及改动的文件清单,我确认后再写代码。
第二种能一次到位,因为补齐了四类只有你知道的信息——技术栈现状、业务规则、硬约束、可参照的既有代码。详细的结构见提示词工程。
「参考现有代码」是性价比最高的一句
比起描述你们的规范,直接指一个文件让它照着写更省事也更准:
照 PaymentService 的分层风格写:
- 入参校验在 controller 做完
- service 方法上标事务,远程调用不放事务里
- 异常统一抛 BizException,不 catch 后 return null
它能从代码里读出你们的隐式约定——命名习惯、日志格式、异常处理风格。这些东西写成文档要半页,指个文件只要一行。
项目级的通用约定别每次重复,写进规则文件一次搞定,见 AI编程工具。
二、让 AI 写业务代码
先要计划,再要代码
新功能不要直接说「实现它」。分两步:
第一步:列出要改动的文件、每个文件改什么、涉及的表和接口。先别写代码。
看完计划再决定放不放行。计划阶段发现方向不对,改一句话;代码生成完发现方向不对,白干半小时。
计划里最该盯的三件事:
- 它有没有漏掉边界(并发、幂等、失败回滚)
- 它有没有自作主张扩大范围(顺手重构了无关代码)
- 它假设的技术栈对不对(用了你们没有的依赖)
小步走,每步能验证
❌ 把这个功能实现了
✅ 先只写 OrderTimeoutJob 的扫描逻辑和幂等控制,
库存回滚先留个 TODO。写完我跑一下再继续。
一次一小步的好处不是”稳”,是出问题时你知道是哪一步错的。这和小步提交是同一个道理。
让它自己跑一遍
代理型工具能执行命令。明确要求它跑验证,产出质量完全不同:
写完跑 ./mvnw test -Dtest=OrderTimeoutJobTest,失败就改到通过再告诉我。
它会自己看报错、自己改。你收到的是「已验证能跑」的代码,而不是「看起来对」的代码。
一个反直觉的点:别一次要太多
AI 一次能生成几百行,但你 review 不了几百行。生成速度不是瓶颈,你的审查速度才是。
按一次能审完的量来切——大约就是一个方法、一个类,或者一处明确的改动。
三、改存量代码
改比写难,因为存量代码有你不知道的历史。
先让它读,再让它改
先读 OrderService.cancel,告诉我:
1. 这个方法都被谁调用
2. 它依赖哪些外部服务
3. 有没有隐式的顺序依赖
读完等我确认,先别改。
这一步经常能发现「这里不能动,因为 XX 依赖它」——省掉一次线上事故。
划定边界,明确禁止扩散
AI 有很强的「顺手优化」倾向:你让它改一个方法,它把整个类重构了。
只改 cancel 方法内部,不要动方法签名,不要动其他方法,
不要调整 import 顺序,不要加新的抽象层。
说了基本就听——新模型对这类约束遵循得不错。不说,它就按自己的审美改。
大重构:让它做机械部分,你做判断部分
| 重构环节 | 谁来做 |
|---|---|
| 找出所有调用点 | AI(比你 grep 得全) |
| 决定拆成什么结构 | 你 |
| 按既定结构机械改造 | AI |
| 判断行为是否等价 | 你 + 测试 |
重构前先补测试——没有测试的重构,AI 改完你没法验证是否等价。可以让 AI 先补测试(见 AI辅助测试与评审),再重构。
四、什么不该让 AI 写
判断标准不是「AI 写得了吗」,是**「写错了代价多大、验证起来多容易」**:
| 代价 / 验证 | 容易验证 | 难验证 |
|---|---|---|
| 代价低 | ✅ 放心交(DTO、格式转换、样板代码) | 🟡 交,但要抽查 |
| 代价高 | 🟡 交,逐行审(CRUD 接口) | 🔴 自己写(钱、权限、删数据) |
具体清单:
🔴 自己写
- 涉及金额计算、账务处理的
- 涉及权限判断的
- 涉及数据删除、批量更新的
- 依赖你们特有业务规则的核心逻辑——它不知道你们的规则,只会编一个合理的
🟡 可以交,但要逐行审
- CRUD 接口:结构能用,事务边界/异常处理/参数校验要改
- 并发相关:它会写锁,但不一定用对粒度
- 涉及外部服务调用的:超时、重试、降级它经常漏
✅ 放心交
- DTO / VO / 枚举 / 配置类
- 格式转换、字段映射、解析
- 测试用例骨架
- 一次性脚本、数据订正 SQL(跑之前自己看一遍 WHERE 条件)
五、review 的重点
AI 生成的代码,和实习生写的代码,问题分布不一样。按这个顺序看效率最高:
- 有没有编 API —— 不存在的方法、拼错的配置项、幻想出来的注解。这是 AI 特有的错误类型,人不会犯,见大模型基础概念
- 边界条件 —— 空值、越界、除零、并发。它写的主流程一般没问题,边界经常漏
- 是不是过度设计 —— AI 倾向于加不必要的接口、抽象层、防御性判断。删掉比加上更需要你动手
- 异常处理对不对 —— 常见问题是 catch 住然后吞掉,或者笼统 catch Exception
- 业务逻辑正确性 —— 只能靠你,它不知道你们的业务规则
前四项能靠经验快速扫过,第五项才是你该花时间的地方。
常见追问
-
AI 写的代码风格和项目不一致怎么办? 三个办法,按性价比排:写进规则文件(一次生效,长期有用);让它参照某个现有文件(一句话,立即生效);接 formatter/lint 到 CI(机械问题机械解决)。别靠每次口头强调。
-
它总说「已完成」但其实没做完? 明确要求验证:「跑通测试再告诉我完成」「把改动的文件列出来我核对」。能执行命令的工具会真的去跑,比口头承诺可靠。收到「已完成」时习惯性问一句「验证过了吗、怎么验的」。
-
多人协作时怎么避免 AI 生成的代码风格打架? 规则文件进 git,全员共用一份。这是 AI 时代的
.editorconfig——统一约定放在仓库里,不放在各人的对话历史里。 -
生成的代码要不要标注「AI 生成」? 团队规范问题,没有标准答案。但不建议在代码注释里标——review 标准应该只看代码质量,不看谁写的;标了反而容易让 review 松懈或带偏见。要追溯就在 commit message 里体现。
-
让 AI 写完我看不懂怎么办? 这是危险信号,两个处理方式:让它解释(「逐行说明这段在干什么、为什么这么写」);或者直接推翻重来,要求用更朴素的写法。看不懂的代码不该合进主干——不管谁写的。