我是如何用 AI Agent + RAG 把告警平均修复时间(MTTR)从 30 分钟降到 3 分钟的
一个运维开发者的 AIOps 实战之路:从"告警风暴中疲于奔命"到"AI 自动诊断+修复+通知全闭环"
摘要
本文完整复盘了一套从零搭建的 AIOps 平台,通过 AI Agent + RAG 知识库实现 MTTR 从约 30 分钟降至约 3 分钟(10 倍提升)。系统以 FastAPI + AsyncSSH 构建 Auto-Remediation Pipeline,LLM 生成的修复命令经 三层安全防护 后执行;同时引入 RAG 将团队特有运维经验向量化,让 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% 等规则。
表面上看,监控体系很完善。但实际上:
告警风暴:凌晨 3 点,一个 Java 应用内存泄漏,连锁触发 12 条告警——CPU 高、内存高、GC 频繁、接口超时……我要从 12 条告警中找到根因。
知识在脑子里:“上次这个服务 OOM 是因为 JVM 参数没配 -XX:MaxMetaspaceSize”——但这句经验只在我脑子里,别人值班遇到同样的问题还是抓瞎。
操作风险:凌晨迷迷糊糊 SSH 上去,kill -9 打错 PID 怎么办?rm -rf /tmp/logs 多打了一个空格变成 rm -rf / tmp/logs 怎么办?
重复劳动:80% 的告警都是"磁盘满了,清理日志 → 重启服务"这种固定套路,但我每次还是要手动执行一遍。
核心矛盾:告警发现是自动的,但告警处理完全靠人。
我决定做一套系统,让 AI 来填补"告警触发"到"问题修复"之间的鸿沟。
三、架构总览
#mermaid-svg-1y5Lu6POru2gbEIx{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1y5Lu6POru2gbEIx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1y5Lu6POru2gbEIx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1y5Lu6POru2gbEIx .error-icon{fill:#552222;}#mermaid-svg-1y5Lu6POru2gbEIx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1y5Lu6POru2gbEIx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1y5Lu6POru2gbEIx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1y5Lu6POru2gbEIx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1y5Lu6POru2gbEIx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1y5Lu6POru2gbEIx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1y5Lu6POru2gbEIx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1y5Lu6POru2gbEIx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1y5Lu6POru2gbEIx .marker.cross{stroke:#333333;}#mermaid-svg-1y5Lu6POru2gbEIx svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1y5Lu6POru2gbEIx p{margin:0;}#mermaid-svg-1y5Lu6POru2gbEIx .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-1y5Lu6POru2gbEIx .cluster-label text{fill:#333;}#mermaid-svg-1y5Lu6POru2gbEIx .cluster-label span{color:#333;}#mermaid-svg-1y5Lu6POru2gbEIx .cluster-label span p{background-color:transparent;}#mermaid-svg-1y5Lu6POru2gbEIx .label text,#mermaid-svg-1y5Lu6POru2gbEIx span{fill:#333;color:#333;}#mermaid-svg-1y5Lu6POru2gbEIx .node rect,#mermaid-svg-1y5Lu6POru2gbEIx .node circle,#mermaid-svg-1y5Lu6POru2gbEIx .node ellipse,#mermaid-svg-1y5Lu6POru2gbEIx .node polygon,#mermaid-svg-1y5Lu6POru2gbEIx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1y5Lu6POru2gbEIx .rough-node .label text,#mermaid-svg-1y5Lu6POru2gbEIx .node .label text,#mermaid-svg-1y5Lu6POru2gbEIx .image-shape .label,#mermaid-svg-1y5Lu6POru2gbEIx .icon-shape .label{text-anchor:middle;}#mermaid-svg-1y5Lu6POru2gbEIx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1y5Lu6POru2gbEIx .rough-node .label,#mermaid-svg-1y5Lu6POru2gbEIx .node .label,#mermaid-svg-1y5Lu6POru2gbEIx .image-shape .label,#mermaid-svg-1y5Lu6POru2gbEIx .icon-shape .label{text-align:center;}#mermaid-svg-1y5Lu6POru2gbEIx .node.clickable{cursor:pointer;}#mermaid-svg-1y5Lu6POru2gbEIx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1y5Lu6POru2gbEIx .arrowheadPath{fill:#333333;}#mermaid-svg-1y5Lu6POru2gbEIx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1y5Lu6POru2gbEIx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1y5Lu6POru2gbEIx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1y5Lu6POru2gbEIx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1y5Lu6POru2gbEIx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1y5Lu6POru2gbEIx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1y5Lu6POru2gbEIx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1y5Lu6POru2gbEIx .cluster text{fill:#333;}#mermaid-svg-1y5Lu6POru2gbEIx .cluster span{color:#333;}#mermaid-svg-1y5Lu6POru2gbEIx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1y5Lu6POru2gbEIx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1y5Lu6POru2gbEIx rect.text{fill:none;stroke-width:0;}#mermaid-svg-1y5Lu6POru2gbEIx .icon-shape,#mermaid-svg-1y5Lu6POru2gbEIx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1y5Lu6POru2gbEIx .icon-shape p,#mermaid-svg-1y5Lu6POru2gbEIx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1y5Lu6POru2gbEIx .icon-shape .label rect,#mermaid-svg-1y5Lu6POru2gbEIx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1y5Lu6POru2gbEIx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1y5Lu6POru2gbEIx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1y5Lu6POru2gbEIx :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
外部系统
数据层
服务层
用户层
运维人员
Nginx 反向代理 :80
FrontendNext.js 16 + React Flow
BackendFastAPI + asyncio
Multi-Agent AI Engine12个专业Agent
WorkflowEngineDAG 拓扑排序 + 并行执行
APScheduler300秒定时巡检
SSH Connection PoolAsyncSSH · 最大30连接
RAG 语义检索sentence-transformers
PostgreSQL 16告警/服务器/审计
Redis 7会话/限流/缓存
LLM APIGLM-4 / DeepSeek / OpenAI
目标服务器群ECS × 20+
通知渠道钉钉/企微/飞书/邮件
技术选型原则:每一步都选最"轻"的方案。
| 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 PoolRAG 知识库LLM APIPostgreSQLFastAPI /alerts/webhookPrometheus通知渠道目标服务器SSH Connection PoolRAG 知识库LLM APIPostgreSQLFastAPI /alerts/webhookPrometheus#mermaid-svg-hUvpDQCEOOXAsRkh{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hUvpDQCEOOXAsRkh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hUvpDQCEOOXAsRkh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hUvpDQCEOOXAsRkh .error-icon{fill:#552222;}#mermaid-svg-hUvpDQCEOOXAsRkh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hUvpDQCEOOXAsRkh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hUvpDQCEOOXAsRkh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hUvpDQCEOOXAsRkh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hUvpDQCEOOXAsRkh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hUvpDQCEOOXAsRkh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hUvpDQCEOOXAsRkh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hUvpDQCEOOXAsRkh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hUvpDQCEOOXAsRkh .marker.cross{stroke:#333333;}#mermaid-svg-hUvpDQCEOOXAsRkh svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hUvpDQCEOOXAsRkh p{margin:0;}#mermaid-svg-hUvpDQCEOOXAsRkh .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-hUvpDQCEOOXAsRkh text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-hUvpDQCEOOXAsRkh .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-hUvpDQCEOOXAsRkh .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-hUvpDQCEOOXAsRkh .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-hUvpDQCEOOXAsRkh .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-hUvpDQCEOOXAsRkh #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-hUvpDQCEOOXAsRkh .sequenceNumber{fill:white;}#mermaid-svg-hUvpDQCEOOXAsRkh #sequencenumber{fill:#333;}#mermaid-svg-hUvpDQCEOOXAsRkh #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-hUvpDQCEOOXAsRkh .messageText{fill:#333;stroke:none;}#mermaid-svg-hUvpDQCEOOXAsRkh .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-hUvpDQCEOOXAsRkh .labelText,#mermaid-svg-hUvpDQCEOOXAsRkh .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-hUvpDQCEOOXAsRkh .loopText,#mermaid-svg-hUvpDQCEOOXAsRkh .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-hUvpDQCEOOXAsRkh .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-hUvpDQCEOOXAsRkh .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-hUvpDQCEOOXAsRkh .noteText,#mermaid-svg-hUvpDQCEOOXAsRkh .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-hUvpDQCEOOXAsRkh .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-hUvpDQCEOOXAsRkh .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-hUvpDQCEOOXAsRkh .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-hUvpDQCEOOXAsRkh .actorPopupMenu{position:absolute;}#mermaid-svg-hUvpDQCEOOXAsRkh .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-hUvpDQCEOOXAsRkh .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-hUvpDQCEOOXAsRkh .actor-man circle,#mermaid-svg-hUvpDQCEOOXAsRkh line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-hUvpDQCEOOXAsRkh :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}Webhook POST (CPU 95%)去重查询 (alert_name+instance+firing)无重复 → 新建告警语义检索告警相关运维经验Top-3 相关知识片段告警上下文 + RAG知识 → 生成修复命令```bash\\n预检→修复→验证\\n```13项危险命令安全检查 ✓ 通过获取连接 (host:port:user)systemctl restart java-appOK (exit 0)执行结果 → 分析是否成功修复成功, 服务已恢复写入 RemediationLog更新 Alert 状态 → resolved推送修复结果 (钉钉+企微)
#mermaid-svg-QaACDDX4cCZQ8sRj{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QaACDDX4cCZQ8sRj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QaACDDX4cCZQ8sRj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QaACDDX4cCZQ8sRj .error-icon{fill:#552222;}#mermaid-svg-QaACDDX4cCZQ8sRj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QaACDDX4cCZQ8sRj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QaACDDX4cCZQ8sRj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QaACDDX4cCZQ8sRj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QaACDDX4cCZQ8sRj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QaACDDX4cCZQ8sRj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QaACDDX4cCZQ8sRj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QaACDDX4cCZQ8sRj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QaACDDX4cCZQ8sRj .marker.cross{stroke:#333333;}#mermaid-svg-QaACDDX4cCZQ8sRj svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QaACDDX4cCZQ8sRj p{margin:0;}#mermaid-svg-QaACDDX4cCZQ8sRj .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-QaACDDX4cCZQ8sRj .cluster-label text{fill:#333;}#mermaid-svg-QaACDDX4cCZQ8sRj .cluster-label span{color:#333;}#mermaid-svg-QaACDDX4cCZQ8sRj .cluster-label span p{background-color:transparent;}#mermaid-svg-QaACDDX4cCZQ8sRj .label text,#mermaid-svg-QaACDDX4cCZQ8sRj span{fill:#333;color:#333;}#mermaid-svg-QaACDDX4cCZQ8sRj .node rect,#mermaid-svg-QaACDDX4cCZQ8sRj .node circle,#mermaid-svg-QaACDDX4cCZQ8sRj .node ellipse,#mermaid-svg-QaACDDX4cCZQ8sRj .node polygon,#mermaid-svg-QaACDDX4cCZQ8sRj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QaACDDX4cCZQ8sRj .rough-node .label text,#mermaid-svg-QaACDDX4cCZQ8sRj .node .label text,#mermaid-svg-QaACDDX4cCZQ8sRj .image-shape .label,#mermaid-svg-QaACDDX4cCZQ8sRj .icon-shape .label{text-anchor:middle;}#mermaid-svg-QaACDDX4cCZQ8sRj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QaACDDX4cCZQ8sRj .rough-node .label,#mermaid-svg-QaACDDX4cCZQ8sRj .node .label,#mermaid-svg-QaACDDX4cCZQ8sRj .image-shape .label,#mermaid-svg-QaACDDX4cCZQ8sRj .icon-shape .label{text-align:center;}#mermaid-svg-QaACDDX4cCZQ8sRj .node.clickable{cursor:pointer;}#mermaid-svg-QaACDDX4cCZQ8sRj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QaACDDX4cCZQ8sRj .arrowheadPath{fill:#333333;}#mermaid-svg-QaACDDX4cCZQ8sRj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QaACDDX4cCZQ8sRj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QaACDDX4cCZQ8sRj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QaACDDX4cCZQ8sRj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QaACDDX4cCZQ8sRj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QaACDDX4cCZQ8sRj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QaACDDX4cCZQ8sRj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QaACDDX4cCZQ8sRj .cluster text{fill:#333;}#mermaid-svg-QaACDDX4cCZQ8sRj .cluster span{color:#333;}#mermaid-svg-QaACDDX4cCZQ8sRj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QaACDDX4cCZQ8sRj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QaACDDX4cCZQ8sRj rect.text{fill:none;stroke-width:0;}#mermaid-svg-QaACDDX4cCZQ8sRj .icon-shape,#mermaid-svg-QaACDDX4cCZQ8sRj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QaACDDX4cCZQ8sRj .icon-shape p,#mermaid-svg-QaACDDX4cCZQ8sRj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QaACDDX4cCZQ8sRj .icon-shape .label rect,#mermaid-svg-QaACDDX4cCZQ8sRj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QaACDDX4cCZQ8sRj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QaACDDX4cCZQ8sRj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QaACDDX4cCZQ8sRj :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
新告警
重复
危险
安全
成功
失败
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 实现方案
#mermaid-svg-yifKjSzjzXVCtwIQ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yifKjSzjzXVCtwIQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yifKjSzjzXVCtwIQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yifKjSzjzXVCtwIQ .error-icon{fill:#552222;}#mermaid-svg-yifKjSzjzXVCtwIQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yifKjSzjzXVCtwIQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yifKjSzjzXVCtwIQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yifKjSzjzXVCtwIQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yifKjSzjzXVCtwIQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yifKjSzjzXVCtwIQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yifKjSzjzXVCtwIQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yifKjSzjzXVCtwIQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yifKjSzjzXVCtwIQ .marker.cross{stroke:#333333;}#mermaid-svg-yifKjSzjzXVCtwIQ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yifKjSzjzXVCtwIQ p{margin:0;}#mermaid-svg-yifKjSzjzXVCtwIQ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-yifKjSzjzXVCtwIQ .cluster-label text{fill:#333;}#mermaid-svg-yifKjSzjzXVCtwIQ .cluster-label span{color:#333;}#mermaid-svg-yifKjSzjzXVCtwIQ .cluster-label span p{background-color:transparent;}#mermaid-svg-yifKjSzjzXVCtwIQ .label text,#mermaid-svg-yifKjSzjzXVCtwIQ span{fill:#333;color:#333;}#mermaid-svg-yifKjSzjzXVCtwIQ .node rect,#mermaid-svg-yifKjSzjzXVCtwIQ .node circle,#mermaid-svg-yifKjSzjzXVCtwIQ .node ellipse,#mermaid-svg-yifKjSzjzXVCtwIQ .node polygon,#mermaid-svg-yifKjSzjzXVCtwIQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yifKjSzjzXVCtwIQ .rough-node .label text,#mermaid-svg-yifKjSzjzXVCtwIQ .node .label text,#mermaid-svg-yifKjSzjzXVCtwIQ .image-shape .label,#mermaid-svg-yifKjSzjzXVCtwIQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-yifKjSzjzXVCtwIQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yifKjSzjzXVCtwIQ .rough-node .label,#mermaid-svg-yifKjSzjzXVCtwIQ .node .label,#mermaid-svg-yifKjSzjzXVCtwIQ .image-shape .label,#mermaid-svg-yifKjSzjzXVCtwIQ .icon-shape .label{text-align:center;}#mermaid-svg-yifKjSzjzXVCtwIQ .node.clickable{cursor:pointer;}#mermaid-svg-yifKjSzjzXVCtwIQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yifKjSzjzXVCtwIQ .arrowheadPath{fill:#333333;}#mermaid-svg-yifKjSzjzXVCtwIQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yifKjSzjzXVCtwIQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yifKjSzjzXVCtwIQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yifKjSzjzXVCtwIQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yifKjSzjzXVCtwIQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yifKjSzjzXVCtwIQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yifKjSzjzXVCtwIQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yifKjSzjzXVCtwIQ .cluster text{fill:#333;}#mermaid-svg-yifKjSzjzXVCtwIQ .cluster span{color:#333;}#mermaid-svg-yifKjSzjzXVCtwIQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yifKjSzjzXVCtwIQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yifKjSzjzXVCtwIQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-yifKjSzjzXVCtwIQ .icon-shape,#mermaid-svg-yifKjSzjzXVCtwIQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yifKjSzjzXVCtwIQ .icon-shape p,#mermaid-svg-yifKjSzjzXVCtwIQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yifKjSzjzXVCtwIQ .icon-shape .label rect,#mermaid-svg-yifKjSzjzXVCtwIQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yifKjSzjzXVCtwIQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yifKjSzjzXVCtwIQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yifKjSzjzXVCtwIQ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
结果
在线查询
离线阶段
是
否
运维知识库22+ 条 Markdown 条目
SentenceTransformerall-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 不只是采集指标
传统的巡检就是跑个 top、free、df,超过阈值发告警。我加了日志事件检测——八类系统异常自动识别:
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
| 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 并行执行
#mermaid-svg-dttE64hyPSQulCHV{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dttE64hyPSQulCHV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dttE64hyPSQulCHV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dttE64hyPSQulCHV .error-icon{fill:#552222;}#mermaid-svg-dttE64hyPSQulCHV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dttE64hyPSQulCHV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dttE64hyPSQulCHV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dttE64hyPSQulCHV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dttE64hyPSQulCHV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dttE64hyPSQulCHV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dttE64hyPSQulCHV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dttE64hyPSQulCHV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dttE64hyPSQulCHV .marker.cross{stroke:#333333;}#mermaid-svg-dttE64hyPSQulCHV svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dttE64hyPSQulCHV p{margin:0;}#mermaid-svg-dttE64hyPSQulCHV .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-dttE64hyPSQulCHV .cluster-label text{fill:#333;}#mermaid-svg-dttE64hyPSQulCHV .cluster-label span{color:#333;}#mermaid-svg-dttE64hyPSQulCHV .cluster-label span p{background-color:transparent;}#mermaid-svg-dttE64hyPSQulCHV .label text,#mermaid-svg-dttE64hyPSQulCHV span{fill:#333;color:#333;}#mermaid-svg-dttE64hyPSQulCHV .node rect,#mermaid-svg-dttE64hyPSQulCHV .node circle,#mermaid-svg-dttE64hyPSQulCHV .node ellipse,#mermaid-svg-dttE64hyPSQulCHV .node polygon,#mermaid-svg-dttE64hyPSQulCHV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dttE64hyPSQulCHV .rough-node .label text,#mermaid-svg-dttE64hyPSQulCHV .node .label text,#mermaid-svg-dttE64hyPSQulCHV .image-shape .label,#mermaid-svg-dttE64hyPSQulCHV .icon-shape .label{text-anchor:middle;}#mermaid-svg-dttE64hyPSQulCHV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dttE64hyPSQulCHV .rough-node .label,#mermaid-svg-dttE64hyPSQulCHV .node .label,#mermaid-svg-dttE64hyPSQulCHV .image-shape .label,#mermaid-svg-dttE64hyPSQulCHV .icon-shape .label{text-align:center;}#mermaid-svg-dttE64hyPSQulCHV .node.clickable{cursor:pointer;}#mermaid-svg-dttE64hyPSQulCHV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dttE64hyPSQulCHV .arrowheadPath{fill:#333333;}#mermaid-svg-dttE64hyPSQulCHV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dttE64hyPSQulCHV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dttE64hyPSQulCHV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dttE64hyPSQulCHV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dttE64hyPSQulCHV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dttE64hyPSQulCHV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dttE64hyPSQulCHV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dttE64hyPSQulCHV .cluster text{fill:#333;}#mermaid-svg-dttE64hyPSQulCHV .cluster span{color:#333;}#mermaid-svg-dttE64hyPSQulCHV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dttE64hyPSQulCHV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dttE64hyPSQulCHV rect.text{fill:none;stroke-width:0;}#mermaid-svg-dttE64hyPSQulCHV .icon-shape,#mermaid-svg-dttE64hyPSQulCHV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dttE64hyPSQulCHV .icon-shape p,#mermaid-svg-dttE64hyPSQulCHV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dttE64hyPSQulCHV .icon-shape .label rect,#mermaid-svg-dttE64hyPSQulCHV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dttE64hyPSQulCHV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dttE64hyPSQulCHV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dttE64hyPSQulCHV :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
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"。
解决:
坑 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_buffers、work_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 最小可行方案(一周可上线)
这就已经是一个能用的 AI 自动修复管道了。
10.2 进阶方案
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 类型、新的知识库条目。
一个人走得快,一群人走得远。
作者注:本文所有代码均为生产环境实际运行代码,非 Demo 演示。欢迎转载,请注明出处。
网硕互联帮助中心




评论前必须登录!
注册