告别 AI 放飞自我:项目级 Spec 驱动开发(Spec-Driven AI Coding)与工程实践
当你让 AI 开发一个“小需求”时,它像个精明利落的高级工程师,几秒钟就能交付一段优雅的代码; 但当你让它接手一个“跨前后端的中大型系统级需求”时,它往往迅速退化成一个缺乏工程常识的初级实习生——遗漏边界条件、前端用假数据糊弄、页面粗糙没有五态、后端没有事务与并发保护、甚至自作聪明脑补需求…… 问题的本质不是大模型不够聪明,而是:我们试图用“聊天提示词(Chat Prompts)”来驾驭必须靠“软件工程规范(Software Engineering Specs)”才能约束的复杂系统。
一、真实世界的复盘:为什么上一代工作流在“大需求”面前失效了?
今年 6 月,我曾在博客分享过一篇《让 AI Agent 接力开发中大型需求:一套可持续的多会话 Coding 工作流》,并开源了 large-feature-ai-coding Skill。那套方案的核心,是通过 final_design.md(最终设计)和 execution_plan.md(执行计划工作包台账),试图把一次漫长的开发拆解成一个个单会话工作包,让 Agent 跨会话接力。
在之后的两三个月里,这套方法在一些中小型功能或独立模块内部的重构中表现尚可。但随着我们在业务中尝试让 AI 接管更大颗粒度的需求(如跨前后端的大型业务中心、多角色权限流转的复杂表单系统、或者是近乎从零开始的子系统),现实狠狠地泼了一盆冷水:
AI 依然非常容易“放飞自我”。
1.1 大需求下 AI 的五大经典翻车现场
如果你长期让 Cursor、Codex 或 Claude Code 跑复杂需求,下面这些场景你一定不会陌生:
- 需求遗漏与隐蔽漂移
你洋洋洒洒提了 8 点要求,AI 热情满满地列了个计划。前两步做得挺好,到了第 4 步开始,它就悄无声息地漏掉了第 3 点的权限控制和第 7 点的数据导出;或者在多轮会话后,它已经彻底忘记了最初定下的业务边界。 - 前端界面粗糙丑陋、交互肤浅
AI 常常从后端接口或数据结构直接“蹦”到前端代码。由于缺少严肃的前端设计阶段,生成的界面往往极其简陋:没有设计系统 Token,充满各种突兀的硬编码颜色和间距;没有 Loading 骨架屏、没有 Empty 空状态、没有 Error 重试反馈;甚至按钮点击只是在控制台打印一个console.log("submit"),根本谈不上真实可用。 - “降级交付”与 Happy Path 偏执
AI 本能地喜欢把问题简单化。只要遇到跨组件状态同步、复杂的表单联动或边缘异常,它就会倾向于“先用假数据写死”、“做个简化版示意”、“这里留个 TODO 后续完善”。你以为功能完成了,一连真实接口或者断个网,系统立刻崩溃。 - 后端质量糟糕与逻辑不自洽
表结构没有索引,实体字段直接当作接口 DTO 暴露给前端;写操作没有事务边界,多表写入失败后数据残留;状态流转没有防重与幂等,并发操作靠运气;报错码随手捏造,导致前端完全不知道怎么向用户展示错误。 - 单会话单脑过载,团队与多 Agent 无法协同
随着代码和讨论越来越长,单一会话的上下文迅速撑爆。更致命的是,所有的计划都揉成一张大表,你根本无法让两三个不同平台的 AI Agent(或者团队里的其他人)安全地分工并行,因为谁也搞不清谁动了哪块、契约到底由谁说了算。
1.2 根因定位:缺乏“需求基底”与“工程门禁”
为什么 final_design + execution_plan 在大需求下撑不住了?
深入复盘后,我发现症结在于:
- 没有明确的需求基底(Single Source of Truth):原始需求缺乏编号(BR-xx),没有明确的验收标准(AC)。需求一旦变化,直接去改代码,导致文档、契约与代码彻底分家。
- 前端缺少“设计阶段”:代码工作包直接驱动编码,AI 在完全没有想清楚视图清单、信息架构、组件复用和五态设计时,就已经在敲 JSX 了。
- 模块之间没有契约隔离:没有一个类似于
module-common的纯净契约层,导致前端模块和后端模块互相猜测字段,牵一发而动全身。 - 没有强制性的停顿点与完成定义(DoD):只要 AI 敲完了代码,它就以为自己做完了。缺乏浏览器真实走测与接口正反例校验的刚性门禁。
我们必须建立一套全新的范式——Spec 驱动的 AI 开发(Spec-Driven AI Coding)。
二、核心理念:Spec 驱动与可追溯需求链
大厂在研发复杂软件时,从不会让工程师直接对着一句大纲写代码,而是遵循严密的工程流转:从 BRD / PRD 到架构方案,再到模块任务拆解与测试用例。
在 AI 时代,这套机制不仅没有过时,反而变得空前重要。
对 AI Agent 而言,它的上下文窗口是有限的,它的注意力衰减是必然的。Spec 模式的核心精髓在于九个字:
降难度、减 Token、多人/多 Agent 开发。
2.1 把 AI 当作“零上下文的新人”
与 AI 协作的第一铁律是:把 AI 当作一位智商很高、但没有任何团队默契、极容易照字面意思脑补的“零上下文新人”。
- 你只要给的描述存在模糊词(“合理提示”、“适当分页”、“优化界面”),AI 就会按照它预训练模型里的概率分布随意发挥;
- 你只要没有定义异常分支,它就一定会假装异常永远不会发生;
- 你只要没有明确接口契约,前端 Agent 就会自己捏造一套响应结构,后端 Agent 则写出另一套。
因此,消除模糊性的唯一手段,就是建立一条从业务目标到代码验收的端到端可追溯链:
在这条链路里,每一个概念都有其不可替代的定位。
三、概念透析:BRD、BR、R、Design、T 到底是什么?
初次接触这套 Spec 规范的同学,可能会被几个缩写搞懵。其实只要理顺了粒度和职责,逻辑极其自然:
3.1 BRD:需求的总账与最高宪法
在 spec-driven-ai-coding 体系中,BRD 是一个文档,不是一条具体需求。在大型(L 级)项目中,它对应根目录下的 brd.md。
它必须包含:
- 业务背景与成功指标
- 用户角色矩阵与权限边界
- 极其明确的范围外(Out of Scope,本次坚决不做什么)
- 编号的业务需求列表(
BR-01,BR-02...) - 核心用户流程与异常流程
- 非功能需求(数字化的性能指标、并发预期)
- 技术约束、语言约定(如统一中文开发)与未决问题表
铁律:
BRD是全项目的“唯一需求基底”。如果后续模块文档、技术方案或代码与 BRD 发生冲突,一律以 BRD 为准。任何新增想法或改动,必须先改 BRD,再向下扩散。
3.2 BR:业务视角的真实承诺
BR 是 BRD 里的单条业务需求,例如:
编写 BR 的关键在于坚持业务视角,不要过早暴露技术实现。
- ❌ 错误的 BR:
新增 DELETE /api/orders/:id 接口,前端加一个红按钮(这是技术方案,不是业务需求) - ✅ 正确的 BR:
用户可以自主取消尚未支付的订单;取消后订单不可继续支付,库存同步释放;超时未支付订单自动触发相同取消流程。
3.3 R:模块对 BR 的可落地契约
现实中的业务需求往往不是单个模块就能搞定的。比如上述的 BR-01,必然同时涉及订单系统和前端界面。
此时,我们需要把 BR 拆解映射到各个模块的 requirements.md 中,形成带有明确编号的 R:
看懂了吗?
- 一条业务需求
BR,映射出多个模块的具体契约R; - 每条
R都清晰写着它的来源BR; - 每条
BR必须至少被一条R覆盖。
这样一来,无论团队有多少人、换了多少个 AI Agent,业务需求永远不会在分工中被遗忘。
3.4 Design 与 T:从怎么做到怎么施工
- Design:技术方案。数据表怎么建、状态机怎么跳、接口入参出参长什么样、前端有哪些视图和组件、五态怎么表现、代码落在具体哪个文件路径下。
- T(Task):实施任务。每个任务必须关联
R,规定好依赖关系,且控制在一次会话(1 Session)内必须能完整交付的粒度(通常是新建/修改 $\le 8$ 个文件或 $\le 300$ 行核心变更)。
一句话总结它们的关系:
BRD是总账,BR是业务要什么,R是模块必须提供什么,Design是怎么做,T是这次会话具体做哪几件事。
四、模块拆分与多 Agent 并行开发协议
过去让 AI 开发大项目,最痛苦的是“上下文污染”。一旦一个项目超过 50 个文件,你把需求一股脑塞给 Agent,它读了前端又读后端,读了工具类又看配置文件,几轮下来上下文窗口充斥着无关代码,Token 费用飞涨,注意力彻底涣散。
在 spec-driven-ai-coding 中,我们制定了清晰的模块物理隔离与多 Agent 协同协议。
4.1 目录组织:module-common 与业务模块
在规范中,大型项目按如下结构组织文档:
特别警示:不要在源码中生造 module-xxx 目录!
很多初学者容易犯一个教条主义错误:看到文档里有 module-auth 和 module-order,就跑去工程源码目录里也新建一个 src/module-auth/ 文件夹。
这是完全错误的!
- 项目源码的目录结构,必须遵循项目本身既有的技术栈规范(例如 Java Spring Boot 的
controller/service/repository,或者 Next.js 的app/(routes)/、components/、lib/)。 module-xxx纯粹是需求分析与任务管理的逻辑单元。- 逻辑模块与真实代码的映射,是通过每个模块
design.md中的**【代码落点表】**来明确绑定的:
这张表就像一个安全栅栏,它严正告诫 Agent:在本模块的本次会话中,你只准修改这张表里声明的文件及其测试,绝不允许擅自修改其他无关文件!
4.2 module-common 的战略枢纽地位
为什么以前模块一多分工就乱套?因为缺乏公共契约。
module-common 是整个系统的基石,它不包含具体业务逻辑,专门负责定义:
- 全局通用的实体类型与枚举定义
- 统一的 HTTP 响应结构(
code,message,data,traceId) - 系统统一错误码表与命名规范
- 分页、排序、筛选的标准参数结构
- 鉴权 Header 与上下文提取中间件
- 前端通用设计 Token、公共基础组件、全局布局与常用工具函数
并行开发的铁律:module-common 的设计与核心任务必须处于阶段 0,由最初的会话率先锁定并冻结。其余业务模块在实现时,只能引用 common 中声明的契约,严禁跨模块私自调用对方的未公开逻辑!
4.3 “一 Agent、一模块”:真正的多端并行实战
有了清晰的契约和隔离边界,多 Agent 并行开发才真正具备了实操可能:
你可以同时在 Cursor 里开一个会话开发后端服务,在终端开一个 Claude Code 开发前端页面,甚至你自己亲自写最核心的算法。每个 Agent 的上下文都极其纯净——它只需要读:
brd.md的范围与约束;module-common/design.md的公共契约;- 本模块的三件套(
requirements,design,tasks); task-list-overall.md确认前置依赖是否就绪。
任务做完,各自更新自己的台账和实施记录(records/)。互不打架,互不污染。
五、拒绝豆腐渣:三大质量门与防放飞规则
让 AI 产出高质量代码的关键,不是祈求它的道德自觉,而是在每个关键节点设置无法逾越的工程门禁(Quality Gates)。
5.1 前端质量门:拒绝粗糙、空洞与无五态
前端被 AI 写得稀烂,核心原因就是“跳过设计直接写代码”。在 spec-driven-ai-coding 的 references/frontend-quality.md 中,我们做出了刚性约束:任何涉及 UI 的模块,在进入编码前,其 design.md 必须交出 10 项完整产出,缺一不可!
必备的“五态设计”规范
任何前端列表、详情或表单,必须在设计文档中明确五态,并在开发时全部实现:
强制执行的“浏览器自检流程”
在任何前端任务标记为 已完成 之前,Agent 必须真实执行自检流程:
- 必须启动开发服务器;
- 用真实形态的数据(禁止
test、111、aaa)走完主流程; - 手动或模拟触发五态(清空数据看 Empty,模拟接口报错看 Error,断网或限速看 Loading);
- 调整浏览器窗口至最小支持断点,确认没有出现水平溢出破版;
- 浏览器控制台必须保持零 Error、零 Warning;
- 检查通过后,将测试结果记录在实施文档中。没在浏览器里跑过的 UI,绝对不允许标记为已完成!
5.2 后端质量门:契约在前,拒绝侥幸
针对后端的质量失控,规范在 references/backend-quality.md 中立下了 12 项设计门禁,重点打击以下顽疾:
- 契约先行:接口路径、HTTP Method、入参结构、响应包装、错误码表必须在设计阶段定死,禁止一边写接口一边改字段。
- 状态机防护:有状态变更的实体(如订单、审批流),必须明确合法的状态跃迁矩阵,非法的状态跳转必须由代码显式拦截并返回专用错误码,绝不允许由前端来保证逻辑正确。
- 并发与幂等:对关键写操作必须定义幂等键或基于版本号的乐观锁,防止重复点击造成脏数据。
- 硬性上限:所有列表查询必须强制分页且限制单页最大数量(如不超过 100 条);批量操作必须设定数量上限,拒绝“全表查询”隐患。
- 安全越权校验:任何针对资源的更新和删除,必须在 Service 层校验“当前操作者是否拥有该资源的所有权”,禁止仅做登录校验就放行。
接口正反例验证流程
后端任务完成后,不能只跑一个正常请求就交差。必须在集成测试或脚本中覆盖:
- 正例请求:入参完整,返回数据结构与契约 100% 一致;
- 缺参 / 越界反例:故意少传必填字段,校验拦截器必须返回合法的 400 类错误码;
- 鉴权 / 越权反例:未带 Token 或访问他人资源,必须被 401/403 拦截;
- 不存在反例:查询不存在的 ID,返回语义清晰的 404 类错误码;
- 并发 / 重复反例:连续快速发送两次完全相同的创建请求,验证系统幂等性。
5.3 完成定义(DoD)与“防放飞”反模式黑名单
在工作流中,我们列出了一份公开的反模式黑名单。只要 Agent 触犯其中任何一条,当次评审立刻挂起(Reject):
六、掌控权在手:三大检查点(Checkpoints)与“不脑补”机制
在人机协作中,最可怕的状态是:人类一觉醒来,AI 已经在错误的方向上狂奔了 50 个 Commit。
为了确保系统演进始终在人类的掌控之下,工作流设置了三大刚性检查点(Checkpoints,简称 CP)。每到一个检查点,Agent 必须强制停下,汇报当前产出,等待人类审核批准:
6.1 妙用“AI 补充细节”而不失控
在实际开发中,我们常常既不想写得事无巨细,又不想让 AI 乱猜。业内常见的 prompt 是:
“由 AI 自行补充细节并设计方案,可以联网参考相似内容。”
这句话非常好用,但如果缺乏制度约束,AI 就会肆无忌惮地脑补。
在我们的规范中,对这句话建立了严格的防沉迷机制:
- 允许调研:AI 可以且应当联网检索 1~3 个成熟竞品的交互和数据设计;
- 强制显式化:AI 做出的每一个补充决策,绝对不允许暗戳戳写进代码里,而必须编号为
A-01、A-02(Assumption,假设表),附带备选方案与理由,明确写入discovery.md或brd.md; - 在 CP1 / CP2 批量确认:在到达检查点时,Agent 会把这张假设清单直接呈递给人:“针对未尽细节,我做出了以下 5 项假设,请确认是否符合预期。” 人类看一眼,打 5 个勾,或者指出其中第 3 项需要修改。
既解放了人类的梳理精力,又牢牢守住了业务的确定性。
七、实战分级(S / M / L)与存量项目适配
不是所有需求都需要惊动全套大部队。如果改一个文案或者修一个空指针,也要搞 BRD、拆五个模块、跑一遍 CP,那就是典型的方法论中毒。
因此,工作流内置了弹性分级机制:
7.1 存量老项目怎么玩?拒绝“全项目重写文档”
很多团队抗拒规范,是因为他们觉得“我们是个老项目,哪有时间给整个系统补写一份 BRD?”
这是对 Spec 模式的巨大误解。在存量老项目中开发新功能:
- 坚决不为老系统补全量 BRD;
- 仅针对本次新需求建立 Spec 目录(如
docs/开发设计文档/user-analytics/); - 但在需求编写前,必须执行严格的**“代码现状调研”**:去老系统里读真实的路由、找现成的组件库、查数据库表结构,将调研结果记录在 BRD 的【现状与集成点】一节。
新需求依托老系统而生,既保持了局部敏捷,又确保了新功能的工程质量。
八、闭环之魂:新需求与修改点的回流机制
软件开发唯一的永恒,就是需求在不断变化。
以前的灾难在于:测试测出了一个 Bug,或者老板临时加了一个字段,开发者直接让 AI 在代码里改了。改着改着,设计文档作废了,任务台账失真了,后续进来的新会话 Agent 读着陈旧的设计文档,在早已面目全非的代码上修修补补,最终系统崩塌。
在 spec-driven-ai-coding 里,面对随时可能出现的“新需求 / 修改点”,我们确立了神圣不可侵犯的回流铁律:
代码可以重构,但真理只有一个。 只要坚持“修改先改需求基底,再改模块设计,最后动代码”的闭环,你的项目文档就永远不会沦为废纸,而是随着系统演进越来越健壮的数字资产。
九、配套开源工具链:脚手架与静态校验器
为了不让大家停留在“手敲模板”的痛苦中,我把整套思想打包成了一个全新的开源 Skill:spec-driven-ai-coding,已正式合入我的公共技能仓库 qiuye-skills。
除了详尽的方法论和 9 套开箱即用的 Markdown 模板外,它还附带了两个轻量、零外部依赖的 Python 工具:
9.1 一键脚手架:init_spec.py
无论是轻量级的 M 级需求,还是包含 module-common 与多个子模块的复杂 L 级项目,一条命令即可生成完整工程骨架(已存在的文件绝不覆盖,安全幂等):
它会自动替你创建:
- 需求基底
brd.md(自动预填模块矩阵行) - 总任务台账
task-list-overall.md module-common以及各个业务模块的三件套- 变更记录目录
changes/与实施记录目录records/ - 人工测试清单
manual-test-checklist.md
9.2 静态一致性与追踪门禁:check_spec.py
在到达 CP2 之前,或者在合并代码前,运行内置的静态检查脚本:
这个小脚本会在毫秒级内遍历整个 Spec 文档集,执行严格的编译级检查:
- 需求覆盖追踪:检查 BRD 中的每一条
BR是否都被模块的R覆盖,模块R的来源BR是否真实存在; - 任务认领覆盖:检查模块里的每一条
R是否至少被一个开发任务T覆盖; - 依赖与自闭环:检查任务引用的前置依赖
T是否存在,严禁循环自依赖; - 状态合法性:严格只允许
未开始 / 进行中 / 已完成 / 阻塞 / 废弃五种状态; - 台账双向一致性:自动比对
task-list-overall.md与各个模块tasks.md中的任务行状态,任何一方不同步直接报错; - 假完成打假:标记为
已完成的任务,检查其完成日期与实施记录文件是否存在于磁盘中; - 反模糊词 Lint:扫描文档中是否残留“等等”、“适当”、“合理提示”等禁用模糊词。
在自动化流水线或 CI 里跑一遍 check_spec.py,任何浑水摸鱼的“假交付”立刻现形!
十、写在最后:从“提示词工程”走向“上下文架构工程”
过去一年多,大家都在津津乐道各种神奇的 Prompt 技巧,甚至迷信“一句话让 AI 生成一个淘宝”。
但在真正经历过生产级工业软件的拷打后,我们不得不承认:大模型的概率涌现,天然对抗着软件工程对确定性、一致性和可维护性的苛刻追求。
试图单纯靠精妙的提示词让 AI 驾驭大项目,就像试图在一盘散沙上建造摩天大楼。
spec-driven-ai-coding 并不是给开发者增添繁重的文档负担。相反,它是一套帮助人类工程师重新找回系统掌控力、同时把 AI 的强劲生产力约束在确定轨道上的脚手架。
- 它把散乱的思维收敛到
BRD里; - 它把庞大的架构切分成纯净的模块沙箱;
- 它给前端立下了不可退让的五态与自检铁律;
- 它给后端筑牢了事务、权限与契约的堤坝;
- 它让多 Agent 并行从幻想变成了可落地的工程日常。
当写代码这件事情变得越来越廉价,如何定义问题、如何划分边界、如何验证结果,正在成为软件工程师最不可替代的立身之本。
相关资源与安装
新版 Skill 现已全面开源,你可以通过以下方式安装到你的本地环境(支持 Cursor、Claude Code、Codex 等主流 Agent):
如果你在实际项目中尝试了这套流程,或者踩到了新的坑,欢迎在评论区或 GitHub Issue 中与我交流!