1. 为什么我坚持让 AI 先写方案再写代码
1.1 一个让我彻底改变习惯的翻车现场
去年帮一个做跨境电商的朋友改一套订单同步服务,需求听起来很简单:把三个平台的订单拉到一个中台库,做去重和状态映射。我当时图快,直接让 AI 生成了一版 Python 脚本,跑起来看着挺顺,结果上线第二天就出事了——某个平台的订单状态字段是字符串枚举,另一个平台是数字码,AI 在生成代码时自己"猜"了一套映射关系,把"已发货"映射成了"待付款"。朋友那边客服被客户骂了一整天。
事后复盘,问题根本不在 AI 写得对不对,而在我压根没让它先把映射规则、字段语义、异常分支这些事讲清楚。代码只是方案的落地,方案没定,代码写得再漂亮也是空中楼阁。
从那以后我改了个习惯:任何非玩具级的任务,先让 AI 输出一份方案文档,我审完、改完、确认无误,再让它动代码。这个习惯救了我至少五次。
1.2 方案先行到底解决了什么问题
很多人对 AI 编程的理解还停留在"我描述需求,它吐代码"。这在 LeetCode 级别的题目上没问题,但真实项目里,代码只占工作量的三成,剩下七成是:边界条件是什么、数据从哪来到哪去、失败了怎么回滚、并发下会不会打架、以后谁来维护。
让 AI 先写方案,本质上是把这七成的思考过程显性化。方案里会自然暴露出这些问题:
- 输入输出的契约:字段类型、取值范围、空值怎么处理
- 状态流转:一个订单从创建到完成经过哪些状态,哪些状态可以互相跳转
- 异常路径:网络超时、第三方返回错误码、数据格式不符预期时怎么办
- 非功能需求:QPS 大概多少、要不要幂等、日志打到什么粒度
这些东西如果藏在代码里,你得逐行读才能发现;写成方案,扫一眼就知道哪里没想清楚。我实测下来,一份 800 字的方案能省掉后面至少两小时的调试和返工。
1.3 这套方法适合谁,不适合谁
适合的人:有一定工程经验、能判断方案好坏的开发者;带小团队的技术负责人;需要快速验证想法但不想埋雷的独立开发者。
不太适合的人:完全零基础、连变量作用域都还没搞明白的新手。因为方案审阅需要你有能力判断"AI 说的这个方案对不对",如果你判断不了,那方案和代码对你来说都是一样的黑盒。新手可以先从"让 AI 解释它写的代码"开始,等有了判断力再上方案先行。
提示:方案先行不是让你写八股文。一份好的方案应该控制在 500 到 1500 字,超过这个长度说明你在写设计文档而不是方案,效率反而下降。
2. 方案到底该写什么:一份可复用的模板拆解
2.1 我常用的方案骨架
经过几十次迭代,我固定下来一套提示词模板,让 AI 按这个结构输出。你可以直接抄:
请针对以下需求先输出一份技术方案,不要写代码。 方案需包含: 1. 需求理解:用你自己的话复述一遍,指出我描述里模糊或矛盾的地方 2. 输入输出定义:数据结构、字段类型、示例值 3. 核心流程:分步骤描述,标注每步的输入输出 4. 异常与边界:列出至少 5 种可能的异常情况及处理策略 5. 技术选型:用什么语言/库/中间件,为什么 6. 潜在风险:这个方案可能在哪里出问题 7. 待确认问题:你需要我补充哪些信息才能继续 需求如下:[你的需求]这个模板的关键在于第 1 条和第 7 条。第 1 条逼着 AI 复述需求,很多时候它复述出来的东西和你想的完全不一样,这就是需求歧义的早期信号。第 7 条让 AI 主动提问,把"它不知道但假装知道"的部分挖出来。
2.2 需求理解环节:把歧义扼杀在摇篮里
我拿一个真实例子说明。之前要做"扫盘代码"类的文件扫描工具,需求是"扫描指定目录下所有文件,找出重复文件"。如果直接让 AI 写代码,它会给你一个基于文件大小和 MD5 的脚本,看起来没问题。
但让它先写方案,它在"需求理解"里会问:
- "重复"的定义是什么?内容完全相同,还是文件名相同?
- 大文件(比如 10GB 的视频)要不要参与比对?全量算 MD5 会很慢
- 软链接和硬链接怎么处理?要不要跟随
- 扫描结果怎么输出?控制台、文件还是数据库
这四个问题里,第三个和第四个我当初压根没想过。软链接如果处理不当,可能造成无限递归;结果输出方式决定了整个程序的结构。你看,方案阶段花五分钟,省掉的是后面重构的半天。
2.3 输入输出定义:契约先于实现
这一块是方案里最"硬"的部分,也是最容易被跳过但最不该跳过的。我要求 AI 用表格把数据结构列清楚,包括字段名、类型、是否必填、示例值、备注。
举个数据同步的例子,AI 输出的契约表大概长这样:
| 字段名 | 类型 | 必填 | 示例值 | 备注 |
|---|---|---|---|---|
| order_id | string | 是 | "SO20240115001" | 平台订单号,全局唯一 |
| status | int | 是 | 2 | 1待付款 2已付款 3已发货 4已完成 5已取消 |
| amount | decimal | 是 | 199.00 | 单位元,保留两位小数 |
| created_at | string | 是 | "2024-01-15 10:30:00" | 平台本地时间,需转 UTC |
有了这张表,后面写代码时字段映射就是照抄,不会出现我开头说的那种"AI 自己猜映射"的事故。而且这张表可以直接拿去做单元测试的用例,一举两得。
2.4 异常与边界:AI 最容易偷懒的地方
说实话,如果你不明确要求,AI 写方案时对异常处理往往是敷衍的,一句"做好错误处理"就带过去了。所以我在模板里强制要求"列出至少 5 种异常情况"。
还是订单同步的例子,强制要求后 AI 列出来的:
- 第三方接口超时(超过 10 秒无响应)
- 第三方返回限流错误码(429)
- 订单状态字段出现未定义的值(比如平台新增了状态码 6)
- 金额字段为负数或超过合理范围
- 同一订单号在两次拉取中状态回退(已发货变回已付款)
第 3 条和第 5 条是真实项目里最坑的。平台悄悄加状态码,你的程序如果没做兜底就会崩;状态回退如果不处理,中台数据就乱了。这些在方案阶段列出来,写代码时自然就会加上对应的分支。
注意:异常列表不是越长越好,重点是覆盖"会导致数据错误"和"会导致程序崩溃"这两类。纯粹的日志级别问题不用在这里展开。
3. 从方案到代码:怎么让 AI 按方案落地
3.1 把方案作为上下文喂回去
方案确认后,下一步不是重新描述需求,而是把方案原文贴回去,让 AI 基于方案写代码。提示词大概是这样:
以下是我们确认过的技术方案,请严格按照方案实现代码。 要求: - 每个函数上方用注释说明它对应方案里的哪一步 - 异常处理必须覆盖方案第 4 节列出的所有情况 - 关键逻辑处加日志,日志级别按方案约定 - 先输出代码结构(有哪些文件、每个文件负责什么),我确认后再写具体实现 方案如下:[粘贴方案]这里有个小技巧:先让它输出代码结构,别急着写实现。因为结构错了,实现写得再好也得推倒重来。结构确认这一步通常只要一两分钟,但能避免大量返工。
3.2 分模块生成,别一次性要全部代码
我踩过的坑:一次性让 AI 生成一个包含五个模块的完整项目,结果它写到第三个模块就开始"忘记"前面的接口定义,函数签名对不上,变量名前后不一致。后来我改成按模块生成,每个模块生成完立刻做一次接口对齐检查。
具体做法是,让 AI 先输出所有模块间的接口定义(函数名、参数、返回值),确认后再逐个模块实现。这样即使某个模块生成得不好,也不会污染其他模块。
3.3 代码诊断插件的配合使用
方案落地阶段,我习惯开着代码诊断插件(比如静态分析工具)实时看提示。AI 生成的代码经常有一些"能跑但不规范"的地方,比如未使用的变量、可能的空指针、资源没关闭。这些诊断插件会直接标出来,比人工 review 快得多。
我的流程是:AI 生成一个模块 → 诊断插件扫一遍 → 修掉明显问题 → 人工看核心逻辑 → 进入下一个模块。这个循环走下来,代码质量比"生成完再统一 review"高不少,因为问题在刚产生时就被修掉了,不会累积。
3.4 一个完整的落地示例
拿"文件去重工具"举例,方案确认后我让 AI 按这个顺序实现:
第一步,它输出结构:
scanner.py - 目录遍历,产出文件列表 hasher.py - 计算文件哈希,带缓存 dedup.py - 分组比对,输出重复组 cli.py - 命令行入口,参数解析第二步,我确认结构合理(比如我要求 hasher 支持分块读取大文件)。
第三步,逐个模块生成,每个模块生成后跑一次诊断。
第四步,写一个小的测试脚本,造几个重复文件验证。
整个过程大概四十分钟,其中方案阶段占了十分钟。如果跳过方案直接写,我估计得花一个半小时,而且大概率会漏掉大文件分块读取这个点。
4. 实操中踩过的坑与排查技巧
4.1 AI 方案"看起来很对"但实际跑不通
这是最常见的问题。AI 写的方案逻辑自洽,但落到具体环境就出问题。比如它建议用 Redis 做去重缓存,方案里写得头头是道,但你的环境根本没有 Redis,或者版本太老不支持某个命令。
排查思路:方案确认阶段,凡是涉及外部依赖的,我都会追问一句"这个依赖在我的环境里是 X 版本,方案还成立吗"。让 AI 针对你的实际环境做适配,而不是给一个通用方案。
4.2 方案和代码不一致
有时候 AI 写代码时会"自作主张"偏离方案,尤其是方案里没写死的细节。比如方案说"超时重试 3 次",代码里写成了无限重试。
我的应对办法是在提示词里加一句"如果实现时发现方案有问题,先停下来告诉我,不要自行修改方案"。这句话很管用,能把偏离扼杀在发生前。
4.3 常见问题速查表
| 问题现象 | 可能原因 | 处理方式 |
|---|---|---|
| 方案里字段类型和代码不一致 | 生成代码时没带方案上下文 | 把方案原文贴回,要求逐字段对齐 |
| 异常分支代码里缺失 | 方案异常列表不够具体 | 方案阶段强制列 5 种以上异常 |
| 大文件处理卡死 | 方案没考虑分块 | 方案阶段明确数据规模上限 |
| 模块间接口对不上 | 一次性生成太多模块 | 先定接口,再分模块实现 |
| 依赖环境不匹配 | 方案用了通用假设 | 方案阶段声明实际环境版本 |
4.4 几个我压箱底的小技巧
第一个,让 AI 在方案最后附一段"如果我是 reviewer,我会质疑这个方案哪里"。这招能挖出 AI 自己都没把握的地方,往往就是风险点。
第二个,方案里的每个技术选型,都让它给一个"不用这个会怎样"的对比。比如"为什么用消息队列而不是直接调用",这个对比能帮你判断选型是否过度设计。
第三个,代码生成后,让 AI 自己写一份"这份代码和方案的对应关系表",逐条列出方案里的要求对应代码的哪一行。这个表既是自检,也是以后维护的索引。
5. 把这套方法扩展到更复杂的场景
5.1 多模块项目的方案拆分
当项目大到单个方案装不下时,我会做分层方案:先出一份总方案,定清楚模块划分和接口;再针对每个模块出子方案。总方案控制在 1000 字以内,子方案各 500 字左右。
这样做的原因是,AI 的上下文有限,一份两万字的巨型方案它记不住,生成代码时照样会丢细节。拆成小块,每块都在它的"注意力范围"内,质量稳定得多。
5.2 涉及第三方服务的方案要点
只要方案里涉及调用外部服务,我一定会让 AI 补充这几项:超时时间、重试策略、降级方案、鉴权方式、限流应对。这五项缺任何一项,上线后都可能出问题。特别是降级方案,很多人不写,结果第三方一挂自己的服务也跟着挂。
5.3 方案文档的长期价值
方案不只是给 AI 看的,它还是团队协作的载体。新人接手时,看方案比看代码快十倍。我现在的习惯是,方案确认后存进项目仓库的 docs 目录,代码里引用方案章节号。半年后回头看,这份方案就是最好的设计文档。
而且方案是可以复用的。同类需求第二次做时,把上次的方案调出来改改就行,比从零开始快得多。我手上已经攒了十几份方案模板,覆盖数据同步、文件处理、接口对接、定时任务这几类常见场景,新项目基本是"改模板"而不是"从零写"。
5.4 什么时候可以跳过方案
也不是所有事都要写方案。我的判断标准是:如果这个任务你闭着眼睛都能写对,那就跳过。比如写个快速排序、格式化一段 JSON、改个配置,这些直接让 AI 写代码就行,写方案反而是浪费时间。
但只要满足以下任一条,我就一定先写方案:涉及数据持久化、涉及外部服务调用、有并发或定时逻辑、代码量预计超过 200 行、需要别人维护。这几条基本覆盖了真实项目里 90% 的坑。
说到底,让 AI 先写方案再写代码,核心不是流程本身,而是逼着自己在动手前把问题想清楚。AI 只是把这个思考过程加速了、显性化了。我用了大半年,最大的收获不是省了多少时间,而是代码返工率明显下降,晚上睡觉踏实多了。