首页
/ LobeHub Agent Chaos 实验管理:Fixture 契约、安全护栏与故障注入机制

LobeHub Agent Chaos 实验管理:Fixture 契约、安全护栏与故障注入机制

2026-09-05 23:14:01作者:滕妙奇

LobeHub 将混沌工程(Chaos Engineering)应用到 Agent 系统的可靠性验证中:应用专属的故障实验 Fixture 统一存放于 .agents/chaos/ 目录,由 @achaos/* 混沌基础设施包负责解析与执行。本文基于该目录的官方说明,结合 Fixture Schema 定义Runner 执行引擎 与三个真实 Fixture 示例,完整讲解混沌实验契约的每个字段、安全策略的生产级护栏,以及"概率性故障发现 → 确定性回归 Fixture"的沉淀流程,帮助读者理解如何在 Agent 编排系统中安全地注入并验证故障。

.agents/chaos 目录:应用专属实验 Fixture 的存放地

.agents/chaos/README.md 给出了该目录的核心约定:所有应用专属的实验 Fixture 都存放在这里(Application-specific experiment fixtures live here),每个 Fixture 必须满足一组强制性声明要求:

强制项 含义
环境允许清单(environment allowlist) Fixture 只能在声明的环境中运行,如 testci
确定性种子(deterministic seed) 用固定 seed 驱动可复现的伪随机序列
有界超时(bounded timeout) timeoutMs 必须为正整数,保证实验不会无限挂起
目标适配器(target adapter) 声明故障注入通过哪个适配器、命中哪个选择器
故障效应(effect) 声明注入什么类型的故障(抛错、延迟、重复等)
至少一个独立 Oracle 独立于被测系统自身的判定器,用于评估实验结果

同时该文档划定了生产环境的边界:生产环境要求外部审批策略(external approval policy),且可移植 Runner(portable runner)不会默认启用生产注入。这与 Runner 源码 中的设计一致:RunChaosExperimentOptions 提供了 approveProduction 回调与 environmentTier 主机分类字段,且注释明确"未知环境名默认按生产安全策略处理"(Unknown environment names default to production-safe handling)。

从源码结构看,Runner 在执行前会先用 chaosExperimentSchema.safeParse 对实验做严格校验(run.ts#L98-L115),任何不满足契约的 Fixture 会被标记为 ChaosConfigError 并直接以 aborted 状态终止——这就是"每个 Fixture 必须声明上述字段"在工程上的强制执行点。

Fixture 契约全解:字段、取值范围与默认值

Schema 定义 使用 zod 的 .strict() 构建,即不允许出现任何未声明的字段。以下是完整契约:

字段 类型与约束 说明
id 字符串,匹配 ^[a-z0-9]+(?:-[a-z0-9]+)*$ 小写 kebab-case 实验标识,如 tool-failure
description 非空字符串 实验的一句话描述
layer 枚举 L0-infra / L1-model-runtime / L2-agent-runtime / L3-orchestration / L4-business-logic / L5-human-trust 故障注入所属的抽象层级
discoveredFrom 可选字符串 实验来源(事故、评估发现或显式假设),详见下文"来源沉淀"
seed 非空字符串 确定性随机种子,Runner 用它初始化 createSeededRandomrun.ts#L120
timeoutMs 正整数 整个实验的有界超时
cleanup 枚举 always / on_success / never,默认 always 清理策略,保证注入不残留
safety 对象,必含非空 allowedEnvironments;可选 destructive 布尔、maxInjections 正整数 安全策略
target 对象:adapter(非空字符串)+ selector(记录) 故障目标定位
trigger 对象:when 枚举 immediate / before / after,可选 probability(0–1) 注入时机与概率
effect 判别联合,见下表 故障效应本体
oracles 至少 1 个元素;每项含 name、可选 paramstimeoutMs 独立判定器规格
tags 可选字符串数组 分组标签

六种故障效应(effect)

effect 契约 是一个以 type 为判别键的 strict 联合类型:

  • delay:需 durationMs(非负整数),注入延迟;
  • duplicate:需 count最小 2,即重复至少两次),用于验证消费端幂等性;
  • drop:无参数,直接丢弃(如工具调用、完成消息);
  • throw:需非空 errorType,可选 message,模拟提供商风格的类型化错误;
  • replace_result:需 content 字符串,替换执行结果(如返回不完整或矛盾的验收证据);
  • kill_process:可选 signal: 'SIGKILL',进程级破坏性注入。

Agent Runtime 钩子 中可以看到效应如何落到真实调用链上:executeToolAttemptWithChaos 包裹每次 executeToolWithRetry 尝试,命中 delay 时挂起、命中 drop 时返回 ChaosDroppedToolCallkind: 'retry',让真实重试策略接管)、命中 throw 时返回带指定 errorType 的失败尝试——故障被设计为"可重试的类型化失败"而非进程崩溃,从而真正演练系统的重试与降级逻辑。

三个真实 Fixture:分层注入示例

.agents/chaos/fixtures/ 下按层级目录组织,现存三个代表性 Fixture,恰好覆盖 L1/L2/L3 三层:

L1 模型运行时:工具故障与重试

tool-failure.yaml 让选定的 search 工具在 tool_attempt 阶段确定性收到一次 RateLimited 风格故障:

id: tool-failure
layer: L1-model-runtime
seed: tool-failure-v1
timeoutMs: 5000
cleanup: always
safety:
  allowedEnvironments: [test, ci]   # 环境允许清单
  maxInjections: 1                    # 单次运行最多注入 1 次
target:
  adapter: runtime
  selector:
    apiName: search
    phase: tool_attempt
trigger:
  when: before
  probability: 1                      # 确定性触发(概率固定为 1)
effect:
  type: throw
  errorType: RateLimited
oracles:
  - name: tool-failure-observed
    timeoutMs: 1000

注意 probability: 1seed 的组合:Fixture 虽允许概率触发(probability 取值 0–1),但沉淀下来的回归 Fixture 通过固定种子和概率 1 保证每次运行行为一致。

L2 Agent 运行时:过期操作回收

operation-reclaim.yaml 针对"运行中的操作租约(lease)过期后,旧尝试不能被复活、必须由替换尝试接管"的不变量,通过 state 适配器对 operationStatus: running 的状态做 delay(300 秒)注入,Oracle operation-reclaimed 在 5 秒窗口内验证回收发生。

L3 编排层:完成消息重复投递

duplicate-completion.yamlduplicate 效应(count: 2)把同一完成消息投递两次,Oracle completion-idempotent 验证消费端幂等。

这三个示例与 [Fixture 契约] 的强制项一一对应:各自声明了 allowedEnvironments: [test, ci]maxInjections: 1、确定性 seed、有界 timeoutMstarget 适配器与至少一个 Oracle。

安全护栏:环境允许清单与生产审批

安全边界在三层实现:

  1. Fixture 声明层safety.allowedEnvironments 必填且非空;maxInjections 限制单次运行的注入次数;破坏性效应可通过 destructive: true 显式标注。
  2. Runner 执行层runChaosExperiment 接收 environment 实际环境名并比对允许清单;生产环境注入必须经过 approveProduction 审批回调。Runner 源码中 environmentTier 注释表明未知环境名按生产安全策略兜底——即"默认拒绝"原则。
  3. 组织流程层.agents/chaos/README.md 明确"生产环境要求外部审批策略,且不被可移植 Runner 启用",即审批是仓库外的独立策略,而非 Runner 内建开关。

配套的 cleanup 策略(默认 always)与 适配器契约 进一步保证注入可回滚:ChaosAdapter 可选实现 cancelInjectioncleanup,保证未完成的注入不会在超时后"迟到生效"。

故障来源(Provenance)与"概率发现 → 确定性 Fixture"生命周期

.agents/chaos/README.md 的后半段定义了 Fixture 的来源与沉淀规则,这是混沌体系从"一次性实验"变成"回归资产"的关键:

  • 来源(provenance) 有三类:事故(通过 discoveredFrom 字段追溯)、评估发现(evaluation finding)、或显式假设。对照真实 Fixture 可见:tool-failure 标注 discoveredFrom: first-phase reference scenario(显式假设),而 operation-reclaim 标注 discoveredFrom: Goal runtime resilience canary incident(事故沉淀)。
  • 沉淀规则:"一旦概率性运行发现故障,必须保留其种子(seed),并将其归约(reduce)为稳定 Fixture"。即:概率触发用于发现,确定性 Fixture 用于回归——这与 Goal 集成文档 末尾的表述一致:"A discovered probabilistic failure becomes a reduced deterministic fixture before it is accepted as regression coverage",且每个 campaign 必须保留种子、结果 JSON、trace id、基线修订与候选修订。

执行管线:从 Fixture 加载到 Oracle 裁决

Runner 包 提供 loadChaosExperiments(校验式加载)、ChaosRegistry(适配器/Oracle 注册表)与 runChaosExperiment(确定性生命周期执行)。结合 Runner 实现核心类型,一次实验运行遵循固定时间线:

run_startedsteady_state_checkedfault_injectedsystem_exercisedoracle_evaluatedcleanup_startedcleanup_completedrun_completed

每个阶段受 timeoutMs 约束(内部通过 Promise.race + AbortController 强制超时并中止,见 run.ts#L41-L65)。最终产出 ChaosRunResult(状态为 passed / failed / inconclusive / aborted),其中包含完整 timeline、Oracle 结果、注入回执(injection receipt,含 injectionIdadapterdetails)与种子。Reporter 提供 writeChaosResult / formatChaosResult 将其落盘或格式化,供后续作为验收证据(Acceptance evidence)引用。

随机性由 createSeededRandom 基于 experiment.seed 生成并注入 ChaosRunContext.random,这是"同一 Fixture 多次运行可复现"的实现基础。

应用侧集成边界:机制与业务模型分离

packages/achaos/README.md 划定了清晰的分层原则:包代码只包含机制,不包含 LobeHub 业务模型(package code contains mechanisms, not LobeHub business models);应用事故与 Fixture 归属 .agents/chaos@achaos/* 命名空间包含:

  • @achaos/core — 实验、效应、安全、Oracle、回执与结果的可移植契约;
  • @achaos/runner — 校验式 Fixture 加载与确定性生命周期执行;
  • @achaos/runtime — Agent Runtime 钩子与完成投递适配器(即上文 executeToolAttemptWithChaos 所在处);
  • @achaos/database — 与 schema 无关的变更与回滚端口;
  • @achaos/process — 带所有权校验的破坏性进程注入;
  • @achaos/testing — 确定性测试目标与场景辅助。

这一边界由 Goal 集成规范 反向确认:Goal 通过应用自有适配器消费 Agent Chaos,@achaos/* 不得反向导入 Goal、Task、Drizzle schema、QStash 或服务器服务。具体集成代码放在 apps/server/src/services/goal/__chaos__/,测试装配流程为:在 getTestDB() 中构造真实 Goal Graph / Work Task / Topic / Agent Operation → 注册 createRuntimeChaosHooks(controller) 做 preflight 结果替换/丢弃故障 → 注册 @achaos/database 端口做作用域化 lease/state 变更 → 用生产动作(如 GoalService.tick)驱动实验 → 用应用自有 Oracle 评估持久化状态,绝不把构建器 Agent 的文本输出当作证明 → 将 ChaosRunResult JSON 与 trace 事件附到 Acceptance evidence。

分层与 CI 梯队

layer 字段对应的 L0–L5 六层模型(ChaosLayer 类型)把故障定位到从基础设施到人类信任的抽象高度,而 goal-integration.md 定义了与之配套的 CI 梯队:

  • PR 级:确定性进程内 + PGlite/Postgres campaign;不做真实进程杀死或网络故障;
  • Nightly 级:服务器重启、QStash 重复/乱序、异构 Agent 与真实子进程 kill;
  • Canary 级:允许清单内的非破坏性实验,配 kill switch 与严格爆炸半径;
  • Production 级:在独立审批策略存在之前,仅做观测与 trace 采集。

小结

LobeHub 的 Agent Chaos 体系可以概括为三条设计主线:

  1. 契约先行:Fixture 是 strict schema 校验的 YAML 声明,环境清单、种子、超时、适配器、效应、Oracle 六项强制声明缺一不可,生产注入被 Runner 默认拒绝并要求外部审批;
  2. 机制与业务分离@achaos/* 只提供可移植的注入/判定机制,应用事故知识全部沉淀在 .agents/chaos 的 Fixture 与集成规范中;
  3. 概率发现、确定性回归discoveredFrom + seed 构成故障溯源链,概率性发现必须归约为固定种子的稳定 Fixture 才能进入回归覆盖,且每个 campaign 需保留种子、结果 JSON、trace id 与代码修订基线。

这套机制让"Agent 在故障下是否保持安全(safety)、存活(liveness)、一致(consistency)"从口头承诺变成了可执行、可复现、可审计的持续验证。

登录后查看全文
热门项目推荐
相关项目推荐