一个 SRE Oncall Triage Harness:agent 自主调查,mutation 主权归人

英文版:English

Why

一次 oncall 调查里,主 agent 真正要做的是判断:这是不是假警报、根因在哪、下一步查什么、要不要升级。判断需要一个清醒的 context 窗口。可是一次 raw range query 回来可能就是 30K token,一段日志更多。如果主 agent 自己去拉这些数据,等它走到需要下关键判断的阶段,context 已经被原始数字淹没,判断力也被榨干了。

这就是全系统建立其上的第一性约束:context 是稀缺的 RAM,不是无限的硬盘。谁占用它,谁就该为占用付出代价。由此直接推出一条铁律,主 agent 只保留导航、判断、命令生成,一切原始数据获取下沉给 subagent,只回收 ≤500 token 的结构化摘要。这不是优化,是架构约束。

我构建这个 harness,就是要在真实 oncall 负载下守住这条线。下面的设计,全是这一条约束的推论链。

设计:四个控制原语,不是角色拟物

多数「多 agent」框架在做角色扮演:PM agent、工程师 agent、QA agent。这是拟物,把人类组织架构照搬给 agent,看着直观,实则没有工程意义。真正有意义的是四个控制原语:

flowchart TD SPEC["SPEC · 声明式意图<br/>持久文件写明期望终态<br/>必须含机器可检的验收标准<br/>可 diff · 可 review · context 压缩后可恢复"] LOOP["LOOP · 收敛循环<br/>观察现状 → 比对 Spec → 行动 → 验证<br/>验收标准越紧, loop 越能自治"] HOOK["HOOK · 准入控制<br/>audit 记证据 / deny 硬阻断 / HITL 等人批准<br/>红队审查也是 hook"] FORK["FORK · 上下文隔离<br/>为隔离而 fork, 不为角色扮演<br/>隔离收益 > briefing + merge 成本才 fork"] SPEC -- "定义收敛目标" --> LOOP HOOK -. "插在 loop 的关键节点" .-> LOOP LOOP -- "需要隔离时派生" --> FORK FORK -- "结果合并回主 loop" --> LOOP LOOP -- "验收全过 → 终态" --> DONE(("✓"))

三条设计决策承担了大部分工作。

Subagent Isolation。 主 agent 继承最强的模型,只做判断;VictoriaMetrics/Loki 的 raw query 和 Slack 读取分派给 subagent,只回收 ≤500 token,一个带时间戳的极值、一个 step jump 标记、一个 baseline 比值。这是 Fork 的 capacity-bound 与 attention-bound 理由的具体形态:把一次 30K token 的查询隔离进一个干净窗口,主 context 永远看不到它。反模式是主 agent 自己跑查询,拿回 200 个数据点,走到决策阶段时已经 token-exhausted。

Phase Lock。 Karpathy 观察过一种典型 agent 失败:看到 deploy 记录就脑补根因,症状还没看清就被「最近改过什么」带跑。我用一个状态机把这个失败模式设计掉。plan 文件顶部的 phase: 字段物理限制主 agent 当前能读什么:Phase A 时它根本读不到 deploy history,也就无从脑补。进入下一阶段的门是显式前置条件,不是提醒。

stateDiagram-v2 [*] --> A : plan.md 写入 phase A A : Phase A · 调查者 A : OK debug-trees / patterns / references, MCP read-only A : NO runbooks 源 / cases 全文 / deploy history B : Phase B · 决策者 B : OK 解锁 cases 全文 / deploy history / runbook README B : NO runbook 命令体 (.sh / .yaml) C : Phase C · 操作员 C : OK 解锁 runbook 全部内容, 生成 INTENT 命令草稿 C : 仍受 Mutation Approval Gate A --> B : root_cause_hypothesis 非空 且 >=1 条假设验证 B --> C : 用户显式确认根因 C --> [*] : 命令生成 后 等 approve

红线。 模型会幻觉。这是前提,不是缺陷,所以系统安全性绝不能建立在「模型会自觉遵守约束」之上。判断(是不是假警报、根因在哪)交给模型。一切不可逆操作(删除、scale、drain、IAM 变更)交给确定性的 shell hook 硬阻断,agent 再怎么幻觉也绕不过一个 exit 2。这条红线把「安全」从「希望模型别犯错」变成「模型犯错也没关系」。

一条可迁移的直觉:这就是 Kubernetes 控制平面

对 SRE 来说这套东西并不新,它就是把 Kubernetes 控制平面思想搬进 agent。Spec 是期望状态 manifest;Loop 是 controller 的 reconcile loop;Hook 是 admission webhook;Fork 是 pod 级隔离加一个独立审计者。底下的命题是:我们不是用 AI 取代 SRE,而是用几十年沉淀的可靠性工程,去约束和运营一个不确定的推理内核。

真正落地的安全

一条 mutating 命令要真正落地,必须闯过四关,任何一关拦下都到不了生产:

flowchart TD GEN["主 agent 生成命令 (Phase C)<br/># INTENT: 中文意图<br/>scale deploy ... (泛化, 不带集群 context)"] --> U{"关 1 · Skill 层<br/>用户显式 approve?"} U -- "无 approval" --> STAY["命令留在 report.md · 零自动执行"] U -- "approve / 执行 / go" --> PERM{"关 2 · settings.json permissions"} PERM -- "deny 名单命中" --> D1["拒绝"] PERM -- "allow / ask 通过" --> GATE{"关 3 · k8s-gate.sh (PreToolUse hook)"} GATE -- "硬阻断名单 或 PROD+mutating" --> D2["exit 2 · 打印命令给人手动跑"] GATE -- "放行 (DEV / dry-run / 读操作)" --> PRE["audit-pre.sh 记 phase=pre + INTENT"] PRE --> RUN["Bash 实际执行"] RUN --> POST["audit-log.sh 记 phase=post 结果"] POST --> VF{"关 4 · 强制验证<br/>rollout status / get / helm status"} VF -- "验证失败或含糊" --> HALT["停下报告, 不继续变更"] VF -- "验证通过" --> OK["完成"]

关 1 是 skill 层:没有 approval,命令就留在 report 里。关 2 是静态 allow/deny 名单,最快但最粗。关 3 是确定性执行者:6 个 shell hook,理解「集群 alias → 环境分级」并 fail-closed,未分类的 alias 一律按生产处理。这是模型绕不过的那一层,也是红线真正的执行者。关 4 是强制的事后验证。其中两个 hook 甚至嵌套第二次模型调用(claude -p),在批准那一刻审查当前模型的计划,AI 审 AI,恰好把红队 hook 挂在 Spec 冻结的时刻。

为什么越用越好

复利不是「把报告存起来」,而是一个 delta 判断:和已有 130+ 篇 knowledge 文件比,这次到底学到了什么东西。完全匹配就更新旧文件;新根因路径就新建 case;新信号就更新路由表。三条防腐原则保证它不腐化:只记 delta;AI 写的知识要人工 review 后才从 draft 提升到 stable;每条都用 derived_from 可溯源回本次 triage report。今天这个知识库覆盖 34+ cases、21+ runbooks、15+ cards,下一次告警的 fast path 直接检索进去。

而且每一次真实 oncall 就是一次 eval run。verify.py 用退出码守单次质量(required sections 齐全、每个结论有 evidence chain、Slack response 不过度断言),slo.py 跨调查跟踪通过率趋势、暴露 skill 本身的退化。所以这个系统不是静态工具,而是一个随使用自我改进的闭环。

Takeaways

  • 一个 agent 系统的约束是 context 窗口,不是模型。把 context 当 RAM,隔离架构就自己长出来了:判断留在主 agent,raw data 下沉给 subagent,用 500 token 契约收口。
  • 安全属于确定性代码,不属于 prompt。让模型判断,让一个返回 exit 2 的 shell hook 掌管一切不可逆操作,幻觉就不再是安全风险。
  • 这是本站另一处论点的实物证据:在 agent 时代,SRE 的工作是成为一个不确定内核外面那层可靠的 outer shell。