总觉得需求“说不清楚”,这个问题我带了五六年,直到最近才找到一套让我顺手的解决方式,就是 OpenSpec。OpenSpec 是一套规范驱动的项目工作流工具,核心思路是把产品需求、技术方案和实施任务统一成一组结构化的 Markdown 规范文件,让团队里的人类和 AI 都能在同一份上下文上对齐。它的使用方式不复杂:初始化一个目录、按模板写一个变更提案、把需求拆成若干条 spec,然后按任务执行。网上很多 OpenSpec 使用教程都写成了命令说明书,把一堆参数扔给你就完事,我不打算那么干。这篇更想讲清楚它背后的设计思路,以及我在实际项目里怎么把它嵌进日常流程。适合谁?适合那些在 AI 辅助编码中用得不顺手的人,也适合被 PRD 和代码永远对不上号困扰的团队。
1. OpenSpec 是什么:把“说不清楚的需求”变成可执行规范
1.1 为什么我在 AI 编码时代开始认真对待“需求描述”
先说一个我自己的经历。前两年我开始大量使用 AI 编码助手,刚开始觉得惊艳,复杂点的页面、脚本、接口示例,它都能在几十秒里给你列出来。但慢慢的,问题暴露了:它写出来的代码看着没问题,一跑就发现业务逻辑不对。我一开始以为是模型能力不行,后来复盘发现,八成问题出在我自己身上——提示词里那句“改一下登录逻辑,加个记住我”,在不同语境下能被理解成至少五种方案。
这是个很典型的场景。AI 编码工具再强,本质上还是一个“读完上下文后做预测”的系统。你喂给它的需求描述越模糊,它就越倾向于用最常见、最保险的实现方式猜。但业务需求偏偏不是“最常见”就能满足的:要不要长期 token?过期多久?记住我之后要不要自动刷新 token?这些细节,你得先想明白,才有资格让 AI 帮你写代码。
OpenSpec 恰好切入的就是这个位置。它不负责替你决策,而是强制你把决策落在纸面上,并且用一种机器和人都容易读的结构来组织。说白点,它就是把“模糊想法”变成“结构化规范”的中间层。传统做法是人跟人开会对齐,OpenSpec 的做法是把对齐的产物、变更提案和 spec 文件直接沉淀到仓库里,谁都能看、谁都改得动、AI 也读得懂。
1.2 OpenSpec 与 PRD、用户故事的差异
有人可能会问,这不就是写 PRD 或者用户故事吗?还真不一样。
PRD 通常面向的是“人类评审”,写得好的 PRD 讲究排版、句式、上下文,但这些自由格式对程序来说是灾难。产品经理写了一段很漂亮的描述,比如“希望用户在登录后有更流畅的体验,提升留存”,这句话人看了可能点头,但 AI 无法从里面提取出一个“可以验证”的行为。它缺少边界条件,缺少可观测的验收标准,缺少具体的触发场景。
用户故事又往往太简短,通常就是“作为用户,我希望……以便……”。它适合排优先级、适合站在用户视角思考,但作为实现说明书来说,颗粒度完全不够。一个“记住我”的故事背后,涉及前端存储、后端认证、安全策略、失效机制,靠三行用户故事根本讲不清楚。
OpenSpec 把规范拆成了一个相对完整的结构:每个变更有 proposal,里面写清楚动机和影响;每个 spec 文件只承载一个可验证的行为要求;tasks 再把实现步骤列清楚。本质上,它是把敏捷开发里经常挂在嘴边的“Definition of Done”落到了文件层面,让每个变更在被实现之前,先被定义清楚。而且最关键的是,这些文件进入 Git 仓库后,天然支持 diff、评审、回溯,完全可以像代码一样走审核流程,这是传统 PRD 很难做到的。
| 维度 | 传统 PRD | 用户故事 | OpenSpec spec |
|---|---|---|---|
| 面向对象 | 人类评审 | 产品讨论 | 人 + AI 共同执行 |
| 可验证性 | 弱,依赖人为解读 | 弱,缺少验收细节 | 强,逐条可验收 |
| 变更追踪 | 靠文档版本管理 | 靠看板备注 | 随 Git 进版本库,天然可 diff |
| 粒度控制 | 整体方案 | 故事级别 | 单条 spec 独立可拆 |
1.3 这套思路到底解决了什么核心问题
我梳理下来,OpenSpec 解决的核心问题有三个维度。
第一是“减少歧义”。同一句话,产品经理、后端、前端、AI 助手理解出来的东西基本都不一样。把需求拆成一条条带前置条件、行为描述、验收标准的 spec 后,歧义空间被大幅压缩。即使最终实现有问题,你也能快速定位到是“哪条 spec 写错了”,而不是在代码层面猜需求。
第二是“让 AI 的使用成本下降”。使用 AI 编码助手最贵的不是 API 费用,而是上下文对齐成本。你把 2000 字的 PRD 扔给 AI,它可能只会关注最后一段;但你把结构清楚的 spec 文件逐条喂给 AI,它可以按图索骥地实现。很多 AI 支持仓库级分析和项目上下文,OpenSpec 的结构化文件正好可以被 AI 高效读取,相当于给 AI 一份“边界清晰的任务书”。
第三是“让变更可追溯”。有了提案和 spec 文件,你就能回答“这个功能当时为什么这么做”“那条限制是谁加的”。这些信息散落在聊天记录里最容易丢失,放在代码注释里又太零散,但在 OpenSpec 的目录结构中,它们跟着代码一起走,形成了一条完整的决策链。
2. 一次变更的骨架:目录、状态机与规范文件
2.1 先看目录结构:每个文件在说什么
要理解 OpenSpec,最容易上手的方式是先看目录结构。以我常用的版本为例,初始化一个项目后,会生成类似下面这样的一套骨架:
openspec/ ├── project.md ├── specs/ └── changes/ ├── 20250201-add-login-remember/ │ ├── proposal.md │ ├── specs/ │ │ ├── auth-remember-token.spec.md │ │ └── frontend-remember-checkbox.spec.md │ └── tasks.md └── 20250210-refactor-cache/ ├── proposal.md ├── specs/ └── tasks.mdproject.md是项目级说明,相当于整个项目的高空视图,写清项目目标、整体约束、技术选型,让任何一个新加入的人或 AI 在最短时间内了解项目背景。specs/目录放那些已经稳定、跨变更共享的通用规范,适合沉淀一些“所有模块都必须遵守”的规则。changes/目录则是每一次独立变更的家,每一个子目录对应一次变更提案,里面再拆成 proposal、specs、tasks 三个部分。
这种设计最聪明的地方在于:它把“一次变更”这个虚的东西变成了一个实体目录。以前你参与一个改动,流程是“开会讨论、拉群沟通、写代码、提 MR、被打回、再开会”,整个过程是离散的,信息散落在各个角落。在 OpenSpec 的组织下,所有相关信息都收敛在一个目录里,你要 review 一个改动,只需要看这个目录下这几个文件,心智负担一下子小了很多。
2.2 提案状态流转:从 Draft 到 Archive
在 OpenSpec 的工作流里,每个 change proposal 都有自己的生命周期。我习惯把它理解成一条流水线:起草、评审、接受、归档。
起草阶段,你创建一个新的变更目录,这时候 proposal 还处于 Draft 状态,内容是草稿,随时可以改。评审阶段,你把它提交到团队里让人 review,关注点不只是代码,而是“需求定义是否准确”“spec 是否可验证”“影响范围是否完整”。评审通过后,方案被接受,开始进入实现阶段,spec 文件成为你写代码时的事实依据。等到代码合并、功能上线,这条 proposal 就可以归档,从 active 状态变成 archived。
你可能觉得这有点形式主义,但经历过几次“需求变更没有记录”之后,你会发现状态流转真的能救命。有一次我在一个旧项目里看到一个奇怪的配置项,翻遍 wiki 都没有说明,最后是在一个已归档的 OpenSpec proposal 里找到了当初的设计讨论,三分钟就把来龙去脉搞清楚了。这种体验是聊天记录永远给不了你的。
| 状态 | 标识 | 核心动作 |
|---|---|---|
| 草稿 | Draft | 自由编辑 proposal 与 spec |
| 评审中 | In Review | 焦点是需求定义与可验证性 |
| 已接受 | Accepted | 开始按 spec 实现,代码以 spec 为准 |
| 已归档 | Archived | 保留决策记录,移出当前视图 |
2.3 为什么 spec 文件要“小而专”
我总结过 OpenSpec 里最容易踩的坑之一,就是把 spec 写得又大又全,一个文件把所有需求揉在一起。这看起来省事,实际上到了评审和验收的时候非常痛苦,因为没法逐条验证。
OpenSpec 的思路跟测试里面的“单一断言”很像:一个 spec 文件只描述一个行为、一项决策或一条约束。比如实现登录的“记住我”,可以拆成几个 spec:认证接口需要支持 remember 参数、前端需要根据勾选状态处理 token 持久化、服务端 token 过期策略需要在记住我场景下调整。每个 spec 都是独立可验证的,A 条失败不影响 B 条完成,而且实现顺序可以并行。
这样一来,AI 也能受益。你把三条独立 spec 交给 AI,它每完成一条就能确认一次,而不是让它一次性生成一个两千行的登录改造方案,出了问题根本不知道从哪里排查。小而专,本质上是把复杂度分解,让人和机器都能在一个可控的粒度上思考。
3. 实操过程:从零初始化到第一个变更跑通
3.1 安装与初始化:一分钟搭好骨架
如果你要试 OpenSpec,最直接的方式是先把它装到全局环境里。我的常见做法是使用 npm 安装,具体命令如下:
npm install -g openspec安装完成后,进到一个干净的项目目录,执行初始化命令:
mkdir openspec-demo && cd openspec-demo openspec init正常情况下,项目下会自动生成 openspec 目录和对应的骨架文件。这一步基本不需要动脑,但有一个细节值得注意:初始化之后先打开project.md看一眼,把里面项目名称、定位、技术栈这些信息改成真实的。千万别跳过,因为后续 AI 或者新同事一进项目就会优先读取这个文件,它直接影响整个项目上下文的准确度。我第一次用的时候偷懒没改,后来 AI 在生成代码时一直误以为项目是某个示例工程,排查了好久。
3.2 创建第一个变更提案
初始化完成后,就可以尝试创建一次变更了。以“给登录页面增加记住我功能”为例,命令大致是这样的:
openspec new "Add remember me to login flow"执行后,changes/目录下会多出一个以“日期-名称”格式命名的子目录,里面是模板文件。打开proposal.md,你会看到需要填写的几个核心部分:为什么做、做了什么、影响哪些模块、变更类型是新增、修复还是重构。这个地方不用写太多字,但要把目的写清楚,尤其是“为什么做”这一项,很多人在实际使用时会忽略,直接跳到技术方案。等到三个月后你再看这次变更,唯一还能看懂的就是这个 why,代码实现早就忘了。
3.3 把需求拆成 spec 并落地任务清单
proposal 写完之后,重点来了:拆分 spec。我会在specs/目录下为每条白纸黑字的需求建立一个文件,命名尽量带上模块名和关键字。还是上面的例子,我大概会拆出这么几条:
specs/ ├── auth-remember-token.spec.md ├── auth-token-expiry-policy.spec.md └── frontend-remember-checkbox.spec.md每份 spec 文件内部的格式,我建议至少包含三个部分:背景与目的、行为描述、验收标准。行为描述写清楚“当用户勾选记住我并登录成功后,系统应该返回一个有效期 30 天的长效 token”;验收标准则写成可检查的条目,比如“使用勾选记住我的账号登录,关闭浏览器后再次打开,用户仍然处于登录态”。这一步做完,需求已经基本具备了可执行性。
接下来是tasks.md,这一步是把 spec 再往下落一层,变成具体的开发任务。每一个任务最好能对应到具体文件、接口或组件,比如“在后端认证接口中增加 remember 参数处理”“在前端登录表单中增加记住我复选框”。任务列表可以和 spec 一一对应,也可以拆得更细,只要实现的时候能一条一条清掉就行。
3.4 把 spec 交给 AI:一次真实的协作过程
说实话,OpenSpec 真正让我觉得值回票价的时候,是把它接到 AI 编码流程里之后。我现在的做法是:在 AI 助手里明确告诉它项目根目录下有一套 OpenSpec 规范,然后直接把当前变更的 proposal 和 specs 路径丢给它。
一个比较稳的提示词写法大概是:
请先阅读 openspec/changes/20250201-add-login-remember/ 目录下的 proposal.md 和所有 spec 文件, 然后按照 tasks.md 里的任务顺序逐项实现。每完成一项,同步更新 tasks.md 的完成状态。这里有个很实在的经验:千万不要让 AI 一下子把所有任务全干完。我试过让 AI 一口气实现整个变更,结果它在第三项任务上发挥想象,生成了一个跟需求完全不一样的设计,返工成本比手写还高。改成逐项实现之后,每完成一项我就检查一次,及时纠正,整体效率反而高很多。OpenSpec 的 task 拆分正好非常适合这个节奏,天然把一个大需求切成了 AI 能够稳妥吃掉的小块。
另外,如果 AI 支持仓库级语义检索,它会自己去翻 spec 文件,你只需要告诉它“变更文档在 openspec/changes 下”。如果 AI 不支持,你就手动把相关 spec 文件的内容复制到上下文里。结构化文本的另一个好处就在这:复制出来也不会乱,AI 能很轻松地按条目执行。
4. 把 spec 写好的四个心法
4.1 用验收标准倒推内容
写 spec 最常见的误区是从“实现方案”出发,上来就写“我们要用 Redis 缓存、要用 JWT 做认证”。这些实现细节不是不能写,但 spec 的第一输出应该是“行为”,而不是“技术选型”。我自己的方法是倒着写:先写完验收标准,再往上补行为描述和背景。
怎么理解这招?以“记住我”为例,我先列验收标准:关闭浏览器后重开,记住我用户登录态保持 30 天;未勾选记住我,关闭浏览器后需要重新登录;30 天后 token 过期,重新登录可刷新。这些验收标准列完,技术方案基本就被限定在很窄的空间里了,后面不管是 JWT、Redis 还是别的实现,都不会跑偏。先定义“怎么算完成”,再讨论“怎么做”,是我认为写 spec 最重要的一条原则。
4.2 别把非功能约束丢掉
很多团队用 OpenSpec 只写功能需求,性能、兼容性、安全这些非功能约束经常被忽略。但恰恰是这些约束,在 AI 生成代码时最容易出问题。你如果不告诉 AI“这个接口需要在 200ms 内返回”,它可能写出一个同步调用外部服务的实现,性能直接翻车;如果不写“token 必须使用 HttpOnly Cookie 存储”,AI 可能随手把 token 塞进 localStorage,留下安全隐患。
所以我在写 spec 的时候,会专门为那些容易忽略的约束留出位置:有没有性能指标?要不要兼容旧版本?涉及用户数据,有没有权限和安全要求?这些东西哪怕只写一句话,都能在关键时候保住工程质量。AI 不会主动替你思考安全边界,但你把边界写清楚了,它能做得很稳。
4.3 让每条 spec 都能被“判定 OK 或 NOT OK”
我判断一条 spec 写得好不好,唯一的标准是:一个没参与过讨论的新人,能不能在看完这条 spec 后明确地对实现结果说一句“这不对,这里没达到要求”?如果答案是可以,这条 spec 就是合格的。
这要求描述要足够具体。比如“登录功能要支持记住我”,这句话就不合格,因为没法判定;改成“用户勾选记住我登录成功后,服务端返回有效期 30 天的刷新令牌,客户端持久化保存并在会话恢复时自动使用”,这才是可判定的。把 spec 当验收单来写,而不是当需求笔记来写,效果完全不一样。
4.4 该归档就归档,保持变更区的干净
最后一条是运维层面的经验。OpenSpec 的 changes 目录里会不断累积变更提案,如果不定期归档,目录很快就会变成一个越来越大的垃圾堆。归档不是说删掉,而是把已经完成的提案从 active 移到 archived,让它退出当前视图,但仍然保留历史记录。
我自己的习惯是,每个合并到主分支的变更,在发布后立即归档。这样好处很明显:当你想知道当前有哪些改动在飞,打开 changes 目录一眼就能看全;当你想查历史决策,去 archived 里翻。干净的状态意味着低的认知负担,这话放在代码里成立,放在需求管理里同样成立。
5. 常见问题与排查技巧实录
5.1 命令执行报错:先检查是不是没在项目根目录
我在使用过程中遇到最多的报错,其实不是什么高深问题,而是把openspec init执行错了位置,或者在多个项目之间切来切去时,跑到别的目录里去执行命令,结果 CLI 找不到 openspec 目录。遇到这种情况,先看一眼当前目录下有没有 openspec 文件夹,再确认有没有执行过 init。很多时候,问题出在不是工具本身,而是使用习惯。
另外,版本差异也可能导致命令不兼容。不同时期的 OpenSpec CLI,命令名和参数可能会有调整。我的建议是,遇到命令不认识或者参数对不上,先执行openspec --help或openspec <command> --help看当前版本的说明,不要硬记命令,因为工具还在快速迭代阶段。
5.2 spec 写得太多或太少,尺度怎么把握
这个问题几乎每个试用 OpenSpec 的人都会问:一个变更到底拆多少条 spec 合适?我的经验是,以“可独立验证”为准。如果你发现一条 spec 里包含了两个以上的验证点,那就该拆;如果两条 spec 永远只能同时完成同时验证,那就该合并。
举一个反面例子,有次我把“用户资料编辑和头像上传”写进了同一条 spec,结果评审的时候大家都很痛苦,因为两个功能互相纠缠,验收标准写不清楚。后来拆成两条独立的 spec,每个人都轻松了,开发也可以并行。宁可稍微拆多一点点,也不要写成一坨,因为拆开容易合并,写糊了想拆就得重新梳理逻辑。
5.3 AI 依旧理解偏了,多半是 spec 本身有歧义
如果在 AI 按 spec 实现后仍然偏离需求,先不要急着怪 AI,回头看看 spec 里的动词是不是太虚了。像“优化”“提升”“支持更好的体验”这类词,几乎必然导致污染。你可以试着把所有模糊词汇列出来,一个个换成可量化、可观测的表述,通常问题就解决了。
还有一种情况是 spec 之间互相矛盾。比如 A spec 说 token 有效期 30 天,B spec 说 token 在会话结束后立即失效,AI 当然会混乱。这时候需要你人工检查整个 changes 目录下所有 spec 的一致性。OpenSpec 的优势在于所有信息集中在一个目录里,这种矛盾排查起来并不难。
5.4 团队不买账,推行 OpenSpec 的技巧
如果你是团队里第一个想引入 OpenSpec 的人,很可能会遇到抵触情绪,大家会觉得“又多了流程”。我的实际感受是,不要一开始就让全员全流程使用,而是先从一个痛点最明显的项目切入,比如一个频繁被 AI 改错需求的项目,用 OpenSpec 把流程跑通,让效果说话。
其次,尽量把使用成本降到最低。我的做法是先只用 OpenSpec 的目录结构,不去强制所有字段都填,甚至可以先不引入 CLI,纯粹靠模板就能跑起来。等到大家体会到“需求变更有了记录”“AI 输出质量提高了”这些好处后,再逐步把评审、归档这些环节加进来。工具是拿来解决问题的,不是拿来表演流程的,这是我一直提醒自己的话。
5.5 任何时候都适合上 OpenSpec 吗
最后聊一句大实话:OpenSpec 不是银弹,也不是所有项目都需要它。一个很小的个人试验项目,或者一个只有几百行代码的脚本工具,硬套这套规范反而会拖慢节奏。我自己的判断标准是:只要这个变更需要别人 review、需要被记录、需要交给 AI 实现,它就值得走一遍 OpenSpec 的流程。
反过来,如果你一个人闷头写代码,完了就不管了,那 OpenSpec 确实不太必要。规范的价值来自长期积累和多人协作,一个人写给自己看的备注,用不上这么重的仪式感。这一点想清楚,你就不会把工具用变形。
6. 最后,说点工具之外的体会
从第一次接触 OpenSpec 到现在,我最大的变化不是代码写得更快了,而是想问题的方式变了。以前拿到需求,第一反应是“怎么改”,现在会先想“这条需求到底能不能被验证”“背后的约束条件是什么”。这种思维迁移看起来不起眼,但它让我和 AI 协作时的返工率明显下降,也让团队里的沟通从“你猜我想什么”变成了“一起看 spec 对不对”。
如果你也正在被需求歧义、AI 代码跑偏、评审流于形式这些问题困扰,我建议你拿一个小需求试一次 OpenSpec,不用追求一步到位,先从把 proposal 写清楚开始。工具本身很简单,真正值钱的是那份把需求打磨到可以执行的习惯。希望这篇基于个人实操的梳理能帮你在用的过程中少踩几个坑,也欢迎你把我没提到的经验留言分享出来,大家一起把这个流程越用越顺。