AI 赋能的业务监控:从被动告警到基于 LLM 的主动异常检测

发布时间:2026/7/22 11:19:02

AI 赋能的业务监控:从被动告警到基于 LLM 的主动异常检测 AI 赋能的业务监控从被动告警到基于 LLM 的主动异常检测一、传统监控的告警疲劳困境如果用一个词形容我们团队 2024 年的监控状态那一定是告警疲劳。Prometheus Grafana Alertmanager 这套经典组合每天产生的告警数量在 200~400 条之间波动。值班同事的工作模式逐渐变成了收到告警 → 看一眼 Grafana 面板 → 如果看起来没什么大问题就关闭。统计数据显示2024 年 Q3 的告警中真正需要人工介入处理的有效告警仅占 7.3%。其余 92.7% 的告或是阈值设置过于敏感产生的噪音如 CPU 瞬时飙升至 85% 又立即回落或是关联告警的重复通知同一磁盘故障触发了 12 条不同维度的告警或是已知的周期性波动每天凌晨 2 点的批处理任务导致数据库连接数峰值。告警系统的核心问题不是告得不够多而是告得不够聪明——它只能做简单的阈值比较完全不具备对系统行为的理解能力。二、分层异常检测的架构设计我们设计了一套分层异常检测架构从下到上分为三层。第一层统计异常检测。保留传统的阈值和同比/环比检测但将阈值从固定值升级为动态基线。通过统计过去 30 天的指标分布计算 P5/P95 分位数仅在指标突破分位数范围时触发。这消除了由于固定阈值设置不合理导致的大多数误报。第二层向量化异常检测。这是引入 AI 的核心创新点。我们将系统的正常状态编码为高维向量。具体做法是以每分钟为粒度采集当前系统的 Top-50 指标CPU、内存、GC 频率、接口 P99 延迟、QPS、错误率、数据库连接池使用率、MQ 积压数量等组成一个 50 维的特征向量。通过 Isolation Forest 算法训练无监督异常检测模型发现偏离正常状态簇的异常时刻。异常检测不是简单地告诉你某个指标超了而是告诉你当前系统的整体状态与过去 30 天同一时段有显著差异。这一层的告警质量远高于单纯的阈值告警。第三层LLM 根因分析。当异常被检测到时系统自动收集异常发生前后 5 分钟的指标快照、日志关键信息、调用链异常节点等上下文数据格式化为结构化的 Prompt 提交给 LLM 进行分析。/** * 分层异常检测引擎 */ Service public class AnomalyDetectionEngine { Resource private MetricCollector metricCollector; Resource private IsolationForestModel anomalyModel; Resource private RootCauseAnalyzer rootCauseAnalyzer; /** * 每分钟触发一次的异常检测主流程 */ public void detect() { // 采集当前时刻的系统多维指标 double[] currentVector metricCollector.collectCurrentVector(); if (currentVector null || currentVector.length 0) { log.warn(指标采集为空跳过异常检测); return; } // 动态基线检测第一层 ListString thresholdAlerts checkDynamicThresholds(currentVector); // 向量异常检测第二层 AnomalyScore score; try { score anomalyModel.predict(currentVector); } catch (ModelException e) { log.error(异常检测模型预测失败, e); score AnomalyScore.normal(); // 降级为正常 } if (!score.isAnomalous() thresholdAlerts.isEmpty()) { return; // 系统正常无需处理 } // 异常确认收集上下文信息 AnomalyContext context AnomalyContext.builder() .timestamp(LocalDateTime.now()) .anomalyScore(score) .thresholdAlerts(thresholdAlerts) .metricSnapshot(metricCollector.snapshot(5)) // 前后5分钟快照 .recentLogs(logCollector.collect(5)) .traceAnomalies(traceCollector.detectAnomalies(5)) .build(); // LLM根因分析第三层 try { RootCauseReport report rootCauseAnalyzer.analyze(context); // 根据严重程度决定告警策略 if (report.getSeverity() Severity.CRITICAL) { alertService.sendUrgent(report); } else { alertService.sendWarning(report); } log.info(异常检测完成: severity{}, summary{}, report.getSeverity(), report.getSummary()); } catch (AnalyzerException e) { log.error(LLM根因分析失败降级为传统告警, e); alertService.sendFallbackAlert(thresholdAlerts); } } private ListString checkDynamicThresholds(double[] vector) { ListString alerts new ArrayList(); DynamicBaseline baseline baselineService.getBaseline(); for (int i 0; i vector.length; i) { double value vector[i]; BaselineStats stats baseline.getStats(i); if (stats null) continue; if (value stats.getP95() * 1.2 || value stats.getP5() * 0.8) { alerts.add(String.format(指标[%d]异常: 当前值%.2f, 基线P5-P95[%.2f, %.2f], i, value, stats.getP5(), stats.getP95())); } } return alerts; } }三、LLM 根因分析的 Prompt 工程根因分析是整个系统中 Prompt 设计要求最高的环节。输入信息包含多种格式的结构化数据时序指标、日志片段、调用链图谱。如何让 LLM 从这些异构数据中推理出正确的根因我们的 Prompt 设计分为三个区块。上下文简报用不超过 200 字的自然语言概括当前异常的整体情况哪些维度异常、异常严重程度、是否有已知的关联事件。结构化数据以 Markdown 表格形式呈现关键指标的当前值与基线对比值偏高用 ↑ 标记偏低用 ↓ 标记以列表形式呈现最近的异常日志仅保留 ERROR 和 WARN 级别去重后不超过 10 条以文本形式描述调用链中的异常节点和对应的下游服务。历史关联检索过去 90 天内相似异常的工单和处理记录作为参考。最后通过一个严格的输出格式约束要求 LLM 按最可能的根因 → 置信度 → 关联证据 → 建议操作 → 是否需要立即处理五段式输出。/** * LLM根因分析服务 */ Service public class RootCauseAnalyzer { Resource private LLMClient llmClient; Resource private HistoricalTicketSearcher ticketSearcher; /** * 分析异常上下文生成根因报告 */ public RootCauseReport analyze(AnomalyContext context) throws AnalyzerException { // 检索历史相似异常工单 ListTicket similarTickets ticketSearcher.searchSimilar( context.getMetricSnapshot(), 5); String prompt buildAnalysisPrompt(context, similarTickets); String response; try { response llmClient.chat(prompt); } catch (LLMException e) { throw new AnalyzerException(LLM调用失败, e); } try { return parseRootCauseReport(response); } catch (ParseException e) { log.error(根因报告解析失败: {}, response); // 解析失败时构建一个基础的降级报告 return buildDegradedReport(context); } } private String buildAnalysisPrompt(AnomalyContext context, ListTicket similarTickets) { StringBuilder prompt new StringBuilder(); prompt.append(你是一个资深的系统运维专家。请分析以下异常检测结果找出根因。\n\n); // 异常概况 prompt.append(## 异常概况\n); prompt.append(String.format(检测时间: %s\n, context.getTimestamp())); prompt.append(String.format(异常评分: %.2f (阈值0.7)\n, context.getAnomalyScore().getValue())); prompt.append(String.format(触发阈值告警数: %d\n\n, context.getThresholdAlerts().size())); // 关键指标对比表格形式 prompt.append(## 关键指标对比\n); prompt.append(| 指标 | 当前值 | 基线均值 | 偏差 |\n); prompt.append(|------|--------|----------|------|\n); for (MetricSnapshot metric : context.getMetricSnapshot().getMetrics()) { String deviation metric.getDeviationPercent() 0 ? ↑ String.format(%.0f%%, metric.getDeviationPercent()) : ↓ String.format(%.0f%%, Math.abs(metric.getDeviationPercent())); prompt.append(String.format(| %s | %.2f | %.2f | %s |\n, metric.getName(), metric.getCurrentValue(), metric.getBaselineMean(), deviation)); } // 异常日志 prompt.append(\n## 异常日志\n); for (String logLine : context.getRecentLogs()) { prompt.append(- ).append(logLine).append(\n); } // 历史相似工单 if (!similarTickets.isEmpty()) { prompt.append(\n## 历史相似工单\n); for (Ticket ticket : similarTickets) { prompt.append(String.format(- [%s] %s (处理方案: %s)\n, ticket.getResolvedTime(), ticket.getTitle(), ticket.getResolution())); } } // 输出格式要求 prompt.append(\n请严格按以下格式输出分析结果\n); prompt.append(根因: 最可能的根因描述\n); prompt.append(置信度: 0~100的数值\n); prompt.append(关联证据: 支持该结论的具体证据\n); prompt.append(建议操作: 具体的处理步骤\n); prompt.append(紧急度: critical/high/medium/low\n); return prompt.toString(); } private RootCauseReport parseRootCauseReport(String response) { // 解析LLM返回的五段式结构化报告 RootCauseReport report new RootCauseReport(); String[] lines response.split(\n); for (String line : lines) { if (line.startsWith(根因:)) { report.setRootCause(line.substring(3).trim()); } else if (line.startsWith(置信度:)) { String value line.substring(4).trim().replace(%, ); report.setConfidence(Integer.parseInt(value)); } else if (line.startsWith(建议操作:)) { report.setSuggestedAction(line.substring(5).trim()); } else if (line.startsWith(紧急度:)) { report.setSeverity(Severity.fromString(line.substring(4).trim())); } } return report; } private RootCauseReport buildDegradedReport(AnomalyContext context) { RootCauseReport report new RootCauseReport(); report.setRootCause(LLM分析结果解析失败请人工排查); report.setConfidence(0); report.setSuggestedAction(请查看原始监控数据和日志进行人工分析); report.setSeverity(Severity.MEDIUM); return report; } }四、告警聚合与降噪引入异常检测和根因分析后单条告警的质量大幅提升。但随之而来的新问题是根因分析的报告数量仍然不少高峰时每小时仍有 15~20 条报告。值班同事反馈信息质量提高了但信息量还是太大。我们引入了一个轻量级的告警聚合引擎从两个维度聚合一是时间维度将 5 分钟窗口内的多条根因报告合并取置信度最高的一条作为代表其余的作为补充细节二是拓扑维度通过服务依赖关系图基于调用链数据自动生成将有关联的服务告警聚合成一条影响链报告明确展示异常传播路径如Redis 连接超时 → 订单服务降级 → 支付服务队列堆积。五、效果评估与下一步方向系统上线 4 个月后的对比如下有效告警占比从 7.3% 提升至 62%平均故障发现时间MTTD从 23 分钟降至 3.2 分钟平均故障修复时间MTTR从 87 分钟降至 41 分钟值班同事反馈的告警疲劳感从 8.5 分降至 3.2 分10 分满分制。下一步的优化方向包括一是引入预测性异常检测在故障发生前 5~10 分钟预警已在小规模实验中取得 72% 的提前预警率二是构建自动化修复决策对于置信度超过 90% 且修复方案明确的告警如重启 Pod、扩容 HPA自动触发修复操作三是将异常检测场景从后端监控拓展到业务指标如订单量异常下降、支付成功率异常波动实现从技术监控到业务监控的全面覆盖。AI 赋能监控的核心价值不是替代运维工程师而是让机器处理那些确定性的、重复性的、低价值的判断工作将人的精力集中在真正需要经验和创造力的疑难问题上。作者李然程序员鸭梨Java 架构师专注可观测性与智能运维体系建设。

相关新闻