Incident investigator
incident-investigator 是 Ongrid worker 中最深的一个。只要用户要的是根因而不是症状摘要,coordinator 就派给它。这个 persona 把因果链从观察到的告警一路追回最初源头(persona prompt 里叫 "0 号病人"),然后返回一份结构化报告。
RCA 背后就是它
HLD-013 因果 RCA 流水线(2026 年 5 月在测试环境上线)建在这个 persona 上。/incident/<id> → Get RCA 跑起来时,manager 把 incident id 预填进 prompt 然后 spawn 这个 worker。
coordinator 何时挑它
persona 文件声明触发模式。frontmatter 原文:
when_to_use: |
coordinator 在用户问以下场景时 spawn 本 worker:
• "这条告警的根因是什么 / 到底是谁导致的"
• "incident 123 怎么排查 / 受影响范围 / 持续多久"
• "这个告警是不是误报 / 跟上次那个相关吗"
• "这台机器 mem 飙了,看一下"换言之:用户问为什么而不是是什么时。investigator 交付的是回溯到源头的因果链,不是"当前状态"快照。
工具袋
在 persona 里白名单 —— runtime filter 把其他全剥掉:
tools:
- query_knowledge # KB / vault / uploads
- get_incident_detail
- query_incidents
- correlate_incident # metric+log+trace pulled together
- query_change_events # config / rule / device mutations
- query_promql
- query_logql
- query_traceql
- get_edge_summary
- query_alert_rules
- query_devices
- get_host_load
- get_host_processes
- expand_topology
- find_topology_node
- host_find_large_files
- host_du_summary
- host_stat_file
disallowed_tools:
- execute_skill
- host_restart_service
- run_shell
permission_mode: read-only关键后果:
- 只读。 没有
host_restart_service、execute_skill、run_shell。investigation 得出"得重启某服务"的结论时,作为建议返回给 coordinator;coordinator 派specialist-ops带写意图,由 reviewer 把关。 - 拓扑 + 变更事件。 它相对 specialist 独有的优势是
expand_topology+find_topology_node(沿服务图谱回溯上游)以及query_change_events(围绕告警fired_at关联症状与最近的配置 / 规则 / 设备变更)。 - 没有跨主机 bash 和单机探针。 那些归 specialist(
specialist-network、specialist-compute、specialist-disk);investigator 在可观测数据面上做协调。
5 步工作流
persona 正文写死的流程。每次 investigation 都跑:
- KB 先行(强制)。 拿到
incident_id之后用规则名 + 症状作为自然语言 query 调一次query_knowledge(如 "swap_high 告警怎么排查")。命中(score ≥ 0.6)就跟 playbook;最终答案带(参考 KB: <title>)。miss 进入第 1 步。 - 症状 + 影响面。
get_incident_detail拿规则名 / 严重度 / 目标 /fired_at/ labels。这是因果链的尾(果),不是根因,别停在这。 - 时间线。
correlate_incident一次性把同 incident 窗口的 metric + log + trace 拉到一起。按fired_at/ 首次偏离时间排序。最早信号是源头候选;下游的高 CPU / 高延迟通常是果,不是因。"最响" ≠ "最早"。 - 上溯一跳。 选一个目的清晰的工具:
- 什么变了? →
query_change_events(around_ts=fired_at)。产品侧变更往往就是 patient zero。 - 依赖? →
expand_topology上游(不是下游影响面)/find_topology_node。 - 追调用链? →
query_traceql找最慢 span 的起源。 - 首个错误? →
query_logql按 device_id grepfired_at之前最早的 ERROR / PANIC / OOM。 - 谁先动? →
query_promql找最先偏离的指标。
- 什么变了? →
- 递归。 把上游候选当成新的当前点,重复第 3 步,直到下列之一:
- 触底 —— 没有系统内上游了。叶子是一个进程 / 一次变更 / 一个外部依赖 = 0 号病人。
- 信号耗尽 —— 走不下去了。报"最深这一层 + 还需要什么信号才能继续"。
- 验证。 提出的根因必须能解释整条下游链 —— 时间上先于症状,量级和方向一致。否则降级为"假设"并说明。
18 次工具预算 —— 深挖,但不空转
persona 严格执行一套迭代纪律。正文里:
你有 ~18 个工具调用预算(够上溯 4-6 层)。深挖允许,但死分支立刻砍:
- 工具返回空(
result:[]/streams:[]):第一次空可换思路;第二次空立刻停这条线,换方向或就此上溯为止。- 同一工具失败 / 空 ≥2 次 → 必须换工具或换方向,禁止反复换表达式空转 (v0.7.51-55 的失败都栽在这).
- 每一步都要朝"再上溯一层"前进 — 调之前问自己 "这步能让我更接近源头吗"。
- 上溯到 4-5 层仍未触底、或预算用到 ~15:停,输出"目前最深一层 + 缺失信号",别为凑满空转。
frontmatter 里 max_turns: 40 是硬上限 —— eino 的 graph 用 MaxStep = MaxIterations*2+2,所以 40 → MaxStep=82 → 大约 41 个 ChatModel turn。18 次工具预算是 prompt 里的软指引;硬上限是 runtime 安全网。
死分支没得商量
investigator 的 prompt 把这条作为显式"不要做"的规则,因为早期 v0.7.51-55 evals 看到 worker 烧 30+ turn 反复变着花样写 PromQL 期望空 range query 能返回数据。一次空结果是信息;第二次空意味着这条线学到的已经学到了 —— 转向或上溯。
输出格式
最终回给 coordinator 的 Markdown 字面如下:
**根因(0 号病人)**
{One-line patient zero — process / change / upstream service+node /
config. Concrete identifiers (pid + cmdline / service name / change
key) — this is the source of pinpoint_target. If we didn't hit bottom:
"未触底,最深到 X;要继续需 Y 信号".}
**因果链**
{Source → … → alert symptom. One line per hop, each with "why this
caused the next" plus evidence (PromQL / LogQL / trace span /
process line).}
**现象**
{1-2 sentences: when did it start / which host / what crossed
threshold / for how long.}
**置信度与验证**
{High / medium / low + reason. Plus: "what query or action would
further validate or falsify this root cause".}coordinator 把这个综合进面向用户的回复(单一语言、单段、KB 命中时带引用)。investigator 的原始 Markdown 也作为 worker 的 Result 持久化进 session —— RCA UI 在 Reasoning 折叠下原样呈现。
F1 端到端测试
F1 是在测试环境对本 persona 拿 seed incident 跑的端到端 eval。形态:
- 在
node-01(device_id=7)seed 一条合成swap_highincident,pin 一个searxng进程 30 分钟 95% RSS。 - 把告警流水线接好,让 incident 以预期 label +
fired_at触发。 - 派 investigator,
prompt = "rca incident 1234"。 - 断言最终回复包含:
现象提到swap_high规则。根因(0 号病人)里识别出searxng进程,带 pid + 命令行。因果链至少 2 跳(症状 → 上游)。- seed 的 KB 有匹配 playbook 时,带
(参考 KB: …)引用。
HLD-013 第一版 F1 跑挂,是因为 DB 里没设 default_provider —— resolver 回退到 openai 但拿的是 glm 模型名,chat model 报错,worker 返回空分析。教训:F1 同时也覆盖 LLM resolver 作为副产物,所以它是"RCA 端到端真的通了吗"的标准 gate。
常见的提前停止
persona 诚实地返回 "patient zero 未到达" 是在以下情况:
- 原因在集群外 —— DNS 服务商、上游 API、电力。
query_change_events看不到 manager 作用域之外的基础设施变更。 - trace 缺数据 —— 对应服务 TraceQL 返回空 span。investigator 没有 trace 就走不了调用链;它报 "缺失 trace 信号"。
- 指向触发器的日志行已经轮转 —— Loki 保留期短于"首次调查的时间间隔"。investigator 如实说,并建议为重复调查延长保留。
这种诚实是有意的。一个自信的错答比"我们走到 X 信号,需要 Y 才能继续"更糟。
调优
fork 时可能想改的:
- 加领域专属 KB 条目 —— 给你们常见的失败模式写 playbook,通过 vault 发出去,investigator 的
KB 先行步骤会捡到。 - 调整工具白名单 —— 链路栈不是 Tempo 就加
query_traceql变种;不想 investigator inline 做磁盘巡检就移掉host_du_summary(默认是通过 worker 自己的输出委托给specialist-disk—— 但 persona 确实 自带这些工具,遇到能快查的就自己查)。 - 收紧预算 —— 模型按 token 计费很敏感,把
max_turns降到 25-30。persona 正文那 18 次软预算已经把多数 investigation 控在更低。
挂载你的 fork 覆盖内置版本,见 Custom agents。