1. 从告警风暴到根因定位:AIOps提示工程到底在解决什么问题
1.1 告警归因的技术链路拆解
AIOps告警归因这个场景,说起来其实很直白:线上某个服务出问题了,监控系统在几分钟内刷出几百条告警,值班同学需要快速判断“到底哪条是根因、哪些只是连带反应”。过去靠人肉翻监控、查日志、看调用链,遇到大促或者深夜故障,往往一两个小时过去了还在“抢救现场”。而AIOps要做的,就是把这些数据交叉分析后,直接给出一句话结论:核心数据库连接池耗尽,导致订单服务超时,触发下游缓存和网关告警。
但如果真在运维侧落过地,就会发现一个尴尬现实:市面上很多AIOps平台,规则引擎、异常检测模型都做得很重,可一到“告警归因”这一步就露怯。传统的关联规则能发现“A告警和B告警经常一起出现”,可一旦出现新故障模式,规则库就失效了;机器学习模型能把告警聚成几类,但“为什么会发生、影响面多大、先处理哪个”依然说不清楚。
大模型出现后,很多人觉得机会来了:让LLM读一堆告警文本和监控数据,直接输出根因分析不就行了?理论上确实可以,但实际一上手就会遇到三个问题:第一,告警上下文太长,模型记不住;第二,输出格式五花八门,没法接下游工单系统;第三,模型一本正经地说错根因,还自信满满。这些问题单靠“提示词写得更细一点”根本解决不了,就需要一套系统性的提示工程方法。
这里说的提示工程,不只是“写prompt”,而是从输入上下文构造、输出格式约束、推理链路控制到效果评估反馈的完整工程链路。圈里最近把“上下文工程”单独拎出来讲,我觉得是好事,因为对于告警归因这种强依赖上下文的任务,上下文怎么组织,往往比提示词本身更决定效果。
1.2 为什么说提示工程是生产落地的分水岭
我在不同团队见过两种做告警归因的方式:一种是拿开源模型本地部署,喂几条示例就指望它在生产环境稳定输出;另一种是买了商业AIOps产品,背后的算法是黑盒,告警归因结果出来也不敢直接信。这两种都没真正解决“可上生产”的问题。
“能用到可上生产”之间的差距,我总结下来就是四道坎:稳定性、可解释性、可控性和可迭代性。稳定性指连续跑一个月,输出质量和响应延迟不能忽高忽低;可解释性指分析结果得有证据链,不能只给结论;可控性指输出格式必须能被上下游系统解析;可迭代性指遇到新场景时,能快速调整策略而不是推翻重来。
这四道坎,恰好对应提示工程落地告警归因的四个阶梯:第一阶梯用模板化提示把流程跑通,第二阶梯用上下文工程把信息喂够,第三阶梯用结构化输出和证据约束把模型“管住”,第四阶梯用反馈闭环让系统越用越准。下面我把每个阶梯的实操要点和踩过的坑都展开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 阶梯一:模板化Prompt,先让归因流程跑起来
2.1 最小可用提示模板长什么样
第一阶梯的目标很朴素:有一个Invoke接口能调,输入一批告警,输出一个像样的根因结论。不要一上来就搞复杂的Agent编排和工具调用,先把链路最简化。
我当时落地时用的最小模板大致是这样:
text复制你是一名资深SRE工程师。以下是系统在{timestamp}产生的告警列表,请判断根因并给出分析。
告警列表:
{formatted_alerts}
请按以下格式返回:
根因:...
影响范围:...
处理建议:...
别小看这个模板,能跑通本身就有很多门道。格式化告警列表这一步,我建议不要把原始告警文本直接拼接,而是统一转成结构化字段再拼。比如Prometheus告警里有alertname、instance、job、summary、description,如果全塞进去,上下文又长又乱。更好的做法是只保留核心字段,而且用统一的KV格式:
text复制- 告警名称: HighErrorRate
实例: 10.0.1.23:8080
服务: order-service
当前值: 23.5%
阈值: 5%
时间: 2025-01-12 14:03:22
描述: 订单服务错误率超过5%持续5分钟
字段要控制在一行一个,别用JSON,因为JSON的嵌套结构会占用大量token,而且大模型对扁平KV格式的注意力分布更稳定。这一点我后来对比过,同样信息量下,KV格式比JSON格式的提取准确率能高好几个百分点。
第一阶梯还有一个关键操作:把“根因示例”写进提示词。你要是只给模板不加示例,模型第一次可能输出“根因:系统存在异常”,这种废话没有任何价值。但你要是给一条正例和一条反例,比如“根因:数据库连接池满导致订单服务上游故障”,再配合“不要输出‘系统异常’这类无信息量结论”,输出质量立刻不一样。
跑通第一阶梯后,你大概率会发现:它能用,但很脆。单独测试几个告警组时表现还行,一旦告警数量多、场景复杂,就开始胡说。这就逼着你往第二阶梯走。
2.2 阶梯一的典型翻车现场
第一阶梯最容易翻的车,我遇到过的有三种。
第一种是告警一多就乱来。一次模拟故障里同时触发了80多条告警,模板全塞进去后,模型开始反复提及最后几条告警,把最前面的关键告警忽略了。原因是Transformer对长上下文的中间位置信息保持能力有限,而告警列表越长,这个“lost in the middle”问题越明显。解决办法不是无限堆提示词,而是要控制输入规模、调整信息排布。
第二种是模型“和稀泥”。你问它根因是什么,它回答“可能是网络问题,也可能是资源问题,需要进一步排查”。这种输出在生产环境完全没有价值,还会让值班同学更焦虑。原因在于我们对输出约束得不够狠,模型感知到告警信息不完整后,本能地选择安全策略。
第三种是延迟完全不可控。告警归因响应时间是有要求的,一般根因分析要在2分钟内给结果。可如果你把大量日志原文、监控截图全塞进去,提示词超大,大模型推理时间线性上涨,等它吐完,故障都快恢复了。
所以说,第一阶梯的核心价值是“把管线打通”,不是“把效果做好”。要清醒认识到模板化Prompt是地基,不是终点。
3. 阶梯二:上下文工程,把告警现场完整摊开
3.1 告警上下文需要哪些信息
如果只把告警列表丢给模型,就好比只给医生看一张化验单上的异常箭头,不让看病人主诉和历史病历,再厉害的医生也没法确诊。生产环境的告警归因,上下文至少要覆盖四类数据:告警自身信息、关联指标数据、变更事件、历史相似故障。
告警自身信息不难理解,就是告警的时间、级别、对象、阈值触发现状。关联指标数据要额外从时序数据库里拉,比如告警实例过去30分钟的CPU、内存、QPS、错误率、延迟等。变更事件更关键,很多故障的诱因就是当天有人发布了新版本或改了配置,这项数据通常要去发布平台、配置中心拉。历史相似故障则可以从之前的故障工单里找,告诉模型“上次类似告警的根因是X,处理方案是Y”。
这么多信息,肯定不能全塞,否则上下文爆炸。我建议按“谁先谁后”决定优先级:先放告警列表和关键指标,再放变更事件,最后放历史相似案例。而且每类数据都要汇总好再拼进提示词,不要让模型自己从原始数据里做聚合。
一个实测有效的信息组织方式,是把指标数据转换成文字描述,而不是直接把JSON数据丢进去。比如:
text复制order-service 错误率从 14:00 起持续上升,14:03 达到23.5%。
同一时段,该服务数据库连接池使用率达到92%,平均响应时间从120ms升至850ms。
14:01 有发布事件:order-service v2.3.1 上线,变更内容为数据库连接池配置调整。
这种叙述性上下文,比纯数据表格更贴合模型的训练分布,模型更容易建立因果关系。
3.2 上下文拼装的优先级与截断策略
上下文工程的核心问题不是“有哪些信息”,而是“给哪些、不给哪些”。我给它起名叫“告警现场摊开”——把有用信息平铺在模型面前,同时把噪声尽最大可能滤掉。
时间窗口要卡准。别拿24小时数据,绝大多数告警归因只需要看故障前30分钟到当前时刻的数据。窗口太宽,模型会被无关波动干扰;窗口太窄,又看不到趋势变化。经验值是根因分析窗口设为30到60分钟,根据故障类型动态调整也行,但初期固定住更容易评估效果。
告警去重和合并要提前做。告警风暴来了之后,同一个实例可能连续触发几十条同类型告警,这些不合并,上下文一下就满了。这一步最好在进入模型之前用规则做掉:同实例同类型同级别告警,合并成一条,附带“连续触发N次”的标注。
处理不了的长日志要截断,但截断不能只留头尾。大模型对开头和结尾的记忆最深刻,中间内容容易忽略。所以截断策略应该是:保开头(告警发生时间、服务名、实例)、保结尾(当前状态、最近变化),中间部分只保留异常片段。如果你有检索或摘要能力,用摘要替代截断效果更好,但本地小模型做摘要本身就有成本,需要权衡。
做到这个阶段,模型的分析质量会有肉眼可见的提升,但新的麻烦又来了:输出不可控。一会儿输出JSON,一会儿输出Markdown,一会儿又是散文。下游工单系统根本没法解析,评估效果也只能靠人肉读。这就到了第三阶梯。
4. 阶梯三:结构化输出与证据链约束
4.1 用JSON Schema约束大模型输出
可上生产的告警归因系统,输出必须是严格结构化的,因为后续要做工单自动创建、处理建议执行、效果回填,每一步都是程序化对接。第三阶梯的第一要务,是让大模型“说什么都按格式来”。
业界现在最稳妥的做法是采用函数调用(Function Calling)、结构化输出模式或者JSON Schema校验。以OpenAI风格为例,可以定义这样一个输出结构:
json复制{
"root_cause": {
"type": "database|network|code|config|resource|unknown",
"object": "mysql-001",
"detail": "连接池耗尽导致连接获取超时",
"confidence": 0.87
},
"evidence": [
{
"source": "metrics",
"content": "数据库连接池使用率在14:01达到92%",
"timestamp": "2025-01-12T14:01:00Z"
},
{
"source": "event",
"content": "14:01 order-service v2.3.1上线,包含连接池配置变更",
"timestamp": "2025-01-12T14:01:00Z"
}
],
"impact": ["order-service响应时间上升到850ms", "payment-service调用order-service超时率12%"],
"suggestion": "回滚order-service v2.3.1或调大数据库连接池上限,先恢复服务",
"confidence_level": "high"
}
为什么根因类型要限定枚举值?因为开放式的“根因分析”会让模型自由发挥,但生产环境需要的是可归类、可统计、可归档的根因标签。你枚举出database、network、code、config、resource、unknown这几个大类,再让模型在枚举范围内输出,后续就能自动统计哪类故障最多、哪类需要重点治理。
证据链是结构化输出里最容易被忽略但最重要的字段。每一个根因结论,都得给出一到多条可供人快速复核的证据。这个设计直指AIOps的信任问题:值班同学看到AI说“根因是数据库连接池”,第一反应是“凭什么信你”,有了证据链,他就能快速核对指标和变更事件,自己判断要不要采纳。
我在生产实践里还加了硬性校验:如果模型输出的evidence为空,或者confidence低于阈值,这条结果直接标记为“low_confidence”,不走自动工单,只推送到“参考建议”栏。这相当于给大模型输出加了一道安全闸门。
4.2 置信度、兜底策略和回滚开关
结构化输出只有配合置信度和兜底策略,才能真正上生产。置信度不是让模型拍脑袋输出一个数字,而是要和证据链做联动约束。你可以在提示词里写:
text复制只有当证据同时包含指标异常和变更事件时,confidence可以标注为high;
如果因果链存在推测成分,confidence标注为medium;
如果主要依赖经验推测,confidence标注为low。
这样既限制了模型滥用“高置信度”,又让置信度有了可解释的含义。我见过一些团队直接让模型输出0到1之间的小数,结果大多数结论都集中在0.85到0.99之间,参考价值很低。原因就是缺少可操作的置信度定义,模型只是模仿格式而已。
兜底策略方面,我强烈建议准备三层:第一层,模型“不敢决定”时,输出unknown并转人工,这是划算的;第二层,模型结果校验不过时,降级到传统规则引擎的关联分析结果,至少给用户一个基于规则的参考;第三层,模型服务整个挂掉时,走原有告警聚合页面,不能让AIOps成为新的单点故障。
回滚开关也是我踩过坑之后才加上的。有一版提示词优化上线后,模型突然开始频繁判断“根因是K8s节点资源不足”,速度之快让人以为是故障加重了。后来排查发现是上下文里引入了节点CPU指标后,模型对这个维度的信息过分敏感。这种回归问题很难通过一次测试发现,所以配置中心一定要留一个开关,能快速切回上一版提示词,而不是等紧急发版。
第三阶梯做完,你已经有了一个“能输出结构化结论、带证据、带置信度、有兜底”的系统。但生产环境对AI系统的要求不止是“单次结果好”,还要“长期稳定可优化”。第四阶梯就是解决这件事的。
5. 阶梯四:可观测、可反馈、可迭代的生产闭环
5.1 推理链路追踪怎么做
在算法侧和工程侧摸爬滚打久了,你会发现一个残酷现实:大模型应用上线后,最大的成本是排查“为什么AI这次判断错了”。如果提示词、模型版本、上下文输入都无法回溯,效果优化就无从谈起。
所以在第四阶梯,第一件事是给每次告警归因请求生成一个trace_id,把以下信息全部存下来:输入了哪些告警、取了哪些指标、拼接后的完整提示词(注意脱敏)、模型返回的原始输出、解析后的结构化结果、后校验是否通过、最终推送给用户的内容。这些数据落到对象存储或者ES里,按trace_id检索就能完整回溯某次分析的全过程。
有人会问:提示词全文存储有没有泄露风险?有,所以要做好字段脱敏,告警内容里的IP、主机名、业务关键字可以用占位符替换再存储。在内部系统,为了排查问题,这个成本是值得花的。
有了链路追踪,你才能回答这些关键问题:某条根因判断是哪一版提示词产生的?模型的哪个上下文部分影响了它的判断?后校验规则是否误伤了好结果?没有这些数据,所谓的“效果优化”全是拍脑袋。
5.2 效果评估与反馈标注
告警归因的效果评估,和搜索、推荐这类系统不太一样,它更接近“决策支持类任务”的评估,既要看结论准确度,也要看时效和落地价值。
我建议从三个维度建指标体系。
结论准确率:将模型的根因结果和人工最终确认的根因比对,这个指标直接反映“AI有没有说对”。实现方式是每次故障处理完成后,让值班同学在工单里标注实际根因,然后系统自动对比。难点在于根因不是唯一的,需要定义归一化规则,比如“网络”“DNS”“负载均衡”可以归一为“网络域”。
建议采纳率:看模型给出的处理建议被人工采纳的比例。这个指标比根因准确率更贴近实际价值,因为有时候AI根因说对了,但建议太泛,没人用;有时候根因表述有偏差,但建议刚好可行,被采纳了。
平均归因时长:从告警触发到生成高置信度根因结论的耗时。这个指标反映的是“快不快”。如果模型效果好但推理要五分钟,值班同学早就自己查完了,系统就失去了存在意义。
反馈标注怎么做很关键。我的经验是不要追求给每条结果都做人工标注,成本太高,而是只对两类样本标注:一类是模型高置信度但人工确认错误的,这代表系统产生了误导性结果;另一类是模型低置信度但人工确认正确且快速的,这代表系统有潜力但模型没有抓住。其他中间地带的结果,自动归为“待观察”,不要浪费人工精力。
6. 常见问题与排查技巧实录
6.1 告警风暴下的上下文爆炸和响应延迟
告警风暴是最考验系统的场景。大量实例同时故障,告警数量从几十跳到几百甚至上千,如果不控制,提示词长度和检索成本都会爆炸。
我的处理方案分三截:入口处做告警合并聚合,同类告警30秒内只保留一条,附带重复次数;中间层做严重度分级过滤,只保留严重和紧急告警,信息类告警直接丢弃,这一步能砍掉70%的上下文量;最后对真正进入模型的告警做数量上限控制,比如最多80条,超出部分用“另有N条同类告警未展示”标注。
实测下来,这样的预处理让提示词长度保持在可控范围,响应时间也能稳定在20到40秒内。注意别小看“另有N条同类告警未展示”这句话,它对模型有很强的心理暗示作用,模型会明白还有大批量告警没有逐条列出,更倾向于判断是大规模故障而不是单点问题。
6.2 模型幻觉根因的处理思路
大模型给出一个看起来很有逻辑、实际上完全没发生的根因,这是告警归因里最危险的情况。比如指标明明没有异常,模型看了历史案例就给一个“内存溢出”的结论,导致值班同学上线盲目处理,反而把好服务搞挂了。
这类问题光靠提示工程解决不了,要靠证据约束来兜住。我让“证据”字段和“根因”字段必须严格对应:根因里提到的对象,必须在证据中有一条指标的记录,或者一条变更的事件记录。如果某条证据在提示词的输入上下文中根本不存在,那条结论直接被判断为不可采纳。
再配合规则层校验,比如根因为“数据库连接池耗尽”时,证据里必须有连接池使用率超过80%的指标记录,否则驳回。用这种“规则+模型”双层校验,幻觉问题能压下九成以上。
6.3 反馈闭环的标注成本控制
做过效果评估的人都知道,上AI系统不难,难的是持续有人愿意给你标注“这次判断对不对”。生产值班环境里,大家最反感的工作就是额外填表格。我的经验是把标注嵌入到已有流程里,哪里的流程天然需要人工确认,就把反馈收集点设在哪里。
比如故障处理后,值班同学本来就要写故障复盘和选择故障原因类型。那就把系统标记的根因直接展示在复盘表单里,让同学确认或修正一下就行,不用重新填一份问卷。审批流程、切换工单、关闭告警,这些都是天然的反馈采集点。采集到的数据自动回流到评估系统,不断积累成“人工确认过的根因样本集”,这些样本以后还能反哺提示词的少样本示例。
7. 实践心得与后续扩展
走完这四个阶梯,告警归因系统才算真正从“能演示”变成“能值班”。但我想强调一点:这四个阶梯不是一次性完成就结束了,它是一个长期演进的过程。告警系统在变、架构在变、故障模式也在变,提示词必须跟着迭代。
我目前在做的几个扩展方向,供大家参考。一个是引入RAG,把故障处理手册和历史工单做成向量索引,让模型在分析时能检索到更类似的历史案例,目前看对老故障的识别很有帮助。另一个是在上下文里加入服务依赖拓扑信息,让模型在分析时能感知服务间调用关系,减少“只知道根因对象、不知道上下游影响”的问题。还有一个方向是尝试用更小的模型配合高质量提示词做线上推理,降低延迟和成本,不过效果还在验证中,小模型对复杂上下文的理解确实有差距。
最后分享一个我踩过很多次坑之后的习惯:任何一版提示词修改,都要先在回放的样本集上跑批一下再上线。我维护了一个覆盖两个月真实告警的回归样本集,每次改完提示词,先离线批量跑一遍,对比改动前后的准确率和置信度分布。不要高估自己的直觉,也不要全信模型在几个样例上的表现,一百条历史告警跑一遍,比任何评审都有说服力。这个习惯帮我把线上告警归因的准确率稳定地维持在了人工复核可接受的水平上。
