08-Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人-决策记录生成
08 决策记录生成:用 ADR 固化架构决策
这是《Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人》系列的第 8 篇。前几篇我们蒸馏了结构、历史、文档、模式,这一篇蒸馏最"贵"的东西——决策。代码会过时,文档会过时,但"为什么这么设计"的决策,是项目最持久的资产。ADR(Architecture Decision Record)就是固化决策的标准方法。
一、ADR 概念与价值
1.1 什么是 ADR
ADR(架构决策记录)是一份简短的文档,记录一个架构决策的背景、决策、理由和后果。它回答的不是"系统做了什么",而是"系统为什么这么做"。
一个典型的 ADR 长这样:
# ADR-001:使用 Pinia 替代 Vuex 作为状态管理方案
## 状态:已接受
## 背景
项目最初使用 Vuex 管理全局状态。随着项目规模扩大,跨模块调用 store 变得繁琐:
- 每个模块需要写大量 getter/mutation
- TypeScript 类型推导不友好
- setup 风格组件中调用繁琐
## 决策
迁移到 Pinia,使用其 setup 风格定义 store。
## 理由
- Pinia 的 setup 风格更直观,与组合式 API 一致
- TypeScript 支持更好,类型推导完整
- 官方维护,Vue 3 生态主流选择
## 后果
- 正面:状态管理代码量减少约 40%,类型安全提升
- 负面:需要一次性迁移所有 store,迁移期工作量较大
- 风险:团队需要学习 Pinia 的 API
## 关联
- 相关 ADR:无
- 相关代码:src/stores/
- 相关 issue:#123
1.2 ADR 的价值
| 价值 | 说明 |
|---|---|
| 知识留存 | 决策理由不随人员离职而流失 |
| 新人上手 | 新成员通过 ADR 快速理解"为什么" |
| 避免重复决策 | 遇到类似问题先查 ADR,不重新发明 |
| 决策审计 | 复盘时能追溯每个决策的来龙去脉 |
| 虚拟人素材 | ADR 是虚拟人 memory 中"决策知识"的核心 |
核心认知:代码是"结果",ADR 是"原因"。蒸馏仓库时,如果只提取结果不提取原因,蒸馏出的知识就是"知其然不知其所以然"。
二、从历史中挖掘决策
ADR 不是"现在补写"的,而是从历史中挖掘出来的。决策藏在三个地方:
2.1 从 PR 中挖掘
PR 的 body 和评审讨论,是决策最集中的地方:
# 拉取所有已合并 PR
gh pr list --state merged --limit 500 --json number,title,body,mergedAt
# 查看 PR 的评审讨论
gh pr view 456 --comments
PR 中的决策信号:
- “我们决定用 X 而不是 Y,因为……”
- “经过讨论,最终选择……”
- “这个方案有个 trade-off……”
2.2 从 issue 中挖掘
# 拉取带决策标签的 issue
gh issue list --label "decision" --state all --json number,title,body
# 查看 issue 的完整讨论
gh issue view 123 --comments
issue 中的决策信号:
- 标题含"方案选型"、“讨论”、“决策”
- 讨论中出现多个候选方案对比
- 最终有人拍板"就用 X"
2.3 从提交历史中挖掘
# 找"重构/迁移/升级"类提交(往往是决策的执行)
git log --oneline --grep="重构\|迁移\|升级\|替换\|改用"
# 找技术栈切换的提交
git log --oneline -S "Vuex" -- src/
git log --oneline -S "Pinia" -- src/ --reverse | head -1
提交历史中的决策信号:
- 技术栈切换(
-S检测旧库消失、新库出现) - 大规模重构(一次改 50+ 文件)
- 目录重组(架构调整)
2.4 决策挖掘清单
把挖掘到的决策整理成清单:
# 决策挖掘清单
| 编号 | 决策主题 | 来源 | 时间 | 状态 |
|------|---------|------|------|------|
| D-01 | 状态管理选型(Vuex→Pinia) | PR #456 | 2022-06 | 已确认 |
| D-02 | 目录结构分层方案 | 提交 a1b2c3d | 2021-06 | 已确认 |
| D-03 | API 错误处理规范 | issue #123 | 2022-03 | 需补充理由 |
| D-04 | 微前端引入 | 提交 e4f5g6h | 2024-01 | 待确认 |
三、ADR 编写规范
3.1 ADR 标准结构
业界常用的 ADR 结构(基于 Michael Nygard 的经典模板):
# ADR-XXX:<决策标题>
## 状态
<提议中 / 已接受 / 已废弃 / 已取代>
## 背景
<为什么需要做这个决策?面临什么问题?>
## 决策
<我们做了什么选择?>
## 理由
<为什么选这个方案?对比了哪些方案?>
## 后果
<正面影响 / 负面影响 / 风险>
## 关联
<相关 ADR / 相关代码 / 相关 issue>
3.2 编写要点
| 要点 | 说明 | 反例 |
|---|---|---|
| 背景要具体 | 说明当时的约束和痛点 | “项目需要状态管理”(太泛) |
| 理由要对比 | 说明为什么不是别的方案 | “Pinia 更好”(没对比) |
| 后果要诚实 | 正面负面都写 | 只写好处(不客观) |
| 状态要更新 | 决策被取代时更新状态 | 废弃了还标"已接受" |
3.3 ADR 目录组织
docs/adr/
├── README.md # ADR 索引
├── ADR-001-pinia.md
├── ADR-002-layering.md
├── ADR-003-error-handling.md
└── ADR-004-micro-frontend.md
索引文件:
# ADR 索引
| 编号 | 标题 | 状态 | 日期 |
|------|------|------|------|
| ADR-001 | 使用 Pinia 替代 Vuex | 已接受 | 2022-06 |
| ADR-002 | 目录分层方案 | 已接受 | 2021-06 |
| ADR-003 | API 错误处理规范 | 已接受 | 2022-03 |
| ADR-004 | 引入微前端 | 提议中 | 2024-01 |
四、从挖掘到成文:一个完整示例
4.1 挖掘到的原始信息
从 PR #456 的讨论中提取到:
“之前用 Vuex 的时候,跨模块调用 store 特别痛苦,每次都要写一堆 getter。后来我们讨论了很久,决定迁移到 Pinia,因为它的 setup 风格写起来更直观,而且 TypeScript 支持更好。迁移的时候踩了个坑,Pinia 的 store 不能在 setup 外直接调用,会报错。”
4.2 提炼成 ADR
# ADR-001:使用 Pinia 替代 Vuex 作为状态管理方案
## 状态
已接受
## 背景
项目最初使用 Vuex 管理全局状态。随着项目规模扩大(2022 年 6 月时已有 20+ 模块),
跨模块调用 store 变得繁琐:
- 每个模块需要写大量 getter/mutation,样板代码多
- TypeScript 类型推导不友好,容易写错
- setup 风格组件中调用繁琐
## 决策
迁移到 Pinia,使用其 setup 风格定义 store。
## 理由
对比了三个方案:
1. **继续用 Vuex**:改动最小,但无法解决样板代码和类型问题
2. **迁移到 Pinia**:setup 风格直观、TS 支持好、官方维护,但需要一次性迁移
3. **自研状态库**:可控但成本高、风险大,不划算
最终选择 Pinia,因为它在"改进程度"和"迁移成本"之间最平衡。
## 后果
- 正面:状态管理代码量减少约 40%,类型安全提升,开发效率提高
- 负面:需要一次性迁移所有 store,迁移期约 2 周
- 风险:团队需要学习 Pinia API;Pinia store 不能在 setup 外直接调用(已踩坑)
## 关联
- 相关代码:src/stores/
- 相关 issue:#123
- 相关 PR:#456
4.3 批量生成脚本
对于大量决策,可以写脚本辅助生成 ADR 骨架:
#!/usr/bin/env python3
# scripts/gen_adr.py
# 用法: python gen_adr.py "001" "使用 Pinia 替代 Vuex" "已接受"
import sys
from datetime import date
def gen_adr(num, title, status):
return f"""# ADR-{num}:{title}
## 状态
{status}
## 背景
(待补充:为什么需要做这个决策?面临什么问题?)
## 决策
(待补充:我们做了什么选择?)
## 理由
(待补充:为什么选这个方案?对比了哪些方案?)
## 后果
(待补充:正面影响 / 负面影响 / 风险)
## 关联
(待补充:相关 ADR / 相关代码 / 相关 issue)
"""
if __name__ == "__main__":
num, title, status = sys.argv[1], sys.argv[2], sys.argv[3]
print(gen_adr(num, title, status))
# 生成 ADR 骨架
python scripts/gen_adr.py "001" "使用 Pinia 替代 Vuex" "已接受" > docs/adr/ADR-001-pinia.md
五、输出决策记录
5.1 决策记录汇总
# 决策记录汇总
| 编号 | 决策 | 状态 | 日期 | 关键理由 |
|------|------|------|------|---------|
| ADR-001 | 使用 Pinia 替代 Vuex | 已接受 | 2022-06 | setup 直观、TS 支持好 |
| ADR-002 | 目录分层方案 | 已接受 | 2021-06 | 可维护性 |
| ADR-003 | API 错误处理规范 | 已接受 | 2022-03 | 错误处理一致 |
| ADR-004 | 引入微前端 | 提议中 | 2024-01 | 待确认 |
5.2 决策记录的用途
决策记录是蒸馏流程的**"为什么"层**:
- 给 09 知识图谱:决策是图谱的"决策"节点,连接背景和后果
- 给 12 虚拟人化:ADR 是虚拟人 memory 中"决策知识"的核心,让虚拟人能回答"为什么这么设计"
- 给 13 落地:虚拟人回答架构问题时,ADR 是权威依据
六、小结
这一篇的核心收获:
- ADR 概念:一份记录"背景、决策、理由、后果"的简短文档,是项目最持久的资产。
- 从历史挖掘:PR、issue、提交历史是决策的三个来源,用
ghCLI 和git log -S挖掘。 - 编写规范:标准结构(状态/背景/决策/理由/后果/关联),要点是"背景具体、理由对比、后果诚实"。
- 输出决策记录:ADR 目录 + 索引 + 汇总表,是虚拟人"为什么"知识的核心。
下一篇,我们把所有知识织成网:[09 知识图谱构建:连接知识节点](09-Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人-知识图谱构建.md)——把前几篇蒸馏出的知识,连接成一张可查询的知识网络。
上一篇:[07 代码模式提炼:从实现中抽象通用模式](07-Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人-代码模式提炼.md)
下一篇:[09 知识图谱构建:连接知识节点](09-Git 仓库蒸馏术:从代码仓库到 OpenClaw 虚拟人-知识图谱构建.md)
更多推荐
所有评论(0)