Topologie
La topologie est le graphe qui transforme « un incident sur le host edge-prod-04 » en « un incident qui met à terre payments, search et email ». Sans elle, le LLM ne peut raisonner que sur la série unique en feu.
ADR-025
Les BaseTools de topologie actuels (expand_topology, find_topology_node) ont atterri le 2026-05-18. Avant ça, le LLM avait une liste plate de devices et aucune façon de parcourir les relations ; « qu'est-ce qui dépend de X » nécessitait que l'opérateur sache déjà la réponse.
Le modèle de données
Quatre tables, toutes en MySQL :
| Table | Contient |
|---|---|
topology_nodes | Une ligne par nœud. A un type (device / service / cluster / ...), un name et un props_json libre. |
topology_node_types | L'ensemble fermé de valeurs node.type autorisées. |
topology_relations | Arête dirigée src_node_id -> dst_node_id avec un type. |
topology_relation_types | Ensemble fermé de types d'arêtes, chacun tagué d'un champ semantics (hard_dep / runtime_dep / traffic / annotation / observation). |
Le tag semantics est l'idée clé. Une arête tagguée hard_dep propage la défaillance (si src meurt, dst est affecté) ; une arête tagguée annotation non. La marche de blast-radius s'en sert pour filtrer.
Voir internal/manager/biz/topology/.
D'où viennent les données
Trois sources, en couches :
- Auto depuis les spans — le processeur
service_graphde Tempo émet des arêtesservice_a -> service_bavec un tag de sémantiqueroutes_to. Le manager les miroir danstopology_relationssur un tick de sync. - Auto depuis les edges — chaque edge enregistré devient un nœud
type=device; l'id de nœud est back-linké vers la colonnehost_devices.node_idpour queexpand_topology(device_id=X)se résolve à travers. - Manuel — les opérateurs ajoutent des nœuds
type=service/type=clusteret des arêtes via la page/topologyde la SPA. Utilisé pour les nœuds que vous voulez adresser mais qui ne sont pas directement observés (une base de données managée, une API tierce).
Outils
expand_topology
Marche vers l'extérieur depuis un nœud, renvoie chaque nœud atteignable plus comment il a été atteint. Profondeur BFS par défaut 2, plafond 5. Direction par défaut both (le blast radius est symétrique — ce qui pourrait casser ceci, ET ce que ceci casse).
{
"node_id": 142,
"depth": 2,
"only_propagating": true,
"direction": "downstream"
}Ou, quand vous partez d'un id de device :
{ "device_id": 17, "depth": 3 }L'outil résout device_id → device.node_id automatiquement. only_propagating=true (défaut) ne parcourt que les arêtes hard_dep / runtime_dep / traffic ; passez à false pour inclure les arêtes observation / annotation (utile pour les cas « montre-moi tout ce qui est lié à X »).
Les hits retournés portent les métadonnées de chemin dont le LLM a besoin pour raisonner sur l'impact :
{
"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" }
]
}La liste plate (pas de struct imbriquée par voisin) est intentionnelle — garde le JSON bon marché à embarquer dans le prompt. Voir expand_topology_basetool.go.
find_topology_node
L'étape préalable « j'ai un nom donné par un humain, donne-moi un node_id ». La persona exécute ceci avant expand_topology chaque fois que le prompt mentionne un service / host par nom :
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, ... }Les deux sont enregistrés comme BaseTools ScopeManager (pas d'argument edge_id) — la DB de topologie vit côté manager.
Marche de blast-radius en pratique
Le prompt de la persona investigator inclut un « après avoir identifié le service en feu, appelle expand_topology pour voir ce qui d'autre est affecté » explicite. C'est ainsi que le related_alerts du rapport et la section « 业务影响 / Business impact » se peuplent — l'agent parcourt le graphe depuis le device en feu vers le haut / le bas et cross-check quels autres incidents sont partis dans la même fenêtre sur ces nœuds.
Le chemin de code pertinent :
correlate_incidentrenvoie des résumés métriques + logs + traces plus ledevice_idde l'incident.expand_topology { device_id, direction: both, depth: 2 }renvoie le set atteignable.- L'extraction Pass-2 lit la narrative du worker et tire
pinpointed_target(le patient zéro) +related_alerts(la cascade).