用AI编程智能体写功能,最怕的不是它不会写代码,而是你只丢一句话需求,它写出来的东西跟你脑子里的东西完全不是一回事。改到第三轮你会发现,改这里坏那里,需求也悄悄变了样子。我最近按“规范驱动开发”的思路跑完整套流程,先写规格文档,再让智能体按规格实现、验证、落地,稳定性比直接对话明显高出一截。这篇文章把从规格文档到功能落地的流程拆开讲:规格文档怎么写、任务怎么拆、每一步怎么验收、出了问题先查哪里。适合正在用AI编程助手接实际需求、又觉得结果不可控的开发者。
1. 先回答关键问题:规范驱动开发到底在防什么
1.1 直接对话让AI写功能,为什么总在第三轮崩
主流AI编程智能体处理单点代码生成问题时都不差。给它一个明确的小函数,往往一次就能写对。但一到真实业务功能,对话式开发就崩了。原因不在模型能力,而在“需求变了,对话没跟着变”。
举个例子。你让智能体实现一个订单查询接口,第一轮它返回了正确字段。第二轮你说“把金额单位换成元”,它改了。第三轮你说“加上用户权限校验”,它加了权限,但金额单位又回到了分。为什么会这样?因为长对话里,智能体每次都要把上下文重新理解一遍,前面的约定会被后面的新指令覆盖。它没有一份稳定的“事实基准”可以回退。
这就是需求漂移。人脑里有完整需求,AI只看到最近几轮对话。你以为双方在同一个版本上,实际已经在两条线上跑。另一个常见问题是:代码能跑,但边界条件全没处理。它只按最后一句指令执行,不知道你心里还装着超时、空值、重复提交这些隐性要求。规范驱动开发要防的,就是这两件事:需求在对话里漂移,边界在实现里丢失。
1.2 规格文档不是PRD,也不是README,是一份可验收的契约
很多人说“我写了PRD,怎么智能体还是乱来”。这里要区分清楚:
- PRD描述“为什么做、给谁用”,是给产品、设计、开发一起对齐的背景材料。
- README描述“这个系统已经有什么”,是用来告诉后来者怎么使用和修改的。
- 规格文档描述“这次功能具体要有什么行为”,每一项都必须能被验证。
对AI编程智能体来说,规格文档真正起作用的不是“描述”而是“约束”。每一条规格最终要变成一道测试:输入是什么,预期输出是什么,异常情况下应该怎样。比如“对金额做格式化”不算合格规格;“当金额小于0时返回参数错误并记录日志,金额等于0时正常返回0.00”才是。
所以写规格时可以用这个自我检查标准:如果团队里一个没参与讨论的初级开发拿了这份文档能直接写出代码和测试,它才算合格。如果还需要你补解释,说明规格还没写完。
注意:规格文档是写给你自己、团队和智能体三方共同遵守的契约。不要把它当成一次性写作任务,后续每次需求变更都要同步更新它。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前先准备:干净仓库、一键测试和一份可验收规格
2.1 运行条件里最容易漏掉的是“可运行基线”
规范驱动开发的前提,是智能体能“自己动手验证”。如果它只能生成代码、不能运行命令,那你写再细的规格也没用,因为没人替它判断结果对不对。开始之前,建议先确认这几件事:
- 仓库能正常拉取,依赖安装干净,当前分支处于可运行状态。
- 项目里至少有一套一键执行的测试命令。没有的话,先补一条最基础的启动冒烟测试。
- 智能体工具本身具备运行命令、读写文件的能力。
- 准备一份带固定编号的规格文档,放在仓库固定目录下,后续沟通都以编号引用。
- 准备一个干净分支,让智能体在分支上改,避免直接污染主分支。
这里最容易忽略的是“可运行基线”。我遇到过好几次:让智能体改代码,它改了两轮发现项目根本启动不了,结果是环境变量没配。智能体把环境问题当成自己的代码问题反复重写,越改越乱。所以基线必须先验证,再开始写功能。
2.2 规格文档必须写清楚六类信息
根据实测经验,一份AI能动得起来的规格文档,至少包含六个部分:
| 部分 | 说明 | 示例 |
|---|---|---|
| 背景与目标 | 为什么做这个功能,涉及哪些模块 | 解决后台订单金额显示单位不一致 |
| 输入定义 | 参数、类型、格式、范围、来源 | title:字符串,1到100字符 |
| 输出定义 | 返回值、文件、界面、日志的格式 | 返回规范化字符串 |
| 行为规则 | 正常路径按什么顺序执行 | 先校验输入,再查询,再格式化 |
| 边界与异常 | 空值、超时、重复、越界怎么处理 | 收到空字符串时返回参数错误 |
| 验收标准 | 用什么命令和测试确认“做到了” | 新增测试全部通过,旧测试无回归 |
六个部分里,最容易漏的是“边界与异常”。AI生成代码时天然偏爱正常路径,你不在规格里写空指针、超时、非法输入,它就不处理。这些不是细节,是质量问题的主要来源。
2.3 一个最小规格示例:从描述到可测试
下面是一份简化但结构完整的示例,功能是给文章标题生成URL别名:
markdown复制# FEAT-001:URL Slug 生成器
## 背景
文章发布时需要根据标题生成唯一 URL 别名。
## 输入
- title:字符串,1 到 100 个字符,允许中文、字母、数字、空格和标点。
## 输出
- 返回 slug 字符串,只包含小写字母、数字和连字符。
- 连字符不连续、不放在开头或结尾。
## 行为规则
1. 去除标题首尾空格。
2. 将连续空格和标点替换为单个连字符。
3. 中文转拼音后再小写化处理。
4. 超长时截断到 60 个字符,以完整词边界结尾。
## 边界与异常
- title 为空:抛出参数错误。
- title 全部为标点:返回空字符串,不抛错,记录 warn 日志。
## 验收标准
- 新增测试全部通过。
- 手工验证标题"你好,世界!Hello World"的输出符合预期。
- 不允许修改已有接口签名。
这份规格看起来短,但每一句都对应一个可测行为。智能体实现时不需要猜需求,写完可以直接对照验收标准自查。实际项目规格可以更长,但结构不变。
3. 从规格到功能落地的三个执行阶段
3.1 拆任务:小到能独立验证,大到不琐碎
规格文档是一整份需求,但你不能让智能体一口气全部实现。一次改太多文件,上下文太长,中间任何一个细节被漏掉,后面排查非常痛苦。我的做法是把功能拆成多个子任务,每个子任务满足三个条件:
- 只聚焦一个小逻辑点,比如字段校验、格式转换、查询逻辑。
- 有对应的验收测试,跑完能明确判断成功或失败。
- 代码改动量可控,通常不超过两三个文件。
拿上面的 Slug 生成器举例,可以拆成:输入校验、标点与空格归一化、中文转拼音、截断逻辑、对外接口接入。每个子任务分别给智能体一次指令,一次只改一件事。
为什么要拆这么细?因为AI智能体的可靠性跟任务粒度强相关。任务小,上下文占用少,它不容易遗忘前面的约定;验证点单一,出问题定位快;即使某个子任务实现错了,回滚也只影响一小块,不会把整个功能带崩。
3.2 逐条实现:让智能体先跑测试再汇报
给智能体的指令可以按这个模板组织:
text复制需求来源:docs/specs/xxx.md 中的 FEAT-001-2。
任务:实现输入校验逻辑。
要求:
1. 先阅读规格中对应编号,不要修改其他子任务代码。
2. 实现后运行对应测试命令。
3. 测试失败就修复再汇报,不要减少测试覆盖。
4. 汇报时给出改动文件清单和测试结果摘要。
这样写有三个好处。第一,所有信息有唯一编号,智能体不会拿过期的需求做判断。第二,明确“先跑测试再汇报”,它不能说自己“觉得没问题”。第三,限定改动范围,避免它顺手重构别的地方。
每个子任务完成后,建议人工快速看一遍改动差异。不用逐行审,但要确认:改动文件是否在预期范围内,有没有引入跟任务无关的修改,测试结果是否符合预期。看完没问题,再进入下一个子任务。
3.3 收尾回归:智能体说完成不代表功能完成
所有子任务通过之后,才是真正容易翻车的地方。单点逻辑各自正确,不代表组合起来正确。我会按这个顺序做收尾:
- 跑全量测试套件,确认没有回归。
- 启动服务或应用,走一遍真实链路,用真实数据和边界数据各测一次。
- 检查日志输出、错误提示、命名规范、格式一致性。
- 确认规格文档和最终行为一致。如果有意调整了行为,先改规格再改代码。
- 提交分支,写清楚每个子任务对应的提交信息。
这里要特别提醒:智能体说“完成了”不等于功能完成了。它有概率漏掉联调步骤,或者只测了正常路径。收尾检查必须由人来做,至少做一次端到端的真实调用。
4. 执行过程中盯住的三类判断标准
4.1 任务粒度和上下文长度的平衡
任务粒度没有固定标准,但我一般用这几个信号判断:
- 预计新增代码超过150到200行,就继续拆。
- 一个任务涉及三个以上文件,就考虑拆开。
- 验收测试数量超过十来个,说明任务负载偏大。
- 智能体开始复述旧代码、重复问同一个问题、把早期约定改掉,说明上下文已经比较拥挤,要开新任务而不是继续追加指令。
上下文长度不是越长越好。长上下文里,早期约束会被后来的指令稀释。与其把所有需求塞进一次对话,不如让每次对话的负责范围小一点。让规格文档承担长期记忆,让对话只承担当前子任务的执行。
注意:上下文拥挤时,最适合的动作是开新会话并重新带上规格编号,而不是继续在旧对话里追加“记住我之前说的”。
4.2 验收不是“能跑”,而是四个维度全通过
很多开发者觉得“测试通过了”就万事大吉,这在AI生成代码的场景下远远不够。我建议至少看四个维度:
| 维度 | 判断方法 | 什么算通过 |
|---|---|---|
| 功能正确 | 子任务测试与全量测试 | 新用例全通过,旧用例无回归 |
| 边界覆盖 | 空值、超长、重复、并发 | 边界用例通过,异常有日志 |
| 集成稳定 | 真实链路调用一次 | 端到端走通,耗时在预期内 |
| 代码可维护 | 看改动范围、命名、注释 | 没引入无关重构,结构干净 |
如果某个维度没过,别急着让智能体“再改改”。先定位是规格没写清楚、测试写错,还是实现确实有问题。很多时候你发现改了三四遍都不对,回头一看,是规格里根本没有定义结果长什么样。
4.3 长流程要靠进度表而不是对话记忆
当一个功能包含很多子任务时,光靠记忆管理进度不现实。建议把进度机制化:
- 在规格文件里增加一个“任务状态表”,每个子任务一行,标注:待开始、进行中、已实现、已验证。
- 每个子任务完成时更新状态,同时在提交记录里留下对应编号。
- 遇到失败的任务,不要原地反复重试。先保留失败现场,再交给下一个子任务或人工排查。
进度表不仅能让你看清还剩多少活,更重要的是,它能防止智能体在长流程里“自我感觉良好”。它每完成一步,你都有明确的证据链。
5. 常见问题排查顺序与适用边界
5.1 代码能跑但不是你要的逻辑,先查规格再查测试
这类问题最常见,排查顺序我一般这样走:
- 先看规格:验收标准是否可执行?是不是“金额格式化”这种模糊描述?
- 再看测试:测试本身是否覆盖了预期行为?有没有可能测试写错?
- 再看上下文:智能体是不是基于旧消息实现,没有读到规格更新?
- 再看环境:依赖版本、配置、路径有没有变化?
- 最后才是让智能体重写。
这个顺序的错误率很低。原因很简单:AI生成的功能不符合预期,大部分时候是预期没有被完整传递,而不是模型不会写代码。规格不准确,测试就不可靠;测试不可靠,智能体根本不知道什么叫“做对了”。
5.2 反复修改越改越乱时,果断重开会话而不是继续追加
有些功能改了五六轮,每次只改一个点,但代码结构越来越差。这时候可以坚持几个原则:
- 每次只提一个明确的修改点,对应到规格编号。
- 让智能体给出最小改动,禁止它顺便格式化、重构无关代码。
- 如果改动牵涉多个子任务,回到规格层面更新,再按子任务重新执行。
- 用版本管理的对比功能确认改动范围,超出预期的部分退回。
改到第三轮还不对,就不要在这个对话里继续了。新建一次会话,把最新规格和当前代码状态重新喂给智能体,效果往往比继续追加指令好。
5.3 这些项目先别让智能体直接落地功能
规范驱动开发能提升稳定性,但解决不了所有问题。下面这些场景,我会建议先把范围收窄:
- 遗留大仓库,模块间依赖极多,规格很难写清楚边界。
- 安全敏感逻辑,比如支付、权限、数据脱敏,必须人工逐行审查。
- 项目连基本测试都没有,规格写得再好也没有验证手段。
- 需求本身还没想清楚,今天一个样明天一个样,先别急着写规格,先做需求梳理。
- 纯视觉和交互体验要求很高的界面,靠文字规格很难约束。
这些场景不是说不能用AI编程智能体,而是不适合“直接落地功能”。更稳妥的用法是:让智能体做单个小模块、写测试、补注释、做重构辅助,核心逻辑由人掌控。
我现在的工作习惯是:先写规格,再拆任务,再让智能体实现,最后人工验收。这套流程不会让AI编程智能体瞬间变强,但会把“不可控”变成“可追踪”。功能做得对不对,不再靠感觉,而是靠一份能验收的规格和一组能跑通的测试。真正值得盯住的,不是它写了多少行代码,而是每一步是否有明确的产出和验证结果。
