news 2026/11/2 8:00:14

OpenSpec规格驱动开发实战:从零搭建AI编码工作流

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenSpec规格驱动开发实战:从零搭建AI编码工作流

1. 规格驱动开发到底在解决什么问题

第一次接触 OpenSpec 是在一个 Laravel 项目里,当时团队三个人同时改一套订单模块,接口文档散落在飞书、注释和某位同事的脑子里。前端按旧字段对接,后端悄悄改了返回结构,联调那天下午全在互相甩锅。后来有人扔了个 OpenSpec 的仓库链接进群,说“试试这个,先把规格写死再写代码”。那是我第一次意识到,规格驱动开发不是又一个新名词,而是把“先对齐再动手”这件事从口头约定变成了可执行的工程约束。

OpenSpec 的核心思路很朴素:在写任何业务代码之前,先用一份结构化的规格文件把“系统应该做什么”描述清楚,这份规格既是人类之间的契约,也是 AI 编码工具(比如 Claude Code、Codex 这类)的输入上下文。它解决的不是“代码怎么写”的问题,而是“我们到底要写什么”的问题。传统开发里,需求文档写完就过期,接口文档靠自觉维护,测试用例另起炉灶,三套东西各说各话。OpenSpec 想做的,是让规格成为唯一的真相来源,代码、测试、文档都从它派生。

这套东西适合谁?如果你是一个人写小工具,可能觉得多余;但只要你满足下面任意一条,它就值得认真看:团队超过两个人协作、项目生命周期超过三个月、需要接入 AI 辅助编码、或者你被“改了 A 坏了 B”折磨过。尤其是现在 Claude Code、Codex 这类工具越来越普及,它们对上下文的理解能力很强,但前提是你得给它一份清晰的规格,否则它只会根据你的只言片语瞎猜,生成一堆看着能跑、实则偏离需求的代码。

我个人的判断是,规格驱动开发的价值在 AI 时代被放大了。以前规格主要给人看,人还能靠经验脑补缺失的部分;现在规格要给机器看,机器不会脑补,你写得不清楚它就理解错。所以 OpenSpec 这类工具的出现,本质上是把“需求表达的精确度”这件事的优先级提到了前所未有的高度。

2. OpenSpec 的核心概念与整体设计思路

2.1 规格即契约:OpenSpec 的基本组成

OpenSpec 的仓库结构不复杂,但每一块都有明确职责。核心是specs目录,里面按能力域(capability)组织规格文件,通常用 Markdown 或类似的结构化格式书写。每个规格描述一个独立的能力,包含这个能力要满足的行为、输入输出、边界条件。旁边一般会有changes目录,用来记录对规格的变更提案,类似轻量级的 RFC 流程。

我理解它的设计哲学是“能力导向”而非“接口导向”。传统 API 文档是按 endpoint 组织的,GET /orders返回什么字段。OpenSpec 更倾向于先定义“订单查询”这个能力应该具备哪些行为,再落到具体接口。这个顺序的差别很关键:接口会变,能力相对稳定。你先想清楚能力,接口调整时规格不用大改,只需要更新实现映射。

另一个关键设计是规格的可验证性。好的规格不是散文,而是能被拆解成一条条可判断真假的陈述。比如“当库存不足时,下单接口应返回 409 并附带缺货商品列表”,这就是可验证的;而“下单要处理好库存问题”就是废话。OpenSpec 鼓励你写前者。我踩过的坑是,一开始把规格写成了需求文档的翻版,全是“支持”“优化”“提升”这类词,结果 AI 读完还是不知道要干嘛。后来强迫自己每条规格都写成“给定什么条件,执行什么操作,期望什么结果”的句式,效果立刻不一样。

2.2 为什么选规格驱动而不是测试驱动或文档驱动

有人会问,测试驱动开发(TDD)不也是先写测试再写代码吗,有什么区别?我的理解是层次不同。TDD 的测试是代码级的,关注函数输入输出;规格驱动关注的是系统级行为,粒度更粗,更接近业务语言。你可以把规格看成 TDD 的上游:规格定义“系统该做什么”,测试验证“代码有没有做到”,两者配合而不是替代。

文档驱动的问题在于文档没有约束力。写文档的人知道它不会被强制执行,所以写得含糊;读文档的人知道它可能过期,所以不敢全信。规格驱动把规格变成了流程的必经环节——代码合并前要检查是否覆盖了规格,AI 生成代码时要拿规格当输入,测试用例要从规格派生。有了这些强制关联,规格才活得下去。

至于为什么现在值得关注,跟 AI 编码工具的普及直接相关。Claude Code、Codex 这类工具的能力边界,很大程度上取决于你给它的上下文质量。一份结构清晰的 OpenSpec 规格,能让 AI 生成的代码命中率大幅提升。我实测过同一个需求,给 AI 一段模糊描述和给一份规格文件,生成结果的可用性差距非常明显。前者要来回改五六轮,后者基本一两轮就能用。

2.3 与 Laravel 等框架的配合方式

Laravel 项目用 OpenSpec 有个天然优势:它的目录结构和约定优于配置的理念,跟规格驱动很搭。我通常会在 Laravel 项目根目录建一个openspec文件夹,跟app、routes平级。规格按业务域拆分,比如orders、users、payments,每个域下面再分具体能力。

映射到 Laravel 代码时,一个规格能力通常对应一个 Controller 或一组相关 Controller,规格里定义的行为对应具体的 Action 或 Service 方法。我习惯在 Controller 方法上方用注释标注对应的规格 ID,这样改代码时能快速定位到规格,改规格时也能搜到哪些代码受影响。这个习惯看起来笨,但在项目跑了半年后,它救了我好几次——有次改支付回调逻辑,靠规格 ID 反查发现还有两个边缘场景没覆盖。

需要提醒的是,别指望 OpenSpec 自动帮你生成 Laravel 代码。它是个规格管理工具,不是代码生成器。它的价值在于让规格和代码之间保持可追溯的关联,而不是替代你写代码。市面上有些工具号称能从规格直接生成 CRUD,我试过几个,生成的代码质量参差不齐,后期维护成本反而更高。规格驱动开发的重点是“驱动”,不是“自动”。

3. 从零搭建 OpenSpec 工作流的实操步骤

3.1 环境准备与工具安装

开始之前先把基础环境理清楚。OpenSpec 本身是个基于 Node 的工具链,所以第一步是确认 Node 环境。我建议用 Node 18 或 20 的 LTS 版本,太新的版本偶尔会有依赖兼容问题。装完之后用node -v和npm -v确认一下,版本号能正常输出就行。

node -v npm -v

接下来安装 OpenSpec 的命令行工具。官方推荐用 npm 全局安装,这样在任何目录都能调用openspec命令。

npm install -g openspec

装完之后跑一下openspec --version,能输出版本号说明安装成功。如果提示命令找不到,大概率是 npm 全局 bin 目录没加到 PATH 里。Windows 上一般是%APPDATA%\npm,macOS 和 Linux 是/usr/local/bin或~/.npm-global/bin,具体看你的 npm 配置。用npm config get prefix能看到全局安装路径。

如果你打算配合 Claude Code 或 Codex 使用,这两个工具也建议提前装好。Claude Code 的安装方式跟 OpenSpec 类似,也是 npm 全局装。Codex 稍微麻烦一点,Windows 上有时会遇到虚拟化平台相关的报错,需要在系统设置里确认相关功能已启用。这些工具的具体安装细节网上教程很多,这里不展开,重点放在 OpenSpec 本身。

3.2 初始化项目与目录结构规划

在项目根目录执行初始化命令:

openspec init

这个命令会创建基础的目录结构,通常包括specs、changes和一个配置文件。初始化完成后,我建议先别急着写规格,花十分钟想清楚能力域怎么划分。划分得太粗,一个规格文件几百行,没人愿意看;划分得太细,文件数量爆炸,找起来费劲。

我的经验是按“业务能力”划分,而不是按“技术分层”。比如电商项目,我会分成order-management、inventory、payment、user-account这几个域,而不是controllers、services、models。因为规格是给业务和技术双方看的,业务语言比技术语言更容易对齐。

目录结构大概长这样:

openspec/ specs/ order-management/ create-order.md cancel-order.md inventory/ stock-check.md changes/ proposed/ archived/ openspec.config.json

每个规格文件用 Markdown 写,顶部用 frontmatter 标注元信息,比如能力名称、负责人、状态。正文部分按“行为描述”“输入输出”“边界条件”“验收标准”几个小节组织。这个结构不是强制的,但用下来觉得最顺手,AI 读起来也清晰。

3.3 编写第一份规格文件

拿“创建订单”这个能力举例,一份合格的规格大概是这样:

--- capability: create-order domain: order-management status: active owner: backend-team --- ## 行为描述 用户提交订单时,系统校验商品库存、计算价格、生成订单记录,并返回订单号。 ## 输入 - userId: 用户唯一标识 - items: 商品列表,每项包含 skuId 和 quantity - addressId: 收货地址标识 ## 输出 - 成功:返回 orderId 和应付金额 - 失败:返回错误码和原因 ## 边界条件 - 库存不足时返回 409,附带缺货商品列表 - 商品已下架时返回 410 - 地址不属于该用户时返回 403 - 单次下单商品种类超过 50 种时返回 400 ## 验收标准 1. 正常下单返回 200 和有效 orderId 2. 库存不足场景返回 409 且缺货列表准确 3. 并发下单同一商品时库存扣减不超卖

写这份规格时有个细节要注意:边界条件尽量穷举。我一开始只写了正常流程,结果 AI 生成的代码完全没有错误处理,上线后各种异常场景直接 500。后来强迫自己把能想到的异常都列出来,AI 生成的代码质量立刻上了一个台阶。这不是 AI 的问题,是我给的信息不全。

另一个心得是验收标准要可执行。别写“性能良好”这种没法验证的话,要写“单次下单响应时间 P99 低于 500ms”这种能测的。OpenSpec 本身不执行验收,但它会把这些标准作为上下文传给 AI,AI 生成的测试用例会参考这些标准。

3.4 把规格接入 AI 编码工具

规格写完,接下来是让它真正“驱动”开发。以 Claude Code 为例,在项目里启动它之后,可以直接把规格文件路径喂给它:

请阅读 openspec/specs/order-management/create-order.md,按照规格实现对应的 Controller 和 Service。

Claude Code 会读取规格内容,结合项目现有代码风格生成实现。这里有个技巧:先让它只生成接口签名和空实现,你确认结构没问题后再让它填充逻辑。一次性生成完整实现,如果方向错了,改起来很痛苦。

Codex 的用法类似,把规格作为 prompt 的一部分传进去。如果规格文件较长,可以只传相关章节,避免超出上下文窗口。我一般会把“行为描述”“输入输出”“边界条件”三节传进去,“验收标准”留着后面生成测试用。

实测下来,接入规格后 AI 生成代码的首次可用率大概能从三成提到七成左右。剩下的三成问题主要集中在:规格本身有歧义、项目里有规格没覆盖的隐含约定、AI 对框架版本的理解偏差。前两个靠完善规格解决,第三个靠你在 prompt 里补充框架版本信息。

4. 规格与代码同步的维护策略

4.1 变更流程:先改规格还是先改代码

这是实践中最容易乱的地方。我的原则是:任何影响外部行为的改动,先改规格,再改代码。内部重构不影响行为的,可以只改代码。判断标准很简单——如果这个改动会让前端或调用方需要调整,那就是外部行为变更,必须走规格。

具体流程我一般这么走:先在changes/proposed下建一个变更提案,描述改什么、为什么改、影响哪些能力。团队 review 通过后,更新对应的规格文件,然后再动代码。代码合并时,PR 描述里关联变更提案的链接。这样半年后回头看,任何一个行为变更都能追溯到当时的决策原因。

有人觉得这个流程太重,小改动也要走一遍。我的折中方案是:影响单个能力且不涉及接口契约的改动,可以直接改规格文件,在 commit message 里说明;涉及多个能力或接口契约的,才走完整提案流程。这个度需要团队自己把握,但底线是规格不能落后于代码。

4.2 用规格反查代码覆盖率

规格写多了之后,怎么知道哪些规格已经实现、哪些还没?我试过几种办法,最后觉得最实用的是在规格文件的 frontmatter 里加一个implementation字段,标注对应的代码路径。

implementation: - app/Http/Controllers/OrderController.php - app/Services/OrderService.php

然后写个简单的脚本,扫描所有规格文件,检查标注的路径是否存在、文件是否最近有改动。这个脚本不用很复杂,几十行 Node 或 Python 就够。跑一遍就能看出哪些规格对应的代码很久没动(可能已废弃),哪些规格还没标注实现(可能还没做)。

这个做法看起来原始,但比引入一套重型工具实在。我见过团队为了做需求追溯,上了一整套 ALM 系统,结果没人维护,数据全是脏的。轻量方案的关键是维护成本低,低到大家愿意顺手更新。

4.3 规格的版本管理与归档

规格文件跟代码一样进 Git,这个没争议。争议点在于废弃的规格怎么处理。我的做法是:能力下线时,不删规格文件,而是在 frontmatter 里把status改成deprecated,并注明废弃原因和替代能力。文件移到specs/archived目录。

这么做的好处是,后来的人看到某段代码时,能查到它当初对应的规格,理解设计意图。直接删掉的话,历史就断了。我经历过一次,接手一个老模块,代码里有个奇怪的判断逻辑,谁都不知道为什么。翻了半天 Git 历史,找到一份已删除的规格,才明白是为了兼容一个早已下线的渠道。如果那份规格还在,能省我半天时间。

归档规格时记得在changes/archived里也留一份变更记录,说明为什么下线。这两处关联起来,就是一份完整的能力生命周期档案。

5. 常见问题与排查技巧实录

5.1 规格写了但 AI 不按它执行

这是最高频的问题。原因通常有三个:规格本身有歧义、规格没被正确传入上下文、AI 被项目里其他信息干扰。

先检查规格有没有歧义。把规格读给一个不了解项目的同事听,如果他听完能准确说出系统该做什么,说明规格合格;如果他反问“这里到底什么意思”,那就是歧义点。常见歧义包括:代词指代不明(“它”指谁)、条件不完整(只说“库存不足时”,没说不足的判定标准)、结果描述模糊(“返回错误”没说错误码和结构)。

再检查上下文传递。Claude Code 和 Codex 都有上下文窗口限制,规格太长可能被截断。我一般会把规格拆成小块,只传当前任务相关的部分。另外确认一下规格文件路径写对了,相对路径和绝对路径在不同工具里行为可能不一样。

最后检查项目里的干扰信息。如果项目里有一份过期的接口文档,AI 可能会参考它而不是你的规格。解决办法是把过期文档清理掉,或者在 prompt 里明确说“以 openspec 目录下的规格为准,忽略其他文档”。

5.2 规格与代码不一致时怎么处理

发现不一致时,先别急着改代码。第一步是判断哪边是对的。有时候是代码写错了,有时候是规格过期了。判断依据是当前业务需求——如果业务已经变了,规格没跟上,那就改规格;如果业务没变,代码偏离了,那就改代码。

我踩过的坑是默认“代码是对的”,直接改规格去迁就代码。结果后来发现代码本身就是个 bug,规格才是正确的,白改了一圈。后来养成习惯:发现不一致时,先找最近一次变更记录,看是规格先改的还是代码先改的,顺着时间线找原因。

如果实在判断不了,就把不一致的点记下来,找相关同事确认。别自己猜,猜错了后面要返工。规格驱动的核心价值就是消除模糊,如果在这里又引入模糊,就本末倒置了。

5.3 团队协作中的规格评审要点

规格评审跟代码评审一样重要,但容易被忽视。我总结的评审要点有这么几条:

评审项检查内容常见问题
完整性正常流程和异常流程是否都覆盖只写正常流程,异常全靠猜
可验证性每条行为是否能写出对应测试出现“合理”“适当”等模糊词
一致性与已有规格是否冲突两个能力对同一资源的定义矛盾
边界清晰能力的职责范围是否明确一个规格管了太多不相关的事
术语统一同一概念是否用同一术语一会儿叫“订单”一会儿叫“单子”

评审时我习惯让规格作者先口头讲一遍,讲的过程中卡壳的地方往往就是规格没写清楚的地方。讲完再逐条过验收标准,看能不能直接转成测试用例。转不了的,说明标准不够具体。

5.4 性能与规模上的注意事项

规格文件多了之后,管理成本会上升。我建议单个规格文件控制在 200 行以内,超过就拆分。一个域下的规格文件控制在 20 个以内,超过就考虑拆域。这不是硬性规定,但超过这个量级后,查找和维护的体验会明显下降。

另一个注意点是规格的加载性能。如果你写脚本批量处理规格,注意别每次全量读取。我一开始图省事,每次跑脚本都遍历整个specs目录,几百个文件读下来要好几秒。后来加了缓存,只读最近改动的文件,速度立刻上来了。这个优化在规格数量少的时候无所谓,多了之后差别很明显。

还有一点是规格里的代码示例。我建议规格里尽量少放具体代码,多放行为描述。代码会过时,行为描述相对稳定。如果非要放,标注清楚是示意而非实现,避免 AI 直接照抄。我有次在规格里放了一段伪代码,结果 AI 生成的实现跟伪代码一模一样,连里面的占位变量名都没改,哭笑不得。

6. 我个人的一些实操体会

用 OpenSpec 这套东西大概一年多了,最大的感受是它逼着我把“想清楚”这件事提前了。以前习惯边写边想,写到一半发现方向不对再回头改,浪费的时间其实更多。现在强迫自己先把规格写明白,写规格的过程就是理清思路的过程,真正动手写代码时反而快。

另一个体会是,规格驱动开发对 AI 工具的加成是实打实的。但前提是规格本身质量过关。我见过有人把规格写成了需求文档的复制粘贴,然后抱怨 AI 生成的代码不对。问题不在 AI,在规格。AI 是个放大器,规格清晰它放大清晰,规格模糊它放大模糊。

最后分享一个小技巧:我会在项目根目录放一个AGENTS.md或者类似的说明文件,告诉 AI 工具这个项目的规格在哪里、代码风格是什么、有哪些约定。Claude Code 和 Codex 都会读这个文件作为上下文。花十分钟写这个文件,能省后面很多来回解释的时间。这个文件不用很长,把关键约定列清楚就行,比如“规格在 openspec/specs 下”“Controller 不写业务逻辑,业务逻辑放 Service”“所有接口返回统一结构”。这些约定写进去之后,AI 生成的代码跟项目风格的一致性会好很多。

规格驱动开发不是什么银弹,它解决的是协作和上下文传递的问题,不解决架构设计的问题。但如果你正被需求模糊、代码偏离、AI 生成结果不可控这些问题困扰,它值得花时间试试。从一个小模块开始,写一份规格,走一遍完整流程,感受一下跟以前有什么不同。合适就推广,不合适就放弃,成本可控。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 7:59:25

多智能体系统一致性算法在电力调度中的实践与优化

1. 多智能体系统一致性算法在电力调度中的核心价值电力系统经济调度问题本质上是一个复杂的优化问题。传统集中式调度方法需要收集全网信息进行计算,存在单点故障风险、通信带宽压力大、隐私数据暴露等问题。而基于多智能体系统(MAS)的一致性…

作者头像 李华
网站建设 2026/11/2 7:58:59

软件测试质量回溯模板:从缺陷现象到根因定位

简介:这份《华为软件测试回溯模板》面向软件测试、质量管理与研发流程改进人员,系统梳理华为供应链质量管理部在质量回溯、根本原因分析与持续改进上的方法框架,可用于定位测试及交付中的重复问题、沉淀失效模式并推动流程优化。压缩包共1个P…

作者头像 李华
网站建设 2026/11/2 7:58:36

Bruno脚本分层执行与跨阶段代码共享实践

接口调试这件事,真正让人头疼的往往不是请求发不出去,而是脚本写着写着就散了。团队里 A 同学前段时间在 Bruno 里调一个带签名的下单接口,pre-request 里生成了 nonce 和时间戳,post-response 里想拿这两个值去比对服务端回显&am…

作者头像 李华
网站建设 2026/11/2 7:58:36

Agent开发入门:搞懂Harness层,两天从调API到跑通Agent

1. 为什么现在学 Agent 开发,得先搞懂 Harness 这层1.1 从“会调 API”到“能跑住一个 Agent”之间差了什么很多人第一次接触 Agent 开发,脑子里想的都是“我调一下大模型接口,让它自己规划、自己调工具,不就完事了”。真上手写两…

作者头像 李华
网站建设 2026/11/2 7:57:04

博弈动态规划:对抗性决策的最优策略解析

1. 博弈DP的本质与核心思想博弈类动态规划(Game Theory DP)是动态规划中一个极具挑战性的分支,它将传统DP与博弈论思想相结合,用于解决双方或多方在对抗性决策中的最优策略问题。与常规DP不同,博弈DP的状态转移需要考虑…

作者头像 李华
网站建设 2026/11/2 7:56:59

MiMo-V2.6技术报告深度解读:从架构到部署的技术拆解

MiMo-V2.6的技术报告发出来之后,我第一时间通读了一遍。说实话,现在大模型的技术报告越写越厚,但真正值得细嚼的部分往往就藏在几张表格和消融实验里。这篇解读不想重复报告里的目录结构,而是想换个思路:从架构选型、训…

作者头像 李华