做AIOps告警归因,很多人刚开始的想法特别朴素:把告警文本丢给大模型,写一句“帮我分析一下根因”,然后拿结果去展示。真让你把这套东西放到生产环境,每天接几十万条告警、P95延迟要压到几秒、还不能瞎给结论的时候,你马上会意识到,“提示工程”这三个字的分量,比想象中重太多。
这篇文章不聊纯理论,而是把我在监控平台改造项目里总结出来的四个阶梯完整拆开:跑通单条告警归因、注入运维上下文、加评估与兜底、规模化运营。适合正在做AIOps告警归因的SRE、平台工程师,也适合刚入门提示工程、想搞明白“生产级Prompt”和“Demo级Prompt”到底差在哪的人。市面上的AIOps书籍,比如《智能运维:从0搭建大规模分布式AIOps系统》,能帮你建立整体框架,但真正把告警归因做到可上生产,靠的还是在一轮轮踩坑里攒下来的细节。
1. 先拆概念:告警归因的难点,恰好是提示工程能插手的地方
1.1 告警不等于根因,归因的本质是“从现象反推原因”
运维里的告警,绝大多数只是“现象”。数据库连接池打满的时候,你的监控面板上会同时冒出几十条告警:API错误率升高、P99延迟飙到几秒、订单服务超时、下游支付超时、某个实例健康检查失败……值班同学如果一条一条点开看,大概率要花掉十几分钟才能理出头绪,而这十几分钟里业务可能已经受损了。
告警归因要解决的,就是从这一堆“现象”里找到最像“原因”的那一两条,并且给出站得住的推断逻辑。传统做法分几派:规则引擎靠人工维护的if-then,拓扑分析靠节点间依赖关系,时序算法靠指标突变的根因定位,聚类算法把相似告警揉在一起。坦白讲,这些方法都有效,但它们在“语义理解”上有天花板。规则很难覆盖长尾场景,拓扑分析遇到跨系统调用链就抓瞎,时序算法只能告诉你哪个指标变了,说不清为什么变。
大模型的出现补上了这块短板。它能同时读告警文本、看指标趋势摘要、理解变更记录和日志片段,再把它们串成一条有逻辑的归因链。说白了,大模型在这里扮演的角色,像一个经验丰富的老值班员工,配了一个能把监控数据快速整理好放在他面前的助手。但也正因为大模型的“读和想”靠的是提示词,提示词写得好不好,直接决定了这个助手是靠谱还是满嘴跑火车。
1.2 提示工程在AIOps里补的不是“话术”,而是信息编排与推理约束
很多人一听提示工程,第一反应是“怎么把Prompt写得漂亮”,比如加一个“你是AIOps专家”、强调“请仔细思考”。这些当然不坏,但真正到了告警归因场景,你会发现生产级提示工程的核心是两件事:信息编排和推理约束。
信息编排解决的是“模型该看什么”。一条告警发生的时候,相关的数据可能是天量的:几十个指标、几百行日志、拓扑关系、变更记录、历史工单。你的Prompt窗口装不下所有东西,必须有取舍、有顺序、有摘要地把最关键的信息摆到模型面前。这才是我在实操里最花时间的部分,也是“上下文工程”(Context Engineering)为什么越来越重要的原因——它本质上就是提示词工程的进阶形态,决定哪些数据进入上下文窗口、以什么粒度进入、按什么顺序排列。
推理约束解决的是“模型该怎么答”。告警归因的结论要被告警平台消费,就不能是“我觉得可能是数据库有点问题”这种自然语言,而是要输出结构化JSON,包含候选根因、置信度、证据、建议处置动作。再往深一点,还要让模型知道“证据不足时必须承认不足”,而不是硬编一个理由出来。这些约束,全都得靠提示词和输出协议一点点焊死。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 第一阶梯:单条告警归因,先把“能用”跑通
2.1 开工之前,先把输入字段和输出协议定死
我见过太多团队上来就写Prompt,写了两周发现没法用,回过头来才意识到:输入和输出的格式没定,后面的所有东西都在流沙上盖楼。
告警归因的输入,一定要先盘清楚有哪些字段可用。一般我会从告警平台事件里抽这几类:
- 告警名称和描述:比如“MySQL连接数过高”
- 触发时间、持续时间、告警级别
- 资源对象:主机IP、实例名、服务名、集群名
- 标签和维度:可用区、环境、所属应用
- 监控数据:当前值、阈值、触发时长、环比变化
这些字段不是全都要塞进Prompt,但你必须知道有哪些。因为后面做上下文工程时,很多数据要从这里关联出去。
输出协议更重要。生产环境里模型输出是要被下游系统消费的,绝对不能是长篇大论的自然语言。我建议第一版就定成JSON,最外层固定两个字段:summary和candidate_root_causes,后者是数组,每个元素包含confidence、reason、evidence、suggested_action。
text复制请对下面的告警进行根因归因,并严格按照如下 JSON 格式输出,不要输出任何解释:
{
"summary": "一句话概括当前告警现状",
"information_sufficiency": "sufficient",
"candidate_root_causes": [
{
"confidence": 0.7,
"reason": "根因推断的简述",
"evidence": ["能从告警字段中引用的依据"],
"suggested_action": "建议的处置动作"
}
]
}
这些字段的意义后面会细说,但你要记住一个原则:输出协议里的每个字段,都必须是可解析、可落库、可驱动下游动作的。不是为了好看,是为了让程序能接得住。
2.2 系统提示词怎么组织:角色、任务、约束三件套
单条告警归因的Prompt,我会分成三大段来写:角色设定、任务定义、输出约束。每一段都有它存在的理由。
角色设定别写得太浮夸。“你是一名资深SRE,擅长数据库、中间件和应用故障排查”,就够了。我不建议写“你是无所不能的运维专家”,因为太宽泛的角色定义会让模型倾向于给出泛泛而谈的结论。你要的是“有明确经验边界的工程师”。
任务定义要聚焦。明确告诉模型:你现在拿到的是告警平台的一条事件,你要基于这些字段推测最可能的根因,并且给证据。这里的关键词是“基于字段”——它是在要求模型一切推断都有出处,而不是凭空想象。
输出约束就是上一步那个JSON协议,再加上几条硬性规则:每条结论必须引用输入字段;证据不足时允许在candidate_root_causes返回空数组,并设置information_sufficiency为insufficient;confidence低于0.4的结论不要列出来。
第一版Prompt其实不复杂,但你要清楚地知道每句话在干嘛。角色设定是在划边界,任务定义是在定目标,输出约束是在管质量。
2.3 常见坑:模型一本正经地胡说八道
这个阶段的坑我用一句话总结:模型特别擅长在信息不足的情况下,硬给你编一个看起来合理的根因。
原因也不难理解。告警文本很多都是模板化文案,比如“disk used percentage > 85%”,你让模型去猜根因,它只能根据训练数据里的“常见套路”来编。它可能会告诉你“可能是日志文件过大,建议清理日志”,听起来很对,但实际环境里根因可能是某个新上线的任务把临时文件全写到了同一个分区。你没给它看变更数据,它就只能瞎猜。
对策有两个。第一,在提示词里明确要求“每条结论必须从输入字段中引用证据,如果没有任何字段能支撑,请返回insufficient”。第二,在消费端做一层校验,对evidence为空的结论直接打回。这个阶段不求准确率高,只求输出结构稳定、可被系统消费。我一般会用大概15到20条历史告警来验收,要求JSON解析成功率100%、其中至少70%的结论人工判断为“可用”。达不到这个标准,就别急着上上下文。
3. 第二阶梯:上下文工程,让模型“看”到该看的东西
3.1 为什么只有告警文本远远不够
单条告警的归因跑通之后,你会发现一个尴尬的事实:准确率上不去,卡在50%上下,模型给出的结论总是“正确的废话”。
问题不在模型,在信息。我举个例子:某天凌晨磁盘使用率超过85%触发告警,告警内容本身只描述了现象。但真正的根因是前一天晚上十点上线了一个日志采集任务,这个任务把所有实例的日志统一写到共享盘上,把盘撑爆了。模型看不到这个变更信息,它怎么可能归因出“新任务导致磁盘占用突增”?
所以第二阶梯的核心,就是从“只给告警文本”升级到“给一套和这条告警相关的运维上下文”。这一步就是上下文工程发挥作用的地方。提示词工程师如果只会写措辞,那叫提示词写手;会做信息装配,才叫上下文工程。
3.2 上下文装配清单:按需拿,不是全量塞
上下文也不是越多越好。Token有限,塞太多无关数据反而会稀释关键信息。我得出一份上下文装配清单,每次按需取用:
| 上下文类型 | 典型数据 | 为什么要放 | 注意事项 |
|---|---|---|---|
| 变更事件 | 发布、配置变更、扩缩容、定时任务 | 很多根因紧贴着一次变更发生 | 只取告警触发前24小时内的变更,按时间排序 |
| 指标趋势摘要 | 当前值、环比突增率、是否突破历史基线 | 判断问题是持续性问题还是突发抖动 | 挑3到5个核心指标,不要列几十个 |
| 拓扑依赖关系 | 资源的上游服务和下游依赖 | 判断根因是自身问题还是依赖方导致 | 最多取两跳,太多会让模型迷失 |
| 日志摘要 | 异常关键词、最近异常日志片段 | 补充直接证据,帮助定位具体错误 | 提前离线抽取关键片段,不要丢原始日志全文 |
这张表背后的逻辑是:变更事件回答“最近发生了什么改变”,指标趋势回答“现象有多严重”,拓扑依赖回答“责任在谁”,日志摘要回答“直接证据是什么”。四样凑齐,模型才有可能做出高质量的归因。
3.3 提示词的信息排列顺序,也有讲究
很多做提示词的人会忽略顺序,但这是我实测下来对效果影响很大的一个点。模型的注意力天然集中在上下文窗口靠前的位置,所以信息排列要遵循“先事实、后分析”的原则。
我的模板大致长这样:
text复制【告警信息】
告警名称:MySQL连接数过高
触发时间:2025-01-12 03:22:00
资源对象:prod-db-01
当前值:312 / 阈值:200
【相关指标】
- 活跃连接数:312,环比上升120%
- CPU使用率:68%,与历史同时段持平
- InnoDB锁等待:突增5倍
【最近变更】
- 01-12 02:00,订单服务 v2.3.1 发布,涉及新增批量接口
- 01-11 22:00,prod-db-01 参数max_connections调整至200
【依赖关系】
- 上游:订单服务、支付服务
- 下游:商品库、库存库
【历史相似告警】
- 2025-01-05,类似告警,根因:批量接口未做连接释放
【输出要求】
请基于以上信息,分析根因,按JSON格式输出。
能看到一个顺序逻辑:先让模型知道发生了什么,再给它变化和证据,最后让它结合历史经验给出结论。如果一上来就塞拓扑和变更,模型可能根本还没搞清楚当前告警是什么,就开始推理了。
3.4 少样本示例:用三个案例固定推理风格
上下文工程的另一个重要手段,是少样本示例(Few-shot)。单有指令不够,模型对“归因推理”应该长什么样没有具象感知。我会在Prompt里固定放三个示例,覆盖三种最常见场景:
- 依赖故障:服务A大量超时,根因在下游服务B的GC停顿。
- 资源瓶颈:连接池打满,根因是新接口未释放连接。
- 变更触发:磁盘使用率突增,根因是日志采集任务写入共享盘。
每个示例都由三段组成:一段精简的上下文摘要、一个JSON格式的归因结果、一句极简推理链。这里有一个关键心得:推理链一定要短。你写长了,模型会学着“长篇大论地分析”,输出延迟和Token消耗都会涨,效果也不见得更好。
还有一个特别容易踩的坑:示例不要带上过强的“唯一标识”。比如三个示例里两个都用“订单服务”,模型遇到Redis的告警也容易猜成订单服务。我一般会故意把示例里的服务名、资源名替换成中性词,降低对特定实体的过拟合。
3.5 输出稳定性:坏掉的JSON是常态,不是意外
提示词调得再好,模型还是偶尔会给你输出一段带着“```json”围栏的文本,或者干脆吐一堆自然语言。应对方案有三层。
第一层,能用平台能力就用平台能力。现在主流大模型都支持结构化输出或函数调用,相当于在协议层锁死了JSON格式,比在提示词里反复强调“只输出JSON”要可靠得多。
第二层,后端再做一套脏数据修复。我常用的处理流程是:先把代码围栏剥掉,再用正则提取最外层花括号,然后尝试JSON.parse。大多数情况下,模型只是包了一层壳,剥掉就能用。
第三层,重试时带上坏例子。如果解析还是失败,我会把上一次的坏输出当作一个反例,塞进重试Prompt里,明确告诉模型“这是错误输出,请不要这样写,请只输出纯JSON”。这一招实测能挽回不少错误的输出。
到这一步,“能用”基本达成了。但请注意:能解析、有人看的懂,和能上生产,中间还隔着一条大河。
4. 第三阶梯:生产可用,靠的是评估、兜底与版本管理
4.1 上线前先搭一套评估集,别拍脑袋
我见过不少团队,模型效果靠“人工点几个例子看看”来验收。这在PoC阶段行,但真要上生产,必须有一套可持续运行的评估集。没有评估集,你改了一版Prompt,到底是变好了还是变坏了,完全靠感觉,这是生产环境绝对不能接受的。
评估集怎么来?最简单有效的方法是从历史已解决的告警工单里抽。选那些根因明确、处置动作清晰的工单,人工标注出“期望根因类型”“期望资源对象”“期望处置动作”,攒到100到300条就够用。样本要覆盖数据库、中间件、应用、网络这几大类,别全是同一类故障。
4.2 用四个指标来度量归因效果
我的生产评估指标基本固定为四个,每个都有明确的参考线:
| 指标 | 含义 | 我建议的参考线 |
|---|---|---|
| 结构解析成功率 | 输出JSON可解析的比例 | ≥99% |
| Top1 归因命中率 | 模型给出的第一个根因和人工结论一致 | 起步50%,逐步往70%走 |
| Top3 归因覆盖率 | 前三条候选根因里包含人工根因 | ≥80% |
| 无效归因率 | 模型返回“信息不足”但实际能归因的比例 | ≤10%(可调) |
端到端延迟也要看。值班场景下,告警归因如果拖到几十秒才有结论,意义就大打折扣了。我一般会要求P95延迟控制在5秒以内,如果超了就往下砍上下文长度或者换更快的模型。
4.3 置信度与兜底策略:让模型学会“承认不会”
这是生产化里最重要的一件事:模型必须允许“答不出来”。硬答的代价,比不答高得多。一个低置信度的错误归因,会把值班人员引到完全错误的方向上。
我的做法是在输出协议里加上confidence和information_sufficiency两个字段,然后在提示词里明确约束:当证据不足或相互矛盾时,candidate_root_causes返回空数组,不允许硬猜。
生产链路上再加一道兜底:如果模型返回了低置信度结果(比如最高confidence低于0.5),就不把这个结果作为“最终归因”推送给值班人员,而是自动切换到传统规则聚类链路,把规则引擎的结论和模型结论并排展示,让值班人员自己判断。这一步很重要。它意味着模型不是唯一依赖,系统整体可用性不会因为模型抽风而崩塌。
4.4 提示词版本化管理:Prompt也是代码
上生产之后,你一定会频繁改提示词,可能是为了提升准确率,可能是为了适配新的告警类型。但Prompt的改动对输出的影响往往是非线性的,可能只改了一句话,整套结果都变了。
所以Prompt必须版本化,而且要落到日志里。每次请求都记录用的是哪个版本的提示词,后面做效果对比时才能追溯。灰度发布也是必须的:按告警类型切流量,比如先让50%的数据库告警走新版Prompt,其他告警走旧版,跑一到两天看评估集和线上抽检对比,再决定是否全量。
线上抽检我建议做成常态化机制,每天抽20条归因结果,让值班人员点“有用”或“没用”。这些标记数据会成为后续迭代的核心资产。
4.5 数据脱敏与部署边界
告警信息里经常带着IP、账号、实例ID,甚至可能有连接串。这些信息在进入大模型之前,一定要做脱敏处理。我的做法是在告警接入层做一层清洗,把IP替换成脱敏编号、账号信息打码、密钥直接剔除。
部署上要守住数据边界。如果公司要求数据不出内网,就用私有化部署或合规的企业版服务,网络隔离按公司安全规范来。日志也不要记全量告警原文,只保留脱敏摘要、Prompt版本号、模型返回的JSON结果。这块宁可保守一点,也别等出了事再补。
5. 第四阶梯:规模化运营,从“一条告警”走向“一群告警”
5.1 告警风暴来了,单条归因会直接被淹没
生产环境里,告警往往不是一条条来的,而是成群结队地来。某个核心服务抖动,五分钟内可能产生几百条告警。你要是拿单条归因的Prompt去逐条分析,延迟和成本都扛不住,而且这些告警之间高度相关,单独分析本身就是一种浪费。
我的做法是先聚类、再归因。聚类的维度不复杂:按资源对象、告警类型、时间窗重合度做一个粗粒度分组。把同一服务、同一类型、在相近时间段内触发的告警归到同一个场景里。聚类之后,对场景做一次整体归因,而不是对每条告警分别归因。
场景归因的Prompt和单条归因有所不同,它需要包含场景内告警的数量、Top类型的分布、共同的资源对象、整体的指标趋势。信息密度更高,但对模型的推理要求反而更集中了。
5.2 用已确认案例库做动态少样本,效果比堆Prompt明显
固定三个Few-shot示例,在场景一多之后会显得不够用。不同故障类型的归因套路差别很大,固定示例只能覆盖最通用的场景。这时候我建议建一个“已确认案例库”,把每次人工确认过的根因沉淀下来。
检索方式不需要很重。给每条案例做向量化,存到轻量向量库里,查询时用当前告警的文本和资源信息去检索最相似的1到3条案例,动态注入到Prompt里当少样本示例。时间衰减要注意,三个月前的案例和三天前的案例权重应当不同。
这个案例库的维护门槛很高。只有人工确认过的根因才能进库,模型自己输出的结果,哪怕置信度很高,也不能直接成为历史案例。否则一个错误归因被重复学习,整个系统的准确率会越来越偏。这是我在实操里吃过亏的地方。
5.3 建立线上反馈闭环,持续迭代
生产环境的告警归因系统,运行几个月后和初始版本的效果差距,往往不来自模型升级,而来自反馈闭环的完善。
值班界面上一定要有“采纳/纠正/无效”这三个操作。值班人员看到模型归因结果后,点一下“采纳”,这条结果和告警的关联就进入案例库;点“纠正”,则要记录人工认为的正确根因,作为错误样本;点“无效”,说明模型这次完全跑偏了。
这些反馈数据攒到一定量级后,每两周做一轮分析:错在哪里、哪类告警容易被误判、是不是Prompt里缺了什么上下文。然后针对性改提示词或案例库,再跑回归集。我实测下来,这种小步快跑的迭代方式,稳定性远好于憋一个大版本然后大改。
5.4 降本与延迟:钱和性能都得管
上生产之后,成本意识和之前完全不同。每万次归因调用的Token消耗,直接决定这个方案能不能长期跑下去。
我的经验是三个方向。第一,给上下文做瘦身:指标只给摘要,日志只给抽出来的异常片段,历史案例只给最相似的一两条。能少给Token就少给,效果并不会因为少两行数据而崩塌。第二,分级调用:规则能覆盖的简单告警先用规则引擎,只有复杂场景才调用大模型。数据库连接池打满这种有明显规律的,规则引擎几毫秒就出结论,根本不用大模型。第三,做缓存:同一资源短时间内重复触发同类告警,如果上下文没有实质变化,可以直接复用上次的结论。缓存结果要标注来源,避免被误认为实时分析。
加上缓存和分级之后,我见过不少项目的成本能降到原来的三分之一以下,P95延迟也明显改善。
6. 最后说点实在的:踩坑心得
这套东西摸着石头走到今天,有一些教训特别想分享。
输出协议一定要一开始就定成JSON。我见过有团队用自然语言做输出协议,后面做解析和落库的时候痛苦到怀疑人生。Prompt写得再华丽,输出没法被程序稳定消费,一切等于零。
别迷信“你是AIOps专家”这种万金油话术。模型听了这句话并不会开挂,真正让它变准的,是上下文质量和案例质量。把时间花在梳理变更数据、指标摘要、历史案例上,性价比远比在提示词里堆形容词高。
案例库必须设人工审核门槛。错误案例一旦进库,就会一遍遍地被检索出来作为示例,每次都在给模型错误的示范,准确率只会越来越差。宁可案例库小一点,也要保证每一条都干净。
不要试图用大模型替代所有传统手段。规则引擎在很多简单场景里依然又快又准,大模型的价值是补足长尾和复杂推理。保留规则链路做兜底,整体可靠性会高很多。
如果你现在正要开始做这件事,我的建议很简单:从单条告警加一个二三十条样本的测试集开始,先把输出结构和解析链路跑通。别一上来就想着“全场景Agent化”“自动处置”,先把“看一条告警,给一个说得通的根因”这个动作做到稳定,后面的路自然会清晰。
