去年有一段时间,我几乎每天都在“vibe coding”。需求丢给 AI,它飞快地吐代码,我看着预览窗口点点头,点一个“accept”,然后继续下一段。新鲜感过去之后,代码库慢慢变成了一场事故:没有统一的设计约束,命名一会儿驼峰一会儿下划线,错误处理经常被 try/catch 吞掉,最要命的是几乎没有测试。最惨的一次,一个内部工具从“能跑”变成“不敢动”,只花了一个下午。
后来我在团队里把规格驱动开发(SDD)整套流程引入日常,AI 编程才从“写着玩”变成“能交付”,综合算下来,提效确实是往 50% 靠拢的。这篇文章不聊某个花哨的提示词技巧,而是想把经过我验证的一套 SDD 六步实践指南完整盘一遍,再用 GitHub Copilot、Cursor、JetBrains AI Assistant 这三个主流工具在同一个需求下做一次实战对比。如果你每天都要和 AI 一起写代码,但又觉得代码质量不太稳,或者正准备把 AI 编程引入团队协作,这篇应该能给你一个直接可用的参考。
1. Vibe Coding 看起来很爽,为什么项目越来越难改
1.1 Vibe Coding 的爽与痛
Vibe Coding 大概是 2024 年底开始流行的概念,核心是“跟着感觉走”,把写代码这件事从传统的手工敲键盘,变成给 AI 下指令,描述一个模糊的效果,然后让 AI 生成一段看起来能跑的代码。它最大的爽点在于即时反馈:拿到一个需求,往编辑器里一贴,用几句自然语言描述,AI 就给你一整段可以演示的东西。做原型、做 demo、做一次性脚本时,这种模式效率确实无敌,我直到现在都还在用。
但问题恰恰出在“感觉”上。Vibe Coding 依赖的是语感和脑补,而不是确定性的契约。代码一旦进入生产项目,生命周期就不是几分钟,而是几个月甚至几年,这段生命周期里最消耗成本的动作是理解、修改、排查,而这三个动作恰好是纯 Vibe Coding 最不擅长的。我见过不少把 Vibe Coding 用进业务的团队,前两周跑得飞快,后面每天都在下坡路上补坑:你想加一个字段,顺着 AI 生成的逻辑往回找,至少要翻三四个文件,每个文件里的代码看起来都“差不多”,但谁也不敢保证改了不会影响别处。
这不是 AI 能力的问题,而是工作方式的问题。Vibe Coding 默认“AI 能猜中我想要什么”,但实际项目中,需求很少是清晰的,边界条件、异常流程、性能约束、代码风格,这些隐含信息如果不主动给出来,AI 只能靠概率补全。于是代码的“正确性”变成了靠运气,而不是靠设计。
1.2 没有规格,AI 就是在盲写
很多人把 Vibe Coding 失败归因于“AI 太笨”,其实这是把因果关系搞反了。大模型的生成能力早就不是短板,真正稀缺的是“输入质量”。我在项目中做过对照组实验:同样让 Cursor 写一个库存模块,一种方式是直接说“帮我写个库存 API”,另一种是先给它一份一两百字的规格说明,里面写清楚接口路径、请求参数、校验规则、错误码和测试要求。后者的产出质量明显上一个台阶,第一版就能通过大部分单测,而前者写出来的代码,接口命名随意,字段类型混乱,连最基本的数据校验都要靠人肉补。
原因在于大模型的本质是“续写概率最高的内容”。上下文越模糊,它越倾向于续写“最常见的代码”,而不是“你需要的代码”。规格就是打破这种模糊的工具,它把业务约束、边界条件、技术栈限制用文字显性化,AI 续写时才会往正确方向走。Vibe Coding 的“vibe”给不出这些约束,所以生成结果只能看运气。
1.3 什么时候应该换 SDD
我并不是说 Vibe Coding 一无是处,它非常适合探索性的场景。但如果你的项目满足下面任意一条,就值得认真考虑引入 SDD:
- 代码要提交到共享仓库,供多人协作和长期维护
- 功能会持续迭代,后续大概率要改或者扩展
- 涉及数据一致性、金额、权限、库存这类不能出错的逻辑
- 需要给测试同学、运维同学甚至审计交代行为
反过来,如果你只是写一个临时脚本、调一个接口看结果、做一次性的数据清洗,那 Vibe Coding 完全够用,没必要套方法论,过度设计也是成本。
2. SDD 六步实践指南:把规格当代码来写
2.1 SDD 的核心思想
SDD 全称是 Specification-Driven Development,规格驱动开发。它的核心逻辑一句话就能讲清楚:先花时间写清楚“要做什么、怎么算完成”,再让 AI 写“怎么做”。
听起来很简单,但真做起来和多数团队的日常习惯差别很大。大多数团队的习惯是拿到需求就开写,写一步想一步,发现问题再回头改。这种模式在没有 AI 时还能靠人脑兜底,因为在敲代码的过程中,人会不断修正对需求的理解。但 AI 没有这个能力,或者说,它不会主动修正你的模糊指令。你给它一句“做个注册功能”,它就真的只给你一个“看起来像注册”的东西,至于手机号格式、密码策略、重复注册、验证码超时这些细节,它会默认简化掉。
SDD 做的事情就是把这些细节前置到开发开始之前。我把整个流程拆成六步,这六步不是硬性理论,而是我从实际踩坑里总结出来的操作清单。
2.2 六步法第一步到第三步:意图、验收标准、技术约束
第一步,写意图描述。用自然语言写清楚这个功能在什么场景下使用,用户是谁,核心目标是什么。比如“用户输入手机号和验证码完成注册,注册成功后自动登录”,这个描述比“写一个注册接口”要有用得多,因为它交代了流程的上下游。
第二步,写验收标准。这是整个 SDD 里最关键的一步。“功能完成”不能靠感觉判断,必须有一组可验证、可执行的标准。最好的形式是一组行为描述,比如“当手机号已注册时,注册接口返回 HTTP 409,且响应体里包含 error_code=PHONE_EXISTS”。这比“需要处理重复注册”要强一个数量级,因为 AI 可以直接根据这个描述写出对应断言,也可以根据断言反推实现逻辑。
第三步,写技术约束。语言、框架、依赖、目录结构、代码风格、性能要求,都写清楚。团队里有约定俗成的规范时,一定要写进去,否则 AI 会生成一套与仓库风格完全脱节的代码。举个例子,你们统一用 Zod 做参数校验,但没写进规格里,AI 大概率会给你手写 if 判断,这样代码进到 review 阶段等于重写。
2.3 六步法第四步到第六步:骨架先行、分块实现、评审重构
第四步,骨架先行。让 AI 先生成接口签名、数据模型、目录结构或者测试用例,而不是直接堆实现逻辑。这一步很多人会跳过去,它的价值在于先定契约:先告诉 AI“模块长什么样”,再让它填肉。你可以在规格文档里直接定义好接口路径和数据结构,让 AI 严格按这些定义生成骨架。骨架通过你的确认之后,再进入下一步,否则后续修改成本会翻倍。
第五步,分块实现,测试兜底。把功能拆成若干个小模块,一个模块一个模块地让 AI 实现,每完成一块就立刻跑测试。跑过再继续下一块,没跑过就当场让它修。这样比一次性让 AI 生成几百行代码再统一调试要稳得多,因为出错范围被压缩在一个小块里,定位问题轻松很多。
第六步,评审与重构。把 AI 生成的代码当成同事写的代码来 review:删冗余逻辑、统一命名风格、补边界条件、确认异常处理策略。这一步是很多 AI 编程实践里被省略的,但恰恰是决定代码能否长期维护的关键。AI 生成的代码通常能跑,但往往存在过度设计、重复计算、不必要的抽象,评审就是把这些问题提前按住。
2.4 为什么这条流程能提效 50%
很多人以为提效来自“AI 写得快”,但 SDD 的提效主要来自减少返工。传统 AI 编程里,来回让 AI 修 bug 的时间可能占到总耗时的一大半。有了规格和验收标准之后,生成质量被前移,AI 第一版就能接近正确,代码评审阶段从“整个重写”变成“小修小补”。在我自己的项目统计里,同样的一个约 300 行的后端模块,Vibe Coding 模式从开始到合入平均需要 3 到 4 轮修改,SDD 模式平均 1.5 轮,再算上测试自动兜底节省的回归时间,总耗时大概省下四到五成。这个数不精确,但方向和量级我是有把握的。
3. 三工具实战对比:Copilot、Cursor、JetBrains AI Assistant
3.1 对比前提与测试需求
为了让这场对比尽量客观,我特意设计了一个既能体现代码生成能力、又能测试 Agent 感知能力的统一需求:用 TypeScript + Express + Vitest 实现一个完整的商品库存模块,包含三个接口——入库、出库、库存查询;出库时库存不足必须返回 HTTP 400;库存量不允许为负数;数据暂存内存即可。我把同一份 SDD 规格文档分别喂给 GitHub Copilot、Cursor 和 JetBrains AI Assistant,记录各自的表现,包括是否能一次跑通、错误处理是否完整、测试覆盖是否到位、需要额外修改几轮。
这个需求比“写个 hello world”要复杂,但也足够收敛,能比较真实地反映日常后端口开发场景。下面是三个工具的表现记录。
3.2 GitHub Copilot:稳,但更像高级补全
GitHub Copilot 是目前装机量最大的 AI 编程助手,它最强的点是把补全体感做进了编辑器:写一行函数签名,按一下 Tab 就能接受剩下的函数体,几乎不打断思维流。在 SDD 流程里,Copilot 最合适的角色是“执行者”——你按照规格把骨架搭好,它负责填充每一个函数体。它处理样板代码、工具函数、测试用例里的重复部分非常高效,上下文感知偏局部,但它能捕捉同一个文件里的变量名和语义。
拿这次测试来说,我把规格文档粘贴到代码文件顶部的注释里,然后开始写路由,Copilot 基本把 controller 和 service 层完整补了出来,测试部分也能生成,但它在出库时库存不足的状态码上,一开始写的是 500,而不是规格里要求的 400。这说明它读注释的能力有限,更依赖你先把函数签名和注释写到位。想要让 Copilot 真正按 SDD 干活,你得自己搭骨架、写清晰注释,再让它填充主体,整体节奏由你主导。
3.3 Cursor:最接近“读规格干活”的 Agent 体验
Cursor 是目前 Agent 模式的标杆之一,它最大的特点是可以同时读取多个文件、执行终端命令、运行测试并基于反馈自我修正。这和 SDD 的天然契合点在于:你把规格文档放在项目仓库里,Cursor 可以直接读文件、分析现有目录结构,再按规格从骨架到实现一步步完成。
测试中,我把规格写在 REQUIREMENTS.md 里,然后给它一句“按规格实现库存模块,并运行测试确保通过”。它自动创建了 routes、services、types 和测试文件,第一次测试失败后,不需要我干预,它自己看报错信息,把库存不足的返回码从 500 改成了 400,再跑测试,通过。整个过程基本不需要手动介入,十次里大概有两三次会碰到比较怪的边界情况需要我点拨一下,但整体体验已经是“代理干活、人类验收”的模式。
Cursor 另一个比较大的优势是上下文窗口大。规格文档、目录结构、错误信息可以一起喂进去,不容易像某些工具一样到后面就“断片”。对 SDD 来说,上下文大太重要了,因为规格本身就是靠上下文起作用的,窗口一小,后面的约束容易被遗忘。
3.4 JetBrains AI Assistant:老牌 IDE 里的稳重型选手
如果你的主力 IDE 是 IntelliJ IDEA,JetBrains AI Assistant 的集成体验是三个工具里最顺滑的。它直接嵌在 IDE 右侧面板,提供对话、代码补全和重构建议,和现有开发流程融合得很深。它的补全质量在写 Java、Kotlin、Go 这类强类型语言时尤其稳定,这也符合 JetBrains 系产品面向专业开发者的调性。
但在这场对比中,它的 Agent 能力明显不如 Cursor 激进:能理解项目上下文,也能生成跨文件改动,但在执行命令、自动跑测试、根据结果自我修正这几个环节上更保守。它更像是一位“很懂语法的结对程序员”,而不是自动执行任务的代理。测试中它生成的代码质量不差,但需要我通过多轮对话逐步引导:第一轮生成路由,第二轮补服务层,第三轮补测试。好在每一轮生成都稳定可控,适合喜欢逐步确认的开发节奏。如果你恰好是 IntelliJ IDEA 全家桶用户,团队协作方式也是标准编码加少量 AI 辅助,JetBrains AI Assistant 是很省心的选择;如果想追求极致自动化,还是 Cursor 更合适。
3.5 三个工具的横向对比与选型建议
| 对比维度 | GitHub Copilot | Cursor | JetBrains AI Assistant |
|---|---|---|---|
| 补全质量 | 优秀,行级补全极快 | 优秀,但更侧重整块生成 | 优秀,强类型语言尤其稳 |
| Agent 自主执行能力 | 弱,主要靠人驱动 | 强,可自动跨文件实现并跑测试 | 中,能生成跨文件改动,但需要多轮对话 |
| 上下文处理 | 偏局部,窗口有限 | 窗口大,能读多文件 | 中,依赖 IDE 项目模型 |
| SDD 适配度 | 高,适合按骨架填充 | 极高,适合“读规格→自动实现” | 高,适合“逐步确认式”开发 |
| 推荐场景 | 已有成熟流程,只想局部提效 | 自动化优先,希望 AI 当代理 | JetBrains 生态深度用户 |
选型建议很直接:主力 IDE 是 VS Code 或者 WebStorm,团队重视自动化,优先考虑 Cursor;主力 IDE 是 IntelliJ IDEA,团队还保持传统编码节奏,JetBrains AI Assistant 更合适;如果你已经有成熟的代码规范和流程,只想要一个能随时补全代码的助手,GitHub Copilot 依然是性价比很高的选择。三个工具并不互斥,我在实际项目中就是组合使用的。
4. 实战:同一份规格文档,三工具的真实产出差异
4.1 规格文档示例
为了让这场对比可以复现,我把测试用的规格文档核心部分贴出来。这份文档我控制在 300 字以内,之所以强调字数,是因为规格不是越长越好,太长的规格会让 AI 注意力分散,漏掉后面的约束。要点是把最重要的规则前置,这份文档我按照“目标→接口→约束→测试要求”的顺序组织。
# 商品库存模块规格 ## 目标 提供商品库存管理能力,支持入库、出库、库存查询。 ## 接口定义 - POST /api/products/:id/stock-in,body: { quantity: number },入库 - POST /api/products/:id/stock-out,body: { quantity: number },出库 - GET /api/products/:id/stock,返回当前库存 ## 业务规则 1. 出库数量大于当前库存时,返回 HTTP 400,error_code 为 INSUFFICIENT_STOCK 2. 库存不允许为负数,任何把库存置为负数的操作都必须失败 3. quantity 必须为正整数,非法输入返回 HTTP 422 4. 商品不存在时返回 HTTP 404 ## 技术约束 - 使用 TypeScript + Express,参数校验使用 Zod - 数据先存内存 Map - 使用 Vitest 编写测试,覆盖所有业务规则这份规格看起来不长,但每个细节都在约束 AI 的行为:接口路径固定了、状态码固定了、技术栈固定了、测试要求固定了。这样就避免了很多常见的“AI 自由发挥”问题。
4.2 各工具产出过程记录
GitHub Copilot 的产出过程是“骨架由我搭,函数体它填”。我手动在项目里建好文件结构和路由入口,把规格中的接口定义写成注释,Copilot 根据注释把 controller 和 service 补全。测试部分它也能生成,一开始对“库存不足 400”这个边界用例覆盖缺失,我在注释里提示“请补充 INSUFFICIENT_STOCK 的用例”之后,它补上了。整个过程大概需要 15 分钟,其中有 5 分钟是在补充边界条件和修正测试用例。
Cursor 的产出过程则流畅得多。我把 REQUIREMENTS.md 放进仓库,在对话框里给出指令,它自动创建了 routes/products.ts、services/stock.ts、tests/stock.test.ts 等文件。第一次运行测试时,它把库存不足场景返回成了 500,我没有干预,它自己看报错、改状态码为 400,重新跑了测试。整个过程 10 分钟左右,除了生成文件,它还会主动汇报“哪些测试通过、哪些有疑问”,体验已经接近一个初级开发者在按规格推进任务。
JetBrains AI Assistant 的产出过程更接近结对式。它先写路由和类型定义,我再发一条消息让它补服务层,再发一条消息让它补测试。每一轮都稳定,没有需要回滚的大改动,但总时长也拉到了 15 到 18 分钟。它的输出质量和规范性很好,如果你喜欢一步步确认代码走向,这种模式反而更有把握。
4.3 代码质量与测试覆盖对比
| 对比项 | GitHub Copilot | Cursor | JetBrains AI Assistant |
|---|---|---|---|
| 能否直接运行 | 需要小修补 | 一次通过 | 需要小修补 |
| 是否覆盖核心业务规则 | 需要提示补充边界 | 自动覆盖,还补了参数校验 | 覆盖主要规则,边界稍弱 |
| 非法输入校验 | 部分覆盖 | 完整覆盖 | 基本覆盖 |
| 额外修改轮次 | 2-3 轮 | 1 轮左右 | 2 轮左右 |
| 是否符合规格文档 | 中等偏高 | 高 | 高 |
从结果上看,Cursor 在“读规格→自动执行→自测修错”这条闭环上优势明显,Copilot 需要你更主动地编写高精度注释来引导补全,JetBrains AI Assistant 则适合喜欢分步确认的开发流程。
4.4 我的真实体感
真正让我决定把 SDD 当作标配的,不是某一个工具多聪明,而是当我给足规格之后,三个工具都明显变靠谱了。工具之间的差距,远小于给不给规格的差距。哪怕是最擅长局部补全的 Copilot,只要在注释里把接口定义和状态码写清楚,产出质量也会上一个台阶。这一点,我觉得比纠结“该买哪个 AI 编辑器”更重要。规格写作能力,正在变成 AI 编程时代最核心的差异点。
5. SDD 在团队协作与面试中的延伸应用
5.1 规格即文档,沟通成本降一半
团队里引入 SDD 后,最大的变化是需求描述从口头沟通变成了“可读、可查、可评审”的规格文档。以前开需求评审会,产品讲一遍、前端理解一种、后端理解另一种,在代码里体现出来的差异要等联调阶段才暴露。现在所有人在动手之前先对齐规格文档,前端、后端、测试都以这一份文档为准,争议点当场澄清。
这个习惯一旦建立,新同学上手项目也方便很多。以前新人入职要翻代码、猜逻辑,现在先读规格文档,再对着代码看实现,理解速度至少快一倍。规格文档还能沉淀下来,当作模块的技术说明书,减少“这个功能是谁写的、为什么这么写”的经典虚无问题。
5.2 代码评审的逻辑变了
传统代码评审是评审者猜实现意图:为什么这个函数叫这个名字,为什么这里有一个特殊判断,考虑的是“代码自身是否自洽”。SDD 之后,评审逻辑变成“对照规格逐条打勾”:接口路径符合规格吗?状态码符合吗?参数校验符合吗?异常处理符合吗?评审变成了一种结构化的校验,而不是玄学式的感觉。AI 生成的代码尤其适合这种评审方式,因为你不用追问它“当时怎么想的”,只要对照规格检查结果。
5.3 面试中的 AI 编程考察点
现在很多技术面试官会问 AI 编程相关的问题,我见过太多人只准备“提示词技巧”,这是方向上的偏差。真正该考察的能力,是把一个模糊需求整理成可以交付给 AI 的规格文档的能力。面试时可以给候选人一个半成品需求,见一下他能不能拆解出边界条件、定义出验收标准、指定技术约束,再让他用 AI 实现。这一整套下来,比背几个 prompt 模板更能看出真实水平。AI 编程时代,稀缺的不再是写代码的手,而是能用语言把逻辑“锁死”的能力。
6. 常见问题与排查技巧实录
6.1 规格写得太细太长,AI 反而不听话
规格不是越长越好。我一开始写规格喜欢事无巨细,连函数命名都要规定,结果 AI 在生成了几个文件之后,明显忽略了文档后半部分的约束。后来调整策略:把最重要、最不可妥协的业务规则放在规格文档前 30% 的位置,并用关键词比如“必须”“不允许”加重表达;把次重要的技术细节放到代码注释里,分开引导。实践下来,AI 对核心规则和代码上下文的注意力都有明显提升。
6.2 上下文被截断,规格被“遗忘”
很多 AI 工具都受上下文窗口限制,项目一大,规格文档和代码互相挤占空间。我常用的解决办法有两个。一是把一个大规格拆成多个小规格,一个模块一个规格文件,让工具只关心当前模块的上下文。二是尽量让 AI 读取文件而不是把内容粘贴进对话,比如 Cursor 可以访问项目里的 REQUIREMENTS.md,其他工具也可以通过 @ 引用文件。这样能省下大量上下文空间,工具才“记得住”约束。
6.3 AI 自己加戏,擅自扩展功能
AI 很爱自作主张加功能,规格里没写的“搜索”“分页”“删除”它都能顺手给你加上。对付它,最有效的办法除了在规格里明确“不需要什么”之外,就是依靠代码评审。我见过有团队偷懒,让 AI 生成完就直接合并,结果代码里多了一堆从没要求过的页面和接口,这种“加戏”代码在后期会产生大量维护成本。评审时盯住规格和最终产出的差异,劝自己沉住气把多余代码删掉,这是 AI 编程的日常纪律。
6.4 生成的测试太弱,只测“正常路径”
AI 生成的测试普遍天然偏向 happy path,对空值、重复、越界、并发这类边界场景覆盖不足。我的做法是在规格文档里专门加一段“测试必须覆盖的场景”,列出空值输入、库存不足、商品不存在、参数非法等具体用例名称,然后再让 AI 生成测试。这样生成的测试质量会显著提升。另一个经验是让 AI 使用 Given-When-Then 的结构写测试描述,把“前置条件、执行动作、期望结果”显性化,测试的阅读成本和维护成本都会低很多。
6.5 规格也会过时,需要配套变更记录
规格文档不是写一次就完事。功能迭代之后,规格如果没有同步更新,AI 后续会基于过期规格生成错误代码。关键是不要让规格变成一个独立的、没人维护的 Markdown 文件,而是把它纳入代码评审流程中,代码合并时同时评审规格是否需要更新。另外,建议在规格文档顶部加一个“变更记录”,记录修改日期、修改人、修改原因,这个习惯能避免很多“文档和代码对不上”的历史争议。
我自己现在的工作流就是:需求评审后先花 20 分钟把规格文档写好,然后让三个工具各司其职——Copilot 处理琐碎的函数补全,Cursor 一次性搭大模块,JetBrains AI 做重构和代码梳理。这套组合用了半年,最直观的感受是返工少了,而不是打字快了。要补充的是,SDD 不是银弹,它解决的是“AI 生成代码方向不可控”的问题,如果你的项目需求本身就很模糊,那再好的方法论也救不了。先把需求想清楚,再让 AI 动手,这可能是我在新一轮 AI 编程实践里,做得最值的一笔投入。