SRE Agent 设计笔记 11:Agent 的并行化:从序贯 Debug Tree 到 Fan-out Investigation
状态:大纲
核心论点
Oncall agent 慢,常被归因为「LLM 推理慢」或「工具调用多」。但真实原因是一个设计选择:debug tree 把 investigation 建模成了序贯过程。这个序贯不全是真的,其中前半段(事实基座收集)本质上是独立可并行的。Deep Research Workflow 的 Phase 2 并行 fan-out 是同构解法。把 investigation 的前半段从「先 routing 再查」改成「先并行铺开事实基座再 routing」,能在不牺牲正确性的前提下把 wall-clock 时间压缩一个量级。
大纲
1. 问题:Agent 为什么感觉慢
观察到的现象:
- oncall agent 跑完一次 triage 需要几分钟
- 大量时间花在拉 input、分析、理解
- 看不到特别清晰的 sub-agent 被启动
- 主 session 大部分时间在等一个 MCP 查询完成、分析、决定下一个查询
归因误区:
- 以为是 LLM 推理慢(实际上单次推理几秒)
- 以为是工具调用多(单次 MCP 查询也就几秒)
- 以为是 agent 架构重(agent 启动开销只有几十 ms)
真实原因:投资在了串行路径上。每个 MCP 查询的结果决定下一个查询,看起来像必然的因果链。
2. 伪序贯:前半段是可并行的
检视一次典型 oncall 调查的前半段:
- 查当前 pod 状态
- 查最近 5 分钟关键指标
- 查最近部署/配置变更
- 查历史上同告警的频次
- 查同时间窗其他 alerts
这五件事之间有依赖关系吗?没有。它们都只依赖告警本身提取出的最小信号(alertname + cluster + service + event_ts)。串行执行纯粹是因为 debug tree 把它们写成了 Step 1 → Step 2 → Step 3 的顺序。
真正有序贯依赖的是后半段:
- 基于事实基座形成假设
- 针对性深挖某个指标的时序行为
- 验证或否证假设
- 循环直到收敛
这部分是真的序贯,但它占整个 triage 时间的比例其实不高。时间大头在前半段的「广度铺开」。
3. Deep Research 的同构解法
前面 blog 08 分析过 Deep Research Workflow 为什么快又简洁:Phase 2 并行 fan-out,3-5 个 sub-agent 同时开跑。主 session 的职责退化为「路由和汇总」。
这个模式可以直接借用。Oncall 的 Phase 0(事实基座收集)对应 Deep Research 的 Phase 2(并行调研)。每个 sub-agent 负责一个事实维度:
- Current state sub-agent:pod 状态 + 关键指标
- Recent changes sub-agent:部署/配置变更
- Historical context sub-agent:历史 case + 频次
- Correlated alerts sub-agent:同时间窗其他告警
- Topology sub-agent:上下游服务状态
每个 sub-agent 独立跑,typical 10-30s。主 session 等所有返回后汇总(等 max,不是等 sum),整个 Phase 0 约 30-60s 完成。相比原来串行执行可能需要 2-3 分钟。
4. Overlap ≥50% 的类比应用
Deep Research 的 overlap ≥50% 在 oncall 场景的类比:多假设并行调查。
如果 routing 之后 debug tree 指向 2-3 个可能的故障域(比如症状同时能被 Stateful 和 Scheduling 解释),fork 2-3 个 sub-agent 各自走一条 debug path。主 session 看谁先撞到 terminal 节点就采信。
这是 overlap 的变体:多个独立路径验证同一个症状,哪条路径能走通哪条就是对的。代价是一些 sub-agent 的工作会被丢弃,但 wall-clock 时间 = max(paths) 而不是 sequential。
5. 声明式约束的迁移
Deep Research 的三条硬约束(overlap ≥50%、URL 门控、单一交付物)在 oncall 场景的对应:
- Overlap ≥50% → 证据链必须覆盖 L1-L4 四层中至少三层(网络/调度/应用/基础设施)。这强制 agent 不能只从一个角度下结论。
- URL 门控 → 每个 conclusion 必须有对应的 MCP 查询结果 ID。这是现有的 evidence-backed 约束,已经实现。
- 单一交付物 → report.md 作为唯一交付物,sub-agent 返回值不落盘。这是现有设计。
核心迁移:把「投资在串行正确性」改成「投资在并行冗余」。 多查一些看起来可能不需要的信息,但并行做所以不增加 wall-clock,同时提升了证据链的覆盖度。
6. Quick-check 模式
Full triage 有时候过重。用户已经在主 session 讨论某个服务,只想快速看一眼现状,不需要根因和操作命令。这时候需要的是「Phase 0 fan-out + synthesis」,不走 Phase 1+ 的 deep investigation。
Quick-check 可以作为独立 skill,也可以作为 full triage 的前置步骤。两者共享同一套 fan-out 逻辑。升级路径:quick-check 完成后如果用户要深入,已有的事实基座直接作为 full triage 的 Phase 0 输入,不重复查。
这对应 blog 08 和 blog 10 的延续:Skill 作为可复用的 Spec 组件。quick-check 的 fan-out 逻辑被封装成 skill,agent 和主 session 都能直接调用。
7. 判断:什么时候 fork,什么时候不 fork
回到 blog 02 的四原语中 Fork 的判据:
- Independence-bound(验证者必须独立)— oncall 不典型
- Attention-bound(context 太杂)— 对 oncall 适用:sub-agent 拉原始数据传摘要回主,避免主 session 被日志淹没
- Capacity-bound(装不下)— 对大量 logs 可能适用
- Latency-bound(可并行加速)— 这是 oncall 的主要场景
Oncall 主要是 Latency-bound 的 fork。但 Attention-bound 也重要:Sonnet sub-agent 拉 raw logs,只把摘要传回 Opus 主 session 做判断。两个维度组合使用。
8. 实现代价
Fan-out 设计看起来更复杂,但工程代价并不高:
- Sub-agent prompt 模板化(每个事实维度一个固定 prompt)
- Claude Code
run_in_background=true原生支持并行 - 主 session 用 SendMessage 或等待机制收集结果
- 失败处理:某个 sub-agent 超时或失败 → 标记 UNKNOWN,继续
真正难的不是并行本身,是判断哪些是可并行的。这需要把 debug tree 的 step 序列拆解成「真依赖」和「假依赖」。前半段的事实基座查询几乎全是假依赖,后半段的假设验证是真依赖。
涵盖的 Topic
- Topic 新增:Agent 并行化,从序贯到 fan-out(从 session 2026-04-18 讨论提取)
源文件引用
rules/skills/workflow_deep_research_survey.md— Phase 2 并行 fan-out 的正例,overlap ≥50% 规则/Users/rshao/work/work-harness/agents/sre_oncall_triage_agent/CLAUDE.md— 现有 Fast/Slow fork 设计(2026-04-16 landed),sonnet sub-agent 做 case matching/Users/rshao/work/work-harness/agents/sre_oncall_triage_agent/skills/sre-oncall-quick-check/SKILL.md— 本篇论点的工程落地/Users/rshao/work/work-harness/agents/sre_oncall_triage_agent/todo.md— Parallel Fan-out 设计 + 实现 todos- 本系列 blog 02(四原语)— Fork 的判据
- 本系列 blog 08(从 Prompt 到 Skill)— Skill 作为可复用 Spec 组件
- 本系列 blog 10(Context Engineering)— Skills/Facets/Knowledge 的加载策略