拆解但不失全貌:如何在 OpenSpec 中管理复杂 Agent 需求的演进
在使用 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 中回答三个问题:
- Context (上下文):我在哪?(例如:我是 ChatBI 聚合查询澄清 Epic 的一部分)。
- Dependencies (依赖关系):
- Depends On: 我依赖谁?(例如:依赖
01-foundation提供的 Payload 结构)。 - Blocks: 谁依赖我?(例如:为后续的
03-full-learning提供前置的兜底路由)。
- Depends On: 我依赖谁?(例如:依赖
- 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 已经足够小,其内部的 designs 和 tasks 只需要最简单的平铺,开发者一眼就能找到今天该干的活。
总结
OpenSpec 不是为了增加文档负担,而是为了把脑海里的隐性上下文变成显性的工程资产。
当你发现一个 Change 变得难以描述、设计文档开始写不下去时,通常意味着它太大了。果断使用顺序前缀将它拆开,用 proposal.md 拴住它们的关联,把最终的拼图放回主线 specs。这就是驾驭复杂 Agent 工作流的不二法门。
更多推荐


所有评论(0)