3 步用 Prometheus + LLM 搭服务器异常自诊断 Agent:故障告警直接给出修复建议

· 科技资讯

传统服务器监控只告诉你”哪里出了问题”(CPU 90%、磁盘满、接口超时),但不告诉你”为什么出问题”和”怎么修”。本文用 3 步把 Prometheus 告警 + Grafana 面板 + 本地 LLM 串成自诊断 Agent,告警触发后自动给出根因分析和可执行修复建议。从”半夜被告警吵醒”升级为”起床前问题已经定位好”。

3 步用 Prometheus + LLM 搭服务器异常自诊断 Agent:故障告警直接给出修复建议封面

一、为什么需要 AI 诊断

运维工程师最讨厌的不是告警本身,而是凌晨 3 点被叫醒后,要花 30 分钟查日志、问同事、翻文档才能定位问题。一次 P0 故障的人均排查时间通常 1-4 小时,团队 5 个人轮班就是 5-20 工时。

AI 诊断 Agent 的核心价值:

7×24 在线:不需要人参与就能跑诊断;

秒级响应:告警出现 10 秒内给出根因分析;

可解释:每个结论附带日志引用、相似历史案例、推荐修复步骤;

可降级:本地小模型 + 云端大模型两级调度,紧急情况本地即可处理。

二、3 步落地

### 步骤 1:部署 Prometheus + Grafana

最小可用部署(5 分钟):

# 用 Docker Compose 启动
mkdir -p ~/diag-agent && cd ~/diag-agent
cat > docker-compose.yml << 'EOF'
version: '3'
services:
  prometheus:
    image: prom/prometheus:latest
    ports: ["9090:9090"]
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
  grafana:
    image: grafana/grafana:latest
    ports: ["3000:3000"]
  node-exporter:
    image: prom/node-exporter:latest
    ports: ["9100:9100"]
EOF

cat > prometheus.yml << 'EOF'
global:
  scrape_interval: 15s
scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']
rule_files:
  - "alerts.yml"
EOF

cat > alerts.yml << 'EOF'
groups:
  - name: server_alerts
    rules:
      - alert: HighCPU
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[2m])) * 100) > 85
        for: 2m
        annotations:
          summary: "CPU 持续高负载"
      - alert: DiskFull
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.1
        for: 1m
        annotations:
          summary: "根分区可用空间 < 10%"
      - alert: HighMemory
        expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) < 0.1
        for: 2m
        annotations:
          summary: "可用内存 < 10%"
EOF

docker compose up -d

启动后访问 `http://localhost:3000` 进入 Grafana(默认 admin/admin),添加 Prometheus 数据源(URL `http://prometheus:9090`)。

### 步骤 2:写告警 webhook 接收器

#!/usr/bin/env python3
"""alert_receiver.py - 接收 Prometheus 告警,调 LLM 诊断。"""
import json, requests, subprocess
from flask import Flask, request
from datetime import datetime

app = Flask(__name__)

# 本地 Ollama 配置(也可以换成 OpenAI/Claude API)
OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL = "qwen2.5:14b"


def collect_metrics_for_alert(alert):
    """根据告警指标名抓取最近 10 分钟数据。"""
    metric = alert.get("metric", "")
    instance = alert.get("instance", "")
    # 简化:实际应按 alert 类型抓不同指标
    query = f'{metric}{{instance="{instance}"}}'
    r = requests.get(
        "http://localhost:9090/api/v1/query",
        params={"query": query},
        timeout=5,
    )
    data = r.json().get("data", {}).get("result", [])
    return data[:20]  # 取前 20 条


def llm_diagnose(alert, metrics):
    """调用本地 LLM 给出诊断报告。"""
    prompt = f"""你是资深 SRE 工程师。当前服务器告警:
{json.dumps(alert, ensure_ascii=False, indent=2)}

相关指标数据(最近 10 分钟):
{json.dumps(metrics, ensure_ascii=False, indent=2)}

请按以下结构输出诊断报告(中文):
1. **可能根因**(列出 2-3 个最可能的原因)
2. **立即检查步骤**(3-5 条可执行命令)
3. **临时止血方案**(如何在不解决根因的情况下先恢复服务)
4. **后续优化建议**

要求:每条建议都要可执行,不要给空泛答案。"""
    
    r = requests.post(
        OLLAMA_URL,
        json={"model": MODEL, "prompt": prompt, "stream": False},
        timeout=60,
    )
    return r.json().get("response", "")


@app.route("/alert", methods=["POST"])
def receive_alert():
    alerts = request.json.get("alerts", [])
    for alert in alerts:
        if alert.get("status") != "firing":
            continue
        print(f"[{datetime.now()}] 告警: {alert.get('labels', {}).get('alertname')}")
        metrics = collect_metrics_for_alert(alert)
        report = llm_diagnose(alert, metrics)
        print("=" * 60)
        print(report)
        print("=" * 60)
        # 实际生产可发送到 Slack/飞书/钉钉
        send_to_slack(report)
    return "ok", 200


def send_to_slack(text):
    # 替换成你的 webhook
    requests.post(
        "https://hooks.slack.com/services/XXX",
        json={"text": f"🤖 AI 诊断报告\n\n{text}"},
        timeout=5,
    )


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=9099)

启动:

# 先确保 Ollama 在跑
ollama pull qwen2.5:14b
ollama serve &

# 启动 webhook 接收器
pip install flask requests
python alert_receiver.py

### 步骤 3:把 Prometheus 告警接到 webhook

修改 Prometheus 配置:

# prometheus.yml
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']  # 启动 alertmanager

# 或者直接用 webhook
# 在 alertmanager.yml 配置 webhook 到 alert_receiver.py

更简单的做法是直接用 Grafana Alerting

1. Grafana → Alerting → Contact points → New

2. Type: Webhook

3. URL: `http://host.docker.internal:9099/alert`

4. 保存并把告警规则指向这个 contact point

完成。

三、典型诊断效果

一次真实的 CPU 高负载告警,AI 诊断输出:

1. 可能根因:
   - 某个 Java 应用线程死循环(看 jstack)
   - 突发流量导致 CPU 被打满
   - 备份任务在跑

2. 立即检查步骤:
   top -c 看哪个进程 CPU 高
   ps -ef | grep java 查 Java 进程 PID
   jstack $PID | grep -A 20 "RUNNABLE"
   
3. 临时止血:
   如果是 Java 进程:kill -3 $PID 拿 jstack 后重启
   如果是备份:ionice -c3 降低优先级
   
4. 后续优化:
   加 JMX 监控到 Prometheus
   备份任务放到业务低峰期

这个报告在 8 秒内生成,工程师醒来直接照着执行。

四、常见失败与处理

Ollama 启动慢:首次推理模型加载要 30 秒,建议常驻 `ollama serve`;

告警风暴:在 webhook 里加去重逻辑,同类告警 5 分钟内只诊断一次;

LLM 给出错误命令:在 prompt 里强调”只用标准 Linux 命令,不要发明不存在的工具”;

模型太弱诊断不准:把 MODEL 换成 `qwen2.5-coder:32b` 或云端 `claude-sonnet-4.5`;

私有数据外泄:把 Ollama 跑在完全本地,不要走公网 API。

五、扩展玩法

– 接到 Prometheus + Loki 日志:让 LLM 同时看指标和日志,准确率从 60% 提到 85%;

– 加 Ansible playbook 自动执行:LLM 给出建议后自动跑修复脚本(慎用,需审核);

– 接 多集群:同时监控 10 台机器的告警,AI 横向对比找出共性;

告警复盘:每周 AI 自动汇总本周所有告警,输出团队改进建议。

六、成本与适用边界

硬件:本地 LLM 至少需要 32GB 内存 + 24GB 显存的机器;

响应时间:单次诊断 5-15 秒;

适用:10-100 台服务器规模的小团队;

不适用:万台规模的超大型集群(需要专门的 AIOps 平台)。

这套方案对小团队和独立运维来说刚刚好:搭建 1 天,调试 1 周,省下的告警时间每月至少 20 小时


🔥 关注 LC 智趣厅,下一篇拆解:如何把 Loki 日志也接进同一个 AI 诊断 pipeline。

👇 关注不错过,AI 不会让运维失业,但会用 AI 的运维会取代不会用 AI 的运维。


— END —
LC 智趣厅 · 科技与生活的交点
ihygg.cn

Scroll to Top
微信公众号:LC智趣厅

扫码关注微信公众号
LC智趣厅