在使用 OpenSpec 驱动复杂 AI Agent(如 ChatBI 的多轮澄清、错误修复机制)的开发时,团队常常会陷入一种进退两难的工程困境:

  • 大泥球陷阱:把整个业务(比如整个“WHERE 澄清”)的所有分支、重试保护、LLM Prompt 设计全塞进一个 Change(变更)里。结果导致设计文档长达千行,开发周期无限拉长,Code Review 根本无从下手,代码冲突不断。
  • 碎片化陷阱:吸取了教训开始拆分,把大需求拆成了十几个细小的子模块。但由于拆得太细,目录嵌套极深,开发者在写代码时“见树不见林”,完全不知道当前这个小模块(比如 34000 维度消歧)的前置依赖是什么,以及它为后续哪个功能(比如 34100 全量学习)做铺垫。

如何做到“拆解需求”的同时“不失全貌”? 核心解法在于:用主线 Spec 维护全景图,用带前缀的扁平 Change 推进增量,用 Proposal 串联故事线。


最佳实践 1:主干与分支分离 (The Source of Truth)

OpenSpec 最重要的一条原则是分离“当前是什么样”与“这次要改成什么样”。

  • 主线目录 (openspec/specs/):这是系统的“全景地图”。无论底下拆了多少个 Change,当一个变更开发、测试通过并发布后,它的契约增量必须合并到这里。新人看这个目录,就能了解系统现在的完整能力。
  • 变更目录 (openspec/changes/):这是“施工现场”。每一个目录代表一次原子的、可独立验证的交付(通常对应一个 PR)。

切记:永远不要在 changes/ 里的某个变更下存放系统的全量规范。变更目录里只存放Delta(增量)

最佳实践 2:使用顺序前缀管理演进 (Sequential Prefixing)

当一个大 Epic(如 ChatBI 澄清重构)被拆散后,如果在文件系统中它们只是一堆无序的文件夹,逻辑链条就断了。

解法:为 Change 目录增加两位数的顺序前缀。

.agentic/openspec/changes/
├── 01-foundation-chatbi-clarification/      <-- 基础骨架与接口契约
├── 02-where-clarify-34000-dim-name/         <-- 依赖 01:处理 34000 分支
├── 03-where-clarify-34100-full-learning/    <-- 依赖 02:处理 34100 全量学习
└── 04-where-clarify-retry-guard/            <-- 依赖 03:增加全局重试保护

通过这种方式,IDE 的目录树直接变成了一本“目录手册”。谁先谁后、谁是基础谁是进阶,一目了然。

最佳实践 3:让 Proposal 成为故事的串联者

在传统开发中,需求的依赖关系往往存在于 Jira 或 Jira Ticket 的 Links 里,随着代码库的流转,这些上下文很容易丢失。

在 OpenSpec 中,proposal.md 不是一个走过场的空文件,它的核心职责是声明依赖与边界。每个拆分后的微小 Change,都必须在 proposal.md 中回答三个问题:

  1. Context (上下文):我在哪?(例如:我是 ChatBI 聚合查询澄清 Epic 的一部分)。
  2. Dependencies (依赖关系)
    • Depends On: 我依赖谁?(例如:依赖 01-foundation 提供的 Payload 结构)。
    • Blocks: 谁依赖我?(例如:为后续的 03-full-learning 提供前置的兜底路由)。
  3. Scope (边界):我这次坚决不做啥?(防范围蔓延的最强武器)。

最佳实践 4:保持变更目录的扁平化

一旦把大需求按逻辑拆成了小的 Change,就不需要在 Change 内部再维持复杂的模块嵌套了。

错误示范(过度嵌套):

changes/
└── 02-where-clarify-34000-dim-name/
    └── designs/
        └── chatbi-clarification/
            └── where-clarification/
                └── 01-design.md

正确示范(扁平化):

changes/
└── 02-where-clarify-34000-dim-name/
    ├── proposal.md
    ├── designs/
    │   └── 01-dimension-name-ambiguity-34000.md
    └── tasks/
        └── 01-dimension-name-ambiguity-34000.md

因为 Change 本身的 Scope 已经足够小,其内部的 designstasks 只需要最简单的平铺,开发者一眼就能找到今天该干的活。


总结

OpenSpec 不是为了增加文档负担,而是为了把脑海里的隐性上下文变成显性的工程资产。
当你发现一个 Change 变得难以描述、设计文档开始写不下去时,通常意味着它太大了。果断使用顺序前缀将它拆开,用 proposal.md 拴住它们的关联,把最终的拼图放回主线 specs。这就是驾驭复杂 Agent 工作流的不二法门。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐