ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

OpenSpec 深度解读:让 AI 编码助手照着规格干活,不再自作主张(含上手指南与同类选型对比)

OpenSpec 深度解读:让 AI 编码助手照着规格干活,不再自作主张(含上手指南与同类选型对比)

事实基线:本文基于 OpenSpecv1.14.2(2026-10-16)。文中命令、版本与对比结论以官方文档与仓库为准,来源见文末。文中「我认为 / 从设计上看」处为作者判断,非官方结论。

TL;DR

  • 它是什么:OpenSpec 是一个轻量的规格驱动开发(Spec-Driven Development, SDD)框架——先把「要做什么」写成可评审的规格文件,再让 AI 编码助手照着规格实现代码。
  • 最大亮点:它把每次改动收拢成一个独立变更文件夹,用增量规格(delta)表达「改了哪些需求」。于是「评审规格」变得像「评审代码 diff」一样自然。
  • 最适合:已存在的代码库(brownfield)上做增量迭代的团队,尤其是多人 / 多 AI 工具混用、需要一份共同事实来源的场景。
  • 最该注意:它是同类里最年轻、最少强约束的——没有「宪法」式的硬门禁,团队约定得自己补。它管的是「流程」,不是「保证」。

1. 项目背景与要解决的问题

1.1 一个具体的困境:AI「看起来对」的代码

用过 AI 编码助手的人,多半都遇到过下面这几种情况:

  • 你把「给用户资料加个按角色过滤的搜索」丢给 AI,它理解了七成,剩下三成按自己的想象补齐;
  • 它多做了你没要求的功能,或者漏掉了嘴上没明说、但你心里默认要的边界(比如未登录、空结果);
  • 同一个需求换个会话再问一次,产出的结构完全不一样;
  • 代码提交上去了,但为什么这么改没人记得,几个月后没人敢动。

这些问题的共同根源是:意图没有被写下来。没有规格时,AI 不是在「实现」你的需求,而是在「猜」你的需求——它的输出看起来合理,但正确与否全凭运气。

1.2 没有规格时,问题出在哪

传统做法是「聊天驱动」:所有需求都以对话形式存在,留在某个会话的上下文里。它有三个结构性缺陷:

  1. 不可评审。对话无法 diff,你没法像审代码一样一眼看出「这次到底改了什么意图」。
  2. 不可累积。上下文窗口一关,知识就散了;新人接手时无据可查。
  3. 不跨人、不跨工具。同事用 Cursor、你用 Claude Code,两人对同一套系统的心智模型可能完全不同。

1.3 OpenSpec 赌的是什么

OpenSpec 的官方定位是「build the right thing and build it right」(做对的事,并把事做对)——前者靠「规格」,后者靠「校验」。它押的注很明确:

与其试图让 AI「更聪明地猜」,不如要求人先把意图说清楚,让 AI 在一个可评审的约束里工作。

因此它的设计取向是流动而非僵化、迭代而非瀑布、适配存量而非只服务新项目。理解这一点,后面所有设计(为什么用增量、为什么用复选框)都能自洽。


2. 核心概念与整体架构

2.1 核心术语

先扫清术语,后面就不必反复解释:

术语一句话解释
Spec(规格)描述系统当前应该是什么行为的文档,是「真相来源」,不含实现细节
Change(变更)一次改动的完整提案,住在独立文件夹里,从提出到归档是一个生命周期
Delta Spec(增量规格)用ADDED / MODIFIED / REMOVED / RENAMED描述「相对主规格改了什么」,而不是重抄一遍
brownfield已经存在、需要持续演进的代码库(相对绿地/greenfield 新项目)
archive(归档)把已完成的变更合并回主规格,并移入归档目录的动作
Requirement / Scenario规格的最小单元:一条需求 + 至少一个场景(用 WHEN/THEN 描述行为)

2.2 双文件夹模型

OpenSpec 的全部结构就两个目录——「现在是什么」和「想改成什么」:

openspec/ ├── config.yaml 项目设置与喂给 AI 的上下文 ├── specs/ 主规格:系统「当前事实」(初始为空) │ └── <能力>/ │ └── spec.md └── changes/ 进行中的变更提案(初始为空) ├── <变更名>/ 一次改动一个文件夹 └── archive/ 已完成、并已合并回 specs/ 的变更

2.3 一个变更文件夹里有什么

以变更名add-rate-limiting为例:

openspec/changes/add-rate-limiting/ ├── .openspec.yaml 变更元数据(schema、创建日期等) ├── proposal.md 为什么做、要改什么 ├── specs/ 本次的行为变更(增量规格) │ └── rate-limiting/ │ └── spec.md ├── design.md 技术决策(只有需要时才生成) └── tasks.md 实施清单(复选框)

产物的起草顺序是固定的:proposal最先;specs与design不分先后;tasks需要它俩都完成。

┌─ specs ──┐ proposal ────┤ ├── tasks ──▶ apply └─ design ─┘

2.4 五步循环

每一次变更都走同一条回路,这就是它的「工作流内核」:

1 · Explore 探索 ──▶ 2 · Propose 提案 ──▶ 3 · Review 审阅 │ 5 · Archive 归档 ◀── 4 · Apply 实施 ◀────────────┘ │ └──▶ 下一次变更回到 Explore

关键在于:前四步里,没有任何一行产品代码被写出来。代码只在第 4 步出现,而那时计划已经被审过一遍了。


3. 关键机制深入剖析

这一节回答「它凭什么 work」。选三个最能体现设计思想的点。

3.1 为什么是「增量规格」而不是「重写规格」

要解决的问题:系统在演进,主规格必须跟着变;但如果每次改需求都要人去重抄整份规格,成本高、还容易抄漏。

  • 朴素做法与代价:每来一个需求就重写specs/——改一次全量 diff,评审者看不出「这次到底动了哪一条」,改动淹没在噪音里。
  • 它的做法:变更里只写增量,用四种操作显式标注:

## ADDED Requirements # 新增的需求 ## MODIFIED Requirements # 行为改变(必须贴出完整更新后的内容) ## REMOVED Requirements # 废弃(必须写明 Reason 与 Migration) ## RENAMED Requirements # 仅改名(FROM → TO)

  • 收益与代价:收益是评审粒度精准——「这次改了哪条需求」一目了然,和评审代码 diff 是同一个心智模型;归档时把增量合并回主规格,主规格始终保持最新。代价是:MODIFIED必须贴完整更新后的内容,只贴局部会在归档时丢细节;MODIFIED的### Requirement:标题文本要和主规格精确匹配,否则归档时对不上。

我认为这是 OpenSpec 与「一次性生成整份规格」类工具拉开差距的地方:它把「规格的演进」本身做成了一等公民。

3.2 为什么进度只认 tasks.md 的复选框

要解决的问题:AI 实施到一半中断/换会话,怎么知道干到哪了?

  • 朴素做法与代价:靠对话上下文记忆进度——会话一断,进度就丢了,只能重来或人工比对。
  • 它的做法:把tasks.md里的复选框当成唯一的进度真相来源。apply 阶段逐条解析、逐条勾选;中断后新开会话再说一次,它就从第一个未勾选的任务继续。
  • 收益与代价:收益是无隐藏状态——进度是人类可读的 markdown,落盘、可 diff、可随代码一起提交。代价是格式敏感:勾选框里只有x才算完成,- [~]、- []都算未完成;普通项目符号(不以- [ ]开头)完全不被跟踪。

这也解释了「任务要小到一次会话能做完、按依赖顺序排列」这条最佳实践——不是因为工具限制,而是因为「复选框即进度」的模型天然奖励细颗粒、有顺序的任务。

3.3 上下文是怎么进到 AI 手里的

要解决的问题:项目有技术栈、有约定,怎么保证每个产物的生成都带上这些背景,而不用你每次重复啰嗦?

  • 它的做法:openspec/config.yaml里的context字段会被注入到每一个产物(创建、apply、archive 都会收到)。AI 在工作流中调用openspec instructions <产物> --change <id>,这条命令把config.yaml的context/rules与内置指令合并成一段完整提示,AI 再照着写。
  • 收益与代价:收益是「写一次、处处生效」,比如把「所有产物统一用中文书写」「技术栈是 TS + React 18」写进context即可。代价是能力边界明确:config 只能加指令,改不了「有哪些产物、什么顺序、模板长什么样」——想要那种控制力,得 fork 一份 schema。

4. 典型使用场景与示例

4.1 最小上手路径

# 前提:Node.js ≥ 20.19.0 node --version # 安装 CLI npm install -g @fission-ai/openspec@latest openspec --version # 预期输出类似 1.14.2 # 在项目根目录初始化 cd your-project openspec init # 建出 openspec/ 并写入你所用 AI 工具的指令文件

初始化后重启 IDE,斜杠命令才会加载;跨版本刷新生成文件用openspec update。

4.2 一个端到端示例:给应用加限流

第一步 · Explore(只思考,不写码)

帮我探索一下限流在这个应用里应该怎么设计。

AI 会翻代码库、问该问的问题、给备选方案——但不会写任何文件,除非你让它记结论。

第二步 · Propose(产出变更文件夹)

就按刚才讨论的来做提案。

AI 生成openspec/changes/add-rate-limiting/,包含proposal.md、specs/、tasks.md。仍然没有代码。

第三步 · Review(在还是文字的时候改对)

openspec list # 看有哪些进行中的变更 openspec show add-rate-limiting # 看提案与规格 openspec validate add-rate-limiting --strict # 校验结构;把警告当失败

specs/是最值得读的部分——这些需求你能不能认作「做完了」?

第四步 · Apply(变成代码)

实施 add-rate-limiting 这个变更。

建议新开一个会话,干净的上下文下实现效果更好。AI 按tasks.md逐条做、逐条勾。中断了就再开一次会话说同一句话,它从第一个未勾选的任务继续。

第五步 · Archive(合并回主规格)

归档 add-rate-limiting 这个变更。

文件夹会整体移到openspec/changes/archive/2026-08-11-add-rate-limiting/(名字前加当天日期),每一条增量合并进对应的主规格。

4.3 什么场景不要用它

  • 一次性脚本 / 丢弃型原型:写规格的时间可能比写脚本还长。
  • 探索型 UI 设计:设计变化速度超过规格能跟上的速度时,规格反而成了负担。
  • 已经被测试和一行 PR 描述覆盖住的小改动:杀鸡不必用牛刀。

一句话判据:如果写规格比干活还费劲,说明这件事的规模还不够格上框架。


5. 与同类项目对比及优劣势

这条路线上真正会被拿来比较的是三个:GitHub Spec Kit、AWS Kiro、OpenSpec(各工具官方文档 + 公开测评综合,2026-10)。

维度OpenSpecGitHub Spec KitAWS Kiro
形态CLI(npm),无自建运行时CLI 工具包(Python)商业 Agentic IDE(基于 Code OSS)
产物模型活规格 + 变更增量(delta)宪法 + 每个特性的 spec/plan/tasks每份规范的 requirements/design/tasks
变更方向从「当前行为」出发做 diff从「要做的特性」出发从「要做的特性」出发
与现有代码专为 brownfield 设计偏新项目(也可--here)支持,但需配置
耦合度低(跑在你现有的 AI 工具里)低(30+ 工具集成)高(必须用它的 IDE)
治理/约束交给你(无明显强制门禁)靠constitution.md+ 提示约定Hooks + Steering,由工具强制
成本/许可免费,MIT免费,MIT商业,信用点计费(有免费档)
锁定风险低(产物是 git 里的 markdown)低中(hooks/steering 只在 Kiro 内生效)

优劣势结论

OpenSpec 相对强的地方:

  • 最轻、最容易贴到存量代码上——初始化到产出只要几分钟,仪式感最低。
  • 增量 + 归档让「主规格」保持活的,这比「生成一份静态规格然后放那」更抗漂移。
  • 产物是纯 markdown、在 git 里,锁定风险低:即便哪天换工具,迁移成本主要是「工作流重新适应」,而不是「数据搬不出来」。

OpenSpec 明显让步的地方(这些也必须讲):

  • 它是三者里最年轻、生态最小的——这意味着遇到问题时,能搜到的现成答案相对少。
  • 它刻意提供更少的护栏:没有 spec-kit 那样的「宪法」硬约束,也没有 Kiro 那种由工具强制的 hooks。团队约定得自己补,否则「规格驱动」会退化成「写了个文档然后照样乱写」。
  • 校验只查结构、不查内容:openspec validate能查出格式问题(比如场景井号数不对),但查不出「这条需求是不是真的对」。它保证不了「对的事」。
  • 公开测评里也提到:它减少漂移,但不能消除漂移——需要人来把住评审这道关。

一句话选型:多工具混用、以存量代码为主 → OpenSpec;新项目、想要最广的智能体兼容 → Spec Kit;深扎 AWS、想要 IDE 内闭环和最强需求严谨度 → Kiro。这不是质量排名,而是适配不同现实。


6. 适用建议与注意事项

6.1 推荐使用

  • 长期演进的存量代码库,需要一份「系统当前行为」的共同事实来源;
  • 多人 / 多 AI 工具混用的团队(同事用 Cursor、你用 Claude Code,但共享同一套规格);
  • 需要留痕的场景:决策要有出处,改动要可追溯(合规、审计友好)。

6.2 不推荐 / 谨慎使用

  • 一次性脚本、丢弃型原型、探索型 UI(见 4.3);
  • 期望「装了就不用管」的团队——它不给强制门禁,你不投入评审纪律,它就只是个 markdown 生成器;
  • 完全无人评审、全自动跑的流水线:它设计的前提是「人在生成代码前把计划改对」。

6.3 注意事项与坑

  • 场景必须正好四个井号(####)。三个井号或写成列表会静默失败,只有validate才会报出来。
  • 任务必须写成- [ ]复选框。整份文件里一个复选框都没有时,list/status会显示「没有工作」,archive也提示不出未完成项。
  • 变更文件夹不能再套一层命名空间。必须是openspec/changes/的直接子目录;changes/mobile/refresh-token/这种要上移并折进名字,改成changes/mobile-refresh-token/。
  • MODIFIED的标题要精确匹配主规格,且要贴完整内容,否则归档时丢细节。
  • 主规格不该动时用--skip-specs(纯重构、工具、文档类变更)。
  • 归档不会自动清理:OpenSpec 没有保留策略,归档目录会一直留着,需要你自己决定留 or 删。

6.4 上手路径

  1. openspec init后重启 IDE,确认斜杠命令出现;没有就跑openspec update。
  2. 从一个真实的小功能开始走一遍五步循环,不要拿玩具例子。
  3. 把团队的硬约定(技术栈、语言、测试框架)写进config.yaml的context。
  4. 把「评审specs/」变成团队例行动作——这是它能不能产生价值的分水岭。

附录 A · 命令行速查

安装与设置

  • openspec init:初始化;--tools claude,cursor指定工具,--tools none只建结构。
  • openspec update:刷新已安装的指令文件(--force强制重写)。
  • openspec config list|get|set|unset|reset|edit|path|profile:查看与修改全局配置。

变更与规格

  • openspec list:列出变更;--specs/--archived/--all/--json。
  • openspec show <名称>:打印某变更的proposal.md或某规格的spec.md;--diff追加需求差异。
  • openspec view:一屏概览,变更按 Draft / Active / Completed 分组。
  • openspec validate <名称>:校验结构;--all、--strict、--json。
  • openspec archive <名称> -y:归档并合并增量;--skip-specs不碰主规格。

工作流与 schema

  • openspec new change <名称>:只建变更目录与元数据。
  • openspec status --change <id>:看产物完成情况,会给出Next:一行指明下一步。
  • openspec instructions <产物|apply|archive> --change <id>:打印该阶段该遵守的指令。
  • openspec schema which|validate|fork|init:查看 / 校验 / 复制改造 / 新建 schema。

斜杠命令:/opsx:explore、/opsx:propose、/opsx:apply、/opsx:verify、/opsx:archive。不支持斜杠命令的工具,用自然语言说「创建 OpenSpec 提案」「实施这个变更」「归档这个变更」即可。

附录 B · 常见问题

  • 斜杠命令不出现:先重启 IDE;再跑openspec update;仍不行则openspec config set delivery both后openspec update。
  • validate报 0 个任务:任务必须写成- [ ] 1.1 描述的复选框。
  • 场景没被识别:检查是否为四个井号####。
  • 变更文件夹嵌套了目录:必须是changes/的直接子目录。
  • MODIFIED匹配不上主规格:标题文本要与主规格完全一致,且贴完整块。
  • 不确定下一步做什么:openspec status --change <名称>会给Next:一行。

参考

  • 官方站点:https://openspec.dev/ (v1.14.2,72.1k stars,MIT;数据取数日 2026-10-16)
  • 快速开始:https://openspec.dev/docs/quickstart
  • CLI 参考:https://openspec.dev/docs/cli
  • 项目配置:https://openspec.dev/docs/project-config
  • 源码仓库:https://github.com/Fission-AI/OpenSpec
  • 同类对比(综合参考,非单一权威):GitHub Spec Kit(https://github.com/github/spec-kit)、AWS Kiro(https://kiro.dev/)
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进