从决策上下文到 ADR:agent-skills 如何用 orders 服务的事件溯源抉择测试"记录决策"技能
本文以 agent-skills 仓库中 decision-context.md 这份"决策上下文"文档为核心,完整还原 orders 服务在审计需求下面临的三种架构选项及其权衡,并结合 documentation-and-adrs 技能定义 与 行为评测案例 说明:一份合格的决策上下文应包含哪些要素,以及它如何被转化为一份结构完整的架构决策记录(ADR)。读完本文,你能掌握 ADR 中 Context/Alternatives/Consequences 各节的内容来源,并了解该仓库 Tier 3 行为评测如何驱动 Agent 完成"从决策上下文到 ADR"的完整流程。
一、决策上下文原文:orders 服务的审计困境
decision-context.md 是一份为架构决策服务的上下文文档,全文围绕一个真实的工程困境展开。逐段拆解其信息构成:
1. 现状与诉求(Context 素材)
文档开篇交代了两类事实:
- 现状:orders 服务当前存储"可变的订单行"(mutable order rows),并以尽力而为(best-effort)的方式发出 webhook;
- 诉求:审计方(Auditors)需要完整的状态转换历史;客服(Support)必须能够在任意历史时点重建订单(reconstruct an order at a prior point in time)。
这两个诉求直指当前模型的缺陷:可变行只保留"最终态",而 best-effort webhook 无法保证事件不丢。"完整状态转换历史"与"时间点重建"正是事件溯源(Event Sourcing)要解决的两个经典能力——可追溯性(traceability)与可重放性(replay)。
2. 候选方案(Alternatives 素材)
文档明确列出三个被讨论过的选项:
- 保留现有模型,追加一张 append-only 审计表(Keep the current model and add an append-only audit table);
- 对 orders 采用事件溯源,并构建读模型投影(Adopt event sourcing for orders and build read projections);
- 用数据库变更数据捕获(CDC)作为审计历史(Use database change-data capture as the audit history)。
3. 权衡与约束(Consequences 素材)
文档随后给出了关键的权衡陈述:
- 事件溯源的收益:提升可追溯性与重放能力(improves traceability and replay);
- 事件溯源的成本:引入投影重建(projection rebuilds)、事件版本化(event versioning)、最终一致性(eventual consistency)与运维复杂度;
- 团队能力:团队已有事件流(event-stream)经验,降低了选项 2 的执行风险;
- 外部依赖约束:报表服务(reporting service)期望的是同步读(synchronous reads),这与事件溯源天然的事件ually 一致读模型形成张力;
- 作用域边界:该决策仅适用于 orders 限界上下文(bounded context),不波及整个系统。
这份文档的价值在于:它不是结论,而是决策的原材料——现状、诉求、候选项、各方案的利弊、团队能力、外部约束、作用域,全部就位,只差最后的"拍板"。
二、决策上下文如何对接 ADR:documentation-and-adrs 技能
在该仓库中,decision-context.md 对应的技能是 skills/documentation-and-adrs/SKILL.md。该技能的核心主张是:"记录决策,而不只是代码"——最有价值的文档捕获的是 why:导致决策的上下文、约束与权衡。代码展示了"构建了什么",文档解释"为什么这样构建"以及"考虑过哪些备选"。
何时该写 ADR
技能文档列出的触发条件与 orders 场景高度吻合:
- 在相互竞争的方案之间做选择(Choosing between competing approaches)——对应决策上下文中的三个候选项;
- 设计数据模型或数据库 schema(Designing a data model or database schema)——对应 mutable rows 与 event stream 的存储模型之争;
- 任何回退代价高昂的决策(Any decision that would be expensive to reverse)——切换订单存储模型显然属于此类。
现有约定优先(Match the existing convention first)
技能文档要求:在创建 ADR 之前,先检查仓库上下文里是否已有既定约定——现存 ADR、项目说明、ADR 相关配置或工具(如 .adr-dir 文件)。既定约定优先于模板默认值,需要对齐三个方面:
- 位置与格式:如
docs/adr/*.md、Documentation/Decisions/*.rst、MADR 布局或adr-tools配置;匹配现有目录、文件扩展名与标记语言(Markdown vs reStructuredText); - 编号与命名:沿用现有序列与文件命名模式(
ADR-004-Title.rst、0004-title.md……),不要从 001 重新开始,也不要引入第二套编号体系; - 小节标题:复用项目既有的标题集合,而不是强加模板的标题。
若证据相互冲突,应把冲突暴露出来,而不是静默引入另一套体系。只有在确认不存在任何约定时,才使用默认的 docs/decisions/ 加顺序编号方案。
默认 ADR 模板与订单决策的四节映射
在无既有约定时,技能文档给出的默认模板(存储于 docs/decisions/,顺序编号)包含 Status、Date、Context、Decision、Alternatives Considered、Consequences 各节。以 技能文档中的 PostgreSQL 示例 为参照,orders 决策上下文可以清晰地映射进各节:
| ADR 小节 | 从决策上下文中提取的内容 |
|---|---|
| Context | 可变订单行 + best-effort webhook 现状;审计需要完整状态转换历史;客服需要时点重建能力 |
| Decision | 三个候选中拍板其一(上下文中尚未落定,这正是 ADR 要补上的部分) |
| Alternatives Considered | 选项 1(audit table)、选项 2(event sourcing + projections)、选项 3(CDC),各自标注 Pros/Cons/Rejected 理由 |
| Consequences | 事件溯源带来的投影重建、事件版本化、最终一致性与运维复杂度;报表服务同步读诉求带来的适配工作;仅适用于 orders 限界上下文的作用域声明 |
值得强调的是技能文档对 Alternatives 的要求:每个被否决的方案都要写明 Rejected 理由,而不仅是罗列缺点。对应到订单场景:选 CDC(选项 3)意味着审计历史与数据库绑定、重放语义弱于原生事件流;选 audit table(选项 1)能低成本获得追加历史,但"时点重建"仍需靠额外快照或日志回放支撑,且审计表与业务写入是两套机制,容易出现漂移;选事件溯源(选项 2)则把三个成本项(投影重建、版本化、最终一致)转化为长期运维负担——这正是 决策上下文 最后一段权衡陈述的来源。
ADR 生命周期
技能文档规定 ADR 的状态流转为:
PROPOSED → ACCEPTED → (SUPERSEDED or DEPRECATED)
并明确两条纪律:不要删除旧 ADR(它们承载历史上下文);决策变化时,写一份新 ADR 引用并取代(supersede)旧 ADR。这与"代码里不删历史,用 git 保留"的精神一致——文档同样通过版本化而非删除来表达演进。
三、这份决策上下文在评测体系中的角色
decision-context.md 并非普通文档,而是 evals/fixtures/ 下的评测夹具。理解它的定位需要看 evals/README.md 描述的三层评测体系:
| 层级 | 检查内容 | 运行方式 |
|---|---|---|
| 1. 结构层 | frontmatter、命名、必需章节、命令一致性 | CI(validate-skills.js、validate-commands.js) |
| 2. 触发与路由 | 正向 prompt 排名 top-k、负向 prompt 不排名、描述不碰撞 | CI(run-evals.js) |
| 3. 行为层 | 遵循技能的 Agent 满足 expectations[] |
按需(run-evals.js --behavioral,消耗 tokens) |
评测案例:从 prompt 到 expectations
evals/cases/documentation-and-adrs.json 中定义了该夹具对应的行为评测:
{
"id": 1,
"prompt": "Record the decision to adopt event sourcing for the orders service as an ADR.",
"expected_output": "An ADR capturing context, decision, alternatives considered, and consequences",
"files": ["documentation-and-adrs"],
"expectations": [
"The ADR states context, decision, alternatives, and consequences distinctly",
"Trade-offs and rejected options are recorded, not just the winning choice",
"The document is written in timeless language describing current state"
]
}
其中 files: ["documentation-and-adrs"] 声明评测所需夹具的路径,它相对于 evals/fixtures/ 目录——因此执行评测时,Agent 拿到的工作区里就包含这份 orders 决策上下文。三条 expectations 分别验证了 ADR 的四节区分度、"落选方案与被拒绝理由必须记录"的要求,以及"用无时间性语言描述当前状态"的写作规范——例如 ADR 中应写"orders 服务采用事件溯源",而不是"我们在 2026 年决定迁移"。
执行机制:夹具如何变成 Agent 的工作区
从 scripts/run-evals.js 的源码可以看到 Tier 3 评测的完整链路:
- 物化工作区:
materializeWorkspace()为每个评测创建临时目录,通过fs.cpSync把files[]声明的夹具(本例即documentation-and-adrs/decision-context.md)从evals/fixtures/复制进工作区,Agent 拿到的是真实可操作的项目输入,而不是想象中的场景; - 无头执行:评测通过
claude -p无头模式运行,带--verbose --output-format stream-json捕获完整转录(含工具调用),并以--permission-mode acceptEdits加预批准工具列表运行,让 Agent 真正能写文件、跑命令,而不是"口头描述将要做的事"。--append-system-prompt会注入对应SKILL.md全文,执行超时上限 15 分钟; - 评分:完整的 stream-json 转录被作为"不可信数据"用 TRACE 标记包裹,经 stdin 管道传给评分器(避免 argv 超长),评分器按
expectations[]逐条判定并返回 JSON 结果,写入evals/results/(gitignored)。评分器只看 Agent 实际做了什么(工具调用、文件编辑、命令执行),而非其声称做了什么; - 清理:
finally块删除临时工作区,防止夹具数据残留在可读的临时目录中。
这套机制保证了决策上下文夹具不是摆设:Agent 必须在真实拿到 decision-context.md 的前提下,产出一份能被逐条验证的 ADR。
四、可复用的决策上下文写作清单
把 orders 案例与 documentation-and-adrs 技能 的要求合起来,可以提炼出一份"决策上下文"写作清单。在下一次架构评审前,检查你的上下文文档是否包含:
- 现状一句话:当前系统如何工作(mutable rows + best-effort webhooks),缺陷在哪(只有最终态、事件可能丢失);
- 干系人诉求:谁需要什么能力(审计要完整状态转换历史,客服要时点重建),诉求尽量具体到可验证;
- 穷举候选项:至少列出被认真讨论过的 2~3 个选项,而不是只写"我们选了 A";
- 逐选项权衡:每个候选的收益、成本、被拒绝理由都要写全——evals/cases/documentation-and-adrs.json 的第二条 expectation 明确要求"记录被否决的方案,而不只是胜出者";
- 约束与边界:团队能力(有事件流经验)、外部系统约束(报表服务期望同步读)、作用域(仅 orders 限界上下文)——这些约束决定了同一个技术在不同团队、不同上下文里是否成立;
- 既有约定检查:写 ADR 前先确认项目是否有既定 ADR 目录、编号与格式约定,有则完全对齐,无则用默认模板。
最后呼应技能文档的 Verification 清单:决策上下文与 ADR 落盘后,应确认"所有重大架构决策都有 ADR""README 覆盖快速上手、命令与架构概览""已知坑(gotchas)在关键处内联标注""没有遗留被注释掉的代码"。决策上下文的终点不是一份会议纪要,而是一份未来的人类工程师和 Agent 都能据此理解"为什么是这样"的 ADR。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00