11 - 从需求拆解到 OpenSpec:为什么不要直接敲 /opsx:explore

从需求拆解到 OpenSpec:为什么不要直接敲 /opsx:explore

一句话:OpenSpec 不是需求分析的起点,而是需求设计的终点。接到需求先自己做一遍「设计拆解」,再进 explore,才能少返工、少幻觉。


一、引子:两种开工方式

假设你接到一个需求:"做一个任务看板,展示团队的任务列表,能创建、能分配、能修改状态、能标记完成。"

方式 A:直接 explore

你打开 Claude Code,敲下:

text 复制代码
/opsx:explore 我想做一个任务看板

AI 很热情,开始问你:

  • "任务状态有几种?"
  • "列表是看板还是表格?"
  • "分配人是单选还是多选?"
  • "已完成任务能不能删除?"

你一边聊一边发现,自己也没想清楚。于是每轮都冒出新的问题:

  • "等等,'进行中'和'待评审'是不是同一个状态?"
  • "任务优先级是 P0-P3 还是高中低?"
  • "这个枚举值为什么没有任何列用到?"

聊了 20 轮,AI 终于给你画了一张看起来还不错的页面结构图。你很满意,觉得需求"聊清楚了"。

然后 /opsx:propose,生成四件套,进入 /opsx:apply。做到一半你发现:

  • 顶部统计数字的聚合口径和后端字段对不上
  • 分配任务接口原来需要 assigneeId,但 spec 里漏了
  • 状态流转没定义(能不能从"已完成"回到"进行中"?)
  • 已完成任务的"归档"和"删除"按钮,需求文档里根本没写清楚

你开始改 spec、改 design、改 tasks,甚至回到 explore 重新问。原本想省的时间,全花在返工上。

方式 B:先设计,再 explore

你打开 xmind,先画了一张图:

text 复制代码
任务看板
├── 任务状态:PENDING / IN_PROGRESS / IN_REVIEW / DONE / ARCHIVED
├── 状态流转:PENDING → IN_PROGRESS → IN_REVIEW → DONE(单向)
├── 接口契约:GET /tasks / GET /tasks/stats / PATCH /tasks/:id/status
├── 页面结构:Header + 统计 + 筛选 + 列表 + 分页
└── 关键规则:已完成 30 天归档、仅创建者/管理员可删除

然后带着这张图进 explore,只问三句话:

  • "我定的状态机有没有漏业务场景?"
  • "IN_REVIEW 算进行中还是独立统计?"
  • "成员被删除后,历史任务的负责人怎么展示?"

explore 一轮就补完了细节。propose 生成四件套后,你对着主体模板核对一遍 spec,直接 apply。

两种方式,同样的工具,完全不同的效率。


二、为什么要先设计,再进入 OpenSpec?

2.1 直接 explore 的问题

OpenSpec 的 explore 是个极好的工具。当你对业务已有判断时,它是澄清工具:帮你把"已经有的想法"里的缝补上。当你完全没思路时,它也可以帮你从零做初步梳理。

但这篇文章讨论的是有业务判断时的最佳实践:先自己做设计,再让 explore 补细节。因为如果一开始就把设计权交给 AI,问题域会变成无限的:

text 复制代码
没有主体的 explore:                    有主体的 explore:
"你到底要什么?"                        "状态机单向还是允许回退?"
"这个状态怎么处理?"                     "IN_REVIEW 算进行中吗?"
"这里要不要轮询?"                       "成员删除后历史负责人怎么展示?"
     ↓                                    ↓
问题域无限                               问题域收窄成"细节清单"
每轮都产新问题 → 次数多                   一轮问完基本就清 → 次数少

AI 不会主动拒绝回答无限问题,它会一直陪你聊。但你聊得越多,越容易被它的"合理化"带偏------它会把你的模糊需求补成一套逻辑自洽、但未必符合业务的方案。

更危险的是,explore 产出的是对话上下文 ,不是可执行的契约。等你进 propose 时,AI 要凭记忆把 20 轮对话转成 proposal/spec/design/tasks,漏掉或曲解一两个关键决策是常态。

2.2 先设计的收益

先设计,本质上是在做一件事:把问题域收窄

你先把"AI 猜不对、拍错了代价大"的决策钉死,explore 面对的不再是"你要什么",而是"这几个决策对不对"。

维度 直接 explore 先设计再 explore
问题域 无限,每轮冒新问题 有限,只补细节
AI 角色 设计师 + 澄清者 澄清者 + 挑刺者
产出 对话上下文 结构化设计 + 契约
返工概率
适用场景 你完全没思路时 你有业务判断时

关键洞察:explore 适合"想不清",不适合"懒得想"。 如果你自己对业务有判断,先把判断写下来,再让 AI 帮你检查。

2.3 设计的形式不重要,结构化才重要

先设计不等于必须用 xmind。你可以用:

  • xmind:适合发散和树形拆解
  • Confluence / Notion:适合协作和留痕
  • Word / Markdown:适合写文档和 checklist
  • 草稿纸:一个人快速拍板时完全够用

工具只是载体,目的是一致的:在进 explore 之前,把"AI 猜不对、拍错了代价大"的决策结构化地钉死。

所以不用纠结"我是不是应该用 xmind"。只要能回答清楚这四个问题,什么工具都可以:

  1. 接口契约是什么?
  2. 状态/枚举怎么映射?
  3. 页面/系统结构长什么样?
  4. 关键业务规则有哪些?

2.4 正确顺序

text 复制代码
接到需求
  ↓
人做分析设计(xmind / Confluence / Word / Notion / Markdown / 草稿纸)
  ↓
带着主体进 explore 补细节
  ↓
OpenSpec propose 生成四件套
  ↓
apply 照单施工

最难的需求→设计,你自己做;最碎的细节补缺,交给 explore;最终的权威,落在 OpenSpec。


三、需求设计:五步拆解法

复杂项目用 AI,必须分三层:

层级 谁负责 回答什么问题
领域拆分 大需求切成哪几个有界模块?
宏观编排 模块之间谁先谁后?何时能合?
微观执行 AI + 人 Review 每个模块内部怎么实现?

落到执行上,就是五步拆解:

  1. 顶层业务域解耦:按业务闭环切成独立模块
  2. 三大前置锚定:锁死硬约束、影响面、边界规则
  3. 模块内线性流程:接口契约 → 领域模型/数据层 → 业务逻辑 → 接入层/视图层 → 验收
  4. 原子任务颗粒度:每个任务单目标 + 明确输入 + 可验收
  5. 测试验证闭环:做完即验,不等最后

如果 CLAUDE.md / .claude/rules/ 或 OpenSpec config.yaml 已经配置了全局技术规范,三大锚定里不必重复约定技术硬约束,只关注业务硬约束和系统级规则。


四、进 explore 前:先写"主体模板"

不要带着一张 xmind 或一段话进 explore。先把设计写成固定格式的四块:

4.1 接口契约

契约 内容
任务列表 GET /tasks?status=&priority=&page=
任务统计 GET /tasks/stats
分配任务 PATCH /tasks/:id/assign
更新状态 PATCH /tasks/:id/status

4.2 状态映射

text 复制代码
枚举:PENDING / IN_PROGRESS / IN_REVIEW / DONE / ARCHIVED

Tab 映射:
  待处理 = PENDING
  进行中 = IN_PROGRESS + IN_REVIEW
  已完成 = DONE

状态流转:PENDING → IN_PROGRESS → IN_REVIEW → DONE(单向)

4.3 页面结构

text 复制代码
TaskList
├── Header(标题 + 新建按钮)
├── 统计区块
├── 筛选栏
├── 任务列表 / 看板
└── 分页器

4.4 关键规则

  • 聚合算法:待处理 = PENDING;进行中 = IN_PROGRESS + IN_REVIEW;已完成 = DONE
  • 已完成任务 30 天后自动归档
  • 仅创建者 / 管理员可删除任务

这四块就是"AI 猜不对、拍错了代价大"的决策。你自己先拍板,explore 只负责补缝。


五、explore 只补二件事

带着主体模板进 explore,目标明确:

5.1 验收标准

把每个功能翻译成 GIVEN/WHEN/THEN:

  • 顶部统计:GIVEN 用户打开页面 → THEN 展示待处理/进行中/已完成数字 → AND 按聚合算法计算
  • 状态流转:GIVEN 任务已完成 → WHEN 用户尝试回退 → THEN 接口返回 400

5.2 边界异常

  • 列表为空 → 空态展示什么
  • 接口失败 → 是否重试
  • 成员被删除后,历史任务负责人如何展示

主体定了,explore 从"探索"变成"对清单",往返自然少。


六、进 OpenSpec 前先拆 change

6.1 一个 change 装一个模块

一个 change 是"一次变更",不是"一个项目"。

如果你在领域拆分阶段切出了 5 个独立模块,就应该建 5 个 change,而不是把 5 个模块的 spec 和 tasks 塞进同一个 change。

text 复制代码
领域拆分结果                  change 拆分结果
├─ 任务列表页        ───▶    task-list/
├─ 任务详情页        ───▶    task-detail/
├─ 创建任务页        ───▶    task-create/
├─ 成员选择组件      ───▶    member-select/
└─ 共享 service/枚举  ───▶    task-base/      # 底座 change

6.2 为什么要一个模块一个 change?

核心原因:控制上下文规模

一个 change 越大,单次执行需要加载的 spec + design + tasks 就越长。一旦超过上下文窗口,越靠后的步骤越容易丢失前置信息,AI 开始出现:

  • 凭空臆造字段
  • 遗忘既有约束
  • 改错无关模块
  • 前面定的规则后面推翻

拆成多个 change 后,每个 change 只加载自己有限的 spec 和 tasks,上下文可控,逻辑稳定(具体篇幅阈值因项目和模型而异,建议以"一次能完整复核"为准)。

6.3 什么时候必须拆?

满足以下任一条件,就应该拆:

  • 需求涉及 3 个以上独立模块
  • 一个模块的 spec 长到一次读不完、核不动
  • 多个模块会修改共享文件(service / enum / route)
  • 团队多人并行开发
  • 执行到后面开始"失忆"或前后矛盾

6.4 拆分原则

原则 1:页面/模块目录各自独享

每个 change 只负责一个独立模块的代码,互不覆盖:

text 复制代码
openspec/changes/
├── task-list/          # 只改 src/pages/task-list/
├── task-detail/        # 只改 src/pages/task-detail/
└── task-create/        # 只改 src/pages/task-create/

原则 2:共享文件归底座 change

被多个模块引用的共享文件,只归一个底座 change 负责:

text 复制代码
openspec/changes/
├── task-base/          # 负责 src/services/taskService.ts、taskEnum.ts
├── task-list/          # 引用 taskService,但不修改它
├── task-detail/        # 引用 taskService,但不修改它
└── task-create/        # 引用 taskService,但不修改它

原则 3:命名保持业务线聚合感

用统一前缀让多个 change 看起来还是同一个业务:

text 复制代码
task-list / task-detail / task-create / task-base

6.5 不拆会怎样?

问题 表现
上下文膨胀 apply 到后面忘记前面的需求
合并冲突 多个模块同时改共享 service
节奏混乱 一个模块卡住了,整个 change 都动不了
追溯困难 一个 change 里混了太多事,归档后看不懂

6.6 实战中的拆分步骤

拿到需求后,按这个顺序拆:

  1. 领域拆分:先画出有哪些独立模块
  2. 标出共享文件:哪些 service / enum / route 会被多个模块用
  3. 建底座 change :共享文件归到一个 xxx-base change
  4. 建业务 change :每个模块一个 xxx-模块名 change
  5. 声明依赖:业务 change 里写明"依赖 task-base 的接口契约"

这样每个 change 都小而清晰,可以独立 propose、apply、sync、archive。


七、OpenSpec:把设计翻译成契约

explore 结束后,你手里有:

  • 主体模板(接口 / 状态 / 结构 / 规则)
  • 细节答案(验收标准 / 疑点结论 / 边界场景)
  • 拆分方案(哪些模块进哪个 change)

这时再 /opsx:propose,把已确定的决策机械翻译成四件套:

工件 回答的问题 内容来源
proposal.md 为什么做 需求背景 + 模块 Scope
specs/<能力>/spec.md 做什么 主体模板 + 验收标准
design.md 怎么做 页面结构 + 关键规则
tasks.md 怎么执行 线性流程 + 原子任务

xmind 是草稿,OpenSpec 是合同。合同定了,草稿可以丢。

propose 生成后,必须人肉把关 spec:对照主体模板逐条核查接口、状态、规则是否都进了 spec。

7.1 OpenSpec 是 SSOT(唯一真源)

从 propose 完成的那一刻起,OpenSpec 里的 spec.mddesign.mdtasks.md 就成为当前变更的 SSOT(Single Source of Truth)

这意味着:

  • 后续需求变更:不再去改 xmind、Confluence 或草稿纸,而是直接在 OpenSpec 的 spec/design/tasks 中更新,让变更留痕、可追溯。
  • 团队协作:前后端、测试、产品对齐时,以 OpenSpec 中的契约为准,而不是各自拿着不同的文档版本争论。
  • 验收追溯:验收时发现实现与需求不一致,先回查 OpenSpec,再看代码是否偏离了契约。
  • 设计工具退位:xmind、Confluence、Word、Notion、Markdown、草稿纸 只是「设计阶段的工具」,它们帮助你思考、收敛、拍板;一旦进入 OpenSpec,这些工具就完成了使命,不再作为权威依据。

简单说:设计阶段的文档可以有很多份,执行的真相只存一份------在 OpenSpec 里。

把 SSOT 意识立住,才能避免「聊着聊着又回到 xmind 改需求」「代码写一半发现 spec 没更新」「测试按旧文档验收」这类反复。


八、写在最后

OpenSpec 是一个极好的"需求→代码"的翻译器,但它不是魔术师。它能把清晰的设计翻译成清晰的契约,但不能替你思考业务。

最省时间的方式,不是跳过设计,而是把设计做扎实。

接到需求,先用你顺手的工具做设计------xmind、Confluence、Word、Notion、Markdown、草稿纸都可以。把接口、状态、结构、规则钉死,带着这份设计进 explore,让 AI 帮你挑刺。拆好 change 后再 propose,让它生成四件套、照单施工。

你会发现,AI 不再是你返工的原因,而是你执行设计的最强助手。

相关推荐
禁止摆烂_才浅2 小时前
JavaScript 基础 高频面试题
前端·javascript·面试
吃饱了得干活2 小时前
为什么你的Service越写越臃肿?三层架构的“业务逻辑层”是个黑盒
java·后端·架构
何时梦醒2 小时前
Docker 容器化入门:从「我电脑能跑」到「哪台机器都能跑」
后端·docker·面试
禁止摆烂_才浅2 小时前
HTML 高频面试题
前端·面试·html
foggyprojects2 小时前
AI 说销售额下降了,哪些客户拖累了结果?
后端
一拳不是超人2 小时前
Godot 信号不是线程安全的:我是怎么在后台线程里翻车的
前端·架构
用户852495071842 小时前
NestJS 架构实战:给后端代码请来一位“项目经理
后端
唐青枫2 小时前
一个点号省掉一堆类型:Zig .{} 语法、类型推导与实战
后端
月才2 小时前
告别System.out.println,打造专业日志系统
后端