ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

多智能体框架驱动的运维故障诊断:从告警噪音到可追溯根因

多智能体框架驱动的运维故障诊断:从告警噪音到可追溯根因

每次做运维故障诊断,都有一种感觉:监控平台拼了命在“喊”,喊的却全是噪音;日志系统存了一堆数据,却要人肉去翻;大模型能读文本,却分不清哪个指标才是真凶。我最早尝试直接把一堆告警和日志丢给大模型,让它“总结一下根因”,结果它一本正经地把完全无关的CPU波动编成了故障原因。

后面我换了一条路:不追求用一个大模型包打天下,而是基于多智能体框架,把故障诊断拆成“团队作战”——多个各司其职的智能体,像值班小组一样分头取证、汇总假设、逐级收敛。这套思路跑通之后,故障定位从几十分钟缩短到几分钟,更重要的是,每个结论都带上了可追溯的证据链。这篇文章就把这套多智能体故障诊断框架的设计思路、核心实现和踩坑记录完整写出来,给正在考虑把大模型引入运维体系的同学一份可参考的实战样本。

1. 为什么单个大模型搞不定故障诊断这件事

先聊清楚问题的本质。故障诊断和写周报、做翻译这类单点任务完全不一样,它本质上是“多源证据汇聚 + 假设验证”的推理过程。

1.1 故障现场的数据源天然是割裂的

一次典型的生产故障,同时涉及好几类数据:

  • 监控指标:CPU、内存、QPS、错误率、延迟分位数,都是时序数据,秒级或分钟级粒度;
  • 日志文本:服务日志、访问日志、慢查询日志,格式五花八门,量级从GB到TB;
  • 链路追踪:一次请求经过的上下游调用关系、各节点耗时;
  • 变更记录:某个服务什么时候发版、配置什么时候改过;
  • 资源拓扑:服务和主机、数据库、中间件之间的依赖关系。

这些数据放在不同的系统里,时间精度不同,语义粒度也不同。比如监控指标告诉你错误率在14:30突然飙升,日志能告诉你14:31开始出现大量连接超时,变更系统显示14:29刚发了一版代码。人要做的是把这几条线索拼在一起,判断“发版引入了问题”还是“下游数据库先挂了导致错误率飙升”。

单个大模型面对这种场景,天然有四个短板。

首先是上下文窗口不够用。生产环境一次告警风暴可能产生几千条告警、几十万行日志,硬塞给模型既不经济也不现实,模型还会在超长文本里“迷失重点”。

其次是工具调用链条太长。让模型自己决定“先查指标,再根据指标结果查日志,然后查变更”,每一步都有失败概率,链式调用很容易在中途崩掉,而且一旦崩了,很难判断是哪一步出了问题。

第三是幻觉问题。日志和指标之间经常存在矛盾,模型在信息不完整时倾向“脑补”一个听起来合理的根因。这是做运维诊断最致命的一点——宁可说“不确定”,也不能编一个错误结论让值班工程师去重启一堆无辜服务。

第四是缺乏稳定性。故障处理是有固定套路的,先收敛告警、再确认影响面、然后沿着调用链查根因、最后看变更时间线。这个套路是团队多年经验沉淀的SOP,大模型自己“自由发挥”反而容易跑偏。

1.2 把故障诊断看成一场“会诊”,而不是一次“问答”

我后来想明白一件事:故障诊断最像的场景不是“让一个博学的人回答问题”,而是“组织一场多科室会诊”。

会诊里有分诊台护士先做初筛分类,有影像科、检验科各查各的,有主治医生汇总所有检查结果提出假设,最后大家一起验证。每个角色只负责自己那一亩三分地,但共享一套病历系统,最后汇报时每一句话都能指向具体的检查单和报告。

多智能体框架要复刻的就是这个模式:每个智能体只负责一类数据源,工具少而精,职责边界清晰;所有智能体把证据写在一块共享的“线索板”上,不做主观结论;最后由一个决策智能体基于证据链给出根因假设,并给出置信度。这套设计背后有三个原则,在我后续实现中一直贯穿始终:

  • 职责分离:一个智能体只查一种数据,避免“既要查指标又要查日志还要查变更”导致的工具混乱;
  • 证据回溯:任何结论必须能追溯到具体的指标曲线、日志片段或变更记录,没有证据支撑的判断直接视为无效;
  • 确定性优先:检索、过滤、聚类这类高精度操作交给确定性代码去做,大模型只做归纳、假设、排序这类需要语义理解的部分。

2. 多智能体框架的整体架构与角色编排

有了原则,接下来就是怎么落地。我先说结论:智能体不是越多越好,角色划分必须贴合故障诊断的真实工作流,否则只是把混乱从单模型变成了多模型。

2.1 四个智能体角色,对应排查链路的关键节点

我在模拟项目X里把智能体收敛成了四个,外加一个可选的变更关联模块。

第一个是告警感知智能体。它负责对接监控平台的告警流,做的事情有三件:按时间窗口聚合告警、过滤重复告警、提取出“发生了什么事件”。它不负责判断根因,只负责把几百条告警折叠成一个结构化的“事件快照”,输出内容包括受影响的服务、告警类型分布、最早和最晚告警时间。

第二个是指标取证智能体。它拿到事件快照后,自动去查询相关服务的核心指标,包括QPS、错误率、P99延迟、CPU、内存、磁盘等,目标是回答“系统表现异常的时间段和形态”。它会对比故障前后指标曲线的变化,标注出“突变点”。

第三个是日志检索智能体。它负责任何语义层面的探查,拿着指标指定的时间窗口去检索关键服务的日志,抽取异常日志模板,比如超时、连接拒绝、OOM、死锁等。它会按关键词模板输出摘要,而不是把原始日志整段贴出来。

第四个是根因决策智能体。它读取前面几位写下的全部证据,检索故障模式知识库,输出Top 3的根因假设,每个假设都附带支持它的证据列表、置信度分数,以及建议的下一步验证动作。

整个排查流程走的是“串并行结合”:告警感知是唯一的入口,必须最先执行;随后指标取证和日志检索并行执行;所有证据落盘后,根因决策智能体统一收敛。如果决策智能体发现证据不足,会打回给日志检索智能体追加一轮查询,但打回次数限制在两次以内,防止无限循环。

2.2 共享“线索黑板”:智能体之间不直接对话

多智能体系统最容易做坏的地方,就是让智能体之间互相传话来协作。A对B说一句话,B理解了再转述给C,每一层都在损耗信息、放大幻觉。

我的做法是引入一个结构化的全局状态,内部叫“线索黑板”(Shared Context)。它不是聊天记录,而是一组按固定Schema组织的证据条目。每个证据条目包含这些字段:

  • source:证据来源,如prometheus、log、cmdb;
  • timestamp:证据对应的时间点或时间段;
  • affected_entity:涉及的服务名、主机名、数据库实例等;
  • summary:一句话摘要,控制在50字以内;
  • raw_ref:指向原始数据的引用,比如具体的日志查询链接;
  • confidence:该证据的可信度打分,0到1。

所有智能体只做两件事:读黑板、写黑板。写的时候只能追加证据,不能修改别人写的证据。决策智能体做判断时,读取的是黑板上的结构化证据,而不是某个智能体的“个人陈述”。这样做的好处非常明显:系统任何一步产出的结论都是可审计的,一旦判断错了,顺着证据回溯就能定位是哪条线索出了问题。

2.3 编排层选型:状态图取代自由对话

多智能体框架的编排层决定了“谁先执行、并行还是串行、异常怎么处理”。实测下来,用带状态管理的图编排框架比让模型自己决定下一步要稳得多。

我这里用的是LangGraph这类有向状态图方案。整个诊断流程被定义成一个图,节点是各个智能体,边是执行顺序和条件跳转。每执行完一个节点,都会把结果写入共享状态,再根据状态内容决定走哪条分支。好处有三个:流程可观测,每个节点的输入输出都能单独记录;流程可控,不会出现模型自己乱跳节点的情况;失败可恢复,某个节点超时了可以重试或跳过,不会影响整条链路。

模型层我用的是内网部署的开源权重模型,参数量在70B级别。故障诊断的另一个硬性要求是数据不能出内网,所以必须用本地部署。推理框架上整了vLLM做并发推理,多智能体并发查询时吞吐才撑得住。

存储和中间件方面,向量库用了轻量方案负责故障模式检索,日志检索复用现有日志系统,另外用Redis做任务队列,控制各智能体的并发度和超时机制。下面这张表是整个框架的选型清单:

组件选型选择理由
编排层状态图框架流程可视化、分支可控、失败可恢复
模型层内网部署开源大模型数据不出内网,可私有化
任务队列Redis轻量、支持优先级和超时控制
日志检索现有日志平台 + 向量检索复用基础设施,减少改造成本
知识库向量库存故障模式支持语义检索,召回历史经验

这个架构不是一上来就定死的。最开始我也尝试过让一个模型做“自由ReAct”式推理,但发现流程完全不可控,同一个故障每次排查路径都不一样,根本没法评估好坏。换成状态图之后,排查路径收敛成有限的几种,测试成本一下子降下来了。

3. 核心实现:把“会诊”流程工程化

架构设计的部分讲清楚了,接下来是代码和配置层面的具体实现。这一章我会按故障处理的先后顺序,讲清楚每个环节是怎么做的。

3.1 告警风暴收敛:先让几百条告警变成一个事件

告警感知智能体最核心的算法是“告警折叠”。一次故障里,监控平台可能同时触发几百条告警,直接丢给模型,模型根本分不清主次。我的做法分三步:

第一步,把每条告警转成语义向量。告警标题和标签拼接成文本,用嵌入模型编码成向量。第二步,按时间窗口分组,窗口设为5分钟。第三步,在每个时间窗口内做向量聚类,距离小于阈值的告警归到同一个事件下。一个事件会保留最早告警时间、最晚告警时间、涉及服务集合、告警类型分布。

时序相关性分析是这里的关键补充。有些告警虽然文本完全不同,但时间上几乎同时爆发,说明它们很可能是同一个根因的不同表现。所以我额外记录了“事件内告警的时间聚集度”——这个数值越高,越说明是突发的关联故障,而不是零散的偶发告警。

实际效果:某次支付链路故障,原始告警487条,折叠后只生成1个核心事件,涉及8个服务。决策智能体在事件层面做判断,压力小了一个数量级。如果这一步不做,后面所有环节的上下文都会爆炸。

3.2 时间感知的日志检索:先粗筛,再精读

日志检索智能体往上接的是指标取证给出的异常时间窗口。它做的不是把日志文本一股脑塞进模型,而是先跑确定性检索,再做摘要。

我把检索逻辑做成一个带时间感知的RAG流程。第一步,用时间范围和服务名把日志系统里对应的日志先圈出来;第二步,在圈定的范围内做关键词匹配和向量检索,取出最相关的日志片段,这一步会过滤掉至少九成无关日志;第三步,对命中的日志做模板抽取,把相似日志聚类成日志模板,比如“java.sql.SQLTransientConnectionException: connection is not available”,几百条重复异常会被归纳成一条模板;第四步才把日志模板列表交给大模型做语义归纳,总结出“哪个模块、在什么时间、出现了什么类型的异常”。

这里有一个重要经验:不要让模型直接处理原始日志全文,哪怕上下文窗口装得下也不要。原始日志里重复噪音太多了,模型很容易被高频日志带偏,忽略低频但关键的错误。日志模板抽取这一步虽然看起来费事,但它把信噪比提升了一个量级,决策智能体的准确率也随之大幅提高。

日志检索引擎返回给线索黑板的,也是结构化证据,格式类似这样:

{ "source": "log", "timestamp": "2025-06-18T14:30:00Z", "affected_entity": "order-service", "summary": "14:31起出现大量数据库连接获取超时,单次等待超过5秒", "raw_ref": "log_query://order-service?time=14:30-14:40&pattern=conn_timeout", "confidence": 0.92 }

3.3 上下文预算管理:让每个智能体的输出都“可被消化”

多智能体系统里,上下文爆炸不只发生在模型输入层,也发生在智能体之间。决策智能体要同时读指标证据、日志证据、变更记录,如果每个取证智能体都返回长文本分析,决策智能体还是会淹死在细节里。

我给每个证据条目定了硬性预算:摘要不超过50字,支持的细节用附件引用替代;每个智能体每次任务最多输出5条证据;日志检索智能体返回的日志模板最多20条,超出部分截断。这套约束一开始会让取证智能体“答得不够全”,但实际效果是决策智能体反而更准了——因为输入里只剩高信号量信息,模型聚焦容易得多。

如果你在做类似系统,我强烈建议把上下文预算当成一等公民来设计,而不是事后再压缩。写进提示词里的固定指令,比任何后置的“摘要压缩”都更可靠。

3.4 只读工具层:大模型只能“看”,不能“动”

运维场景里,让大模型直接操作生产环境是红线。我在工具层做了强制约束:所有暴露给智能体的工具都是只读的。

  • 查询指标:只允许读取指定时间范围的指标,不允许修改采集配置;
  • 查询日志:只允许检索,不允许删除或修改日志;
  • 查询变更:只允许读取发布记录,不允许回滚或重复触发;
  • 查询拓扑:只允许读取依赖关系。

所有写操作,比如重启服务、回滚版本、调整配置,全部不暴露给智能体。这类操作在系统中只能由人工在审批界面触发。即使未来要做到“半自动”,路径也应该是智能体生成操作建议、人工确认后由自动化平台执行,而不是给模型直连生产环境的权限。

工具调用统一走Function Calling协议,每个工具按参数Schema严格定义,模型只能按Schema生成调用。这样即便模型想发挥一下,也会因为缺失参数而调用失败,不至于产生越权行为。实测下来,这一步是整个框架能过安全评审的关键。

3.5 故障模式知识库:把老师傅的经验写进结构化条目录

多智能体系统能不能收敛到正确答案,很大程度上取决于有没有可检索的历史经验。我把团队过去处理过的故障复盘,整理成结构化的故障模式条目,每个条目包含四个部分:故障现象、证据特征、根因假设、验证动作。

举个例子,一个“数据库连接池耗尽”的故障模式长这样:

pattern: db_connection_pool_exhaustion symptoms: - 服务日志高频出现 "connection is not available" - 应用P99延迟陡增,但CPU和内存无明显飙升 - 数据库侧活跃连接数打到上限 evidence: - log_templates: ["SQLTransientConnectionException", "waiting for connection"] - metric_pattern: "thread_pool_active_ratio 接近1" root_causes: - 慢SQL积压,占满连接池 - 上游QPS突增,连接池容量不足 - 数据库实例异常,连接无法及时释放 validation_actions: - 查看数据库当前活跃连接数和连接等待时间 - 定位耗时排名前N的慢SQL

故障模式入库之后,根因决策智能体不再只靠模型自身知识猜答案,而是先做一次向量检索,把最相似的历史模式连同证据一起作为上下文喂给模型,让模型去匹配“当前故障像哪个历史故障”。这个做法效果非常明显,可以直接把根因命中率往上拉一大截。本质上,知识库承担了模型外部记忆的功能,解决了模型对内部系统认知不足的问题。

4. 落地过程中踩过的坑与工程护栏

架构再漂亮,落地时还是要被现实毒打几轮。这一章分享我在模拟项目X和后续实际接入过程中遇到的最典型的五个坑,每一个都写清楚现象、排查链路和最终修复方案。

4.1 并发告警直接把任务队列打爆

现象:压测时模拟一次大规模故障,几百条告警同时进来,系统瞬间创建了几百个诊断任务,后端模型推理服务直接被打到超时,连正常任务也排不上队了。

排查链路:先看任务队列,发现堆积数在几秒内冲到上千;再看推理服务,已经满载;最后看任务生成逻辑,发现入口处对每个告警都创建了独立任务,完全没做收敛。

修复:加了两道护栏。第一道,入口处先做告警折叠,折叠完成后再生成诊断任务,从源头把任务数压下来;第二道,任务队列加上并发上限和优先级,核心链路故障的任务优先处理,非核心的排队等待。同时给每个智能体调用设置超时时间,超过30秒直接失败重试,不拖累整条链路。

4.2 一本正经地编造根因:幻觉问题比想象的更隐蔽

现象:有次故障真实原因是磁盘空间不足导致日志写不进去,但决策智能体在证据不足时,硬是根据“Kafka消费者延迟”这个不相关线索,编了一个“消息积压导致消费链路阻塞”的结论,还给出了0.87的高置信度。

排查链路:回放了决策智能体的输入,发现日志检索环节因为权限问题没有返回任何日志证据,决策智能体的上下文里根本没有“磁盘告警”这条信息。它面对缺失信息时,选择了“引用最靠近的相似模式”而不是“承认不知道”。这比直接乱猜更危险,因为它包装得很像回事。

修复:做了两条硬约束。第一条是证据强制引用,决策智能体输出的每条根因假设必须对照证据列表逐项引用,不能引用就要标注“无证据支持”。第二条是置信度校准,当证据数量少于阈值时,整体置信度上限被强制压到0.5以下,同时优先输出“信息不足,建议人工介入”。之后模型学会了一个很可贵的表达:不确定的时候说不知道,而不是编一个理由。

4.3 智能体在排查链路上越走越偏

现象:日志检索智能体有一次为了追一个“可疑的用户登录日志”,连续执行了6轮查询,把业务日志翻了个底朝天,最后也没找到任何异常,白白浪费了将近3分钟,还阻塞了后续流程。

排查链路:打开编排系统的时间线,看到这个智能体在每轮查询后都生成了一条“新的线索”,然后基于自己的新线索继续深挖,完全偏离了最初的告警事件。本质是模型在自由探索模式下,缺少“目标锚点”和“终止条件”。

修复:我给取证类智能体加了行动模板约束。提示词里明确规定:每轮最多允许3次查询,每次查询必须围绕原始事件时间窗口展开,不允许无限延伸;每次查询完必须回答“这条线索对定位根因有帮助还是有干扰”;达到查询次数上限或连续两轮线索相关性评分低于阈值,立即停止并总结现有发现。加了这层约束以后,单次诊断任务的平均执行时间下降了一半还多。

4.4 上下文爆炸:模型看得多,反而记不住重点

现象:早期版本让日志检索智能体把“相关日志片段”直接返回给决策智能体,遇到日志量大的故障,单条证据的文本长度能到上万token,决策智能体读到最后已经完全忘了最开始的事件特征。

排查链路:把决策智能体的输入打印出来,发现前面三页全是日志原文,真正高价值的指标突变信息被淹没在中后部位置,模型的注意力机制天然偏向长文本的中前段,后面的证据根本没被有效利用。

修复:这就是前面提到的上下文预算管理的来历。我彻底改变了证据格式,所有输入决策智能体的证据都必须经过“摘要化 + 结构化”处理,原始日志只保留引用链接。同时把证据顺序重排,按“事件摘要 → 指标突变 → 日志模板 → 变更记录”的优先级排列,确保决策智能体一开始就拿到最关键的线索。

4.5 权限护栏差点被误开:一次配置文件引发的虚惊

现象:有一次准备把“日志检索智能体”迁移到新版本,我在配置文件里加了一个新的工具定义,顺手把“服务重启”加到了可用工具列表里。虽然只是调试配置,目录权限设置不当导致它被误发布到了灰度环境。

排查链路:这个问题不是系统自动发现的,是一次人工走查时发现的。虽然该工具没有实际被智能体调用过,但它说明了一个问题:工具注册表和环境权限没有做环境隔离校验。

修复:第一,所有工具定义按环境隔离,生产环境只加载只读工具包,任何写操作工具在加载阶段就被拦截;第二,增加配置校验流水线,发布前检查工具列表中是否存在高危操作;第三,建立工具调用审计日志,每次调用都记录调用者、目标、时间、参数,确保出了问题能回溯。这里用血的教训证明了之前坚持只读原则的重要性。

5. 怎么证明它有效:评估方法与灰度推广路径

多智能体系统最怕“自我感觉良好”。所以从第一天开始,我就坚持用可量化的评测来验证效果,而不是靠几个Demo眼测。

5.1 建立故障回放评测集

评测集来源是过去一年处理过的历史故障,人工整理成标准化样例,每个样例包含四个部分:

  • 原始输入:当时的告警列表、指标数据、日志样本、变更记录;
  • 时间范围:从故障发生到恢复的时间段;
  • 标准答案:事后复盘确认的根因;
  • 关键证据:判断根因所需的核心证据条目。

整理时要注意样本多样性,覆盖应用层故障、基础设施故障、依赖故障、变更引发故障这几大类,每类不少于10个。评测时整体回放,让框架根据输入自己跑一遍诊断流程,再把输出和标准答案对比。这样得到的效果指标才可信。

5.2 核心指标怎么度量

我重点看四个指标:

  • 平均诊断耗时:从告警进入系统到产出根因报告的时间;
  • 根因命中率:Top 3假设中是否包含标准答案;
  • 证据完整率:输出结论是否覆盖了标准答案中的关键证据;
  • 人工采纳率:运维人员实际采纳根因报告并据此处置的比例。

下面是模拟项目X在某次内部评估中的一组数据:

指标原人工模式多智能体辅助模式
平均诊断耗时45分钟9分钟
Top 3根因命中率约70%约85%
平均排查步骤数5次左右7次左右
报告可追溯性低高

注意,平均排查步骤数反而变多了,这是好事——多智能体把很多隐性的排查动作显性化了,过程中采集的证据更多,结论也更容易被复核。

5.3 灰度推广的三阶段路径

我不建议直接把系统的结论接到自动处置流程上。稳妥的路径分三步走。

第一阶段是“只读助手”,智能体只产出诊断报告,不关联任何操作权限,运维人员把它当加速排查的工具。这个阶段跑3到4周,主要看报告质量和人工采纳率。

第二阶段是“建议助手”,智能体在诊断报告基础上,增加处置建议,比如“建议扩容连接池”“建议回滚某次发布”,但执行仍然由人工完成。这个阶段重点验证建议的准确性。

第三阶段是“半自动执行”,只对低风险、高频复现的故障做自动处置,比如重启异常采集器、清理堆积的临时文件,同时保留双人审批。高风险操作继续走人工通道。至于全自动处置,至少在现阶段,我不推荐,运维领域容不下冒险主义。

5.4 这套框架的边界在哪里

最后说一个我一直在提醒自己的事情:多智能体框架不是银弹。它能把故障诊断的过程变得有结构、可追溯,让团队的经验沉淀成可检索的知识库,但它替代不了变更管理的严谨性,替代不了系统设计的健壮性,更替代不了工程师的现场判断。

在真正运行的过程中,我最深的体会是:不要一上来追求“全自动定位根因”,先把“人机协同”跑顺。智能体负责把数据拉齐、把时间线理清、把可疑点排序,人负责在关键节点做决策。随着证据链越来越丰富,人机之间的信任才会逐步建立起来,自动化的边界才能慢慢往前推。

如果你也想做类似的多智能体运维诊断系统,我给你的建议是:把RAG、向量检索、Function Calling这些技术点当成砖块,先设计好一套清晰的故障排查SOP,再把砖块一块块垒进SOP的每个环节里。技术永远服务于流程,一个好的流程本身,就已经是这套系统最核心的资产了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进