凌晨2点,手机连震两下,四分钟内进来七条告警。前端说订单失败,API网关在抛5xx,结账报错、支付变慢、购物车变慢。列表最底下还压着一条缓存服务的低语式警告,以及推荐服务的高CPU告警。
![]()
先看哪一条?多数人会从最响的那条下手。这通常是错的——响的告警是症状,真正的起因往往藏在某个共享服务上的一次小改动里。要把它挖出来,得把一堆点连起来:谁调用谁、谁在什么时候部署了什么、服务归谁管、上一次是怎么修好的。
这就是 RootCause Agent 的由来,一个为 Graph Hacks(WeMakeDevs × FalkorDB)做的AI值班代理,靠走图找出故障的真实起因。作者四天前还没写过一行 Cypher,也不知道AI代理是怎么调用工具的,更说不清图数据库相比 Postgres 该在什么场景选。
他选了 Track 1「Agents That Act on Connected Data」,理由很直接:值班排障这类事,答案就长在连接关系里,不在任何单份文档里。
为什么这是个图问题
值班工程师真正要回答的问题,逐条拆开看:这条告警是起因还是症状,取决于该服务依赖什么;还会有什么跟着坏,取决于谁在几跳之外依赖这个故障服务;什么变了,是部署连到服务、再连到提交的人;该叫醒谁、上次怎么修的,是负责人、历史故障、处理过的人和用过的 runbook。
每一条都是穿过连接数据的路径。于是他把一家网店的 25个服务,连同团队、工程师、部署、告警、历史故障和 runbook 一起建模成 FalkorDB 里的图,用 DEPENDS_ON、OWNS、AUTHORED、DEPLOYED_TO、FIRED_ON、RESOLVED 这些关系连起来。数据全部是合成的。
判定规则只有一句话
一个正在告警的服务,如果它依赖的某个东西也在告警,那它就是症状。剩下的才是候选,先按有多少告警服务依赖它排序,再看它最近有没有部署。
在这个场景里,前端、API网关、结账、支付、购物车全是症状,因为它们各自都位于另一个告警服务的上游。只剩两个候选:缓存解释了5条告警,且在故障前11分钟有过一次部署;推荐只解释2条,近期没有部署。答案是缓存,背后那次部署是 D-1:「Config change: maxmemory lowered」。推荐服务那条CPU告警是干扰项。
核心逻辑是一行 Cypher,一段变长遍历:MATCH (:Service {name: $service})-[:DEPENDS_ON*1..]->(dep) RETURN DISTINCT dep.name。其中 *1.. 的意思是沿 DEPENDS_ON 走一跳或多跳。同样的语义在 SQL 里要写递归连接,在 Cypher 里是两个字符。
顺着这条线,代理还能找出证据路径(前端 → API网关 → 购物车 → 缓存)、爆炸半径(5个关键服务)、该叫醒谁(修过同类问题的 Priya,以及做出这次改动的 Arjun)、历史故障 runbook 里的修法,最后把新故障写回图里。
事实来自图,模型只负责解释
最早的版本让模型直接写完整答案。它写得流畅又自信,偶尔是错的。转折点是一次它建议了一个叫「Restore Cache Memory Settings」的修复方案——这个 runbook 根本不存在,真实的名字是「Roll back cache config」。测试没抓到,因为只校验了根因。
凌晨2点,一个编出来的 runbook 名字比没有答案更糟。于是他定下规则:事实来自图,结构在代码里强制,模型只做解释。模型仍然决定调用哪些图工具、撰写说明,但真正要紧的那几行——首行结论、建议修复、以及「推荐服务是起因吗」这类是/否回答——在任何人看到之前,都由代码从工具结果重建。
证明图真的在干活
说图有用很容易,他想测出来。于是在同一份数据上搭了个向量 RAG 基线:每个节点和关系转成一句话,TF-IDF 检索加停用词和词干处理,把当前告警拼进查询,取前8篇文档,同一个模型。他尽力做到公平——第一版基线意外地不公平,修正之后 RAG 也开始找到缓存了。这让他的说法从「RAG 会答错」变成「这是 RAG 做不到的事」。
然后用从图里读出、而非手敲的答案键给两边打分。RAG 能猜到缓存牵涉其中,但它把 API网关当成主要驱动,从没找到部署 D-1 和提交人,列不出完整爆炸半径,说不出该叫醒谁以及为什么,也无法采取动作。问它「什么变了」,它回答缓存延迟上升——那是告警,不是变更。同样的数据、同样的模型,唯一差别是图。
踩过的坑
第一条根因查询返回全零。他试图用一个大 Cypher 查询干完所有事,拆成简单遍历、在 Python 里合并结果后,一次就跑通了。
MATCH 里放 shortestPath 会报错,在 FalkorDB 里它必须放在 RETURN 或 WITH 中。
爆炸半径在测试里是硬编码的。直到他问自己「为什么它从来不变」才发现,现在每个期望值都来自图。
代理把所有提问都当成当前故障。他输入「auth 挂了,谁负责」,代理却怪到缓存头上、叫醒错的人、还开了故障单——而 auth 根本没在告警。这催生了服务检查模式:问一个没有告警的服务时,代理去图里查它的依赖,标记可能的监控盲区,点名负责人,不开任何单子,且不消耗模型 token。
token 用光了。Groq 免费额度约每个模型每天 20万 token,一次完整排查约耗 1.1万,两轮测试就吃掉一整天。他加了模型降级链、答案缓存和 token 日志,让演示能持续跑。
部署也有意外:.env 还指向 localhost 却想连 FalkorDB Cloud,还有一次把端口粘进了主机字段,于是它去连 ...cloud:59676:59676。
目前它只是合成数据上的一次脚本化故障,时钟固定。下一步是接入真实的服务地图(比如来自 OpenTelemetry)和真实部署历史,再看同一条规则是否依然成立。
四天前他还不懂 Cypher。现在他明白为什么有些问题是图问题,也明白一个凌晨2点回答问题的代理,事实该取自数据,而不是模型的想象。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.