做运维的人应该都有过这种冲动:半夜告警响了,爬起来看一眼,发现只是某个服务抖动了一下,自己恢复了;或者收到一堆日志,排查半天,定位到一个早就该有人处理的配置项。那时候就在想,这些事能不能让机器自己干了?说实话,传统的脚本和自动化能做不少事,但遇到“需要判断、需要协同、需要临时改策略”的场景,脚本就僵住了。最近我在折腾 AI 运维 Agent,试了一套多智能体协同的方案,让几个 Agent 自己分工、自己干活、自己汇报,效果比预期好不少。这篇就聊聊这个系统是怎么搭的、里面的 Agent 怎么协作、以及实测下来的真实表现,踩过的坑也一并写出来。
这适合已经在用自动化脚本、但想往智能化走一步的运维同学,也适合对 Agent 概念感兴趣、想看看它在运维场景里到底能干啥的人。不需要你有大模型训练基础,但得对 Linux、API、工作流编排有点概念。
1. AI 运维 Agent 的“自主做事”,靠的不是大模型本身
先说一个容易误会的点:AI 运维 Agent 不是把大模型接进来就完事了。大模型本身只能理解语言、生成文本,它不会执行命令、拉取指标、改配置。真正让它“自己做事”的,是一套把它跟运维系统连起来的执行链路。
1.1 从“聊天”到“干活”,隔着一个完整的工具链
我见过不少人说“接入大模型之后,能让它帮我查日志吗”。实际上,大模型返回的只是一段文本,甚至可能是一段“我建议你执行 xxx 命令”的文字。要让它真的去查日志、去重启服务,需要做三件事:
第一,给大模型提供工具。每个运维动作都得封装成一个可调用的函数或接口,比如“查 CPU 使用率”“拉取最近 1 小时错误日志”“重启某个 Pod”“回滚某个版本”。这一步很像把所有常用运维操作做成 REST API,Agent 通过调用函数来执行动作。
第二,给大模型观察结果的能力。一次调用可能不够,Agent 得能连续多轮“观察-思考-行动”。比如先查指标,指标异常再查日志,日志里看到某个错误码,再决定下一步动作。这个循环是 Agent 能做决策的基础。
第三,设置边界和审批机制。自主不等于不受控,尤其是生产环境。初期部署时每台机器都配了白名单命令和操作风控,超过阈值的操作会转人工确认。
所以,“自己做事”的本质是:大模型负责推理、规划和拆解任务,工具层负责执行,编排层负责控制节奏和风险。三者缺一不可。
1.2 我的第一个最小闭环 Demo
我最开始跑通的版本很简单:一台测试服务器,部署了一个大模型接口,通过 Python 写了一个执行器脚本,封装了三个函数:get_cpu()、get_disk()、restart_service()。然后给模型一个目标:“检查 CPU 持续 5 分钟高于 80% 时重启应用服务”。
这次跑通过程让我理解了关键的机制:Agent 不是一次性生成答案,而是进入了循环模式。第一轮调用模型,模型返回“先执行 get_cpu()”,执行器去查系统指标,把结果塞回对话上下文,模型看到 CPU 确实高,继续执行restart_service(),然后再检查一次 CPU 是否回落。整个过程没有人工参与。
心跳定时器驱动了这个循环。每检查一次算一个 step,通常任务要 3~6 个 step 才能完成。为了不把上下文撑爆,我给对话历史做了截断,只保留最近的 10 轮往返。这也是后面很多问题的根源,后面会细说。
2. 多智能体协同:不是“一堆模型开会”,而是“流水线 + 分工”
单 Agent 能做的事很有限。真正想覆盖“监控发现、根因定位、止损恢复、通知响应”这条完整链路,得让不同 Agent 各管一段,互相配合。
2.1 每个 Agent 的角色画像和能力边界
我最终部署的这套环境里定义了四个 Agent,每个都有自己的职责和工具集:
Monitor Agent 专职盯告警和指标。它定时轮询监控系统,一旦触发阈值,就生成一条结构化事件。它不负责修复,只负责“发现问题并发出信息”。
Diagnose Agent 专职分析。它拿到 Monitor 的事件后,去拉日志、查依赖关系、看最近变更记录,输出一份带置信度的根因判断。它不直接操作,只给结论。
Executor Agent 专职执行动作。它接收 Diagnose 的判断结果,匹配预案库里的操作步骤,执行重启、回滚、扩缩容等操作。它需要最严格的风控。
Notify Agent 专职通报。所有阶段性结论、执行结果、人工确认请求都由它发出,发到企业微信或钉钉机器人。它不做决策,只是保持信息透明。
四者协作按照标准的三个阶段推进——发现、诊断、处置——构成完整闭环。
2.2 关键在于,Agent 之间如何交换信息
多 Agent 架构里最常见的坑是各说各话。每个 Agent 都接了大模型,如果不做结构化管理,它们之间传的就是一堆自然语言段落,结果后面的 Agent 根本没法稳定地把关键信息提取出来。
我用的办法是:所有 Agent 之间只通过 JSON 结构传消息。Monitor 输出的事件格式固定:
{ "event_id": "evt_001", "type": "cpu_high", "severity": "P2", "target": "order-service", "metrics": { "cpu_usage": 92.5, "load1": 18.3 }, "timestamp": "2025-01-10T14:23:00Z" }Diagnose 拿到这个消息后,解析target和type,决定拉哪些数据源,输出根因判断也走固定格式:
{ "event_id": "evt_001", "root_cause": "jvm_old_gc", "confidence": 0.87, "evidence": ["gc log count=12", "heap usage=95%"], "suggested_actions": ["restart_service", "increase_heap"] }这样做的好处是:每个 Agent 都不需要理解其他 Agent 的“思维过程”,只需要消费结构化的输入、产出结构化的输出。大模型的不稳定性被锁在了各自的处理流程里,Agent 间的通信反而是稳定的。
这一步我强烈建议不要省略。早期版本试过直接传自然语言,Diagnose 经常把 Monitor 的意思理解偏,甚至会自己脑补出不存在的问题。
2.3 协同编排:一个轻量的任务状态机
四个 Agent 不是并行随便跑的,它们得按一个流程走,同时允许异常分支。我用了很轻量的状态机来做编排,没有引入重型工作流框架,就维护一张任务状态表:
| 状态 | 负责 Agent | 流转条件 |
|---|---|---|
| detected | Monitor | 指标越限 |
| diagnosing | Diagnose | 收到事件 |
| root_caused | Diagnose | 输出根因,置信度 > 0.6 |
| executing | Executor | 收到建议动作 |
| recovered | Executor | 恢复命令返回成功 |
| notified | Notify | 消息发送成功 |
| wait_approval | Executor | 置信度低或超阈值操作 |
每个 Agent 异步处理,处理完就更新状态。状态一旦更新,会触发现有定义的下一跳。这套模型足够简单,但也踩了不少坑。后面遇到的最多问题,都是状态没流转到、事件卡死这类细节,让我意识到编排层和 Agent 一样重要。
3. 部署实践:从零搭一个能自主处置告警的 Agent 系统
如果你也想搭一套类似的系统,我这里把可复制的步骤整理一遍,假设环境是:一台 Linux 服务器、Docker、Python 3.9+、已经有大模型 API 的访问权限。监控数据源我们先拿 Prometheus 的 API 来测。
3.1 环境准备和必要的组件清单
系统拆四个模块,部署用 Docker Compose 管理。四个模块分别是:事件总线(用轻量消息队列)、Agent 执行器(Python 进程)、编排引擎(带状态表的小服务,用 FastAPI 写的)、管理面板(只用来查日志和状态)。
实际部署过程中有几件事要提醒:
第一,大模型 API 一定要走内网或代理地址,不然每次 Agent 调用都走公网,延迟不可控。后面排查问题的时候就遇到过一次,因为外网不稳定导致 Diagnose 响应超时,整体任务状态卡了十几分钟。
第二,所有 Agent 需要共享一套时钟。最开始排查一个“事件顺序错乱”的问题,发现是不同容器的系统时间偏差了十几秒,诊断 agent 读到的日志时序是反的。
第三,日志必须全部带结构化字段。最好不要只靠打印字符串。后面调试多 Agent 协作时,一篇混乱的日志根本没法快速定位是哪个环节出了问题。
Docker Compose 的 service 定义大致长这样,单机玩法够用了:
version: "3.8" services: queue: image: valkey/valkey:7.2 ports: ["6379:6379"] executor: build: ./executor environment: - MODEL_ENDPOINT=http://llm-gateway:8080/v1 - TOOL_WHITELIST=restart_service,get_cpu,get_mem volumes: - /var/run/docker.sock:/var/run/docker.sock orchestrator: build: ./orchestrator ports: ["8081:8080"] depends_on: - queue第一版跑起来之后,建议不要一次启用四个 Agent。我是先用假的告警数据流把事件总线拆通,再逐个开启 Agent 验证。
3.2 编写 Executor Agent 的工具封装
一个关键动作是:封装给大模型调用的工具函数。这里最容易踩的坑是模型“乱发明工具”。第一次跑,我让大模型输出工具名,模型自己编了个restart_nginx_if_cpu_high()的函数名,执行器当然找不到。
解决办法是:工具调用不用自然语言输出,而是用 function calling。大模型结构化返回调用的工具名和参数。执行器里注册所有合法工具,模型只能从白名单里选。
以查 CPU 为例:
def get_cpu_usage(host: str) -> float: # 调用 Prometheus API 获取瞬时 CPU 使用率 resp = requests.get( f"http://prometheus:9090/api/v1/query", params={"query": f'avg(rate(node_cpu_seconds_total{{mode!="idle",instance="{host}"}}[5m])) * 100'} ) return float(resp.json()["data"]["result"][0]["value"][1])封装完这一个函数后,需要在 OpenAI 兼容格式的 tools 列表里描述它:
{ "type": "function", "function": { "name": "get_cpu_usage", "description": "获取指定主机的 CPU 使用率百分比", "parameters": { "type": "object", "properties": { "host": {"type": "string"} }, "required": ["host"] } } }tools 描述就像是给大模型的“说明书”。说明书写得好不好,直接影响后面的诊断准确率。
3.3 配置定时巡检与拟人化反馈机制
Monitor Agent 不需要大模型,纯规则就行。它的巡检频率我设为 30 秒一次,查询最近 5 分钟的平均负载。触发条件设置了两级:超过 70% 写一条 warning 日志,超过 85% 进入诊断流程。
巡检本身是死逻辑,但反馈要拟人化。我特意给每个 Agent 设置了不同的“人设”描述和措辞模板。比如 Notify Agent 发消息时会写“CPU 持续高位,已排查 XX 服务的 GC 日志,判断为堆内存不足,已进行重启操作”,而不是只发一个“CPU 高”。
这个细节的效果非常好——因为最终看消息的还是人,措辞越接近人话,响应效率越高。而且如果通知周末凌晨发过来,一眼能看清发生了什么,值班的人也不需要再重新拉一堆日志核实,可以直接决定要不要介入。
3.4 配置权限控制和人工确认环节
自动化程度越高,越要想清楚控制边界。对外面常见的做法是“全自动或者全手动”,其实中间应该有一层灰度策略。我按操作风险分级:
| 操作类型 | 风险等级 | 执行方式 |
|---|---|---|
| 查询指标、拉日志 | 低 | 自动执行 |
| 重启服务、清理缓存 | 中 | 自动执行,写审计日志 |
| 回滚版本、变更配置 | 高 | 自动准备命令,人工确认后执行 |
这个表格是按实际经验总结的。初期谁都不想让机器直接改生产配置,但全手动又失去了 Agent 的意义。折中下来,把“查询和常规重启”交给 Agent 自动做,把“回滚、扩容等有长期影响的动作”设为待确认状态。通知 Agent 会把预执行的命令和变更原因发出来,人工点确认之后,Executor 才真正执行。
有一点很值得说:人工确认不能只在流程末尾加,那样 Agent 可能会在决策过程中做出错误行为。正确做法是把人工确认作为独立的状态节点,嵌入流程中间。例如高风险的变更,在 Executor 生成命令后必须等待确认,不允许先执行后补审批。权限上还要区分不同 Agent 能访问的主机范围,Monitor 和 Diagnose 可以看所有机器,Executor 默认只能操作测试环境的机器,生产环境机器要额外授权。
整套权限体系跑通了之后,我才敢让它处理一部分低风险告警。
4. 实战场景实测:从“告警产生”到“自动恢复”的完整链路
整个系统搭建完成后,我用三个典型故障场景做了压测,模拟了真实环境中容易遇到的告警类型。这几个场景能比较全面地暴露问题。
4.1 场景一:CPU 持续飙高,Executor 自动重启服务
我模拟了某订单业务服务 CPU 打满的情况。用stress-ng在容器里持续占 CPU,让其超过 85% 阈值并保持。Monitor 首次检测到该指标,生成告警事件,写入队列。
Diagnose 收到事件后,先去拉该服务的 CPU 监控曲线,确认不是瞬时尖峰,是持续攀升。然后拉日志,翻到大量线程阻塞信息,结合最近变更记录,判断根因疑似“连接池配置过小导致请求堆积”,最终输入根因结论和建议动作restart_service和increase_pool_size。
由于restart_service属于中风险操作,Executor 执行脚本完成重启。重启过程中,Notice Agent 每步更新进度,避免中间状态无人知晓。最终查到 CPU 负载回落。Notify Agent 发出完整报告,包含触发时间、根因、处置动作、当前状态、后续建议字段。
这套联动从告警发生到恢复用了大约 4 分 40 秒。其中大部分耗时在大模型多次推理上。如果继续优化,可以把 Diagnose 的日志分析改成先做关键词预筛,再让大模型判断,总耗时能压缩到 3 分钟以内。
4.2 场景二:误判差点酿错,人工确认拦住了
第二个场景专门测人工确认机制。我模拟的是磁盘使用率报警。Monitor 发现某台主机的磁盘超过 90%,触发诊断。
Diagnose 分析后发现目录/data/logs占用最多,判断为“日志文件膨胀”,建议动作是“清理 7 天前的日志文件”。这个动作本身没问题,但磁盘上其实还跑着一个数据分析任务,正准备读取/data/logs/archive下的旧文件,直接清理会破坏这个任务。
因为清理动作被列入高风险操作,Executor 生成了命令但没有执行,而是通过 Notify 发给我确认。我看到命令涉及删除文件,手动检查了一下目录内容,发现旧文件还有用,否掉了这个操作,改成让 Diagnose 重新给方案,最终换成了“按文件大小和最后访问时间只清 tmp 目录”。
这个案例很有价值。证明“慢一点,确认一下”不是拖后腿,反而可能是真正的保护。也正因如此,我强烈建议人工确认的阈值设置得偏保守,宁多不少。
4.3 场景三:长任务执行中上下文丢失的惊人后果
第三个场景是暴露问题最狠的。我模拟了一个复杂故障:一个业务依赖了三个组件状态全部异常,一个组件磁盘满,一个组件 OOM,一个组件网络延迟高。
Diagnose 在同一轮上下文里要分析三个组件的日志。但对话历史经过截断,较早的组件 A 信息被挤出上下文,Diagnose 分析到最后只报告了组件 B 和 C 的问题,组件 A 的问题被漏掉。结果 Executor 只处理了 B 和 C,A 的故障未被处置。最终告警主链路没有恢复。
这个案例敲响的警钟远超预期,让我意识到单 Agent 大模型上下文的局限:多组件、多关联任务的情景,个人的记忆窗口就是瓶颈。后续优化方案是:拆分解耦。让 Diagnose 做两级分析,先由一个粗筛 Agent 把所有组件异常汇总成一张清单,再拆成独立子任务分别诊断。每个子任务都是独立上下文,互不污染。
现在这个新架构上线后,再次模拟同样的场景,三个组件异常都能被正确识别和处置,没有出现“高并发的多问题互相挤掉”的现象。上下文丢失的问题算是解决了。
5. 多智能体协同系统跑起来之后的优化经验与避坑指南
整个系统从能跑到能用,中间经历了大量调整。下面写几个我认为最有价值的优化点和最容易踩的坑。
5.1 大模型返回不稳定,怎么办
大模型不是每次都听话的。偶尔会给出越界建议,偶尔会漏掉函数调用,偶尔会生成乱码。我的处理思路是:给所有 Agent 加一个输出校验层。
校验层做两件事:一是格式校验,解析大模型输出的 JSON、工具调用是否合法;二是逻辑校验——比如 Executor 要执行重启,但当前 CPU 负载只有 10%,明显不合理,就拒绝执行并要求重新诊断。
这个校验层也帮我拦下了一次比较危险的操作,某个模型在分析了一句错误日志时建议“重装操作系统”,被校验层直接拦截并标记为异常输出。所以不要把所有判断权都交给大模型,工具层该有的理智,还是要用代码写死。
5.2 消息队列选型和事件幂等设计
多 Agent 系统里的消息队列一开始选型很随意,直接用最简单的 Redis 列表。结果在并发告警多的时候,多个 Executor 同时消费同一个任务,重复执行了操作。原因是消息没有做幂等。
后来换成了 Stream 类型,每条事件带event_id,消费端维护一个已处理集合。遇到相同的event_id直接跳过。这个改动虽然小,但效果非常明显,大量因为消息重复触发的误操作消失了。
另外,Agent 的执行入口必须是幂等的。例如restart_service被调两次,第二次要判断服务状态已经是 running,就跳过。这也是一种保护。
5.3 记忆持久化与上下文管理,是保证长任务稳定性的基石
前文提到的上下文丢失问题,除了拆分解耦,还需要在架构层面做记忆持久化。我引入了一个向量库,用于存历史故障处置案例。当 Diagnose 遇到某个事件时,会先检索相似历史案例,把检索结果拼进 prompt 里,供大模型参考。
这个机制的效果出乎意料地好——第二次遇到同类故障时,Diagnose 的根因置信度明显提高,建议的动作也更贴合之前验证过的方案。这有点像给团队加了一份“历史经验存档”,每次处置完故障之后,整个链路都会自动归档摘要。
现在每次工单结束,我都尽可能地保证归档动作是自动完成的,并且会把最终的根因、处置动作、验证结果都写成结构化摘要。长期跑下来,这套系统会越来越懂这个环境,越用越精准。
6. 这套模式在落地时,实际运维团队应该如何适配
很多朋友看完上面可能会问,我这边没有大模型开发和编排能力,怎么落地这套东西?我觉得核心不是非得自研,而是把现有的工具链和团队分工重新理顺。
6.1 大模型基座:用成熟平台比什么都重要
我尝试过本地部署开源模型,也试过各种微调。最后稳定下来的方案反而最简单——用成熟的大模型 API 服务作为底座。主要原因有三个:稳定性、工具调用的成熟度、持续迭代能力。
部署一个私有模型要处理显存、推理速度、上下文长度这些问题,很影响体验。而成熟服务在 function calling 上做得比较完善,对 Agent 场景支持好。甚至到现在,我的 Agent 系统接入的大模型 API 已经在不同版本间切换了好几次,业务代码几乎没有改动。
建议如果要试,不必纠结必须完全私有化部署,先用成熟 API 把流程跑通,再评估后续需要调整的部分。
6.2 运维人员的角色转型:从“操作员”到“策略制定者”
当 Agent 真的开始接管低风险操作后,运维人员的工作内容会发生变化。团队里最明显的体会是:一线工单少了许多,例如重启、日志清理这些重复操作基本不需要人参与了。但提出问题、制定安全策略、审核 Agent 操作合理性的工作量却变多了。
我现在主要做的一件事,就是不断给工具白名单补充和修正操作边界,以及对 Agent 的决策逻辑给出校验规则。比如某些命令只在特定目录可用,某些环境只允许在维护窗口期执行变更,全部要靠人提前定义清楚。
如果团队里没有这样一个“策略制定者”,Agent 系统很容易暴走。这块需要尽早重视,哪怕初期一个人专职盯控,也比全自动裸奔强。
6.3 灰度发布和评估机制
这套系统从 Demo 走到生产,用了一个还算稳妥的灰度策略:先让 Monitor 和 Diagnose 全量上线,但 Executor 只接入一台测试机;跑了两周,确认没有逻辑错乱,再逐步扩大到低风险操作;每一步都留有人工复核通道。
我个人的判断是,评估机制的关键不在于“自动化率有多高”,而在于“人工介入次数是否逐步下降”。如果今天自动执行了 100 次,但其中 40 次都需要人工干预纠偏,那说明 Agent 的学习和判断能力还没到位。反之,如果人工介入频率逐月降低,说明系统进入了良性循环,新增的自动恢复能力是值得信任的。
7. 一些最后想说的话
折腾这套系统大半年,我最大的感受是“AI 运维 Agent”并不是一个成品,而是一个需要持续调教的协作过程。多智能体协同也不是把多个 Agent 丢在一起就能成事,关键还是清晰的角色分工、稳定的信息流转,以及严格的边界控制。
最让我欣慰的时刻,是它在一次真实故障里成功识别出根因并自动处置完毕,值班同事第二天早上看了一眼报告,发现处理记录比人工写的还要清晰。那种“机器真的在帮忙分担压力”的成就感,很难用语言表达。它不能替代所有判断,但确实把不少重复的、低价值的劳动接了过去。让做运维的人可以去做更复杂、更值得思考的事,这大概就是这套系统最大的价值。