Топология
Топология — это граф, который превращает «инцидент на хосте edge-prod-04» в «инцидент, который выносит payments, search и email». Без него LLM может рассуждать только о единичной срабатывающей серии.
ADR-025
Текущие topology BaseTool (expand_topology, find_topology_node) приземлились 2026-05-18. До этого у LLM был плоский список устройств и не было способа пройти отношения; «что зависит от X» требовало, чтобы оператор уже знал ответ.
Модель данных
Четыре таблицы, все в MySQL:
| Таблица | Хранит |
|---|---|
topology_nodes | Одна строка на узел. Имеет type (device / service / cluster / ...), name и свободную props_json. |
topology_node_types | Закрытое множество допустимых значений node.type. |
topology_relations | Направленное ребро src_node_id -> dst_node_id с type. |
topology_relation_types | Закрытое множество типов рёбер, каждое тегировано полем semantics (hard_dep / runtime_dep / traffic / annotation / observation). |
Тег semantics — это ключевая идея. Ребро, тегированное hard_dep, распространяет отказ (если src умирает, dst затронут); ребро, тегированное annotation, — нет. Blast-radius walk использует это для фильтрации.
См. internal/manager/biz/topology/.
Откуда берутся данные
Три источника, послойно:
- Авто из span'ов — процессор
service_graphTempo эмитит рёбраservice_a -> service_bс тегом семантикиroutes_to. Manager зеркалит их вtopology_relationsна sync-tick. - Авто из edge — каждый зарегистрированный edge становится узлом
type=device; node id обратно-связан со столбцомhost_devices.node_id, так чтоexpand_topology(device_id=X)разрешается насквозь. - Ручной — операторы добавляют узлы
type=service/type=clusterи рёбра через страницу SPA/topology. Используется для узлов, которые вы хотите адресовать, но которые непосредственно не наблюдаются (managed БД, third-party API).
Инструменты
expand_topology
Пройти наружу от узла, вернуть каждый достижимый узел плюс, как он был достигнут. По умолчанию BFS глубиной 2, cap 5. Направление по умолчанию both (blast radius симметричен — что могло сломать это, И что это ломает).
{
"node_id": 142,
"depth": 2,
"only_propagating": true,
"direction": "downstream"
}Или, когда вы начинаете с device id:
{ "device_id": 17, "depth": 3 }Инструмент автоматически разрешает device_id → device.node_id. only_propagating=true (по умолчанию) идёт только по рёбрам hard_dep / runtime_dep / traffic; переключите в false, чтобы включить рёбра observation / annotation (полезно для кейсов «покажи мне всё, связанное с X»).
Возвращённые хиты несут метаданные пути, которые LLM нужны для рассуждения о влиянии:
{
"center": { "node_id": 142, "node_name": "payments-api", "node_type": "service", "hops": 0, "propagates_failure": false },
"max_hops": 2,
"reachable_count": 7,
"reachable": [
{ "node_id": 71, "node_name": "edge-prod-04", "node_type": "device", "hops": 1,
"relation_type": "deployed_on", "semantics_tag": "runtime_dep", "reached_via": "downstream",
"propagates_failure": true,
"via_node_id": 142, "via_node_name": "payments-api" }
]
}Плоский список (без вложенной per-neighbor структуры) — намеренно — держит JSON дешёвым для встраивания в промпт. См. expand_topology_basetool.go.
find_topology_node
Pre-шаг «у меня есть имя, данное человеком, дай мне node_id». Персона запускает это перед expand_topology всякий раз, когда промпт упоминает сервис / хост по имени:
User: "what does loki-write depend on?"
Agent:
→ find_topology_node{ name: "loki-write" }
← { node_id: 219, node_type: "service", name: "loki-write" }
→ expand_topology{ node_id: 219, direction: "upstream" }
← { reachable_count: 4, ... }Оба зарегистрированы как ScopeManager BaseTool (без аргумента edge_id) — БД топологии живёт manager-side.
Blast-radius walk на практике
Промпт персоны investigator включает явное «после того, как вы идентифицировали срабатывающий сервис, вызовите expand_topology, чтобы увидеть, что ещё затронуто». Так раздел related_alerts отчёта и «业务影响 / Business impact» наполняются — агент идёт по графу от срабатывающего устройства вверх / вниз и кросс-проверяет, какие другие инциденты сработали в том же окне на этих узлах.
Релевантный код-путь:
correlate_incidentвозвращает резюме метрик + логов + трейсов плюсdevice_idинцидента.expand_topology { device_id, direction: both, depth: 2 }возвращает достижимое множество.- Pass-2 extraction читает narrative воркера и вытягивает
pinpointed_target(нулевой пациент) +related_alerts(каскад).