从Vibe Coding到Spec Coding:OpenSpec规范驱动开发指南

0 阅读11分钟

一、Vibe Coding的狂欢与隐忧

2024年,Andrej Karpathy抛出 “Vibe Coding” 一词时,整个开发者社区既兴奋又惶恐。兴奋的是:任何人只要会描述需求,AI就能把可运行的代码“震”出来;惶恐的是:当代码的生产速度超过人类理解速度,软件项目就变成了“黑箱沼泽”

Vibe Coding的核心缺陷不是AI能力不足,而是开发流程仍停留在“人<->模型”的无结构对话。聊天记录不是需求文档,LLM的上下文窗口记不住三天前的决策,代码注释也不会自动同步变更理由。

二、Spec Coding:让AI从“聊出来”到“写出来”

Spec Coding(规范驱动开发) 不是新鲜的理论——它在传统工程中叫“契约优先”或“规范先行”。但OpenSpec让它首次适配AI时代的协作粒度

  1. 人负责定义“要什么”和“为什么”,将隐性知识显性化为规范文档
  2. AI负责实现“怎么做”,并且每一步都与规范文档双向绑定。
  3. 规范文档随代码演进,每次变更都是对规范的增量修正,而非全量重写。

Spec Coding ≠ Waterfall:它不是要求你在写代码前写完数百页规格书,而是将每一次“变更”打包成一个自包含的规范单元,让AI在理解现状的基础上,精确修改指定部分

三、OpenSpec是什么?——为AI时代的迭代而生的“规范操作系统”

OpenSpec是由Fission AI团队发起、开源社区驱动的规范驱动开发工作流框架。2026年1月发布的v1.0.0版本是一次彻底重构,其核心定位是:棕地优先(Brownfield-first)

棕地优先——不假设你从空项目开始,专门解决已有数十万行代码、复杂依赖、历史债务的“真实项目”的规范管理问题。

3.1 不是另一个“文档生成器”

工具定位与AI的关系
Swagger/OpenAPIAPI描述格式被动阅读
Cucumber可执行需求需人工编写Gherkin
OpenSpecAI协作工作流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:ffFast-Forward,按依赖图生成全部产物proposal+specs+design+tasks需求明确,一步到位
/opsx:continue一次生成一个“READY”状态的产物单个产物边想边写,逐步完善
/opsx:apply按tasks.md实施代码变更代码AI写代码的主阶段
/opsx:verify检查代码与specs的一致性验证报告代码审查前自检
/opsx:sync将delta specs合并入主规范主规范更新功能完成,知识沉淀
/opsx:archive归档变更目录移入archive/生命周期结束
/opsx:onboard15分钟交互式教学新成员、新项目初始化

六、原理深潜: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 动态指令组装

三层架构

  1. 上下文层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]
    
  2. 规则层openspec/rules/,产物级别的约束描述(如“specs必须包含验收标准”)。
  3. 模板层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/

新成员加入项目时只需要:

  1. 阅读openspec/specs/task/spec.md,即可了解系统当前确切的数据层设计;
  2. 执行/opsx:onboard,AI会用15分钟带他走完一次完整的规范变更流程(例如“添加任务截止时间字段”)。

这就是从Vibe到Spec的转型——从依赖“人肉记忆”到依赖“代码与规范同源”

八、横向对比:OpenSpec vs 其他规范驱动工具

维度OpenSpec v1.0Spec Kit传统TDD
规范存储Git内openspec/,与代码同源Git内spec/测试用例
变更粒度功能级变更(对应一个change目录)模块级规范方法级
AI适配原生支持(规范注入+产物状态机)需手动配置提示词
棕地支持⭐⭐⭐⭐(自动基线+增量合并)⭐⭐(需手动编写)⭐⭐⭐(重构时可加)
多人协作变更隔离,类似Git分支直接改主规范,易冲突代码冲突
学习曲线15分钟(/opsx:onboard2小时(多阶段)低(但仅限测试)

结论

  • 新项目、架构从0开始:Spec Kit更轻量,快速建立规范骨架。
  • 已有项目、日常迭代、多人团队OpenSpec是务实的选择,它的变更隔离和增量合并机制在真实开发中几乎是刚需。

九、结语:Spec Coding不是回归瀑布,而是驾驭Vibe

2026年的今天,没有任何人怀疑AI生成代码的能力。问题已经变成:我们如何与一个拥有高水平编码能力、但从不主动问“为什么”的同事协作?

OpenSpec给出的答案不是“禁止Vibe Coding”——实际上,/opsx:explore正是为快速原型、技术探索保留的自由地带。它的核心主张是:

让每一次“写代码”都有据可循,让每一次“改需求”都可追溯,让团队的集体智慧沉淀在规范里,而不是聊天记录里。

从Vibe到Spec,不是用文档淹没创造力,而是用轻量的约束换取长期的可维护性

欢迎关注公众号度熊君,一起分享交流。