一、Vibe Coding的狂欢与隐忧
2024年,Andrej Karpathy抛出 “Vibe Coding” 一词时,整个开发者社区既兴奋又惶恐。兴奋的是:任何人只要会描述需求,AI就能把可运行的代码“震”出来;惶恐的是:当代码的生产速度超过人类理解速度,软件项目就变成了“黑箱沼泽”。
Vibe Coding的核心缺陷不是AI能力不足,而是开发流程仍停留在“人<->模型”的无结构对话。聊天记录不是需求文档,LLM的上下文窗口记不住三天前的决策,代码注释也不会自动同步变更理由。
二、Spec Coding:让AI从“聊出来”到“写出来”
Spec Coding(规范驱动开发) 不是新鲜的理论——它在传统工程中叫“契约优先”或“规范先行”。但OpenSpec让它首次适配AI时代的协作粒度:
- 人负责定义“要什么”和“为什么”,将隐性知识显性化为规范文档。
- AI负责实现“怎么做”,并且每一步都与规范文档双向绑定。
- 规范文档随代码演进,每次变更都是对规范的增量修正,而非全量重写。
Spec Coding ≠ Waterfall:它不是要求你在写代码前写完数百页规格书,而是将每一次“变更”打包成一个自包含的规范单元,让AI在理解现状的基础上,精确修改指定部分。
三、OpenSpec是什么?——为AI时代的迭代而生的“规范操作系统”
OpenSpec是由Fission AI团队发起、开源社区驱动的规范驱动开发工作流框架。2026年1月发布的v1.0.0版本是一次彻底重构,其核心定位是:棕地优先(Brownfield-first)。
棕地优先——不假设你从空项目开始,专门解决已有数十万行代码、复杂依赖、历史债务的“真实项目”的规范管理问题。
3.1 不是另一个“文档生成器”
| 工具 | 定位 | 与AI的关系 |
|---|---|---|
| Swagger/OpenAPI | API描述格式 | 被动阅读 |
| Cucumber | 可执行需求 | 需人工编写Gherkin |
| OpenSpec | AI协作工作流 | AI主动遵循,自动维护 |
OpenSpec不生产代码,它生产AI执行代码变更时所必须遵守的“契约”。
四、OpenSpec 1.0 核心设计理念
4.1 规范即源码(Spec as Code)
OpenSpec将所有规范文件纳入Git管理,与代码同源、同版本、同评审。项目根目录下会出现:
openspec/
├── specs/ # 系统当前能力的权威描述(只读)
│ ├── task/ # 任务模块规范
│ ├── settings/ # 设置模块规范
│ └── sync/ # 同步模块规范
└── changes/ # 进行中的变更
├── room-migration/ # 迁移到Room数据库
└── dark-theme/ # 深色主题
4.2 产物依赖图(Artifact Graph),而不是线性流程
v1.0最大的架构革新是用图取代流水线。每个变更(Change)包含四个标准产物,它们之间存在逻辑依赖:
proposal (根) ← 为什么要做?价值、范围、放弃方案
├── specs ← 对specs/的增量修改(用## ADDED标记)
├── design ← 技术选型、接口定义、数据模型
└── tasks ← 实现步骤(依赖specs + design)
AI通过openspec status查询当前产物状态图(BLOCKED / READY / DONE),自动选择下一步可执行的动作。这意味着:
- 开发者可以随时回退到proposal修改需求,依赖它的specs/design会自动变为BLOCKED;
- 开发者可以跳过部分产物(如直接写tasks)但系统会警告缺少依赖。
4.3 增量规范(Delta Spec)
这是OpenSpec解决“规范漂移”的核心设计。变更目录下的specs文件不是全量覆盖,而是用语义标记记录变化,比如下述代码变更记录:
# specs/task/spec.md(在changes/room-migration/目录下)
## 现有能力(来自主规范)
- 使用SharedPreferences存储任务列表
- 支持增删改查,但查询效率低
- 无事务支持
## ADDED 能力
- 使用Room作为本地持久化方案
- 支持异步查询(Flow/协程)
- 定义Task实体、TaskDao、TaskDatabase
## MODIFIED 能力
- 【变更】任务查询方式:从直接读取SP改为Flow流式查询
- 【理由】提升UI响应性,自动数据更新
当变更归档时(/opsx:sync),OpenSpec解析这些标记,精确合并到主规范目录,而不是粗暴覆盖。每一次规范变更都成为可审计的diff。
五、OpenSpec 最新命令体系
| 命令 | 作用 | 对应产物 | 典型场景 |
|---|---|---|---|
/opsx:explore | 零成本预研,不生成任何文件 | 无 | 评估多个技术方案、讨论可行性 |
/opsx:new <name> | 创建变更脚手架 | proposal模板 | 开始一个新功能 |
/opsx:ff | Fast-Forward,按依赖图生成全部产物 | proposal+specs+design+tasks | 需求明确,一步到位 |
/opsx:continue | 一次生成一个“READY”状态的产物 | 单个产物 | 边想边写,逐步完善 |
/opsx:apply | 按tasks.md实施代码变更 | 代码 | AI写代码的主阶段 |
/opsx:verify | 检查代码与specs的一致性 | 验证报告 | 代码审查前自检 |
/opsx:sync | 将delta specs合并入主规范 | 主规范更新 | 功能完成,知识沉淀 |
/opsx:archive | 归档变更目录 | 移入archive/ | 生命周期结束 |
/opsx:onboard | 15分钟交互式教学 | 无 | 新成员、新项目初始化 |
六、原理深潜:OpenSpec如何“驯服”AI?
6.1 规范注入(Spec Injection)
OpenSpec不依赖任何专有API或模型微调,它的“魔法”本质是动态提示词工程。
以Claude Code为例,openspec init会生成:
.claude/
├── commands/
│ └── openspec/
│ ├── apply.md
│ └── ff.md
├── AGENTS.md
└── CLAUDE.md
.claude/AGENTS.md 是核心:
<!-- OPENSPEC:START -->
# OpenSpec 工作规范
当用户请求中包含以下关键词时,你必须首先加载本规范并执行`openspec status`:
- “提案”、“变更”、“规范”、“规划”
- 任何涉及新增功能或修改API的请求
- 需要生成多文件的任务
执行流程:
1. 如果用户提供了变更名称,执行`openspec status <name>`;
2. 根据产物状态图确定下一个可执行的OPSX命令;
3. 严禁绕过OpenSpec直接修改`openspec/specs/`下的文件;
4. 代码生成必须严格参照`changes/<name>/tasks.md`的勾选框。
<!-- OPENSPEC:END -->
Claude Code每次启动都会读取该文件,将OpenSpec规则注入系统提示词。当用户提到“迁移到Room”,AI主动查询当前变更状态,并建议执行/opsx:ff或/opsx:continue。
6.2 动态指令组装
三层架构:
- 上下文层:
openspec/config.yaml,记录项目技术栈、测试框架、代码规范链接等。project: language: kotlin framework: android-jetpack android: min_sdk: 24 target_sdk: 34 compose: true test: junit4 agents: allowed_models: [claude-3.7, gemini-2.0] - 规则层:
openspec/rules/,产物级别的约束描述(如“specs必须包含验收标准”)。 - 模板层:
openspec/templates/,各产物的Markdown结构。
当AI执行/opsx:ff时,CLI实时读取三层配置,动态拼装提示词。这意味着开发者修改config.yaml后,所有后续生成的design.md都会自动适配Android Compose + Room,无需人工同步。
6.3 产物状态机(Artifact State Machine)
这是OpenSpec 1.0能让AI自我驱动的底层机制。
stateDiagram-v2
[*] --> PROPOSAL: /opsx:new
PROPOSAL --> READY: proposal.md写完成
READY --> SPECS_BLOCKED: 依赖proposal
SPECS_BLOCKED --> SPECS_READY: /opsx:continue
SPECS_READY --> DESIGN_BLOCKED: 依赖specs
DESIGN_BLOCKED --> DESIGN_READY: /opsx:continue
DESIGN_READY --> TASKS_BLOCKED: 依赖design
TASKS_BLOCKED --> TASKS_READY: /opsx:continue
TASKS_READY --> IMPLEMENTING: /opsx:apply
IMPLEMENTING --> VERIFYING: /opsx:verify
VERIFYING --> [*]: /opsx:sync & /opsx:archive
AI通过openspec status获取当前状态,用户只需说“继续”,AI会自动选择正确的/opsx:continue路径,依次生成specs→design→tasks。整个过程无需人类记住十几条命令的精确顺序。
七、实战:从Vibe到Spec,一次Android数据层重构的完整转型
7.1 初始状态
TaskViewModel.kt
class TaskViewModel : ViewModel() {
private val prefs = PreferenceManager.getDefaultSharedPreferences(getApplication())
private val _tasks = MutableLiveData<List<String>>()
val tasks: LiveData<List<String>> = _tasks
fun loadTasks() {
val json = prefs.getString("tasks", "[]")
val type = object : TypeToken<List<String>>() {}.type
val list: List<String> = Gson().fromJson(json, type) ?: emptyList()
_tasks.value = list
}
fun addTask(title: String) {
val current = _tasks.value?.toMutableList() ?: mutableListOf()
current.add(title)
saveTasks(current)
}
private fun saveTasks(tasks: List<String>) {
val json = Gson().toJson(tasks)
prefs.edit().putString("tasks", json).apply()
_tasks.value = tasks
}
}
痛点:
- 数据逻辑与ViewModel高度耦合;
- 无Repository模式,难以测试;
- 存储使用SharedPreferences,不适合复杂数据;
- 无异步支持,可能阻塞主线程;
- 无任何文档,新成员只能读代码猜意图。
7.2 引入OpenSpec,建立规范基线
# 1. 安装最新版OpenSpec
npm install -g @fission-ai/openspec@latest
# 2. 进入Android项目根目录
cd App
openspec init --tools claude
# 3. 创建规范基线(挖掘现有代码意图)
openspec baseline --auto
openspec baseline是逆向工程命令。它会扫描代码库,生成一份初始的specs目录,描述“当前系统已实现的能力”。
openspec/specs/task/spec.md
├── 数据存储:SharedPreferences + JSON序列化
├── 数据查询:同步阻塞方式,通过LiveData发布
├── 数据操作:增、删、改、查
└── 缺陷:无事务支持,查询效率低,无法响应式更新
此刻,项目的“原理过程”从散落的代码,集中到了specs/。
7.3 发起变更:重构数据层为Room
/opsx:new room-migration
AI自动生成changes/room-migration/proposal.md,我们只需补充“为什么要重构”:
## 问题陈述
当前数据存储存在以下问题:
1. 数据与UI逻辑耦合在ViewModel,违背单一职责;
2. SharedPreferences不适合结构化数据,且查询全量反序列化效率低;
3. 无法实现数据变化自动推送至UI;
4. 无法进行单元测试。
## 目标架构
采用Android官方推荐的架构分层:
- **数据层**:Room Entity + Dao + Database
- **仓库层**:TaskRepository(屏蔽数据源细节)
- **ViewModel**:依赖仓库,通过Flow接收数据
## 放弃方案
- 使用SQLiteOpenHelper + ContentProvider:模板代码过多,维护成本高
- 使用Realm:社区活跃度下降,Kotlin支持较弱
7.4 Fast-Forward生成完整规划
/opsx:ff
AI读取proposal、读取现有代码、参考config.yaml(Kotlin + Compose + Room),自动生成:
design.md(节选)
// 实体定义
@Entity(tableName = "tasks")
data class TaskEntity(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val title: String,
val isCompleted: Boolean = false,
val createdAt: Long = System.currentTimeMillis()
)
// 数据访问对象
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks ORDER BY createdAt DESC")
fun getAllTasks(): Flow<List<TaskEntity>>
@Insert
suspend fun insert(task: TaskEntity)
@Update
suspend fun update(task: TaskEntity)
@Delete
suspend fun delete(task: TaskEntity)
}
// 数据库
@Database(entities = [TaskEntity::class], version = 1)
abstract class TaskDatabase : RoomDatabase() {
abstract fun taskDao(): TaskDao
}
// 仓库接口与实现
interface TaskRepository {
fun observeTasks(): Flow<List<Task>>
suspend fun addTask(title: String)
suspend fun toggleTask(id: Int)
}
class TaskRepositoryImpl(
private val taskDao: TaskDao,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : TaskRepository {
override fun observeTasks(): Flow<List<Task>> =
taskDao.getAllTasks().flowOn(ioDispatcher).map { entities ->
entities.map { it.toDomain() }
}
override suspend fun addTask(title: String) {
withContext(ioDispatcher) {
taskDao.insert(TaskEntity(title = title))
}
}
// ...
}
tasks.md(带依赖关系)
- T1: 添加Room依赖(build.gradle.kts) ⚠️ 依赖:无
- T2: 创建TaskEntity、TaskDao、TaskDatabase ⚠️ 依赖:T1
- T3: 实现TaskRepository接口及Room实现 ⚠️ 依赖:T2
- T4: 重构TaskViewModel,注入TaskRepository ⚠️ 依赖:T3
- T5: 更新Compose UI以适配Flow ⚠️ 依赖:T4
- T6: 编写单元测试(使用TestDispatcher) ⚠️ 依赖:T3
7.5 实施变更与增量规范
/opsx:apply
AI按tasks.md顺序生成代码。关键差异:AI不会直接修改openspec/specs/,而是在changes/room-migration/specs/下生成增量规范文件。
changes/room-migration/specs/task/spec.md:
## MODIFIED 架构描述
- 旧:ViewModel直接操作SharedPreferences
- 新:引入数据层(Room)+ 仓库层(TaskRepository)
## ADDED 组件
- TaskEntity: 数据库实体
- TaskDao: 数据访问接口
- TaskDatabase: Room数据库实例
- TaskRepository: 定义任务操作契约
- TaskRepositoryImpl: 基于Room的实现
## ADDED 能力
- 异步任务存储(协程+Flow)
- 响应式UI更新(collectAsState)
- 单元测试支持(使用Room内存数据库)
7.6 验证、同步、归档
/opsx:verify # AI检查代码是否实现了上述增量规范
/opsx:sync # 将delta规范合并至主规范目录
/opsx:archive # 变更移入archive/
新成员加入项目时只需要:
- 阅读
openspec/specs/task/spec.md,即可了解系统当前确切的数据层设计; - 执行
/opsx:onboard,AI会用15分钟带他走完一次完整的规范变更流程(例如“添加任务截止时间字段”)。
这就是从Vibe到Spec的转型——从依赖“人肉记忆”到依赖“代码与规范同源”。
八、横向对比:OpenSpec vs 其他规范驱动工具
| 维度 | OpenSpec v1.0 | Spec Kit | 传统TDD |
|---|---|---|---|
| 规范存储 | Git内openspec/,与代码同源 | Git内spec/ | 测试用例 |
| 变更粒度 | 功能级变更(对应一个change目录) | 模块级规范 | 方法级 |
| AI适配 | 原生支持(规范注入+产物状态机) | 需手动配置提示词 | 无 |
| 棕地支持 | ⭐⭐⭐⭐(自动基线+增量合并) | ⭐⭐(需手动编写) | ⭐⭐⭐(重构时可加) |
| 多人协作 | 变更隔离,类似Git分支 | 直接改主规范,易冲突 | 代码冲突 |
| 学习曲线 | 15分钟(/opsx:onboard) | 2小时(多阶段) | 低(但仅限测试) |
结论:
- 新项目、架构从0开始:Spec Kit更轻量,快速建立规范骨架。
- 已有项目、日常迭代、多人团队:OpenSpec是务实的选择,它的变更隔离和增量合并机制在真实开发中几乎是刚需。
九、结语:Spec Coding不是回归瀑布,而是驾驭Vibe
2026年的今天,没有任何人怀疑AI生成代码的能力。问题已经变成:我们如何与一个拥有高水平编码能力、但从不主动问“为什么”的同事协作?
OpenSpec给出的答案不是“禁止Vibe Coding”——实际上,/opsx:explore正是为快速原型、技术探索保留的自由地带。它的核心主张是:
让每一次“写代码”都有据可循,让每一次“改需求”都可追溯,让团队的集体智慧沉淀在规范里,而不是聊天记录里。
从Vibe到Spec,不是用文档淹没创造力,而是用轻量的约束换取长期的可维护性。
欢迎关注公众号度熊君,一起分享交流。