挖掘闭环:变更如何沉淀为组织记忆
> Git 提交会变成结构化的变更日志条目和架构决策记录,再反哺回 AI 智能体,成为可查询的组织记忆。
本文中的数字反映的是发布时(2026 年 2 月)的系统状态。如需查看最新数据,请参阅我们的 团队页面。
每个工程团队都面临同一个难题:变更每天都在发生,但这些变更背后的原因却会渐渐消失。六个月之后,有人会问“我们当初为什么在流水线阶段里采用了 DuckDB?”,而答案往往只存在于当初做出这个决定的人脑子里——前提是那个人还在。
我们搭建了一套挖掘工作流,把这个闭环补上了。变更通过 Git 提交流动,经由我们的挖掘流水线处理,变成结构化的变更日志条目和架构决策记录,再通过 CLI 查询反哺回我们的 AI 智能体。结果就是:一份人类和 AI 都能访问的组织记忆。
问题所在:决策会蒸发
设想一个典型场景。某个开发者提交了这样一条记录:
feat(canonical): add DuckDB runtime for pipeline stages
这次提交代表着一个重大的架构选择。团队评估过多个方案、权衡过各种取舍,最终出于特定原因选定了 DuckDB。但所有这些上下文,都散落在:
- 某个 Slack 讨论串里(大概率已经被删了)
- 某个人的记忆里(必然正在淡去)
- 代码里的某条注释里(如果你运气好的话)
三个月后,一位新加入团队的成员问道:“这个新阶段我应该用 DuckDB 还是 SQLite?”没有组织记忆的情况下,他们要么重新发明一遍轮子,要么做出前后不一致的选择。
这个闭环:从提交到上下文
我们的挖掘工作流,把 Git 历史转化为可查询的知识:
Git Commits
│
▼
┌─────────────────────┐
│ mine sync │ ← Build index from git history
└─────────────────────┘
│
▼
┌─────────────────────┐
│ mine candidates │ ← Surface commits for review
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Classification │ ← Human or LLM assessment
│ (changelog or ADR) │
└─────────────────────┘
│
├──────────────────────┐
▼ ▼
┌─────────────┐ ┌───────────────┐
│ Changelog │ │ Decisions │
│ Ledger │ │ Registry │
│ (JSONL) │ │ (YAML files) │
└─────────────┘ └───────────────┘
│ │
▼ ▼
┌─────────────┐ ┌───────────────┐
│ CHANGELOG.md│ │ orkestra CLI │
│ per package │ │ queries │
└─────────────┘ └───────────────┘
│ │
└──────────────────────┘
│
▼
┌───────────────┐
│ AI Agents │
│ (via CLI) │
└───────────────┘
这里的关键洞见是:变更日志和架构决策,都来自同一份 Git 历史,经由同一套统一的流水线处理。这确保了不会有任何东西从缝隙中漏掉。
挖掘是如何进行的
第一步:同步索引
uv run orkestra mine sync
这个命令会扫描 Git 历史,为所有提交建立索引。它会从每次提交中提取结构化信号:
- 符合约定式提交(Conventional Commit)规范的类型(
feat、fix、chore、docs) - 作用域(涉及哪个包或哪个领域)
- 破坏性变更标记
- 涉及的文件以及复杂度指标
第二步:检查覆盖状态
uv run orkestra mine status
我们目前的状态大致是这样的:
Mining Status
=============
Decisions
---------
Coverage: 100.0%
Processed: 15637 (of 15637)
Extracted: 476
Skipped: 15161
Changelog
---------
Coverage: 100.0%
Processed: 15637 (of 15637)
Released: 6799
Skipped: 8838
15,637 次提交已被处理。476 次变成了架构决策。6,799 次变成了变更日志条目。每一次提交都被分类过了。
第三步:获取待审查的候选提交
uv run orkestra mine candidates --limit 50 --full
这会找出尚未处理过的提交,并附带用于分类的完整上下文:
on
{
"sha": "90571786d99166c0039ca2e80e4d9cd96184bd85",
"date": "2026-01-26",
"subject": "feat(canonical): add DuckDB runtime for pipeline stages",
"signals": {
"commit_type": "feat",
"scope": "canonical",
"breaking": false,
"is_releasable_type": true,
"domains_affected": ["pipeline", "data-architecture"]
},
"body": "Establishes DuckDB as canonical in-process analytical database...",
"files_changed": ["packages/canonical/pipelines/stages/duckdb_runtime.py", "..."],
"stats": {"files": 8, "insertions": 450, "deletions": 120}
}
这些信号能帮助指导分类:is_releasable_type: true 暗示这应该出现在变更日志中;较大的插入行数以及涉及的基础设施文件,则暗示它可能同时也是一条架构决策。
第四步:对提交进行分类
到这一步,会分出两条路径:变更日志条目和架构决策。
对于变更日志条目:
uv run orkestra mine classify abc123 --changelog added
这会记录下提交 abc123 应该出现在变更日志的“Added”类别下。
对于架构决策:
首先,获取一个真实的决策 ID:
uv run orkestra decisions new --domain pipeline --dry-run
# Returns: DEC-PL-143
然后用这个决策 ID 进行分类:
uv run orkestra mine classify abc123 --decision DEC-PL-143
这会把这次提交,关联到一条将被创建或更新的决策记录上。
对于批量处理(我们实际采用的方式):
# Generate classifications file with LLM assistance
uv run orkestra mine commit --input classifications.jsonl
JSONL 格式可以在一次处理中同时支持两个领域:
on
l
{"sha":"abc123","domain":"changelog","action":"release","category":"added","summary":"Add DuckDB runtime for pipeline stages"}
{"sha":"abc123","domain":"decisions","action":"extract","decision_id":"DEC-PL-142"}
{"sha":"def456","domain":"changelog","action":"skip","reason":"Chore: dependency update"}
第五步:渲染输出
uv run orkestra changelog render --package <pkg>
这会根据台账(Ledger),为每个包生成 CHANGELOG.md 文件。变更日志是派生产物——删掉它们,也能从源头台账完美地重新生成。
决策记录的结构
提取出的决策,会变成带有丰富元数据的 YAML 文件:
id: DEC-PL-142
title: Adopt DuckDB as Canonical Processing Runtime for Pipeline Stages
domain: pipeline
status: active
created: '2026-01-26'
summary: |
Establishes DuckDB as the canonical in-process analytical database for pipeline
stage transformations. Provides a shared runtime module that resolves settings
from pipeline defaults with stage-level overrides.
context: |
Pipeline stages performing data transformations each independently configured
DuckDB connections. This led to inconsistent settings, duplicated configuration
code, and no way to tune DuckDB globally for a pipeline run.
rationale:
- DuckDB provides efficient in-process OLAP with zero configuration deployment
- Centralized runtime module eliminates duplicated DuckDB setup across stages
- Hierarchical settings enable global tuning with stage-level overrides
- Memory limits and thread counts can be adjusted per-pipeline
impact:
positive:
- Consistent DuckDB configuration across all pipeline stages
- Single point of control for memory/thread tuning
- Reduced code duplication in conversion and export stages
negative:
- Adds dependency on shared runtime module
- Stages must adopt new configuration pattern
source_commits:
- sha: 90571786d99166c0039ca2e80e4d9cd96184bd85
message: 'feat(canonical): add DuckDB runtime for pipeline stages'
date: '2026-01-26'
role: primary
files:
- packages/canonical/pipelines/stages/duckdb_runtime.py
- packages/canonical/pipelines/runner.py
- packages/canonical/pipelines/stages/convert_hdx_admin_boundaries_to_geoparquet.py
related:
- DEC-DA-014 # Data architecture decisions that influenced this
每条决策都会关联回其源头提交,每条决策都会指明它影响哪些文件,决策与决策之间的关系也是明确的。
CLI 集成:查询组织记忆
这正是闭环真正合拢的地方。智能体可以通过 CLI 查询决策:
# Search by topic
uv run orkestra decisions search --query "retry"
返回与重试逻辑、错误处理、恢复模式相关的决策。
# Get full details on a specific decision
uv run orkestra decisions info DEC-PL-142
返回完整的决策记录,包括上下文、理由和影响。
# List recent decisions for context
uv run orkestra decisions list --limit 15
展示最近做出了哪些架构选择。
智能体如何使用它
我们编排器的基础指令中包含了这样一条:
**Essential CLI commands:**
- `orkestra decisions search "X"` — Find architectural decisions
当一个智能体被要求实现与 DuckDB 相关的东西时,它可以先检查:
uv run orkestra decisions search --query "DuckDB"
然后发现 DEC-PL-142,并从中了解到:
- 我们为什么选择 DuckDB(context)
- 该如何正确使用它(agent_guidance)
- 应该查看哪些文件(files)
- 存在哪些相关决策(related)
智能体不需要重新发明轮子,而是在既有模式的基础上继续构建。
三问测试
并非每次提交都值得拥有一条决策记录。我们用“三问测试”来做筛选:
- 这个决定难做吗? 是否需要经过大量分析、权衡评估,或者一番争论?
- 改变它的代价高吗? 如果要推翻这个决定,是否需要大量返工?
- 它是否具有系统级的影响? 是否影响多个包,或者树立了其他人会遵循的模式?
如果一次提交对这三个问题中至少一个的答案是“是”,那它就是决策提取的候选对象。我们通常的比例是:每 100 次提交中有 1 到 4 条决策(大约 1% 到 4%)。
对于变更日志条目,门槛要低一些:任何面向用户的变更(功能、修复、改进)都会被记录下来。内部杂务、文档更新和重构通常会被跳过。我们通常的比例是:每 100 次提交中有 30 到 50 条变更日志条目。
数据存储:仅追加式台账
这套挖掘系统使用仅追加式的 JSONL 台账,以实现无冲突的多智能体协作:
packages/orchestration/ai_assets/reference/changelog/
├── commits_processed.jsonl # Classification ledger (both domains)
├── release_notes.jsonl # Changelog entries
└── commits_index.yaml # Derived index (gitignored)
packages/orchestration/ai_assets/reference/decisions/
├── registry.yaml # Decision index
└── records/
├── DEC-AD-001.yaml
├── DEC-AD-002.yaml
└── ...
这种在 .gitattributes 中使用 merge=union 的 JSONL 格式,意味着多个智能体可以同时对提交进行分类,而不会产生合并冲突。每一行都是独立的。
验证门禁
在任何一次挖掘会话开始之前,我们都会先运行验证:
uv run orkestra mine validate --quick
这会检查:
- SHA 格式是否有效
- 决策 ID 格式是否合规
- 同一个 SHA 是否存在重复条目
- 引用的决策是否真实存在
分类完成之后,我们会在提交改动之前再验证一遍。
为什么这很重要
我们搭建的这个反馈闭环,解决了好几个问题:
对新团队成员而言: 他们不必再问“我们当初为什么这么做”,而是可以直接搜索决策注册表。上下文被完整保留了下来。
对 AI 智能体而言: 它们不再是在真空中运作,而是可以在给出建议之前先查询组织知识。当被要求新增一个流水线阶段时,它们可以发现 DuckDB 这个模式并加以遵循。
对架构一致性而言: 决策是明确的、可搜索的。当有人提出一个与既有决策相矛盾的方案时,系统可以把这个冲突暴露出来。
对变更日志生成而言: 发布说明不再是临阵磨枪赶出来的东西,而是开发过程中持续分类的一个副产品。
对新人上手而言: 新加入的智能体能继承代码库的完整上下文。它们看到的不只是代码本身,还有塑造了这些代码的那些决策。
现状
截至目前:
- 已有 15,637 次提交 经流水线处理
- 已提取并记录了 476 条架构决策
- 已记录了 6,799 条变更日志条目
- 两个领域都达到了 100% 覆盖率
自我们开始以来的每一次提交,都已经被分类过了。这份组织记忆是完整的,并且可以查询。
快速上手
如果你想实现类似的东西:
-
从约定式提交开始。 当提交带有结构化前缀(
feat:、fix:、chore:)时,这套挖掘流水线的效果最好。 -
定义你自己的领域。 我们使用诸如
pipeline、agent-design、observability、data-modeling这样的领域,用它们按区域来组织决策。 -
养成分类的习惯。 只有当团队持续、定期地对提交进行分类时,挖掘才会真正有效。借助 LLM 辅助的批量处理,有助于扩大规模。
-
让决策可以被查询。 当智能体能够通过 CLI 搜索决策时,这份价值会不断复利累积。请为机器可读性来组织你的输出结构。
-
让闭环真正闭合。 决策应该影响未来的工作。请在智能体指令和代码评审清单中,加入对决策的引用。
目标不是追求完美的文档,而是让变更背后的原因——无论是今天,还是六个月之后——对人类和 AI 都保持可访问。当变更沉淀为组织记忆,团队就能在既有模式的基础上继续构建,而不必重新发明它们。
这套挖掘工作流,是我们编排引擎的一部分,具体来说,是我们编排包中的上下文引擎(Context Engine)模块。
相关阅读
更多来自 Maguyva 开发日志的内容
我们为什么把代码搜索升级到了 voyage-4-large_
我们把代码 Embedding 迁移到了 voyage-4-large——目前公开的 RTEB 代码检索排行榜上排名第一的模型。诚实的版本是这样的:我们做出的取舍、我们实际索引的内容,以及我们为什么愿意为高端 Embedding 付费。
语言递归自我提升:在约 280 种语言上打磨代码智能_
我们为约 280 种语言提供代码智能支持,没有任何人能靠人工逐一审核这个规模。于是我们搭建了一套语言递归自我提升循环——抽查、LLM 担任评审、修一处、重新验证——并用一支相互隔离的智能体舰队运行它,直到提取结果真正正确,而不只是“绿灯通过”。
多模态融合搜索:为每一次查询挑选正确的检索器_
像“parseConfig 是在哪里定义的”这样的查询,和“身份验证是怎么工作的”所需要的搜索方式截然不同。Maguyva 会对查询意图进行分类,据此为四种检索模态分配权重,再用加权的 Reciprocal Rank Fusion(倒数排序融合)把结果融合起来。