Skip to content

拓扑

拓扑是把 "edge-prod-04 上一条 incident" 变成 "一条会带垮 payments、search、 email 的 incident" 的。没有它,LLM 只能在单条触发 series 上推理。

ADR-025

当前的拓扑 BaseTool(expand_topologyfind_topology_node)2026-05-18 落地。在那之前,LLM 拿到的是扁平的设备列表,没有走关系的办法;"什么依赖 X" 要靠运维自己先知道答案。

数据模型

四张表,全在 MySQL:

装什么
topology_nodes每个节点一行。有 typedevice / 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 的边不传。爆炸半径走图用它做过滤。

internal/manager/biz/topology/

数据从哪儿来

分层的三种来源:

  1. 从 span 自动来 —— Tempo 的 service_graph 处理器吐 service_a -> service_b 的边,带 routes_to semantics 标签。manager 按同步 tick 把 它们镜像到 topology_relations
  2. 从 edge 自动来 —— 每个注册的 edge 变成一个 type=device 节点;节点 id 反链到 host_devices.node_id 列,这样 expand_topology(device_id=X) 能解到。
  3. 手动 —— 运维通过 SPA 的 /topology 页加 type=service / type=cluster 节点和边。给那些想寻址但没被直接观测到的节点用(托管 数据库、第三方 API)。

工具

expand_topology

从一个节点向外走,返回每一个可达节点以及它怎么被走到的。默认 BFS 深度 2, 上限 5。默认方向 both(爆炸半径是对称的 —— 什么能搞挂这个,这个能 搞挂什么)。

json
{
  "node_id": 142,
  "depth": 2,
  "only_propagating": true,
  "direction": "downstream"
}

或者,从一个设备 id 起步:

json
{ "device_id": 17, "depth": 3 }

工具会自动解 device_id → device.node_idonly_propagating=true(默认) 只走 hard_dep / runtime_dep / traffic 边;翻成 false 把 observation / annotation 边算进来(用于"给我看跟 X 有关的一切"场景)。

返回的命中带 LLM 推断影响时需要的 path 元数据:

json
{
  "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" }
  ]
}

扁平列表(没有每邻居嵌套结构体)是故意的 —— 让 JSON 嵌进 prompt 里便宜。 见 expand_topology_basetool.go

find_topology_node

"我有一个人类给的名字,帮我拿到 node_id" 的前置步骤。persona 在 prompt 里 出现按名字引用的服务 / 主机时,会先跑它再跑 expand_topology

text
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 参数)—— 拓扑 DB 住在 manager 侧。

爆炸半径走图实战

investigator persona 的 prompt 里含一条明确的 "找到触发服务后调 expand_topology 看还有什么受影响"。报告的 related_alerts 和"业务影响 / Business impact" 部分就是这么填出来的 —— Agent 从触发设备向上 / 向下走图, 交叉核对同一窗口里那些节点上还触发了哪些 incident。

相关代码路径:

  1. correlate_incident 返回指标 + 日志 + 链路摘要,加上 incident 的 device_id
  2. expand_topology { device_id, direction: both, depth: 2 } 返回可达集。
  3. Pass-2 抽取读 worker 的叙述,抽出 pinpointed_target(0 号病人)+ related_alerts(级联)。

另见

  • RCA —— 用这些工具的 investigator persona。
  • 技能 —— expand_topology 怎么在 BaseTool 工具包和技能 registry 里同时注册(inventory_bridge)。
  • 概念 —— Edge / Device / Node 词汇表。