ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenSpec规格驱动开发:从需求到代码的AI辅助实践

OpenSpec规格驱动开发:从需求到代码的AI辅助实践 1. 规格驱动开发到底在解决什么问题第一次接触 OpenSpec 的人十有八九会把它当成又一个文档生成器。我一开始也这么想直到在一个真实项目里被反复返工折磨了两个月才真正理解规格驱动开发Spec-Driven Development的价值所在。传统开发流程里需求散落在聊天记录、会议纪要、口头约定和某个同事的脑子里。等到写代码的时候每个人对同一句话的理解都不一样。前端以为用户列表要分页后端以为先返回全部再说测试以为按时间倒序。最后联调的时候三方对不上返工重来。这种场景我相信每个从业者都经历过而且不止一次。OpenSpec 的核心思路是把规格变成整个开发流程的唯一事实来源。它不是简单地写一份需求文档然后丢到一边而是让规格成为可执行、可验证、可追踪的工程资产。规格写好了代码生成、测试用例、接口文档、验收标准全部从这一份规格里派生出来。改一处规格所有下游产物同步更新。这个理念听起来很美好但落地的时候有几个关键问题必须想清楚规格用什么格式写纯自然语言太模糊纯代码又太僵硬。规格和代码之间怎么保持同步人工维护必然脱节。团队协作时规格的变更怎么管理谁有权改、改了怎么通知、历史版本怎么追溯。OpenSpec 对这三个问题给出了自己的答案。它用结构化的规格描述语言来定义行为用工具链自动从规格生成代码骨架和测试桩用版本控制来管理规格演进。这套方法论配合 Claude Code、Codex 这类 AI 编程助手使用的时候效果会成倍放大——因为 AI 最擅长的就是按照明确的规格去生成实现而最怕的就是需求模糊。提示如果你现在的项目还在用口头需求 即时通讯确认的方式推进建议先不要急着上 OpenSpec。规格驱动开发的前提是团队愿意把需求写清楚这个习惯比工具本身更重要。适合读这篇内容的人有一定开发经验、被需求反复变更折磨过、想引入 AI 辅助编程但发现 AI 生成代码质量不稳定的从业者。如果你正在用 Laravel 做后端、用 Claude Code 或 Codex 做辅助开发这篇内容会特别对口。2. OpenSpec 的规格描述语言拆解2.1 规格文件的基本结构OpenSpec 的规格文件不是随便写的 Markdown它有一套约定俗成的结构。一个完整的规格通常包含几个部分能力描述、场景定义、输入输出约束、边界条件、验收标准。我拿一个用户注册功能举例看看规格应该怎么写capability: user-registration description: 新用户通过邮箱和密码完成注册 scenarios: - name: 正常注册 given: 邮箱未被注册 when: 提交有效的邮箱和密码 then: 创建用户记录并返回成功 - name: 邮箱重复 given: 邮箱已被注册 when: 提交相同的邮箱 then: 返回错误提示邮箱已存在 constraints: - 密码长度不少于8位 - 密码必须包含字母和数字 - 邮箱格式必须合法 acceptance: - 注册成功后用户状态为待验证 - 发送验证邮件到注册邮箱这个结构看起来简单但每一行都有讲究。given-when-then的格式强制你把场景想清楚不能含糊。constraints部分把边界条件显式写出来避免开发时靠猜。acceptance部分定义了什么叫做完了测试和开发对验收标准有共识。2.2 为什么不用纯自然语言有人会问我直接用中文写需求文档不行吗行但效果差很多。纯自然语言的问题是歧义太多。用户提交有效信息后系统应该快速响应——多快算快100毫秒还是1秒密码要安全——什么叫安全8位还是12位要不要特殊字符OpenSpec 的结构化描述强迫你把这些模糊的地方明确下来。写规格的过程本身就是一次需求澄清。我自己的经验是写规格花的时间通常在开发阶段能省回来三到五倍。因为返工的成本远高于前期想清楚的成本。2.3 规格的粒度怎么把握这是实操中最容易踩坑的地方。规格写太粗等于没写写太细维护成本爆炸。我的经验法则是规格描述做什么和什么算做对了不描述怎么做。比如用户注册成功后发送验证邮件这是规格该写的用 Laravel 的 Mail facade 调用 SMTP 发送这是实现细节不该写进规格。粒度参考标准粒度层级该不该写进规格示例业务能力必须写用户注册、订单创建场景分支必须写邮箱重复、密码太弱输入输出约束必须写字段格式、长度限制验收标准必须写状态变更、通知触发技术选型不写用哪个框架、哪个库代码结构不写类怎么分、函数怎么命名部署方式不写容器还是裸机这个边界划清楚了规格文件才能既完整又稳定。技术选型会变代码结构会重构但业务能力和验收标准相对稳定。3. 把 OpenSpec 接入 Claude Code 与 Codex 的实操路径3.1 环境准备中最容易被忽略的一步很多人装完 Claude Code 或 Codex 就急着让 AI 写代码结果发现生成的代码和项目风格完全不搭。问题出在缺少上下文注入这一步。OpenSpec 的规格文件需要被 AI 助手读取到才能发挥作用。具体做法是在项目根目录放一个约定文件告诉 AI 去哪里找规格。Claude Code 会读取项目根目录的配置文件Codex 也有类似的机制。我通常会在项目根目录建一个openspec/目录里面按能力模块分文件存放规格。然后在 AI 助手的项目配置里指明这个目录。这样每次让 AI 生成代码时它会先读规格再动手。注意规格文件的命名要规范建议用能力名.spec.yaml的格式。AI 读取文件时是按名字匹配的命名混乱会导致它找不到对应的规格。3.2 让 AI 按规格生成代码的正确姿势直接对 AI 说帮我实现用户注册是最差的做法。正确的做法是把规格文件内容作为上下文然后给出明确的生成指令。我常用的指令模板是这样的请根据 openspec/user-registration.spec.yaml 中的规格 生成 Laravel 的 Controller、Request 验证类和对应的测试用例。 要求 1. 严格遵循规格中的 constraints 和 acceptance 2. 测试用例覆盖所有 scenarios 3. 不要引入规格中没有提到的额外功能这个模板的关键在于最后一句不要引入规格中没有提到的额外功能。AI 助手有个通病就是喜欢自作主张加功能。你让它写注册它顺手给你加上记住我、第三方登录、密码强度提示。这些功能规格里没有加了就是偏离需求。3.3 Codex 与 Claude Code 在这个流程里的分工实测下来这两个工具在规格驱动开发里各有擅长的地方。Claude Code 在理解复杂规格、处理多文件关联方面更强。当规格涉及多个能力模块的交互时Claude Code 能更好地把握整体逻辑。它的上下文窗口大可以一次性读入多个规格文件。Codex 在生成标准化代码、补全测试用例方面效率很高。对于结构清晰的规格Codex 生成的代码往往更贴近模板改动量小。我的做法是用 Claude Code 做规格理解和架构设计用 Codex 做具体代码生成和测试补全。两者配合效率比单用一个高不少。3.4 规格变更后的同步策略规格改了代码怎么办这是规格驱动开发最核心的运维问题。我的策略是分三步走规格变更先提交任何规格修改都先走版本控制提交信息里写清楚改了什么、为什么改。影响面分析用 OpenSpec 工具分析这次变更影响哪些能力模块、哪些场景。增量生成只对受影响的模块重新生成代码不要全量重来。全量重新生成是大忌。AI 每次生成的代码都有细微差异全量重来会导致大量无意义的 diff代码审查根本没法做。增量生成才能保持代码库的稳定。4. 规格驱动开发在 Laravel 项目中的落地细节4.1 Laravel 项目结构怎么和规格对应Laravel 的分层结构天然适合规格驱动开发。Controller 对应能力入口Request 对应输入约束Service 对应业务逻辑Test 对应验收标准。规格文件里的每个部分都能在 Laravel 结构里找到落点。我通常这样映射规格部分Laravel 落点capabilityController 方法scenariosFeature TestconstraintsFormRequest 规则acceptanceAssertion 断言业务逻辑Service 类这个映射关系建立起来之后从规格到代码的转换就有了明确的路径。AI 助手按照这个映射生成代码结构不会乱。4.2 用规格约束 AI 生成的验证逻辑Laravel 的 FormRequest 是输入验证的核心。规格里的 constraints 部分应该直接转换成验证规则。比如规格里写密码长度不少于8位必须包含字母和数字对应的 FormRequest 规则就是public function rules(): array { return [ email [required, email, unique:users,email], password [ required, min:8, regex:/^(?.*[A-Za-z])(?.*\d).$/, ], ]; }这里有个细节要注意规格里写的是业务约束代码里写的是技术实现。两者要能对应上但不要混为一谈。规格说密码要安全代码说min:8 加正则中间这层转换需要人来把关。4.3 测试用例从规格自动派生的方法规格里的 scenarios 部分每个场景对应一个测试方法。given 对应测试的前置条件when 对应操作then 对应断言。我让 AI 生成测试时会明确要求它按这个对应关系来public function test_正常注册(): void { // given: 邮箱未被注册 // when: 提交有效的邮箱和密码 $response $this-postJson(/api/register, [ email newexample.com, password password123, ]); // then: 创建用户记录并返回成功 $response-assertStatus(201); $this-assertDatabaseHas(users, [email newexample.com]); }这样生成的测试用例覆盖率和可读性都有保障。而且当规格变更时测试用例的修改方向也很明确——规格里改了哪个场景就改对应的测试方法。4.4 处理规格与实现的偏差实际操作中规格和实现总会有偏差。有时候是规格写得不完整有时候是实现时发现了规格没考虑到的情况。我的处理原则是发现偏差时先改规格再改代码。不要直接在代码里打补丁然后忘了更新规格。规格和代码不一致比没有规格还糟糕因为后来的人会不知道该信哪个。如果偏差是规格遗漏导致的就在规格里补上对应的场景或约束。如果偏差是实现走偏了就修正代码让它回到规格。这个纪律必须严格执行否则规格驱动开发很快就会名存实亡。5. 规格驱动开发中那些没人告诉你的坑5.1 规格写得越全AI 反而越容易出错这个坑很反直觉。我一开始以为规格写得越详细AI 生成代码的质量越高。实测下来发现当规格文件超过一定长度后AI 的理解准确率反而下降。原因在于 AI 的注意力是有限的。规格太长关键约束会被淹没在细节里。我的经验是单个规格文件控制在 200 行以内超过就拆分成多个文件。每个文件聚焦一个能力模块AI 读取时目标更明确。5.2 场景覆盖的假完整陷阱写规格时很容易陷入一种假完整——场景列了一大堆但都是正常流程的变体真正的边界情况一个没写。比如用户注册很多人会写正常注册、邮箱重复、密码太短。但真正容易出问题的是邮箱大小写、前后空格、特殊字符、并发注册同一邮箱、数据库连接超时。这些才是测试和开发真正需要明确的场景。我的做法是写完规格后强制自己问三个问题如果输入是空的会怎样如果输入是超长的会怎样如果两个请求同时来会怎样这三个问题能逼出大部分边界场景。5.3 AI 生成代码的过度实现问题前面提过 AI 喜欢加功能这里展开说。AI 助手在生成代码时会基于训练数据里的常见模式做补全。你让它写注册它会自动加上记住我、密码强度提示、注册频率限制这些它认为应该有的功能。这些功能本身没错但规格里没写就意味着没有对应的测试、没有对应的验收标准、没有经过需求确认。它们成了代码库里的孤儿功能出了问题没人负责。我的应对方法是在生成指令里明确加一句只实现规格中定义的行为不要添加任何额外功能。如果 AI 还是加了就在代码审查时删掉。这个纪律要反复强调AI 才会逐渐学会。5.4 规格版本与代码版本的对应关系规格改了代码没跟上或者代码改了规格没更新。这两种情况都会导致规格和代码脱节。我的做法是在提交信息里强制关联。每次提交代码如果涉及规格变更提交信息里必须包含规格文件的变更说明。用 Git hook 做检查规格文件变了但代码没变或者代码变了但规格没变都给出警告。这个机制听起来麻烦但能有效防止规格和代码渐行渐远。我见过太多项目规格文档写了三个月就没人维护了最后变成一堆过时的废纸。5.5 团队协作中的规格评审规格驱动开发要落地规格评审这个环节不能省。规格写完了直接拿去生成代码风险很大。规格里的一个理解偏差会被 AI 放大成几十个文件的错误实现。我的做法是规格评审和代码评审一样正式。规格提交后至少要有一个人 review确认场景覆盖完整、约束描述准确、验收标准可测。评审通过后才能进入代码生成阶段。评审时重点看三样东西场景有没有遗漏、约束有没有歧义、验收标准能不能自动验证。这三样过关了规格的质量就有基本保障。6. 从规格到交付的完整工作流复盘6.1 一个真实功能的完整流转过程我拿最近做的一个订单退款功能来复盘整个流程。第一步是写规格。我把退款涉及的所有场景列出来正常退款、部分退款、超过退款期限、订单已发货、退款金额超过实付金额、重复退款。每个场景写清楚 given-when-then。约束部分写明退款期限是 7 天、退款金额不能超过实付、退款后订单状态变更规则。验收标准写明退款成功后资金原路返回、订单状态变为已退款、发送通知。第二步是规格评审。团队里另一个人 review 后指出我漏了退款时优惠券怎么处理这个场景。补上之后规格才算完整。第三步是生成代码。用 Claude Code 读规格生成 Controller、Service、Request、Test 的骨架。然后人工填充业务逻辑的细节部分。第四步是测试验证。跑生成的测试用例发现部分退款场景的断言写错了修正后通过。第五步是规格归档。功能上线后规格文件保留在openspec/目录里作为这个功能的权威描述。后续任何人想了解退款逻辑看规格文件就行不用去翻代码。6.2 效率对比规格驱动 vs 传统开发同一个退款功能我用传统方式做过一次用规格驱动做过一次。对比数据如下环节传统方式耗时规格驱动耗时需求澄清2小时反复沟通1.5小时写规格编码6小时3小时AI 生成人工调整测试用例3小时1小时AI 生成修正返工4小时0.5小时合计15小时6小时差距主要来自返工。传统方式下需求理解偏差导致的返工占了将近三分之一的时间。规格驱动把需求澄清前置了返工大幅减少。6.3 什么情况下不适合用规格驱动规格驱动开发不是银弹。以下几种情况我会建议不要用探索性项目需求本身还在摸索今天想清楚明天就推翻写规格纯属浪费时间。一次性脚本用完就扔的代码写规格的投入产出比太低。极度紧急的修复线上出故障了先修再说事后补规格。个人小项目一个人开发需求在自己脑子里写规格反而增加负担。规格驱动开发适合的是需求相对稳定、多人协作、需要长期维护的项目。判断标准很简单——如果这个功能三个月后还有人要改那就值得写规格。6.4 规格资产的长期维护规格文件是项目的长期资产维护方式和代码一样重要。我的做法是规格文件和代码放在同一个仓库里一起做版本控制。规格的变更走和代码一样的评审流程。每个季度做一次规格审查清理过时的规格合并重复的规格补充缺失的规格。规格目录的结构也要保持整洁。我通常按业务模块分目录每个目录下放对应的规格文件。目录结构和代码结构保持一致这样找规格和找代码一样方便。提示规格文件里不要写待定、TBD这类占位符。写不出来就说明需求还没想清楚这时候不该开始写代码。规格里的每一个待定都是一个未来的坑。7. 规格驱动开发带给我的几个认知转变用了大半年 OpenSpec 之后我对开发的很多看法变了。以前我觉得写文档是负担现在我觉得写规格是投资。规格写清楚了后面所有环节都省事。以前我觉得 AI 生成代码不靠谱现在我发现不靠谱的不是 AI是我给它的输入太模糊。规格清晰的时候AI 生成的代码质量相当稳定。还有一个转变是关于完成的定义。以前我觉得代码跑通了就算完成现在我觉得规格里所有验收标准都通过了才算完成。这个定义的变化让完成这件事变得可衡量、可验证不再靠感觉。最后分享一个我踩过的坑不要试图一次性把所有功能的规格都写完。规格驱动开发是渐进式的做一个功能写一个规格。一开始就想着建一个完整的规格体系大概率会半途而废。从小处着手跑通一个完整流程尝到甜头之后再推广这才是可持续的路径。
返回列表