OpenSpec实战
你有没有遇到过这样的场景:给 AI 写了一段很长的 prompt,结果生成的代码和想象中差了十万八千里?或者每次开新会话,都要重新跟 AI 解释一遍项目背景和约定?
OpenSpec 就是为解决这个问题而生的。
什么是 OpenSpec?
OpenSpec是一个规范驱动开发工具,让你和 AI 编程助手在动手写代码之前,先把需求说清楚。
听起来像是"先写文档"的老套路?不是的。OpenSpec 的核心理念是迭代式而非瀑布式:
- 生成的文档不是一次性定稿,可以随时修改
- 需求变化时,用增量规范(Delta Specs)记录变更,而不是重写整套文档
- 每次变更归档后,AI 下次会话直接读取,不用再重复交代背景
用一句话概括:OpenSpec 把你脑子里的需求,变成 AI 能理解和执行的结构化文档。
三步跑通核心工作流
Step 0:安装
npminstall-g@fission-ai/openspec@latest# 验证安装openspec--version# 输出类似 1.3.1也支持 pnpm、yarn、bun 安装,选你顺手的就行。
Step 1:初始化项目
mkdirmy-project&&cdmy-project# 指定 AI 工具,非交互式初始化openspec init--toolsclaude# 或者支持所有工具openspec init--toolsall初始化完成后,项目里会生成两个关键目录:
openspec/ ├── specs/ # 主规范库(项目的行为事实来源) └── changes/ # 变更管理目录 └── archive/如果你用的是 Claude Code,还会生成.claude/commands/opsx/下的四个斜杠命令文件。
Step 2:创建变更提案
打开 AI 编程助手,输入:
/opsx:propose 给 Todo API 添加完整的 CRUD 接口: - GET /todos - POST /todos - PUT /todos/:id - DELETE /todos/:idAI 会生成4 个制品:
| 制品 | 内容 |
|---|---|
proposal.md | 变更的背景和范围(Why & What) |
design.md | 技术方案和架构决策 |
specs/ | Delta Specs,用 ADDED/MODIFIED/REMOVED 描述需求变化 |
tasks.md | 具体的实现任务清单 |
这 4 个文件都可以手动编辑。觉得 AI 写的方案有问题?直接改design.md。需求描述不够精确?改specs/下的文件。改完再 apply,不用重新 propose。
Step 3:执行实现
/opsx:applyAI 会按照tasks.md的顺序逐条执行,完成后输出汇总报告。
Step 4:归档变更
/opsx:archive归档做两件事:
- 把变更目录移到
openspec/changes/archive/YYYY-MM-DD-<change-name>/ - 把 Delta Specs 合并回
openspec/specs/(主规范库)
为什么归档很重要?随着项目迭代,openspec/specs/会越来越完整。AI 下次读到这份规范,就知道项目现在有哪些 API、用的什么架构、遵循什么约定——不需要你重复交代。
核心工作流总结
openspec init │ ▼ /opsx:explore ← 可选:先理清思路,纯思考,不写代码 │ ▼ /opsx:propose ← 生成 4 个制品(可编辑) │ ▼ /opsx:apply ← 按 tasks.md 逐条实现 │ ▼ /opsx:archive ← 归档,Delta Specs 合并回主规范三条核心命令:propose → apply → archive。
实战案例:Expedia Detail Handler 性能优化
以下是一个真实项目中使用 OpenSpec 完成性能优化重构的完整案例,展示 4 个制品在实际工程中的样子。
背景
ExpediaDetailHandler处理 Expedia 酒店详情数据时极慢:50 个并发 Task,每个 Task 内部串行处理 500 家酒店,每家酒店 10-15 次独立 DB 查询。
proposal.md — 说清楚 Why & What
## 根因分析 - P0:Task 内串行处理(500 家 × 40ms = 20s/task) - P0:每家酒店 10-15 次独立 DB 往返 - P1:Mapping 查询无缓存(每家各打一次 DB) - P1:dbDetail 重复查询(同一对象查 5-6 次) ## 做什么 1. 批量预取 Mapping(N 次 → 1 次批查询) 2. Task 内部改用虚拟线程并发 3. 消除 dbDetail 重复查询 4. 修正 readHotelFile 误导性注释 ## 不做什么 不改事务边界、不引入批量 DB update、不加 Redis 缓存、不引入 Disruptor关键点:proposal 里明确写"不做什么",防止 AI 过度实现。这是 OpenSpec 最容易被忽视的一栏。
design.md — 记录技术决策和理由
## 决策 1:批量预取 Mapping 在 for 循环前调用 batchSelectMapping() 一次性获取所有 mapping 存入 HashMap。 不用 Redis,per-batch 生命周期 HashMap 足够。 ## 决策 2:虚拟线程并发 for 循环改为 Executors.newVirtualThreadPerTaskExecutor()(try-with-resources)。 不用 epsDetailExecutor:该线程池已被 50 个 Task 占满,内部再提交会死锁。 ## 决策 3:消除 dbDetail 重复查询 saveOrUpdateCombine() L265 已查一次 dbDetail,各子方法不应再各自 findByHotelId()。关键点:design.md 不只写"做什么",更要写"为什么不用另一种方案"。这里记录了"不用 epsDetailExecutor 是因为会死锁"——这种隐性约束如果不写下来,下次 AI 很可能重蹈覆辙。
specs/ — 用 GIVEN/WHEN/THEN 描述行为
## Spec 1:批量预取 Mapping GIVEN 一个包含 N 家酒店的 batch WHEN 进入 for 循环前 THEN 调用 batchSelectMapping() 一次性批查,异常时降级为空 map 兜底单条查询 ## Spec 2:虚拟线程并发 GIVEN Task 内部处理 500 家酒店 WHEN 使用 newVirtualThreadPerTaskExecutor() THEN 每家酒店独立 Callable,异常单独捕获不影响其他,completedIds 用线程安全集合 ## 非功能性规格 - 500 家酒店 batch 内 detail_mapping 查询从 ≥500 次降到 1 次 - 不产生新 DB 死锁 - completedIds 使用线程安全结构关键点:specs 里的非功能性规格(查询次数、线程安全)是验收标准,apply 完成后可以用/opsx:verify逐条核对。
tasks.md — 可执行的任务清单
- [x] 1. 新增批量 Mapping 查询接口(batchSelectMapping,复用已有 findByPlatformAndHotelPltIds) - [x] 2. 重构 ExpediaReadTask(虚拟线程 + mappingCache + processSingleHotel 私有方法) - [x] 3. 消除 dbDetail 重复查询(审查结论:无重复,无需修改) - [x] 4. 注释修正 - [ ] 5. 单元测试(batchSelectMapping 测试 + ExpediaDetailHandlerTest) - [ ] 6. 集成验证(本地触发 handler,确认批查次数为 1,全量编译通过)关键点:tasks.md 是进度看板,也是 AI 的执行脚本。任务 3 的审查结论直接写在 checkbox 里——“无重复,无需修改”——这样下次会话 AI 不会重复做这个检查。
实战收益
| 优化项 | 优化前 | 优化后 |
|---|---|---|
| Mapping 查询次数/batch | 500 次 | 1 次 |
| batch 内并发度 | 1(串行) | ~500(虚拟线程) |
| dbDetail 查询次数/酒店 | 5-6 次 | 1 次 |
| 整体吞吐(估算) | 1× | 3-5× |
从这个案例学到什么
- proposal 的"不做什么"和根因分析同等重要:明确边界防止 AI 过度实现
- design 要记录"为什么不用另一种方案":隐性约束(如死锁风险)不写下来就会丢失
- tasks 的审查结论要写进 checkbox:避免下次会话重复调查
- specs 的非功能性规格是验收标准:查询次数、线程安全这类约束要量化
⚡ 重点:用openspec config profile解锁更多命令
默认安装后,你只有 4 个斜杠命令:
/opsx:explore /opsx:propose /opsx:apply /opsx:archive对于入门使用已经够了。但如果你想要更精细的控制,需要主动切换到扩展模式:
openspec config profile# 在交互式菜单中选择 expandedopenspec update# 更新斜杠命令文件(这一步不能少!)切换后,你将获得额外的 6 个命令:
| 命令 | 用途 |
|---|---|
/opsx:new | 创建变更脚手架,不自动生成文档(适合手动精调) |
/opsx:continue | 继续未完成的变更,根据依赖关系创建下一个制品 |
/opsx:ff | Fast-forward,一键生成所有规划文档 |
/opsx:verify | 验证实现是否符合 specs 中的规范 |
/opsx:bulk-archive | 批量归档多个变更 |
/opsx:onboard | 引导式教程,带你走完整个工作流 |
什么时候需要扩展模式?
Core 模式适合:
- 个人项目、小团队快速迭代
- 单次功能开发,需求相对清晰
- 刚开始用 OpenSpec,先跑通核心流程
Expanded 模式适合:
- 复杂功能,需要分阶段细控(用
/opsx:new+/opsx:continue) - 想验证 AI 实现是否真的符合规范(用
/opsx:verify) - 多个并行变更,需要批量处理(用
/opsx:bulk-archive) - 希望有人带着走一遍,彻底搞懂流程(用
/opsx:onboard)
一句话:Core 模式是默认档,Expanded 模式是进阶档。
openspec config profile是解锁进阶档的开关,不运行这条命令,这些命令根本不会出现在你的 AI 工具里。
进阶技巧:用config.yaml固化项目约定
交互式初始化会自动生成openspec/config.yaml。如果你用的是--tools参数非交互式初始化,可以手动创建:
# openspec/config.yamlschema:spec-drivencontext:|Tech stack: TypeScript, Express, PostgreSQL API conventions: RESTful, JSON responses Error format: { code, message, details }rules:proposal:-Include rollback plan for database changesspecs:-Use Given/When/Then format for scenarios配置之后,每次 propose 时 AI 会自动遵循这些约定——不用在 prompt 里重复声明技术栈和规范。
完整 CLI 命令速查
openspec init# 初始化项目openspec init--toolsclaude# 非交互式,指定工具openspec config profile# 切换工作流模式(core / expanded)openspec update# 更新斜杠命令文件openspec list# 列出活跃变更openspec list--specs# 列出所有规范openspec show<name># 查看变更详情openspec status--change<name># 查看制品完成进度openspec validate# 验证格式openspec view# 交互式仪表盘常见问题
Q:每次 propose 生成的文档不满意,能改吗?
可以,直接编辑文件。OpenSpec 的核心理念是iterative not waterfall,生成的文档是活文档,随时可改,改完再 apply。
Q:归档后发现需求写错了,能撤销吗?
不需要撤销。重新/opsx:propose一个新变更就行,Delta Specs 天然支持增量修改——新变更里用 MODIFIED 描述对旧需求的调整。
Q:支持哪些 AI 工具?
Claude Code、Cursor、Windsurf、GitHub Copilot、Cline、RooCode、Amazon Q 等 20+ 工具,openspec init --tools all可以一次配置全部。
Q:tasks.md 里的审查结论要怎么记录?
直接写在 checkbox 后面。比如"审查结论:无重复,无需修改"——这样下次会话 AI 不会重复做同样的调查,也不会误以为这个任务被跳过了。
总结
OpenSpec 解决的核心问题是:让 AI 编程从「模糊 prompt → 不确定输出」变成「明确规范 → 可预期实现」。
上手路径很简单:
npm install -g @fission-ai/openspec@latestopenspec init --tools claude/opsx:propose→/opsx:apply→/opsx:archive
如果 Core 模式的 4 个命令不够用,记住这一条:
openspec config profile# 解锁扩展模式的 6 个额外命令openspec update# 刷新命令文件这是很多人初次使用 OpenSpec 时容易忽略的一步,但它决定了你能用到多少工具。
*官方文档:https://openspec.pro *
*GitHub:Fission-AI/OpenSpec *
