Incident investigator
incident-investigator — самый глубокий из воркеров Ongrid. Coordinator диспетчирует на него всякий раз, когда пользователь хочет корневую причину, а не просто резюме симптома. Персона идёт по причинной цепочке от наблюдаемого алерта обратно к первоисточнику («нулевой пациент» — 0 号病人 в промпте персоны) и возвращает структурированный отчёт.
Это персона за RCA
Конвейер причинного RCA HLD-013 (тестовая среда, выкатка в мае 2026) построен на этой персоне. Когда /incident/<id> → Get RCA запускается, manager порождает этого воркера с incident id, заранее вписанным в промпт.
Когда coordinator его выбирает
Файл персоны декларирует триггер-паттерны. Цитируем frontmatter дословно:
when_to_use: |
coordinator 在用户问以下场景时 spawn 本 worker:
• "这条告警的根因是什么 / 到底是谁导致的"
• "incident 123 怎么排查 / 受影响范围 / 持续多久"
• "这个告警是不是误报 / 跟上次那个相关吗"
• "这台机器 mem 飙了,看一下"Перевод: всякий раз, когда пользователь спрашивает почему, а не что. Поставка investigator — это причинная цепочка обратно к источнику, а не «текущее состояние» снапшот.
Набор инструментов
В whitelist персоны — фильтр рантайма срезает всё остальное:
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Ключевые следствия:
- Read-only. Никаких
host_restart_service,execute_skill,run_shell. Если расследование заключает, что сервис нужно перезапустить, оно возвращает это как предложение coordinator; coordinator диспетчируетspecialist-opsс мутирующим намерением, а reviewer гейтит его. - Топология и change-events. Уникальное преимущество перед specialist — это
expand_topology+find_topology_node(обход графа сервисов обратно к upstream-источникам) иquery_change_events(корреляция симптомов с недавними мутациями конфигов / правил / устройств вокругfired_atалерта). - Межхостового bash и per-host пробов нет. Они живут на specialist (
specialist-network,specialist-compute,specialist-disk); investigator координирует поверх плоскости данных observability.
5-шаговый workflow
Тело персоны кодирует workflow. Каждое расследование запускает:
- KB первым (обязательно). Как только
incident_idпод рукой,query_knowledgeровно один раз с natural-language запросом, составленным из имени правила + симптома (например, "swap_high 告警怎么排查"). Попадание (score ≥ 0.6) означает следовать playbook; финальный ответ несёт цитирование(参考 KB: <title>). Промах — переходим к шагу 1. - Симптом + blast radius.
get_incident_detailдля имени правила / severity / target /fired_at/ labels. Это конец причинной цепочки (эффект), а не корневая причина. Не останавливайтесь здесь. - Таймлайн.
correlate_incidentподтягивает metric + log + trace для того же incident-окна одним вызовом. Сортируйте поfired_at/ времени первого отклонения. Самый ранний сигнал — кандидат-источник; downstream high-CPU / high-latency обычно эффект, а не причина. «Самый громкий» ≠ «самый ранний». - Один причинный шаг вверх. Выберите один инструмент с чёткой целью:
- Что изменилось? →
query_change_events(around_ts=fired_at). Изменения со стороны продукта часто оказываются нулевым пациентом. - Зависимости? →
expand_topologyupstream (не blast radius downstream) /find_topology_node. - Цепочка вызывающего трейса? →
query_traceql, чтобы найти источник самого медленного спана. - Первая ошибка? →
query_logqlgrep по device_id для самой ранней ERROR / PANIC / OOM доfired_at. - Кто первым двинулся? →
query_promql, чтобы найти метрику, которая отклонилась первой.
- Что изменилось? →
- Рекурсия. Считайте upstream-кандидата новой текущей точкой. Повторяйте шаг 3 до одного из:
- Достигли дна — в-системе нет upstream. Лист — это процесс / единичное изменение / внешняя зависимость = нулевой пациент.
- Сигнал исчерпан — дальше нельзя. Сообщите «достигнут глубочайший слой + какой сигнал позволил бы продолжить».
- Валидация. Предложенная корневая причина должна объяснить всю downstream-цепочку — быть темпорально раньше симптома, по масштабу и направлению согласованной. Если нет — понизьте до «гипотезы» и так и скажите.
Бюджет 18 инструментов — копай глубоко, не крутись
Персона форсирует строгую дисциплину итерации. Из тела:
你有 ~18 个工具调用预算(够上溯 4-6 层)。深挖允许,但死分支立刻砍:
- 工具返回空(
result:[]/streams:[]):第一次空可换思路;第二次 空立刻停这条线,换方向或就此上溯为止。- 同一工具失败 / 空 ≥2 次 → 必须换工具或换方向,禁止反复换表达式空转 (v0.7.51-55 的失败都栽在这).
- 每一步都要朝"再上溯一层"前进 — 调之前问自己 "这步能让我更接近源头吗"。
- 上溯到 4-5 层仍未触底、或预算用到 ~15:停,输出"目前最深一层 + 缺失 信号",别为凑满空转。
Ограничение max_turns: 40 в frontmatter — это жёсткий потолок; граф eino считает MaxStep = MaxIterations*2+2, так что 40 → MaxStep=82 → грубо 41 ChatModel ходов. Бюджет 18 инструментов — более мягкое руководство в промпте; ограничение — это runtime safety net.
Мёртвые ветки — не обсуждается
Промпт investigator делает это явным правилом «не делайте этого», потому что ранние evals v0.7.51-55 видели, как воркер сжигал 30+ ходов, переставляя PromQL-выражения, пытаясь заставить пустой range-запрос вернуть данные. Один пустой результат — это информация; второй пустой результат означает, что вы уже узнали то, что узнаете — поворачивайте или поднимайтесь.
Формат вывода
Финальный ответ 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-попадание). Сырой Markdown investigator также сохраняется как Result воркера в сессии — UI RCA показывает его дословно под раскрытием Reasoning.
E2E-тест F1
F1 — это сквозной eval, который прогоняет эту персону против засеянного инцидента на тестовой среде. Форма:
- Засеять синтетический инцидент
swap_highнаnode-01(device_id=7) с процессомsearxng, прижатым к 95% RSS на 30 минут. - Замонтировать конвейер алертов так, чтобы инцидент сработал с ожидаемыми labels +
fired_at. - Диспетчировать investigator с
prompt = "rca incident 1234". - Утверждать, что финальный ответ содержит:
- правило
swap_highупомянуто в现象. - процесс
searxngидентифицирован в根因(0 号病人)с pid + командной строкой. - минимум 2 причинных шага в
因果链(симптом → upstream). - цитирование
(参考 KB: …), ЕСЛИ засеянный KB имеет соответствующий playbook.
- правило
Первая версия HLD-013 провалила F1, потому что default_provider не был установлен в БД — resolver откатился на openai с именем модели glm, chat-модель завалилась, и воркер вернул пустой анализ. Урок: F1 также покрывает LLM resolver как side-effect, поэтому это канонический гейт «RCA реально соединён end-to-end?».
Распространённые причины, по которым он останавливается раньше времени
Персона честно возвращает «нулевой пациент не достигнут», когда:
- Причина вне кластера — DNS-провайдер, upstream API, питание.
query_change_eventsне видит инфра-изменения вне области manager. - Trace-данных нет — TraceQL-запросы не возвращают спанов для релевантного сервиса. Investigator не может пройти цепочку вызывающего без трейсов; он сообщает «缺失 trace 信号».
- Лог-строка, которая указала бы на триггер, ротирована. Loki retention < времени до первого расследования. Investigator говорит об этом и рекомендует расширить retention для повторных расследований.
Эта честность — by design. Уверенный неправильный ответ хуже, чем «мы дошли до сигнала X и нужен Y, чтобы продолжить».
Тюнинг
Что реально менять в форке этой персоны:
- Добавить доменно-специфичные KB-попадания — напишите playbook для ваших частых режимов отказа, отгрузите их через vault, KB-first шаг investigator их обнаружит.
- Подогнать whitelist инструментов — добавьте варианты
query_traceql-, если ваш стек трейсинга не Tempo, или удалитеhost_du_summary, если вы не хотите, чтобы investigator диспетчировал инспекцию диска инлайн (по умолчанию делегирование наspecialist-diskчерез собственный вывод воркера — но персона несёт инструменты, чтобы инспектировать сам, когда быстро). - Затянуть бюджет — если стоимость токенов вашей модели важна, опустите
max_turnsдо 25-30. Мягкий бюджет 18 вызовов в теле персоны и так держит большинство расследований ниже этого.
См. Кастомные агенты, как смонтировать ваш форк поверх встроенного.