Incident investigator
incident-investigator é o mais profundo dos workers do Ongrid. O coordinator despacha para ele sempre que o usuário quer causa raiz, não só um resumo do sintoma. A persona percorre a cadeia causal do alerta observado de volta à fonte originária ("paciente zero" — 0 号病人 no prompt da persona) e retorna um relatório estruturado.
Esta é a persona por trás do RCA
O pipeline de RCA causal do HLD-013 (ambiente de teste, rollout em maio de 2026) é construído sobre essa persona. Quando /incident/<id> → Get RCA roda, o manager dá spawn nesse worker com o incident id pré-preenchido no prompt.
Quando o coordinator a escolhe
O arquivo de persona declara os padrões de trigger. Citando o frontmatter verbatim:
when_to_use: |
coordinator 在用户问以下场景时 spawn 本 worker:
• "这条告警的根因是什么 / 到底是谁导致的"
• "incident 123 怎么排查 / 受影响范围 / 持续多久"
• "这个告警是不是误报 / 跟上次那个相关吗"
• "这台机器 mem 飙了,看一下"Tradução: sempre que o usuário pergunta por quê em vez de o quê. O entregável do investigator é a cadeia causal até a fonte, não um snapshot do "estado atual".
Tool bag
Whitelisted na persona — o filtro do runtime remove tudo o mais:
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-onlyConsequências principais:
- Read-only. Sem
host_restart_service, semexecute_skill, semrun_shell. Se a investigação concluir que um serviço precisa ser reiniciado, ela retorna isso como proposta ao coordinator; o coordinator despachaspecialist-opscom uma intenção mutadora, e o reviewer faz o gate. - Topologia e change events. A vantagem única que ele tem sobre os specialists é
expand_topology+find_topology_node(percorrer o grafo de serviços de volta às fontes upstream) equery_change_events(correlacionar sintomas com mutações recentes de config / regra / device em volta dofired_atdo alerta). - Bash cross-host e probes por host estão ausentes. Esses vivem nos specialists (
specialist-network,specialist-compute,specialist-disk); o investigator coordena sobre o plano de dados de observabilidade.
O workflow de 5 passos
O corpo da persona codifica o workflow. Toda investigação roda:
- KB primeiro (obrigatório). Com o
incident_idem mãos,query_knowledgeexatamente uma vez com o nome da regra + sintoma como query em linguagem natural (ex.: "swap_high 告警怎么排查"). Um hit (score ≥ 0.6) significa seguir o playbook; a resposta final carrega uma citação(参考 KB: <title>). Um miss significa proceder ao passo 1. - Sintoma + blast radius.
get_incident_detailpara nome da regra / severity / target /fired_at/ labels. Isto é o fim da cadeia causal (o efeito), não a causa raiz. Não pare aqui. - Timeline.
correlate_incidentpuxa metric + log + trace para a mesma janela do incidente em uma chamada. Ordene porfired_at/ tempo da primeira divergência. O sinal mais antigo é o candidato a fonte; CPU/latência alta downstream geralmente é efeito, não causa. "Mais ruidoso" ≠ "mais antigo". - Um salto causal upstream. Escolha uma ferramenta com um propósito claro:
- O que mudou? →
query_change_events(around_ts=fired_at). Mudanças no lado do produto frequentemente são paciente zero. - Dependências? →
expand_topologyupstream (não blast radius downstream) /find_topology_node. - Rastrear a cadeia de chamadas? →
query_traceqlpara achar o originador do span mais lento. - Primeiro erro? →
query_logqlgrep por device_id para o ERROR / PANIC / OOM mais antigo antes defired_at. - Quem se mexeu primeiro? →
query_promqlpara achar a métrica que divergiu primeiro.
- O que mudou? →
- Recursão. Trate o candidato upstream como o novo ponto atual. Repita o passo 3 até uma das opções:
- Bateu no fundo — não resta upstream no sistema. A folha é um processo / uma mudança / uma dependência externa = paciente zero.
- Sinal esgotado — não dá para ir mais fundo. Reporte "camada mais profunda alcançada + qual sinal nos deixaria continuar".
- Validar. A causa raiz proposta deve explicar toda a cadeia downstream — temporalmente anterior ao sintoma, magnitude e direção consistentes. Senão, rebaixe para "hipótese" e diga.
O budget de 18 ferramentas — cave fundo, nunca rode em círculo
A persona impõe disciplina estrita de iteração. Do corpo:
你有 ~18 个工具调用预算(够上溯 4-6 层)。深挖允许,但死分支立刻砍:
- 工具返回空(
result:[]/streams:[]):第一次空可换思路;第二次 空立刻停这条线,换方向或就此上溯为止。- 同一工具失败 / 空 ≥2 次 → 必须换工具或换方向,禁止反复换表达式空转 (v0.7.51-55 的失败都栽在这).
- 每一步都要朝"再上溯一层"前进 — 调之前问自己 "这步能让我更接近源头吗"。
- 上溯到 4-5 层仍未触底、或预算用到 ~15:停,输出"目前最深一层 + 缺失 信号",别为凑满空转。
O cap max_turns: 40 no frontmatter é o teto rígido — o grafo do eino conta MaxStep = MaxIterations*2+2, então 40 → MaxStep=82 → aproximadamente 41 turns de ChatModel. O budget de 18 ferramentas é a orientação mais branda no prompt; o cap é a rede de segurança do runtime.
Dead branches são inegociáveis
O prompt do investigator faz disso uma regra explícita de "não fazer" porque as evals iniciais de v0.7.51-55 viram o worker queimar 30+ turns re-permutando expressões PromQL tentando fazer uma range query vazia retornar dado. Um único resultado vazio é informação; um segundo resultado vazio significa que você já aprendeu o que vai aprender — pivote ou suba.
Formato de saída
A resposta final ao coordinator é Markdown verbatim deste formato:
**根因(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".}O coordinator sintetiza isso na resposta voltada ao usuário (um idioma, um parágrafo, a citação se houve hit de KB). O Markdown bruto do investigator também é persistido como o Result do worker na sessão — a UI de RCA o exibe verbatim sob o disclosure de Reasoning.
O teste e2e F1
F1 é a eval end-to-end que exercita essa persona contra um incidente semeado no ambiente de teste. Formato:
- Semeia um incidente sintético
swap_highemnode-01(device_id=7) com um processosearxngfixado a 95% RSS por 30 minutos. - Conecta o pipeline de alerta para que o incidente dispare com as labels esperadas +
fired_at. - Despacha o investigator com
prompt = "rca incident 1234". - Asserta que a resposta final contém:
- Regra
swap_highmencionada em现象. - Processo
searxngidentificado em根因(0 号病人)com pid + command line. - Pelo menos 2 saltos causais em
因果链(sintoma → upstream). - Citação
(参考 KB: …)SE a KB semeada tem um playbook correspondente.
- Regra
A primeira versão do HLD-013 falhou no F1 porque default_provider não estava setado no DB — o resolver caiu para openai com um nome de modelo glm, o chat model deu erro, e o worker retornou uma análise vazia. A lição: F1 também cobre o resolver de LLM como efeito colateral, e por isso é o gate canônico de "o RCA foi conectado end-to-end de verdade?".
Razões comuns para ele parar curto
A persona retorna "paciente zero não alcançado" honestamente quando:
- A causa está fora do cluster — provedor DNS, API upstream, energia.
query_change_eventsnão vê mudanças de infra fora do escopo do manager. - Dado de trace está ausente — queries TraceQL não retornam spans para o serviço relevante. O investigator não pode percorrer a cadeia de callers sem traces; ele reporta "缺失 trace 信号".
- A linha de log que apontaria para o trigger já foi rotacionada. Retenção do Loki < tempo até a primeira investigação. O investigator diz isso e recomenda estender a retenção para investigações repetidas.
Essa honestidade é por design. Uma resposta errada confiante é pior que "batemos no sinal X e precisamos de Y para continuar".
Tuning
Coisas que você realisticamente mudaria num fork dessa persona:
- Adicione hits de KB específicos do seu domínio — escreva playbooks para seus modos de falha comuns, distribua via vault, o passo
KB firstdo investigator vai descobri-los. - Ajuste a whitelist de tools — adicione variantes de
query_traceqlse sua stack de tracing não for Tempo, ou removahost_du_summaryse você não quer que o investigator despache inspeção de disco inline (o padrão é delegar aspecialist-diskvia a própria saída do worker — mas a persona carrega as tools para se autoinspecionar quando é rápido). - Aperte o budget — se o custo por token do seu modelo importa, baixe
max_turnspara 25-30. O budget soft de 18 chamadas do corpo da persona já mantém a maioria das investigações abaixo disso.
Veja Agents customizados para como montar seu fork sobre o built-in.