先确定读法:领域语言与决策各管一件事

CONTEXT.md 定义对象的含义与边界,ADR 记录为什么选择这条边界。两者合起来,才能理解 M-Agent:Definition 是声明,Run 是一次执行,Session 是连续对话,Trace 是观察,Checkpoint 是可复用的确认结果。 它们不能因为都包含“状态”或“历史”,就被合并为一个万能对象。

本文按设计问题的依赖关系串联全部 42 篇 ADR,而不按编号逐条抄写。每项抉择都说明它针对什么问题、为什么这样选,以及把什么成本留给了实现或应用。正文讲设计承诺;实际 API 时序与故障分支在技术页,测试如何提供证据在实验验证。

来源固定为 v0.5.1 对应提交的 CONTEXT.md 与各条 ADR。41 篇状态为 accepted;ADR-0005 已被 ADR-0027 替代。下文不会把被替代的六状态模型当作现行契约,也不会把设计文件中尚需实现核对的措辞自动视为已完成验证。

一、先缩小产品:运行库,不是平台

ADR-0001:只拥有 Agent 执行生命周期

Agent 应用会用到模型、检索、工具、部署和评估,但“应用需要它们”不等于“运行时应实现它们”。M-Agent 选择 Agent Application Runtime:负责执行生命周期、工具调用、状态、策略检查与扩展契约,不拥有业务逻辑、RAG 内部实现、模型推理服务、分布式调度或容器沙箱。

这是后续所有边界的起点。集成者必须自己组合外围能力,开箱即用的功能少了;但运行时可以专注于一次执行的正确性,也避免与独立业务或检索项目重复建设。0001

ADR-0036:直接用户是 Python 应用研发工程师

既然核心产品是运行库,主要入口就应是 Python Library API,文档围绕定义 Agent、注册能力、创建、恢复、观察与评测展开。CLI 服务示例、检查与 Eval,不扩展成平台控制台。

这放弃了直接服务终端用户、低代码工作流设计者和平台管理员的产品面。换来的是清楚的验收问题:开发者是否能把这套执行协议嵌入自己的服务,而不是网站上是否多了一个管理面板。0036

ADR-0009:以异步 Runner 为规范接口

模型和工具调用需要等待,流式输出需要持续消费,取消与不同 Run 的并发也需要明确的协作点。因此 Runner、Model、Tool 采用 async-first,同步接口只包装同一套语义。

代价是应用要理解异步生命周期,并自行管理 worker、队列与服务部署;收益是运行库能够支持这些调用形态,而不为了“自动运行”顺带拥有一套调度基础设施。0009

二、先有执行事实,才谈恢复

ADR-0002:Definition 与 Run 分开

一个 Agent 定义可以被复用,但两次客户请求不能共享一份执行状态。因此 Definition 只声明行为与能力,Run 承担一次输入对应的状态、步骤、用量、Checkpoint 和结果。Session 则关联多次 Run,不代替其中任何一次执行。

这比把同步 Agent.run() 的调用栈当作隐式生命周期更繁琐,却使取消、并发隔离、恢复与检查都有稳定对象。进程没了,Run 的身份仍能存在。0002

ADR-0004:模型调用与单个工具调用各成一步

如果一次模型响应请求了三个工具,前两个已完成,第三个中断,把整轮视为一步就容易重复执行前两个。M-Agent 因此按一次模型调用、每个单独工具调用划分 Step。

较细的粒度增加了记录和恢复逻辑,但允许单独重试或检查每个工具。策略检查、Checkpoint 写入和 Trace 是围绕步骤发生的生命周期行为,不因为它们也会被记录,就变成同一类 Step。Context 的步骤地位由 ADR-0015 进一步明确。0004

ADR-0006:Run Store 与 Trace 分开

日志常需要采样、脱敏、删除或导出。如果恢复依赖日志,改变观测策略就可能改变执行正确性。Run Store 因而保存权威状态与 Checkpoint,Trace 只服务诊断。

两边可能记录部分重复事实,存储和集成成本有所增加;但即使 Trace 全部丢失,恢复仍有明确的事实来源。CONTEXT.md 因此明确反对把 Trace 当成 Checkpoint 或审计事实的默认权威来源。0006

ADR-0005 → ADR-0027:进程故障与业务结论分开

ADR-0005 最初定义 CREATED、RUNNING、WAITING 和三个终态,并作出一个持续有效的选择:进程崩溃不新增 Run 状态,也不自动等于执行失败。它描述运行载体出了问题,不直接决定业务结果。

ADR-0027 后来增加 REJECTED:策略按设计拒绝请求,不应被记成系统错误。现行模型是 CREATED、RUNNING、WAITING,加 SUCCEEDED、REJECTED、FAILED、CANCELLED 四个终态。多一个分支增加统计和处理成本,却避免安全策略正常工作时污染故障率与归因。旧 ADR 关于等待场景的概括不能代替当前具体的等待原因与处置规则。00050027

三、承认外部世界不能与本地存储一起提交

ADR-0003:承诺 at-least-once,不承诺跨系统 exactly-once

通知服务已经接受请求,本地结果却尚未提交时,进程可能退出。仅凭 Run Store 无法知道外部到底发生了什么。运行时因此保存步骤边界与完整结果,允许在可恢复条件下重放,但不宣称任意外部效果恰好发生一次。

这一选择把幂等键、重复执行安全性和外部查证责任留给具体集成。它没有让故障处理更省事,却避免向应用提供无法兑现的保证。0003

ADR-0007:未知工具按非幂等处理

工具用 READ_ONLY、IDEMPOTENT、NON_IDEMPOTENT 声明外部影响。未声明时按非幂等处理,不以“没有说明危险”推断“可以安全重试”。

保守默认降低了旧工具接入时的自动恢复便利性,要求作者补充真实语义。幂等标签本身不实现去重;ADR-0025 又补上独立条件:即使影响类型允许,仍要有显式且有界的 Retry Policy。0007

ADR-0008:无法确认的副作用,由应用处置

非幂等工具结果不确定时进入 WAITING。模型不能自行重试、猜测成功或跳过。应用通过 RETRY_STEP、CONFIRM_STEP(result)、FAIL_RUN 或 CANCEL_RUN 提交决定。

应用要建立查证、审批或运维入口,不能指望模型自行圆回执行历史。作为回报,控制权与事实责任一致:掌握外部通知记录的一方决定是否确认,而 Runtime 只执行受约束的命令。确认不等于再次调用工具,失败或取消也不等于回滚外部效果。0008

ADR-0012:取消是一种协作意图,不是假装撤销

停止请求到达时,外部调用可能已经发出。M-Agent 选择阻止后续 Step,并在可协作的位置尽力停止当前调用,而不承诺撤回通知或其他写操作。

因此取消不能总是立刻成为 CANCELLED。若非幂等效果仍不确定,必须保留 WAITING 交回应用。这牺牲了“点击即完成”的简单反馈,维护的是状态含义:停止推进与撤销已发生的事并不是同一件事。0012

ADR-0013:Lease 管推进权,version 管观察版本

持久化之后,多个进程可能同时看见一个未完成 Run。Lease 为一个 Run 提供带有效期的排他推进权,权威写入还要检查 owner 与记录版本。失去租约的 Runner 不应继续推进;过期后才允许接管。

这增加了租约期限、冲突与迟到结果的处理成本,但避免重复请求或重启让多个推进者无约束地执行同一 Run。Lease 不发现任务、不调度 worker,也不能物理停止已经发出的外部请求。当前 Runner 不自动后台续租,具体运行时序见技术页。0013

四、让失败、重试与实时输出各有含义

ADR-0024:业务拒绝是结果,未捕获异常不是

“订单不允许退款”可以是工具明确返回的 REJECTED 业务结果;“数据库连接断开”则是执行尝试失败。把两者都转成一段文本交给模型,会让基础设施故障被当成业务事实。

工具作者因此必须区分显式 SUCCESS / REJECTED 与未捕获异常,Runner 再按标准失败语义处理后者。代价是适配工作更多,收益是恢复和模型上下文都不依赖异常字符串猜测。原始诊断的保护还须结合 ADR-0033,不能把这条早期决策理解成允许向任意日志或模型暴露堆栈。0024

ADR-0025:重试由失败分类与冻结策略决定

失败分为 TRANSIENT、PERMANENT、UNCERTAIN。Retry Policy 明确尝试上限、退避与超时,未配置时不自动重试。瞬时失败、永久错误、结果不确定不是同一种“再试一次”。

应用要提前声明能承担的重试成本,适配器要负责正确分类。运行时因此不会根据异常文字猜重试策略,也不会用隐藏循环持续增加费用。崩溃后的恢复重放与普通失败重试仍需区分,不能仅凭一个 Effect 标签授予执行权。0025

ADR-0026:策略覆盖整个生命周期,而且必须确定

只在调用工具前检查权限,会漏掉输入、外部上下文、工具返回内容和最终输出。因此 Run Policy 设在 INPUT、CONTEXT、TOOL_REQUEST、TOOL_OUTCOME、FINAL_OUTPUT 五类 Gate,返回 ALLOW、REJECT 或 REQUIRE_RESOLUTION。

首版策略是确定性代码;需要模型判断时,应成为显式模型步骤,而不是藏在一个钩子里。这要求迁移旧 Guardrail 接口,却让拒绝、审核与人工处置成为能记录、能复查的执行语义。0026

ADR-0010:实时更新不复用诊断日志协议

前端需要稳定的状态与增量输出接口,诊断日志却需要独立演进和采样。因此 RunUpdate 面向应用呈现,Trace 面向诊断,Run Store 面向恢复;SSE、WebSocket 和终端传输由应用选择。

多维护一种事件契约是成本,但它避免让界面依赖内部日志格式。RunUpdate 是可丢失的实时通知,重连读取 Store,不把实时流伪装成持久事件总线。0010

ADR-0011:只有完整模型响应能成为 Checkpoint

第一轮流输出 AB 后失败,第二轮重新生成 ABC,如果把两个尝试拼接,就会得到模型从未返回过的 ABABC。增量因此只携带 attempt_id 用于呈现,完整响应持久化后才形成 Checkpoint。

用户可能看到重新生成,应用也要按尝试身份替换临时内容;换来的是恢复只使用真正完整的模型结果,不让界面进度冒充执行事实。0011

五、上下文是有来源的数据,不是隐形指令

ADR-0014:Core 不提供 RAG 专用系统

检索既可以由应用在模型前通过 Context Provider 注入,也可以作为 Tool 交给模型调用。Core 不拥有 ingestion、切块、embedding、索引和 rerank,不把某种 Retriever 当成所有知识接入的共同核心。

这减少了内置 RAG 功能,但允许独立检索系统通过通用边界接入。运行时关心输入是否被记录、如何交付,而不是代替业务决定哪种检索算法最好。0014

ADR-0015:每次 Stage invocation 都有恢复边界

把整个上下文处理藏在一次 Provider 调用里,会让筛选、裁剪和动态读取无法检查。冻结的线性 Context Plan 因此按 scope、trigger 与 stage identity 定位每次 invocation,各自产生 Context Step 与 Checkpoint;重试只增加 Attempt。

记录数量增加了,但恢复可以从未完成阶段继续,已确认阶段不重新读取外部数据。旧的单 Provider 也能被表达为只有一个阶段的 Plan,不需要再维护另一套恢复模型。0015

ADR-0016:保留结构化 Item 与派生关系

裸文本无法回答“这句话从哪来,裁剪前是什么”。Context Item 因而包含稳定身份、来源、直接输入引用、变换类型、安全与版本字段,以及有界 metadata。

排序和筛选记录决定;裁剪、压缩产生引用原项的新 Item,不原地抹掉原内容。Core 校验引用与可序列化边界,不解释相关性分数。适配与存储成本增加,换来引用、问题归因、Eval 与敏感数据控制可以共享同一份来源依据。0016

ADR-0017:外部数据不能提升为 Instruction

检索结果和工具输出始终作为数据进入模型请求,只有 Definition 或应用的受信控制入口能提供 Instruction。这样即使文档里写着“忽略之前规则”,运行时也不会主动把它提升成 system 指令。

这不是模型免疫 Prompt Injection 的保证,而是一个结构上的权限边界。它限制了随手拼接 Prompt 的便利性,却让后续攻击测试与策略检查有可定位的对象。0017

ADR-0040:预算检查与语义压缩必须显式

上下文问题不只在于“有哪些资料”,还在于最终请求能否装得下。Core 冻结线性 Plan、RUN_INPUT / TOOL_OUTCOME / MODEL_STEP 三类 Scope 和 Frame 恢复事实;Companion 提供具体筛选、排序、去重、机械裁剪等算法。这样算法可以替换,预算与恢复语义仍由 Core 约束。

预算针对完整请求与预留输出,使用与冻结模型契约一致、精确或保证不低估的 Model Input Sizer。ADR 要求保留候选 Frame 的受保护证据,通过检查后才形成可 dispatch 的 Frame Checkpoint;超预算明确失败,不隐式裁剪、偷偷压缩或无限等待。代价是集成者要提供可靠计量和显式处理策略,不能用字符数近似伪装成严格保证。

语义压缩是有损模型调用,必须有版本化 Compression Contract、独立用途与预算,保留原 Item、派生引用和省略信息。它不能递归触发整条业务管线、工具或输出修复。更多公开契约与持久化换来的,是成本和信息损失可见,而不是一个悄悄改写上下文的便利函数。0040

六、对话连续性不等于执行恢复

ADR-0018:Session Store 取代泛化 Memory

一次执行的恢复记录,与多轮对话的成功历史有不同生命周期。M-Agent 用 Run Store 与 Session Store 分开表达,不再以 Memory 同时指代二者;长期画像或语义记忆由外部 Context Provider / Tool 拥有。

公开接口需要迁移,但“继续聊天”“恢复工具调用”“检索长期知识”不再共享一个含糊抽象。0018

ADR-0019:创建 Run 前冻结会话输入

SessionRunner 先读取带版本的 Session Snapshot,转换成不可变 Conversation History,再交给 Core 创建 Run。Core 保存这份输入,不认识也不重新查询 Session Store。

长时间执行看不到后来新增的消息,Companion 还要处理执行结束后的历史提交;但同一 Run 中断前后不会忽然换一份对话背景,也保持了 Companion 到 Core 的单向依赖。0019

ADR-0020:同一 Session 先只允许一个非终态 Run

两个 Run 同时基于一份历史生成回复,可能竞争追加并打乱顺序。Session Store 因而原子建立持久化 Claim,同一会话最多一个 CREATED、RUNNING 或 WAITING Run;不同会话仍可并发。

Claim 不靠固定 TTL 自动释放,而与 Run Store 的权威状态对账。这限制了同会话并行能力,也增加跨 Store 对账成本,却避免等待审批的 Run 因超时丢掉占用。将来需要并行,应引入显式会话分支,而不是悄悄覆盖消息。0020

ADR-0021:只提交成功 Run 的最终 Turn

Run 权威进入 SUCCEEDED 后,SessionRunner 才用冻结历史版本与 run_id 追加不可变 Turn;Session Store 原子做版本比较、按 Run 去重与清除 Claim。失败、拒绝、取消只清占用;WAITING 既不提交,也不释放。

Core 已成功而 Session 提交 pending / conflict 是需要承认的中间状态,不用跨库事务假装它不存在。幂等对账避免重复 Turn,中间模型响应、上下文与工具结果仍留在 Run Store,从而减少会话中的冗余和敏感信息传播。0021

七、定义、模型与输出必须能精确追溯

ADR-0022:定义不可变,修改必须升版

同一次执行不能在重启前后使用不同的指令、工具和策略。因此 Definition 有稳定 ID 与不可变版本,Run 冻结执行声明,变更只影响后续 Run。

应用要保留仍可能恢复的旧定义,这是明确的维护成本。还有一处措辞差异需要保留:ADR-0022 与 CONTEXT 的 Snapshot 定义写“首次启动时”冻结,当前 create_run() 实现已在创建时冻结;ADR-0019 的会话输入也明确在创建前准备。这里的设计意图是“执行前冻结且恢复不漂移”,具体冻结时点按技术页说明,不把两个说法写成完全一致。0022

ADR-0023:Snapshot 保存数据,Registry 提供代码

把 Python callable 存进数据库会引入代码反序列化与版本加载问题;只保存一个“最新定义”名称又会漂移。因此 Store 保存快照与能力标识,应用在 Registry 中按 definition_id + version 精确注册可执行实现。

原版本不可用就进入原因明确的 WAITING,等待补回或结束,不自动回退最新版。应用承担旧代码保留,换来恢复语义与代码装载边界都明确。0023

ADR-0030:能力是实例契约,不是一个模糊布尔值

一个 Adapter 类支持 tool calling,不等于每个目标端点都支持 streaming 与 tool calling 的组合。具体实例必须声明 Model Contract 的能力模式、组合、Limits、Sizer 和 usage 字段保证;Definition 声明 Requirements,注册时校验匹配。

缺能力不能静默关闭,缺 usage 不能伪造,prompt JSON 不能冒充原生结构化输出。允许的 fallback 必须预先声明。这增加实例级配置与版本管理,却让供应商协议变化和能力不兼容成为可检查的失败。0030

ADR-0031:输出结构属于 Definition 版本

如果调用方每次临时换 Schema,恢复、模型能力校验与 Eval 就没有稳定的输出语义。因此 Output Contract 包含 Schema、验证规则与允许的 fallback,并随定义版本冻结。

通用 Agent 动态切换任意返回结构不再那么方便,但输出变化有明确版本归属,不会在同一次执行中途改变合格标准。0031

ADR-0032:修复输出是新步骤,不是改写旧结果

模型已经完整返回,只是未通过业务结构验证,这与“原请求因网络错误重试”不同。无效完整响应仍被保存;允许修复时,结构化验证错误进入新的 Output Repair Model Step,并受次数上限约束。

这保留了真实推理与费用轨迹,代价是更多步骤与结果。修复耗尽明确失败,无效输出不写入 Session Turn,而不是覆盖原响应后假装第一次就正确。0032

ADR-0041:把硬契约、运行前偏好和经验质量拆开

这条决策把前面的模型边界连接成完整选择协议。Contract 描述可静态校验的语义,Requirements 描述正确运行的最低条件,Evidence 描述经验表现,Routing Policy 描述应用偏好。 长上下文要用容量表示;“JSON 很可靠”、延迟或工具成功率必须来自证据,不能由 Adapter 自评成硬能力。

Contract 保存稳定身份、版本、能力与序列化指纹,并区分 PINNED 与 PROVIDER_ALIAS。冻结本地契约不等于远端 alias 的模型权重永不变化。usage 按字段区分 REQUIRED、OPTIONAL、UNSUPPORTED:缺必需字段或协议无法归一化是契约违约;成功归一化后不符合业务 Schema 则是输出验证失败。两类错误必须分开统计,不能都压成“JSON 不可靠”。

路由只在 Run 创建前进行。 Catalog 精确引用已经注册的完整 Agent Variant;实例契约是 Adapter 协议上限与目标配置的交集。自定义端点由应用提供事实,注册或路由不隐藏发请求探测。部署地域等硬约束只能引用有效证据,未知不能被默认为合规;凭据、敏感端点与正文也不进入 Catalog、Decision 或 Snapshot。

Router 先按能力、容量、部署条件、证据时效与 hard Eval gate 过滤,再按显式方向、缺失值规则和有效期做字典序排序,最后用稳定身份破除并列,不用隐式加权总分。A/B 或随机流量桶由应用先决定。完整 Routing Decision 保存在独立 Routing Store,Core 只关联标识与摘要;Router 不需要读取原始 Prompt 或敏感历史。

失败也必须可解释:SELECTED、NO_COMPATIBLE_VARIANT、POLICY_UNSATISFIED、EVIDENCE_UNAVAILABLE、CATALOG_CONFLICT、INVALID_POLICY 分别表示选择成功或不同缺口。失败发生在 Session Claim / Run 创建前,零模型 dispatch;只能补证据或显式改用另一版策略,不偷放宽条件。

成本分三层。 Core 约束完整上下文、最大输出与持久化 Model Execution Budget,Run 与用途两级 Attempt 配额在调用前原子预留,失败或不确定仍消费,恢复不退款。Companion 用带版本价格快照做运行前估算和筛选,硬成本条件缺证据就拒绝;账户余额、周期配额与跨 Run 预占由应用或外部服务负责。usage 不可靠时只保留估算范围,不制造精确账单。

PRIMARY、CONTEXT_COMPRESSION、OUTPUT_REPAIR 分别冻结 binding;复用 PRIMARY 也必须显式声明,不能执行到某一步才临时选模。运行中只按冻结策略重试同一契约;确需换模型时,由应用创建关联的 Replacement Run,不继承原 Run 身份和 Checkpoint。动态 RPM、TPM、并发与余额属于 Operational Limits Snapshot,限流仍是原契约下的瞬时失败,不倒推为模型能力缺失。

Availability 来自应用或只读探针,Router 不主动做隐藏健康请求;过期硬证据拒绝,软偏好可以明确警告。Eval 产生 Recommendation 也不能自动改 Catalog、Policy 或 Definition,必须经应用显式批准成新版本。Contract、Definition / Variant、Policy 与价格、可用性、评估等快照分别升版,历史决策不可覆盖。

代价是配置、快照和版本管理明显增加,也没有 Run 内透明故障切换。0.3 因而一次性重置旧能力接口,保守迁移 helper 不能推断缺失声明,0.5 再补路由闭环。收益是价格偏好不污染 Agent 语义,恢复不随路由变化,Eval 不成为生产隐式依赖。负载均衡、熔断、自适应路由、托管 Gateway、账户计费与建议自动采纳都不属于这条官方边界。0041

八、扩展有位置,但不获得 Core 的控制权

M-Agent 四层公共 API 的依赖方向
Runtime Core 不反向导入 Adapter、Companion 或 Testing

CONTEXT.md 区分 Runtime Adapter 与 Runtime Companion:前者实现单个 Core 契约,后者围绕稳定运行时组合更高层能力。Testing 验证这些边界,不能成为 Core 执行的前置依赖。这四层关系让 Runtime Foundation 不必随着每种应用需求扩张。

ADR-0028:Workflow 与 Multi-Agent 是上层组合

多个 Agent 顺序或协作完成任务,不需要在 Core 再造一个隐含执行引擎。Workflow 是应用对步骤或 Run 的编排,Multi-Agent 是其中一种模式,每个参与者仍产生独立可恢复 Run。

旧接口需要迁移到组合或示例位置,核心功能名减少;但复杂编排不会绕过每次执行自己的状态、恢复与观察边界。0028

ADR-0029:Eval 可维护,但不得改写被评估对象

Eval 作为 Runtime Companion 保留两种入口:EXECUTE 启动隔离的受控 Run,OBSERVE 只读应用明确选定的已有 Run。它们归一化为不可变 Observation,再通过授权、最小化 Projection 与版本化 Evidence Adapter 交给 Evaluator。

Eval Execution、不可变 Report revision 和显式 Baseline 位于独立 Eval Store,不修改生产 Run / Session。外部证据缺失不能当作“外部效果不存在”。质量、成本和延迟分别表达,默认发布门槛依赖确定性的 hard / safety evaluator,不用一个总分覆盖安全失败。

LLM-as-judge 必须是专用 Eval Store 中独立、版本化、无业务工具和写能力的 Judge Run,只接收最小脱敏资料,也不能推翻 required deterministic 或 safety failure。更多存储、授权与版本管理是代价,防止评估变成生产副作用入口、数据权限旁路或不可复现比较是收益。0029

ADR-0034:本地内容是受限的只读组合能力

文件读取与搜索由 Local Content Adapter Companion 提供,Core 只认识 Tool 契约,不隐含文件系统权限。Project Root 限定访问范围,Project Content 只包括允许的普通文件;符号链接不是可读取内容。

不内置写文件、Shell 或任意代码执行,限制了开箱即用的操作能力,却避免一个通用运行库默默获得高风险本地权限。这个名字中虽有 Adapter,领域文档仍将它归为 Companion,不能只按命名判断归属。0034

ADR-0035:观测接标准接口,不建观测平台

Telemetry Sink 发出关联 Run、Step、Attempt 的时间、状态、错误码与可用 usage,默认不含正文。可选 OpenTelemetry Adapter 做标准映射,本地 JSONL 适配仍可保留。

应用选择 exporter 和观测系统,Core 不强依赖 SDK、不自建 Dashboard。多一个接入层的成本换来轻量嵌入与标准兼容;本地 exporter 检查也不能冒充真实 Collector 或生产观测验收。0035

九、分发与数据保护同样是设计

ADR-0033:能恢复,不等于应该明文保存一切

恢复需要完整输入、模型内容与工具结果,查询运行状态却不应总要暴露这些正文。Run Metadata 与受保护 Payload 因而分开,Payload 经应用显式配置的 Codec 持久化。

明文 Codec 只用于开发测试,不提供保密性;凭据只由 Adapter 从外部配置读取,不进入 Snapshot 或 Payload。应用承担实际保护方案,Runtime 不伪装成通用 Secret Store。这增加配置成本,却让恢复能力和内容访问边界可以同时成立。0033

ADR-0037:最低 Python 3.11

项目选择现代异步、类型与异常处理能力,接受放弃 Python 3.9 / 3.10 的安装范围。代价是部分环境必须升级,收益是核心正确性不长期背负旧版本兼容分支。ADR 声明的 CI 与支持矩阵是需要测试兑现的承诺,不是本文新产生的平台验收结果。0037

ADR-0038:小型强类型核心,不追求零依赖

公开 Schema、参数和结构化输出需要可靠验证,Core 因而使用 Pydantic,而不是为“零依赖”继续手写薄弱的数据检查。provider、storage、security、telemetry 等接入按可选边界组织,不向 Core 引入 Web 框架、数据库服务客户端或其他 Agent / RAG 框架。

extras 是能力与依赖选择边界,不意味着每一项都必须新增第三方依赖;当前 SQLite / JSONL 可用标准库实现,实际 SDK-backed exporter 仍归应用集成。依赖管理更明确但也更复杂,换来的是公开契约的验证强度与可控安装面。0038

ADR-0039:把开源发布作为明确的项目决定

项目选择 Apache License 2.0,并配套 LICENSE、必要的 NOTICE、贡献与安全报告方式,而不只把源码设为公开。ADR 给出的理由是让使用、修改、分发、贡献及专利授权安排有明确依据。

对应代价是持续维护发布材料与流程。这里记录项目的选择理由,不把许可证名称当作业务合规认证,也不替具体集成作法律判断。0039

十、最后决定怎样证明这些承诺

ADR-0042:参考验收包取代不断膨胀的巨型示例

单个客服示例不能承担 Session、Context、Routing 与 Eval 的全部证明。因此参考验收采用版本化多场景 Pack:core-lifecycle、durable-effects-recovery、session-conversation、context-budget-compression、model-routing、eval-regression 各自隔离执行,共享 Harness、冻结 Manifest、Coverage Matrix 与报告。Durable Support Agent 保留为恢复与副作用示例,不再不断吸收其他责任。

先固定要证明什么,再执行。 每条稳定契约映射 owner、公开入口、正负检查、权威与独立证据、required 层级及 non-claim;缺映射即不完整,覆盖率不代替通过。每个场景还要有受控变异使目标检查失败,否则应怀疑 Harness。恢复故障通过外部边界的持久 sentinel 与真实进程退出制造,required 窗口重复三次;随机 kill 只能补充压力观察。

证据分层,不能互相升级。 CONTRACT 是离线确定性公共契约;HOST 是干净环境安装本次 wheel 后的真实进程与存储运行;PROVIDER 是显式授权、带时效的具体端点合同;FIELD 是应用团队的真实部署。单项只有 PASS、FAIL、ERROR、NOT_RUN、INCONCLUSIVE,optional 成功不能覆盖 required 缺口。Harness 错误保留为 Pack ERROR,上层发布汇总即使判为 FAILED,也不能改写子证据。

发行物身份必须相同。 0.3、0.4、0.5 逐步增加场景,但每次重跑此前 required 集合;最终六场景绑定同一候选 wheel、Manifest、环境与 execution。不同候选结果不能拼接,正式修复在新候选完整重跑。HOST 记录源码、dirty state、构建工具和制品摘要,在仓库外干净环境安装,不用 editable 或源码路径冒充发行物。dirty checkout 只能产生开发证据;平台范围明确限定 Linux 与指定 macOS 次级验证,Windows 不被暗示为已支持。

证据包也需要边界。 每个 Scenario 产生不可变、内容寻址、最小脱敏 Bundle,JSON 为权威数据,Markdown 为呈现。Eval 只消费公开视图,不读前序场景私有数据库;证据丢失、过期或摘要不匹配不能视为没有问题。报告写入失败也不能改写被测状态。官方离线 Evidence Adapter 只提供 journal、snapshot file 与 sentinel,业务系统的真实取证留在 FIELD。

安全与观测是横向必需项。 Telemetry 与权威 inspection 对账,但不获得恢复权威。凭据隔离、测试加密 Codec、Scope、Instruction / Data、Eval 只读和发行物完整性都需要检查;它们不构成业务合规、模型免疫注入或供应链等级认证。OpenTelemetry 的本地契约测试不能替代真实 Collector。

性能与真实端点各自取证。 benchmark 先验证 Run、步骤、效果与数据库完整性,再输出环境限定的吞吐、延迟和持久化开销,只比较兼容 baseline,不合成通用 QPS 或 SLA。live Adapter 的协议与能力变更必须重跑受影响端点;无关变更只能复用指纹匹配且不超过 ADR 所定 30 天的证据,过期、alias 或供应商变化要显式标记。未授权、缺凭据、额度、供应商故障、契约失败与 Harness 错误分别报告,不能都写成跳过。

验收工具也不能渗入 Core。 Pack 属于同一 distribution 的 Testing 层,薄 CLI 默认离线,live 用独立显式授权入口。恢复只续未完成场景,半成品 Scenario 重跑。里程碑还要求对当前工作区全视图与实际 wheel 做独立 Standards / Spec 审查和公开入口探针;另一工作树的证据不能直接移植。

最终演示只是这些证据的受限呈现:先讲四层边界,再展示 durable recovery、Context 预算、路由失败与 Eval hard gate;已有完整候选证据才现场演示,失败时诚实切换到已生成的不可变证据,不使用 live 凭据。代价是 Manifest、场景编排和证据治理明显变重;收益是不让单一成功路径、绿色测试数量或现场效果替代真正的发布判断。0042

这些抉择最终形成什么

从产品定位往下推,M-Agent 得到的不是一个无所不包的 Agent 平台,而是一组相互约束的协议:Run 拥有单次执行事实,Store 保存确认结果,应用拥有外部决策;上下文与会话保留各自来源,模型契约不受临时路由偏好改写,评估和观测没有生产写权限,发布结论受发行物与证据范围约束。

统一的代价是显式配置、更多状态、更多版本和更多检查。统一的收益是:出问题时,应用能够回答“这是谁的状态,哪份事实可信,谁有权继续,以及这个结论究竟被证明到了哪里”。

本文是设计文件的解释,不是 42 条决策的实现合规证明;本次未运行上游验收。API 时序、历史措辞与实现若存在差异,应单独记录并核对,不用一句“源码优先”悄悄覆盖契约。设计如何落到代码继续见技术页,项目为何走到这些选择见迭代记录。

参考资料

  1. ADR-0001 · Agent Application Runtime 边界。 ↩

  2. ADR-0036 · Runtime Integrator。 ↩

  3. ADR-0009 · 异步嵌入式 Runner。 ↩

  4. ADR-0002 · Run 生命周期归属。 ↩

  5. ADR-0004 · 模型与单工具的 Step 粒度。 ↩

  6. ADR-0006 · Run Store 与 Trace 分离。 ↩

  7. ADR-0005 · 已被 ADR-0027 替代的六状态模型。 ↩

  8. ADR-0027 · 拒绝不同于失败。 ↩

  9. ADR-0003 · at-least-once 恢复。 ↩

  10. ADR-0007 · 工具默认非幂等。 ↩

  11. ADR-0008 · 应用拥有副作用处置权。 ↩

  12. ADR-0012 · 协作式取消。 ↩

  13. ADR-0013 · Lease 与版本控制。 ↩

  14. ADR-0024 · 显式 Tool Outcome。 ↩

  15. ADR-0025 · 显式 Retry Policy。 ↩

  16. ADR-0026 · 确定性 Run Policy。 ↩

  17. ADR-0010 · Run Update 与 Trace 分离。 ↩

  18. ADR-0011 · 完整响应 Checkpoint。 ↩

  19. ADR-0014 · 通用 Context Provider。 ↩

  20. ADR-0015 · Context Stage invocation。 ↩

  21. ADR-0016 · 结构化 Context Item。 ↩

  22. ADR-0017 · 外部上下文是数据。 ↩

  23. ADR-0040 · Context 预算与压缩。 ↩

  24. ADR-0018 · 独立 Session Store。 ↩

  25. ADR-0019 · 冻结会话输入。 ↩

  26. ADR-0020 · Session 单活跃 Run。 ↩

  27. ADR-0021 · 只提交成功 Turn。 ↩

  28. ADR-0022 · 不可变版本化定义。 ↩

  29. ADR-0023 · 精确解析定义实现。 ↩

  30. ADR-0030 · 显式模型能力。 ↩

  31. ADR-0031 · 版本化 Output Contract。 ↩

  32. ADR-0032 · Output Repair 是新步骤。 ↩

  33. ADR-0041 · 模型契约与运行前路由。 ↩

  34. ADR-0028 · Workflow / Multi-Agent 组合。 ↩

  35. ADR-0029 · 隔离 Eval Companion。 ↩

  36. ADR-0034 · Local Content Companion。 ↩

  37. ADR-0035 · Telemetry Sink 与 OTel。 ↩

  38. ADR-0033 · 受保护 Payload 分离。 ↩

  39. ADR-0037 · Python 3.11 起点。 ↩

  40. ADR-0038 · 强类型核心与 extras。 ↩

  41. ADR-0039 · 开源发布选择。 ↩

  42. ADR-0042 · 多场景参考验收包。 ↩