☰
OpenSpec:用规范驱动开发,让AI编码不偏离共识
2026/10/10 12:36:44 网站建设 项目流程

有人把OpenSpec和电力行业的“变电站一键顺控改造技术规范”混在一起,原因也不难理解:名字里带“Spec”和“技术规范”,听着就像一本厚重的标准文档。我以前也一度以为它是某种文档模板,真正用起来才发现,OpenSpec是一套面向研发团队的开源CLI工具,核心是spec-driven development(规范驱动开发):把系统能力、约束、变更计划都写成结构化的Markdown规范,放进代码仓库,让人类和AI编码工具照着同一份事实干活。这篇文章我准备从机制拆解讲到完整实例,演示一份“给博客系统加多标签筛选”的变更从proposal到archive的全过程,最后聊聊我在真实项目中踩过的坑。适合正在用或准备用AI编码工具、又不想让AI自由发挥的团队,也适合所有被“口头需求加聊天记录式需求”坑过的开发者。

1. 为什么OpenSpec值得放进工具箱——研发协作里的规范断裂带

1.1 我在项目里反复遇到的“规范断裂带”

上个月的需求评审会上,需求方口头说“标签筛选要支持多选了”,产品经理点头,后端说“我接口改一改就行”,前端说“我UI加个多选框”。听起来很简单,但一周后联调直接炸了:后端认为多标签是AND关系,前端按OR关系做了交互,测试用例照着“只要包含任一标签就返回”写的。三方都觉得自己没理解错,但问题恰恰在于“规范”从来不存在——需求只在口头和IM聊天记录里流转。

这个场景我见过太多次。我把它总结成“规范断裂带”:需求从原始提出者到最终代码实现之间,信息一层层衰减。产品说“多选筛选”,后端理解成“查询参数支持数组”,前端理解成“复选框可以勾好几个”,测试理解成“多选条件下只要匹配任意一个就算命中”。等联调时发现语义不一致,没人能说清当初的准确约定,因为约定从来没有被写下来过。

以前团队靠资深工程师的记忆和脑补来补这条断裂带,现在加了AI编码工具之后就更危险——大语言模型特别擅长从残缺上下文里“合理推测”,而且推测得非常自信。我处理这个问题的方式很简单:让规范成为唯一事实源。OpenSpec的切入点就在这里,它不是让团队写更多文档,而是把“系统当前能力与变更约束”变成仓库里的一份结构化资产,让需求、设计、计划、实现、验收都围绕这份资产转动。

1.2 规范文件不是文档,是可执行资产

我见过不少团队把技术规范写成几十页的Confluence文档,然后没人看。OpenSpec的做法恰恰相反——规范文件是跟着代码一起提交和评审的,它必须像代码一样被维护。

仓库里的openspec目录包含specs、proposals、tasks、archive这几块:每个capability的spec.md是当前基线,每个change是一个待办变更包,每个task是能被执行和勾选的原子工作项。这种设计让规范从“文档”变成了“资产”:可以diff、可以review、可以回滚、可以自动化校验。这也是OpenSpec和普通Markdown笔记的本质区别——普通文档只描述状态,OpenSpec里规范是一等公民,必须进入项目根目录、随代码评审、在CI中校验。

如果你只是需要一个文档模板,OpenSpec对你可能是过度的;但如果你要管的是AI的产出边界和团队的共识一致性,它刚好在点上。

1.3 与ADR、README、API文档的分工

很多人会问:那我和已有的ADR、README、API文档怎么共存?我的经验是它们各管一件事。

ADR(Architecture Decision Records)记录“当时为什么做这个技术决策”,偏向原因和备选方案;README告诉使用者“这个项目怎么跑起来、怎么调用”,偏向上手操作;API文档描述接口细节,偏向契约。OpenSpec管的是“当前系统被约定的能力基线是什么、下一步要改什么、改到什么程度算完成”,偏向过程和演进。

它们可以同时存在于一个仓库,做法是:README里引用openspec/specs指路,docs/adr放决策记录,OpenSpec规范文件放openspec目录。千万不要把OpenSpec当成文档中心,那样它会退化成“又多了一个没人维护的wiki”。

2. 核心机制拆解:一次变更怎么从想法变成任务清单

2.1 三层结构:capability、change、task

要理解OpenSpec的工作方式,先看它的核心模型:capability、change、task三层结构。

capability是系统的一个能力域,可以理解为“一个内聚的业务能力”,比如博客系统的posts、comments、users各是一个capability。每个capability对应一份spec.md,描述这个能力当前被约定的行为、边界和约束,这是团队的“事实基线”。

当需求需要修改这个能力时,你不能直接改spec.md,而是创建一个change——可以把它看成一次“变更提案”,存放proposal.md(为什么要改、改什么、怎么验收)和tasks目录(拆解出的原子任务)。change完成、验证通过后,通过archive把变更合并回spec.md,change本身移入archive目录。

这样一来,spec.md永远是经过评审的过去和现在,change永远是活跃的将来,task永远是现在进行时。这层结构是OpenSpec整个流程的地基,理解它之后,命令只是一个操作这套模型的外壳。一个典型的目录结构长这样:

openspec/ ├── specs/ │ └── posts/ │ ├── spec.md │ └── proposals/ │ └── 2025-06-03-add-multi-tag-filtering/ │ ├── proposal.md │ └── tasks/ │ ├── 001-extend-post-query-api.md │ ├── 002-add-multi-select-filter-ui.md │ └── 003-update-integration-tests.md └── archive/

2.2 命令工作流:init、plan、develop、archive如何配合

OpenSpec的命令数量不算多,但每个命令背后都有明确角色。我整理了一张常用命令表:

命令干什么典型使用时机
openspec init创建工作区骨架,校验CLI与AI工具配置项目开始接入时
openspec change create在某个capability下新建change提案目录新需求启动时
openspec plan基于proposal生成任务清单proposal定稿后
openspec develop展示已批准change的任务列表与完成状态开发期间持续用
openspec archive合并变更到spec.md并归档change功能通过验收后
openspec validate校验openspec目录规范有效性与一致性每次提交/CI
openspec strict-mode开启严格模式,禁止跳过流程直接改规范流程成熟后开启

实际使用时,我的建议是“先认真写proposal,再让plan生成任务”,顺序不要反。因为plan生成的任务质量直接取决于proposal的清晰程度,proposal模糊时生成的任务往往是概念化的套话,对实现没有约束力。

另外,如果需要把任务同步给不敲命令行产品经理或测试同学,可以用sync把task推到GitHub/GitLab Issues,让他们在网页上也能看到进度。不同版本命令细节可能有差异,用的时候记得openspec --help确认当前参数。

2.3 状态流转与强制控制点

模型有了,命令有了,还缺一条把这些串起来的状态流转。一个change通常经历proposed → approved → in progress → archived几个阶段。

proposed是刚用change create建好、等待评审;approved是评审通过、允许进入开发;开发期间由develop跟踪各task状态;全部完成并验证通过后archive归档。

控制点在哪里?proposed到approved之间应该有评审,评审通过的本质门槛是proposal写清楚了问题、范围和验收标准;approved到开发之间应该有plan,把proposal拆成可执行任务。

OpenSpec还提供了strict-mode,开启后强制流程:没approved的change不能生成develop任务清单,没走plan的change不允许archive。如果你团队的流程经常被人绕过,这个模式等于给规范上了锁。

3. 实例演练:给博客系统加“多标签筛选”功能

3.1 初始化:openspec init与现状盘点

我以一个真实的博客系统为例,假设它是一个前后端同仓库的简单应用:后端是Python FastAPI,前端是React,数据存在PostgreSQL里。现在产品提了一个需求:文章列表页支持按标签多选筛选,比如同时选中“AI”和“Rust”时,只显示同时打了两个标签的文章。

我先在一个新分支上初始化OpenSpec环境。它需要正常的Git仓库,所以先git init,然后运行openspec init:

cd my-blog git init openspec init openspec change list

init做的事情主要是:确认CLI版本可用、创建openspec目录骨架、检查项目根目录下有没有可识别的AI编码工具配置。跑完之后,目录结构就会变成上一节展示的样子。

接下来盘点现状:通过openspec change list看一眼仓库里有没有未完成的变更。这一步容易被跳过,但实际项目中很重要——多个并行change同时修改同一个capability时,后归档的人要先rebase自己的规范基线。

提示:如果项目里还没有任何capability spec,建议先把现有系统的核心行为写成一份初始spec.md,哪怕只覆盖关键业务规则和边界,再开始新需求。否则第一个change会背着“补基线”的重担,容易写成一个烂大街的接口大全。

3.2 创建变更提案:change create + proposal写作

现在创建变更提案,命令如下:

openspec change create --capability posts --title "Add multi-tag filtering"

执行后会在openspec/specs/posts/proposals/下生成一个目录,目录名通常是日期加标题slug,比如2025-06-03-add-multi-tag-filtering。里面放了proposal.md和空的tasks目录。

创建之后要做的最重要的事是认真写proposal.md。我放一个实际会写成这样的版本节选:

# Add Multi-Tag Filtering ## Problem Statement 当前posts能力只支持单个标签筛选(tags=ai),无法满足跨标签检索的需求。 ## Current Behavior GET /api/posts?tags=ai 返回任意命中ai标签的文章列表。 ## Desired Behavior GET /api/posts?tags=ai&tags=rust 返回同时包含ai和rust标签的文章列表。 标签之间为AND关系,保持旧的单标签用法兼容。 ## Scope In Scope: - 后端查询接口支持多标签AND语义 - 前端筛选区支持多标签选择并同步URL查询参数 - 针对组合标签场景补集成测试 Out of Scope: - 标签管理后台 - 标签权重/热度排序 ## Test Plan - 单元测试:带两个标签查询时,SQL过滤条件包含两个标签的JOIN条件 - 集成测试:创建同时包含ai和rust的文章,确认双标签查询命中 - 验收标准:多标签选择后URL可分享,刷新后筛选状态保留

我特别想强调proposal里的Desired Behavior和Test Plan两块。AI编码工具在实现时最怕“方向明确但边界含糊”。你把AND语义、兼容范围、验收标准写清楚,后面plan和develop都会顺畅很多。实测下来,proposal阶段多花半小时,实现阶段能省半天。

3.3 让plan把proposal拆成任务清单

proposal写好后,运行openspec plan。它会读取proposed状态下的change,结合posts/spec.md中的现状描述,在tasks目录下生成任务清单。

它的价值是强制“先计划后动手”。AI模型不擅长在没有计划的情况下保持全局一致,但让它基于proposal生成计划,它会自然把接口改造、前端组件、测试回归拆开,避免一把梭改完接口忘了前端。

我运行之后,tasks目录下生成的文件大致如下:

tasks/ ├── 001-extend-post-query-api.md ├── 002-add-multi-select-filter-ui.md └── 003-update-integration-tests.md

每个task文件内部一般有Requirements、Implementation Notes、Definition of Done几个小节。比如001文件里会写:修改posts查询接口,支持tags参数数组,使用AND语义过滤;保持单标签调用兼容。002文件会写:筛选区改为多选组件,状态同步到URL query参数。003文件会写:构造双标签文章数据,覆盖联调场景。

plan阶段如果发现生成的task明显偏离proposal,正确做法是回到proposal里把语义写得更明确,而不是手改task文件去“修正方向”。方向错了,怎么拆任务都白搭。

3.4 用develop跟踪实现、validate校验、archive归档

接下来进入开发阶段。运行openspec develop,CLI会列出当前已批准change的任务清单,并且给每个task标注状态(pending、in-progress、done)。

你或者AI编码agent照着task挨个实现,完成一个勾一个。实现过程中有一个容易忽略的点:task状态更新要跟代码提交同步。我自己习惯的节奏是:每完成一个task,先更新对应task文件的状态、跑一遍相关测试,再提交代码;而不是把所有代码写完后再回来补状态——间隔一长,要么忘,要么状态记录就跟代码实际进度对不上了。

全部task勾完后,先跑一次完整的测试套件和openspec validate,确认规范文件格式正确、所有change处于一致状态。最后执行openspec archive,CLI会把该change的变更内容合并回posts/spec.md,同时把proposal与tasks目录移入archive。

这个动作完成意味着“多标签筛选”从一次变更提案变成了能力基线的一部分。以后任何一个新的change都能引用“posts支持多标签AND筛选”作为已有事实,不会产生重复提案或语义漂移。

4. 实战中绕不开的坑与经验

4.1 规范粒度:宁可一段明确说明,不要一本流水账

第一批用OpenSpec的团队,最常见的问题是“规范到底写多细”。我的经验是:

  • capability的spec.md,控制粒度在“能力边界加关键业务规则”,不要写成接口文档,也不要把每个参数都列进去。
  • 一个change最好控制在3到8个task。超过8个说明change拆得太大,建议拆成多个change分阶段归档。
  • task文件不要替开发者把代码写出来,而是写清楚Requirements和Definition of Done,让实现者有发挥空间但验收标准明确。

判断粒度是否合适的简单方法:问自己,如果两个月后有人要在这个能力上做调整,ta扫一遍spec.md和最近几个change的proposal,能不能搞清楚当时为什么这么设计、边界在哪。如果不能,说明信息密度不够;如果能但需要读十篇文档,说明太啰嗦。

4.2 目录纪律:命名规范与文本可diff

目录纪律是团队协作里最容易松、也最影响体验的部分。几个建议:

  • proposal目录名统一用日期-英文slug,例如2025-06-03-add-multi-tag-filtering,不要用中文和空格。中文文件名在Windows和CI的编码处理下会给你找麻烦。
  • task文件名从001开始三位数字编号,配合短横线命名,保持目录排序和阅读顺序一致。
  • 规范文本里不要塞图片和二进制附件,尽量用纯文本和Markdown表格,保证每个文件都可以diff。这是规范作为“可执行资产”的基本前提。
  • 同一个PR里,改代码和更新OpenSpec目录要配套。只改代码不改规范,等于规范失联;只改规范不实现,等于纸上谈兵。

我一般要求团队把“更新OpenSpec状态”和“更新代码”放在同一个PR,方便review的人一眼看出变更与规范是否一致。

4.3 让CI强制规范流程

流程工具如果只靠人自觉,早晚会崩。我的做法是把OpenSpec校验接进CI:每次push跑openspec validate,保证规范文件格式合法、状态一致。

对已经跑熟的团队,打开strict-mode,让没approved的change无法进入开发态,存在未归档change却直接改核心代码的PR会被拦截。

还有一个更细的组合拳:在CI里加一个检查,凡是有代码改动且涉及已有capability的PR,必须存在对应的in-progress的change,否则用注释自动提醒“先写proposal再写代码”。听起来有点严格,但经历过“AI一天提交十个直接改核心模块的PR、没人知道改了哪里”的团队,都会理解这种防线的好处。接入方式不外乎在CI脚本里加几步openspec命令,成本很低,收益是流程长期不走样。

4.4 和AI编码工具配合的几个细节

最后讲一个很多人没注意到但非常实用的点:OpenSpec和AI编码工具的配合方式。

AI编码工具是通过项目里的agent规则来约束自己的。你可以在规则的全局部分写明:“所有功能变更必须先创建或更新OpenSpec change,更新task状态后再修改代码;代码提交前必须引用对应的change ID。”这样AI从一进入项目就走在规范流程里,而不是先写了代码再补解释。

我自己用下来还有个技巧:让AI实现某个task时,把task文件和proposal.md一起喂给它,同时告诉它“按任务文件里的Definition of Done自测,完成后更新task状态”。这样AI的完成标准是任务里的验收标准,而不是它自己脑补的“看起来能跑”。这套配合方式比单纯发号施令稳定得多,因为OpenSpec把上下文和约束都固化成了文本,AI只是在一个更清晰的边界里执行。

最后分享一个自己最近的习惯:凡是新需求进入待办,我第一件事不是开IDE写代码,也不是拉产品开会,而是先建一个OpenSpec change,把Problem Statement和Desired Behavior敲下来。就这一步,已经帮我挡住了好几个“听起来简单、细想全是坑”的需求。规范驱动开发不是让你多写文档,而是让团队里面最贵的资源——共识,能被低成本地建立和复用。你在项目里第一次跑通一条proposal→plan→develop→archive的完整链路之后,大概率会回头看那些“靠口头对齐”的日子,庆幸自己终于把话说明白了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询