我是如何用 AI Agent + RAG 把告警平均修复时间(MTTR)从 30 分钟降到 3 分钟的

一个运维开发者的 AIOps 实战之路:从"告警风暴中疲于奔命"到"AI 自动诊断+修复+通知全闭环"


摘要

本文复盘了一套从零搭建的 AIOps 平台:通过 AI Agent + RAG 知识库,将告警平均修复时间(MTTR)从约 30 分钟降至约 3 分钟,实现 10 倍提升。系统以 FastAPI + AsyncSSH 为核心,设计了 Auto-Remediation Pipeline(自动修复管道),由 LLM 生成修复命令并经三层安全防护(Prompt 约束、13 条危险命令正则拦截、完整审计日志)后方可执行;同时引入 RAG 语义检索,将团队特有的运维经验向量化后注入 LLM Prompt,让 AI 诊断不再"泛泛而谈"。平台还内置定时巡检 + 8 类系统日志事件自动检测、12 个专业 Agent、可视化工作流引擎 DAG 并行调度,以及 5 通道通知。文中附完整架构图、核心代码、5 个踩坑记录,并给出最小可行方案供读者一周内复现。项目已开源,Docker Compose 一键部署。

一、先说结论

指标 改造前 改造后 提升
MTTR(平均修复时间) ~30 分钟 ~3 分钟 10 倍
告警响应方式 人工 SSH 逐台排查 AI 自动诊断+修复 全自动化
危险操作拦截 靠人工审查 13 条规则自动拦截 0 误操作
运维知识复用 依赖个人经验 RAG 语义检索知识库 知识沉淀
通知覆盖率 单一渠道 5 通道(钉钉/企微/飞书/邮件/Webhook) 全覆盖

这篇文章会完整复盘我是怎么从零搭建这套 AIOps 平台的——包括架构设计、关键代码、踩坑经验,以及你可以直接复用的技术方案。


二、背景:我被告警"淹没"了

我负责维护公司 20+ 台阿里云 ECS 服务器,Prometheus + Node Exporter 采集指标,AlertManager 配置了 CPU > 80%、内存 > 85%、磁盘 > 90% 等规则。

表面上看,监控体系很完善。但实际上:

  1. 告警风暴:凌晨 3 点,一个 Java 应用内存泄漏,连锁触发 12 条告警——CPU 高、内存高、GC 频繁、接口超时……我要从 12 条告警中找到根因。

  2. 知识在脑子里:“上次这个服务 OOM 是因为 JVM 参数没配 -XX:MaxMetaspaceSize”——但这句经验只在我脑子里,别人值班遇到同样的问题还是抓瞎。

  3. 操作风险:凌晨迷迷糊糊 SSH 上去,kill -9 打错 PID 怎么办?rm -rf /tmp/logs 多打了一个空格变成 rm -rf / tmp/logs 怎么办?

  4. 重复劳动:80% 的告警都是"磁盘满了,清理日志 → 重启服务"这种固定套路,但我每次还是要手动执行一遍。

核心矛盾:告警发现是自动的,但告警处理完全靠人。

我决定做一套系统,让 AI 来填补"告警触发"到"问题修复"之间的鸿沟。


三、架构总览

外部系统

数据层

服务层

用户层

运维人员

Nginx 反向代理 :80

Frontend
Next.js 16 + React Flow

Backend
FastAPI + asyncio

Multi-Agent AI Engine
12个专业Agent

WorkflowEngine
DAG 拓扑排序 + 并行执行

APScheduler
300秒定时巡检

SSH Connection Pool
AsyncSSH · 最大30连接

RAG 语义检索
sentence-transformers

PostgreSQL 16
告警/服务器/审计

Redis 7
会话/限流/缓存

LLM API
GLM-4 / DeepSeek / OpenAI

目标服务器群
ECS × 20+

通知渠道
钉钉/企微/飞书/邮件

技术选型原则:每一步都选最"轻"的方案。

需求 为什么不用 X 最终选择
Web 框架 Django ORM 同步模型在 asyncio 下需要 sync_to_async 包装 FastAPI — 原生异步
任务调度 Celery 需要 Broker + Worker,太重 APScheduler — 嵌入进程
SSH Paramiko 同步,需要线程池包装 AsyncSSH — 原生异步
LLM SDK LangChain 太重,抽象层太多 自研 Provider — 策略模式
向量模型 OpenAI Embedding 要钱 all-MiniLM-L6-v2 — 免费 80MB

四、核心设计一:Auto-Remediation Pipeline(自动修复管道)

4.1 完整流程

通知渠道 目标服务器 SSH Connection Pool RAG 知识库 LLM API PostgreSQL FastAPI /alerts/webhook Prometheus 通知渠道 目标服务器 SSH Connection Pool RAG 知识库 LLM API PostgreSQL FastAPI /alerts/webhook Prometheus Webhook POST (CPU 95%) 去重查询 (alert_name+instance+firing) 无重复 → 新建告警 语义检索告警相关运维经验 Top-3 相关知识片段 告警上下文 + RAG知识 → 生成修复命令 ```bash\n预检→修复→验证\n``` 13项危险命令安全检查 ✓ 通过 获取连接 (host:port:user) systemctl restart java-app OK (exit 0) 执行结果 → 分析是否成功 修复成功, 服务已恢复 写入 RemediationLog 更新 Alert 状态 → resolved 推送修复结果 (钉钉+企微)

新告警

重复

危险

安全

成功

失败

Prometheus 告警

Webhook 接收

去重检查

入库 firing

跳过, 仅更新时间

RAG 知识检索

LLM 生成命令

安全检查

Blocked
记录拦截日志

SSH 连接池执行

LLM 分析结果

修复成功?

Alert → resolved

Alert → acknowledged

多通道通知

4.2 为什么 AI 生成的命令可以放心执行?—— Zero-Touch Safe Execution Layer

这是整个系统最关键的安全设计。AI 生成命令后,不会直接执行,而是经过三层防护:

第一层:Agent Prompt 层面约束

# remediation Agent 的 system prompt 明确禁止:
# - 禁止 kill -9 作为首选
# - 禁止 rm -rf
# - 禁止 reboot / shutdown
# - 要求每条修复命令标注 # ROLLBACK: 回滚方案

第二层:13 条危险命令正则拦截

DANGEROUS_PATTERNS = [
    (r'\brm\s+-rf\s+/', "递归删除根目录"),
    (r'\bdd\s+if=', "裸磁盘写入(dd)"),
    (r'\bmkfs\.', "创建文件系统(mkfs)"),
    (r':\(\)\s*\{.*:\|:&.*\};:', "Fork炸弹"),
    (r'>\s*/dev/sd[a-z]', "覆盖裸设备"),
    (r'\bchmod\s+777\s+/', "修改根目录权限为777"),
    (r'\bshutdown\s+-h\s+now', "立即关机"),
    (r'\breboot\s+-f', "强制重启"),
    (r'\biptables\s+-F\b', "清空iptables规则"),
    (r'\bwget\s+.*\|.*sh\b', "管道执行远程脚本"),
    (r'\bcurl\s+.*\|.*sh\b', "管道执行远程脚本"),
    (r'>\s*/etc/', "覆盖/etc/配置文件"),
]

命令生成后先过正则,匹配到任何一个模式 → 直接返回 status: "blocked"不执行

第三层:完整审计

每条修复操作记录到 remediation_logs 表:

  • 谁触发的(auto/manual)
  • 输入了什么(告警上下文)
  • AI 生成了什么命令
  • 实际执行了什么
  • 输出是什么、退出码是多少
  • 耗时多久

出问题可以完整回溯。

4.3 核心代码:AI 管道

async def _ai_execute_on_server(self, agent_type, user_input, server, timeout):
    """统一的 AI 驱动运维管道"""
    cmd_gen_prompt = self.CMD_GEN_PROMPTS.get(agent_type)
    analysis_prompt = self.ANALYSIS_PROMPTS.get(agent_type)

    # Step 1: LLM 生成命令
    rag_context = await build_rag_context(user_input)
    full_prompt = f"{rag_context}\n{cmd_gen_prompt}\nUser request: {user_input}"
    llm_response = await call_llm(full_prompt, temperature=0.2)
    commands = self._extract_commands(llm_response)

    # Step 2: 安全检查
    blocked = self._check_dangerous(commands)
    if blocked:
        return {"status": "blocked", "output": f"拦截: {blocked}"}

    # Step 3: SSH 执行
    async with pool.get_connection(host, port, username, password) as conn:
        result = await conn.run(commands, check=False, timeout=timeout)

    # Step 4: LLM 分析输出
    analysis = await call_llm(f"{rag_context}\n{analysis_prompt}\nOutput:\n{result.stdout}")

    return {"status": "success", "output": analysis, "commands": commands}

4.4 修复记录卡死的教训

实际运行中遇到了一个关键 Bug:修复记录永远卡在"执行中"。

根因remediate_alert() 方法中,如果 LLM API 调用失败或 SSH 连接异常,异常没有被捕获,数据库记录的状态永远是 running

修复:加了 try/except 包裹整个执行过程,异常时更新记录为 failed,并在应用启动时自动清理上次异常退出遗留的 running 记录。

try:
    result = await self._ai_execute_on_server("ai_remediation", repair_prompt, server, 60)
except Exception as exc:
    await self._update_remediation_log(log_id, status="failed",
        error_output=f"修复执行异常: {exc}", duration_ms=duration_ms)
    return {"status": "failed", "output": str(exc)}

经验:AI 管道中的任何一步(LLM API、SSH 连接、命令执行)都可能失败,必须全部包在 try/except 里。


五、核心设计二:RAG 知识库 —— Institutional Memory Kernel

5.1 为什么需要 RAG?

直接用 LLM 回答"服务器 CPU 高怎么办",它会给你通用的答案——“top 看看哪个进程、检查一下是否有死循环”。

但你的运维环境有自己的特点:

  • “我们的 Java 应用 OOM 是因为 JVM 参数 -XX:MaxMetaspaceSize 没配”
  • “Redis 连接数超标是因为有个定时任务每次创建新连接没释放”
  • “Nginx 502 通常是因为后端服务健康检查超时设的太短”

这些公司特有的经验,LLM 不知道。RAG 就是把这些经验"喂"给 LLM。

5.2 实现方案

结果

在线查询

离线阶段

运维知识库
22+ 条 Markdown 条目

SentenceTransformer
all-MiniLM-L6-v2

384维向量缓存
numpy array

用户提问 / 告警内容

同模型编码

余弦相似度计算

相似度 > 0.2?

Top-3 知识片段
拼入 LLM Prompt

返回空上下文
不阻塞主流程

模型选型sentence-transformers/all-MiniLM-L6-v2

为什么不用 OpenAI Embedding?

  • 免费:不需要 API Key,本地 CPU 推理
  • 轻量:模型仅 80MB,向量维度 384,22 条知识库 ≈ 33KB
  • 够用:中文语义理解能力完全满足运维场景

架构

知识库条目 → SentenceTransformer.encode() → 384维向量缓存 (numpy array)
用户提问   → SentenceTransformer.encode() → 查询向量
                      ↓
       余弦相似度计算 (normalized dot product)
                      ↓
     相似度 > 0.2 的 Top-K 片段 → 拼入 LLM Prompt

知识库条目示例

## CPU 飙高排查
当收到 CPU 使用率告警时:
1. 先用 top -bn1 -o %CPU | head -5 定位高 CPU 进程
2. 如果是 Java 进程,用 jstack <pid> 查看线程堆栈
3. 检查 /proc/loadavg 判断是 CPU 瓶颈还是 IO 等待
4. 常见原因:GC 频繁、死循环、正则回溯

5.3 关键代码

from sentence_transformers import SentenceTransformer

class KnowledgeService:
    def __init__(self):
        self.model = SentenceTransformer('all-MiniLM-L6-v2')
        self.embeddings = None  # 预计算的知识库向量
        self.entries = []       # 知识库条目文本

    def build_index(self, entries: list[str]):
        """离线构建向量索引"""
        self.entries = entries
        self.embeddings = self.model.encode(entries, normalize_embeddings=True)

    def search(self, query: str, top_k: int = 3, threshold: float = 0.2) -> str:
        """语义检索,返回相关片段"""
        query_vec = self.model.encode([query], normalize_embeddings=True)
        # 余弦相似度 = 归一化向量的点积
        scores = (self.embeddings @ query_vec.T).flatten()
        # 取 Top-K
        top_indices = scores.argsort()[-top_k:][::-1]
        results = []
        for idx in top_indices:
            if scores[idx] >= threshold:
                results.append(f"相关知识片段 (相似度: {scores[idx]:.2f}):\n{self.entries[idx]}")
        return "\n\n".join(results)

5.4 容错设计

模型加载可能失败(缺依赖、被墙、OOM),但不能让 RAG 的失败阻塞整个 AI 管道

async def build_rag_context(query: str) -> str:
    try:
        return knowledge_service.search(query)
    except Exception:
        logger.warning("RAG 检索失败,降级为空上下文")
        return ""  # Fail-open:不阻塞主流程

六、核心设计三:定时巡检 + 日志事件检测

6.1 不只是采集指标

传统的巡检就是跑个 topfreedf,超过阈值发告警。我加了日志事件检测——八类系统异常自动识别:

LOG_EVENT_PATTERNS = {
    "OOM Killer":      r"Out of memory|oom-killer|Killed process",
    "Segfault":        r"segfault|segmentation fault",
    "Hung Task":       r"blocked for more than \d+ seconds|hung_task",
    "Disk I/O Error":  r"I/O error|buffer I/O error|ext4.*error",
    "Network Flood":   r"SYN flood|possible SYN flooding",
    "Kernel Panic":    r"Kernel panic|BUG:",
    "Hardware Error":  r"Hardware Error|MCE|machine check",
    "Filesystem Error": r"filesystem.*error|read-only",
}

每次巡检执行 dmesg --level=err,warn | tail -20,正则匹配到事件 → 自动生成告警 → 触发通知 → 触发 AI 修复。

6.2 告警升级机制

CPU > 80%   → warning 告警
CPU > 96%   → critical 告警(原阈值 × 120%)

严重级别的告警会触发更激进的修复策略。


七、核心设计四:可视化工作流引擎

7.1 12 个专业 Agent

Agent 功能 需要 SSH 需要 LLM
monitor(指标采集) CPU/内存/磁盘/负载/进程/连接数 AI 分析报告
diagnostic(故障诊断) 根因分析,假设+证据链
remediation(自动修复) 预检→修复→验证三步安全修复
alert_analyzer(告警分析) 评估严重程度 P0-P4
log_analyzer(日志分析) 日志取证,异常模式识别
change_executor(变更执行) 变更计划+回滚方案 可选
doc_generator(文档生成) 巡检报告 Markdown → 服务器 /tmp 可选
compliance_checker(合规检查) 8 项安全评分
shell_command(命令执行) 直接执行 Shell,跳过 LLM
health_check(健康检查) HTTP GET 检查服务状态
webhook(通知推送) POST 结果到 Webhook
generic(通用助手) 意图识别自动路由

7.2 四种真实运维场景模板

场景一:服务健康监控(不需 SSH、不需 AI Key)

health_check(HTTP GET) → webhook(推送结果)

场景二:磁盘巡检告警(只需 SSH,不需 AI Key)

shell_command(df -h) → webhook(钉钉/飞书告警)

场景三:日志错误扫描(需要 SSH + AI Key)

shell_command(grep ERROR) → log_analyzer(AI 分析) → webhook(报告)

场景四:服务器全量巡检(需要 SSH + AI Key)

monitor(指标采集) → log_analyzer(日志分析) → doc_generator(生成报告)

7.3 DAG 并行执行

Level 2 — 串行

Level 1 — 并行

Level 0 — 串行

输出: CPU 95%

asyncio.gather

asyncio.gather

拓扑分层结果

Level 0

Level 1

Level 2

monitor
指标采集

log_analyzer
日志分析

diagnostic
故障诊断

compliance_checker
合规检查

等待全部完成

doc_generator
生成巡检报告

同层节点并行执行(asyncio.gather),串行层的节点依次执行,上游输出自动传给下游。


八、踩坑记录(真金白银的经验)

坑 1:HuggingFace 在国内被墙

现象:Docker 构建时 sentence-transformers 无法下载模型,构建失败。

解决

  • CI 构建(GitHub Actions 境外机器)走 HF 官方
  • Docker 镜像内预下载模型(python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('all-MiniLM-L6-v2')"),运行时不需要联网
  • 国内部署时设置环境变量 HF_ENDPOINT=https://hf-mirror.com

坑 2:修复记录永远卡在"运行中"

现象:AI 修复执行过程中 LLM API 超时或 SSH 断开,数据库记录永远停留在 status: "running"

解决

  1. remediate_alert() 整个执行路径加 try/except,异常时更新为 failed
  2. 应用启动时自动扫描并清理上次异常退出遗留的 running 记录

坑 3:LLM API Key 隔离问题

现象:多个用户共用系统级 Key,手动修复也用系统 Key 计费。

解决UserLLMConfig 表存储每个用户自己的 API Key。Provider 工厂模式:用户有 Key → 创建独立 Provider;无 Key → 回退全局单例。

坑 4:ECS 内存不足 OOM

现象:1.7 GB 内存的 ECS 跑了 PostgreSQL + Redis + Backend + Frontend 四个容器,后端容器频繁 OOM。

解决

  • PostgreSQL 调低 shared_bufferswork_mem
  • Redis 设 maxmemory 64mb
  • 建议加 swap(fallocate -l 2G /swapfile && mkswap /swapfile && swapon /swapfile

坑 5:Agent 命令生成质量不稳定

现象:LLM 有时生成带 Markdown 解释的命令,有时代码块不闭合,有时生成无意义的 echo 语句。

解决

  • 每个 Agent 的 CMD_GEN_PROMPT 极度具体,限制输出格式
  • 代码块未闭合时的兜底提取逻辑(正则处理 LLM token 截断场景)
  • Prompt 要求"Output ONLY a bash code block. The block MUST be closed with "

九、量化成果

指标 数据
Agent 类型 12 个(9 个 AI 驱动 + 3 个实用节点)
API 端点 60+ REST + SSE 流式
通知通道 5 种(钉钉/企微/飞书/邮件/Webhook)
安全检查规则 13 条危险命令黑名单
日志事件检测 8 类系统异常自动识别
知识库条目 22+ 条预设 + 用户自定义
工作流模板 4 个真实运维场景
数据库表 14 张(完整审计追踪)
容器化 Docker Compose 一键部署 + K8s Helm Chart
CI/CD GitHub Actions 自动 lint → test → build → 推送阿里云 ACR

十、你可以怎么复用自己的项目里?

10.1 最小可行方案(一周可上线)

  1. 搭一个 FastAPI 接收 Prometheus Webhook → 解析告警,写入数据库
  2. 接一个 LLM API(GLM-4-Flash 免费) → 让 AI 分析告警内容,生成诊断命令
  3. 用 AsyncSSH 执行命令 → 在目标服务器执行,返回结果
  4. 加 13 条危险命令正则 → 安全拦截
  5. 钉钉机器人通知 → 告警 + 修复结果推送

这就已经是一个能用的 AI 自动修复管道了。

10.2 进阶方案

  1. RAG 知识库 → 用 sentence-transformers 把你团队的运维 Wiki 向量化
  2. 工作流编辑器 → React Flow 拖放编排多个 Agent
  3. 定时巡检 → APScheduler + dmesg 日志检测
  4. 多通道通知 → 企微/飞书/邮件

10.3 项目地址 & 源码

在线演示:http://8.137.178.63 (阿里云 ECS 部署,开源完整平台,注册即用)

源码

git clone https://github.com/okudhdheheuus/Python_AIops.git
cd Python_AIops
docker compose up -d

技术栈:Python/FastAPI + Next.js/React + PostgreSQL + Redis + Docker + Kubernetes


十一、写在最后

做这个项目的初心很简单:我不想凌晨 3 点被叫起来处理磁盘满这种问题。

传统运维的困境在于——监控系统能告诉你"出问题了",但它不能帮你"解决问题"。"发现问题"到"解决问题"之间这段路,以前全靠人走。

AI Agent 的价值就在于填平这段路

它不是替代运维人员,而是让你从"告警响应者"变成"平台建设者"。你把经验沉淀到知识库,把重复操作写成工作流,把安全检查做成规则——然后 AI 替你执行。

如果这篇文章对你有帮助,欢迎 Star、提 Issue、贡献代码。特别欢迎贡献新的通知通道、新的 Agent 类型、新的知识库条目。

一个人走得快,一群人走得远。

附GitHub 源码:https://github.com/okudhdheheuus
在线演示链接:http://8.137.178.63:3000

作者注:本文所有代码均为生产环境实际运行代码,非 Demo 演示。欢迎转载,请注明出处。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐