当你的排查助手变成了AI:大模型辅助根因分析在线上故障排查中的应用
·
当你的排查助手变成了AI:大模型辅助根因分析在线上故障排查中的应用

周一早上9点15分,我刚端起咖啡,告警群就炸了——用户服务持续报502,上游三个业务线投诉说登录功能挂了。
传统排查流程大概是:看Grafana → 查日志 → 看APM → 看变更 → 推理 → 定位。这一套下来,熟练工也要15-30分钟。
但今天不一样。我打开内部排查平台(我们叫它OpsCopilot),输入故障服务名,AI已经自动聚合好了异常指标、关联日志和最近变更。三分钟后,它给出了分析建议。
这篇文章就聊聊大模型在线上故障排查中的落地实践——不是画饼,是真的在生产环境跑了大半年的方案。
一、运维排查的信息过载困境
线上故障排查最大障碍不是"没数据",而是"数据太多"。
一次普通的P1故障,你可能需要看:
| 数据来源 | 数据量级 | 关键信息占比 |
|---|---|---|
| Prometheus指标 | 2000+时间序列 | <1% |
| Elasticsearch日志 | 500万条/小时 | <0.1% |
| Jaeger链路追踪 | 10万Span/分钟 | <0.5% |
| K8s事件 | 50条/分钟 | 约5% |
| 变更记录 | 日均50次 | 约10% |
人工从这些数据中找到关键线索,就像大海捞针。
二、AI辅助排查的核心设计
总体思路:思维链+多步推理
我们不是简单地把数据丢给大模型问"怎么回事",而是设计了一套思维链(Chain-of-Thought)的排查流程:
Step 1: 故障定界 → 这个故障影响谁?入口?出口?
Step 2: 数据聚合 → 异常指标有哪些?错误日志什么内容?
Step 3: 关联分析 → 异常指标和最近变更有关吗?
Step 4: 根因推理 → 给出Top 3可能根因
Step 5: 排查指引 → 下一步应该查什么?
Step 1:故障定界器
# fault_boundary.py — 故障定界
class FaultBoundaryDetector:
"""确定故障的影响边界"""
def detect_boundary(self, service_name: str,
start_time: str) -> dict:
# 查询服务拓扑,确定上下游依赖
upstream = self.get_upstream_services(service_name)
downstream = self.get_downstream_services(service_name)
# 检查各服务的健康状态
boundary = {
'entry_point': service_name,
'affected_upstream': [],
'affected_downstream': [],
'unaffected': []
}
for svc in upstream + downstream:
status = self.check_service_health(svc, start_time)
if status == 'degraded':
boundary['affected_downstream' if svc in downstream else 'affected_upstream'].append(svc)
else:
boundary['unaffected'].append(svc)
return boundary
# 示例输出
boundary = {
'entry_point': 'user-service',
'affected_upstream': ['api-gateway'],
'affected_downstream': ['user-db'],
'unaffected': ['order-service', 'payment-service']
}
# 推理:故障在下游数据库,影响了user-service,进而影响了api-gateway
Step 2:上下文聚合器
# context_aggregator.py — 多源数据聚合
class ContextAggregator:
"""聚合故障上下文,供LLM分析"""
def aggregate(self, service_name: str, boundary: dict,
time_range: tuple) -> dict:
context = {
'service': service_name,
'boundary': boundary,
'time_window': {
'start': time_range[0].isoformat(),
'end': time_range[1].isoformat()
},
'clues': []
}
# 1. 提取异常指标(只提取有异常的,减少噪声)
anomaly_metrics = self.get_anomaly_metrics(service_name, time_range)
for metric in anomaly_metrics:
context['clues'].append({
'type': 'metric',
'source': 'prometheus',
'summary': f"{metric['name']} 从 {metric['baseline']} 突变为 {metric['current']}",
'severity': metric['severity']
})
# 2. 提取关键错误日志(去重,只保留前5种模式)
error_patterns = self.cluster_error_logs(service_name, time_range)
for pattern in error_patterns[:5]:
context['clues'].append({
'type': 'log',
'source': 'elasticsearch',
'summary': f"发现{pattern['count']}条同类错误: {pattern['sample']}",
'severity': 'high'
})
# 3. 检查最近变更
recent_changes = self.get_recent_changes(service_name, time_range[0] - timedelta(hours=2))
for change in recent_changes:
context['clues'].append({
'type': 'change',
'source': 'cmdb',
'summary': f"{change['operator']} 在 {change['time']} 执行了 {change['action']}",
'severity': change.get('risk', 'low')
})
return context
Step 3-5:LLM多步推理引擎
# llm_reasoning.py — LLM推理引擎
import json
from openai import AsyncOpenAI
class OpsCopilotEngine:
"""运维AI助手核心推理引擎"""
def __init__(self):
self.client = AsyncOpenAI(
base_url='http://llm-service:8000/v1',
api_key='sk-xxxx'
)
self.model = 'qwen2-72b-instruct'
async def run_diagnosis(self, context: dict) -> str:
"""执行完整的诊断链路"""
# 第一步:关联分析
correlation_prompt = f"""你是一位SRE工程师,正在排查线上故障。
请分析以下线索之间的关联关系:
故障服务:{context['service']}
影响边界:{json.dumps(context['boundary'], ensure_ascii=False)}
时间窗口:{context['time_window']}
发现的线索(按时间排序):
{json.dumps(context['clues'], ensure_ascii=False, indent=2)}
请分析:
1. 哪些线索可能是因果链中的一环?
2. 哪些线索可能是独立事件?
3. 线索之间是否存在时间上的先后关系?
"""
correlation = await self._llm_call(correlation_prompt)
# 第二步:根因推理
root_cause_prompt = f"""基于以下关联分析结果和原始线索,给出Top 3可能的根因:
关联分析:{correlation}
线索清单:
{json.dumps(context['clues'], ensure_ascii=False, indent=2)}
请按以下格式输出:
## 可能根因(按概率从高到低)
### 根因1:[名称]
- 概率:XX%
- 证据:[引用线索编号]
- 推理过程:[因果链描述]
### 根因2:[名称]
- 概率:XX%
- 证据:[引用线索编号]
- 推理过程:[因果链描述]
### 根因3:[名称]
- 概率:XX%
- 证据:[引用线索编号]
- 推理过程:[因果链描述]
## 推荐排查步骤
1. [第一步做什么]
2. [第二步做什么]
3. [第三步做什么]
"""
return await self._llm_call(root_cause_prompt)
async def _llm_call(self, prompt: str) -> str:
"""调用大模型"""
response = await self.client.chat.completions.create(
model=self.model,
messages=[
{'role': 'system', 'content': '你是资深SRE工程师,基于数据做严谨推理。'},
{'role': 'user', 'content': prompt}
],
temperature=0.1,
max_tokens=2000
)
return response.choices[0].message.content
三、真实案例:用户服务502故障
故障定界输出
入口: api-gateway(异常)
↓
目标: user-service(异常)
↓
依赖: user-db(异常)
redis-cluster(正常)
初步结论:故障在下游数据库,影响user-service后传导到api-gateway
AI诊断输出
## 可能根因(按概率从高到低)
### 根因1:数据库连接池耗尽
- 概率:75%
- 证据:① user-db活跃连接数从50飙升至200;② user-service日志出现
"cannot acquire JDBC connection";③ 该服务近期未上线新版本
- 推理过程:连接数持续上升 → 达到连接池上限 → 新请求获取不到连接 →
请求阻塞超时 → upstream服务感知到502
### 根因2:慢SQL导致连接长时间占用
- 概率:15%
- 证据:① user-db慢查询数从2/min升至120/min;② 某SQL执行时间从5ms升至2.3s
- 推理过程:某SQL执行计划变化 → 全表扫描 → 长时间占用连接 →
有效连接数减少 → 等效于连接池耗尽
### 根因3:上游突发流量
- 概率:10%
- 证据:① api-gateway入口流量突增300%;② 其他下游服务无异常
- 推理过程:突发流量 → 数据库连接数飙升 → 超过连接池阈值 →
部分连接超时
## 推荐排查步骤
1. 立即执行:kubectl exec -it user-db-0 -- mysql -e "SHOW PROCESSLIST"
查看当前数据库连接状态
2. 定位慢SQL:检查mysql-slow.log中的TOP SQL
3. 如果确认连接池耗尽:临时增大数据库的 max_connections 和应用的连接池大小
4. 长期修复:添加数据库连接数的HPA告警和限流措施
实际结果
按照排查指引,第一步执行SHOW PROCESSLIST后,发现大量Waiting for table metadata lock的连接。进一步定位发现是凌晨的一次DDL变更(ALTER TABLE)未提交事务,阻塞了后续所有查询。根因是变更操作未规范执行,这是根因列表中没出现的新线索——AI明确指出了"首次排查方向"。
四、实践经验与局限
做对了的
- 结构化提示词:让AI按固定格式输出,便于后续自动处理
- 多步推理取代单次问答:先关联分析再根因推理,准确率提升约40%
- 约束输出范围:temperature设为0.1,减少幻觉
踩过的坑
坑1:AI过度自信
- 现象:明明证据不足,LLM也会强行给出分析
- 解决:在Prompt中增加"如果证据不足,请明确指出不确定项"
坑2:上下文过长
- 现象:全量日志和指标数据远超LLM上下文窗口
- 解决:先做聚类和摘要,只把关键线索送入LLM
坑3:延迟不稳定
- 现象:LLM API偶尔延迟到30s+
- 解决:增加超时处理和降级策略,超时则只展示聚合数据
五、落地效果
过去6个月的生产数据统计:
| 指标 | 使用AI前 | 使用AI后 |
|---|---|---|
| MTTR(平均修复时间) | 28min | 12min |
| 首次排查正确率 | 62% | 78% |
| 需要升级专家的故障比例 | 35% | 18% |
| 值班工程师满意度 | 6.5/10 | 8.5/10 |
结语
大模型辅助排查不是要把运维工程师"优化掉"。它做的是把信息搜索和初步分析的时间从20分钟压缩到2分钟,让你能把更多精力花在"判断"和"决策"上。
就像自动驾驶一样——L2级别的辅助,仍然需要你手握方向盘、时刻关注路况。但有了辅助,你会开得更轻松、更安全。
本文作者:侯万里(万里侯),云原生运维工程师,专注于AI驱动运维智能化和故障自愈体系建设
更多推荐

所有评论(0)