晚上十一点半,运维群里的告警信息像开了闸一样涌出来:“MySQL 连接数超过阈值(当前 852/500)”“主从同步延迟 30 秒且在持续攀升”“CPU 使用率 98%”。你赶紧打开企业自己的智能运维 Agent 对话框,输入“数据库现在什么情况,怎么处理?”几秒钟后,Agent 回复了一大段标准答案:从排查连接数到检查慢查询,再到必要时切换主库。文字很流畅,结论也“正确”,但问题解决了吗?没有。因为没有人告诉它当前主库上还有两个长事务没有提交,没有人让它去核对连接到底来自哪个应用,它甚至连这台数据库的实例名都没查。
这就是我想聊的问题:企业运维 Agent 不能只会“回答”。它需要能看懂现场、判断根因、执行动作,甚至把一次故障的处理过程沉淀成下一次可复用的经验。这篇博文以一次完整的数据库故障处理过程为线索,拆解一个能干活、敢干活、不掉链子的运维 Agent 应该具备的能力,同时也把我踩过的坑和调整思路一并写出来。内容更适合正在做运维平台、AI Agent 开发、数据库管理的人参考,也适合已经厌倦了“只会查文档”的聊天机器人的运维同学。
1. 故障现场:一条告警背后的真实混乱
1.1 故障回顾:从告警到响应的最初 15 分钟
先交代一下背景。那套系统是一个典型的电商订单库,MySQL 8.0 三节点 MGR 集群,业务侧读多写少,平时连接数稳定在 200 到 300 左右。某天晚高峰刚过,告警平台在 23 点 30 分开始连续上报,监控截图上的数据大致是这样的:
| 监控项 | 正常值 | 故障值 |
|---|---|---|
| 活跃连接数 | 200 ~ 300 | 852,持续上涨 |
| CPU 使用率 | 20% ~ 40% | 98% |
| 活跃事务数 | 0 ~ 5 | 30+ |
| 锁等待次数 | 0 | 每秒 40+ |
| 主从同步延迟 | 0 ~ 1s | 30s 且持续攀升 |
| 磁盘 IO 等待 | 5ms | 120ms |
第一轮告警出现时,大家最先想到的是“是不是又有开发同事跑了一把大查询”。但打开慢查询日志,里面并没有特别离谱的十几秒 SQL,反而是大量执行时间在 100ms 到 300ms 的中低频 SQL 堆积。这时候 Agent 如果只会“回答”,它可能会直接给出“请开启慢日志分析”或者“建议添加索引”,但现场的核心矛盾已经不在单条 SQL 性能上了,而是连接数被打满,新请求全部排队。
前 15 分钟我们其实做了一系列手工操作:先确认 MGR 三个节点状态,再看主库和从库的复制通道,然后用SHOW ENGINE INNODB STATUS抓取事务和锁信息。当看到一段明显的“线程 9909 正在等待一张订单明细表的行级锁,而持有锁的事务已经空闲了 60 秒”时,问题才逐渐清晰起来。也就是说,真正的问题不是数据库突然变慢,而是有个应用连接拿住事务不提交,把一批后续写操作全部堵住了。
这类问题在互联网公司很常见,但“常见”不等于“好处理”。尤其当 Agent 只针对告警标题做知识匹配时,它容易把“连接数高”这个结果当成根因,然后给出一堆无关建议。真正的诊断需要结合连接来源、事务状态、锁等待链、复制延迟等多个维度。
1.2 为什么“会回答”不等于“会运维”
早些时候,我们团队内部做过一次对比测试:把同一份故障描述发给三套不同的“运维大模型助手”,结果它们几乎都给出了结构很完整、措辞很专业的排查手册。有的建议查慢日志,有的建议 kill 掉空闲事务,有的建议直接切换主库。问题在于,没有一套方案结合实际监控指标做推理,也没有一个助手告诉我“需要先拿到 processlist 才能判断”。换句话说,它们是在“回答问题”,不是在“处理故障”。
“会回答”的本质,是从知识库里检索出与当前问题文本最相似的历史文档。这种方式对标准化故障有一定帮助,比如“磁盘空间满怎么处理”“主从延迟一般原因有哪些”,因为这类问题通常有明确的操作手册。但数据库故障更像一个非线性的系统问题:连接数打满可能是慢查询导致,也可能是连接池泄漏导致,也可能是锁等待导致,甚至可能是磁盘故障导致。文本相似度无法区分这些场景。
真正的运维 Agent 应该像一个一线工程师,先看现场再下结论。它至少要能做以下几件事:
- 自动采集当前实例的会话、状态变量、锁等待、复制延迟等核心指标;
- 根据指标变化给出候选根因,而不是只根据问题文本来匹配;
- 对自己给出的每条结论提供数据证据,比如“哪个会话、哪条 SQL、等待了多久”;
- 在人工审批允许的前提下,直接执行安全动作,而不是只丢给用户一段命令让用户自己复制。
这四件事,有任意一件缺失,Agent 就只是一个“高级版搜索框”。我把这种从“感知到执行再到反馈”的链路称为故障处理闭环,下面要讲的完整案例,就是围绕这个闭环展开的。
2. Agent 的角色边界:从“问答机器人”到“故障处理执行者”
2.1 我理想中的运维 Agent 能力分层
在落地之前,我们先把 Agent 的能力拆成了四层。这个分层不是理论推演,而是为了在实际开发中明确边界:不能让一套模型把所有事情都干了。
| 能力层 | 核心职责 | 典型动作 | 失败后果 |
|---|---|---|---|
| 感知层 | 获取数据库与系统的实时状态 | 拉取监控、执行只读 SQL、读取日志 | 拿不到数据,后面全是瞎猜 |
| 判断层 | 对现象做根因分析与假设排序 | 对比指标、识别锁等待链、分析慢查询 | 判断错方向,处理动作全错 |
| 执行层 | 在审批和安全边界内执行动作 | 回收连接、杀掉会话、触发工单、切换只读 | 权限过大可能造成二次故障 |
| 复盘层 | 沉淀本次故障的经验与数据 | 输出报告、更新知识库、标记预案 | 知识不沉淀,下次还得踩坑 |
感知层是根基。很多 Agent 项目一上来就做大模型、做知识库,却忽略了“连数据库操作权限都没有”。没有感知层,Agent 就只是一个记忆库,它不知道当前实例是主还是从,不知道连接数是多少,不知道这条 SQL 写到哪张表。判断层则负责把感知层的数据转化为候选根因,通常也是大模型加上规则脚本混编的部分。执行层强调安全和可靠,在数据库故障场景里尤其要谨慎。复盘层则决定了这个 Agent 是不是越用越聪明。
四层之间并不是严格的串行链路,而是可以带反馈的环:执行完一个动作后,感知层要重新采集指标,判断层要确认“执行前假设是否成立”。比如 Agent 判断是“空闲事务阻塞”,执行了 kill 后,应该立刻再查锁等待是否消失,而不是直接宣布故障恢复。
2.2 数据库故障场景下 Agent 必须拿下的关键技术点
既然要处理数据库故障,Agent 不能只懂通用“数据库增删改查”。它至少要对下面这些场景形成条件反射,而且每个场景都要知道对应的采集命令和判断逻辑。
连接管理。连接数被打满是最常见的故障入口。Agent 需要能查information_schema.processlist,并按照user,host,db,command,state字段做聚合,找出连接来源是哪个应用实例,哪些连接处于Sleep状态但没有释放,哪些连接在Query状态下卡了很久。判断是否是连接池泄漏时,需要对比同一来源 IP 在不同时刻的连接数变化。
锁等待与死锁。传统优化偏重索引和慢查询,但实际生产里的锁问题比想象中多。Agent 需要会看sys.innodb_lock_waits和performance_schema.data_lock_waits,把阻塞链路中的“谁等谁”梳理出来,并关联到具体事务的起始时间和持有的行锁数量。出现“数据库死锁”告警时,还要能分析SHOW ENGINE INNODB STATUS里 LATEST DETECTED DEADLOCK 段,定位是哪两条 SQL 在交叉加锁。
慢查询定位。慢查询不能只看执行时间,还要看 SQL 的扫描行数和返回行数。Agent 需要能读取 MySQL 慢日志或性能库中的统计信息,识别出“低频但每次执行代价很高”和“高频但单次不慢”两类问题。前者通常是缺少索引,后者通常是连接风暴或锁等待叠加。
主从复制与数据一致性。对集群数据库来说,主从延迟是另一个高频问题。Agent 不仅要会看SHOW REPLICA STATUS里的延迟字段,还要对 MGR 等架构有自己的判断逻辑,比如从库回放线程是否卡在临时表、大事务是否拖慢提交、网络带宽是否打满。处理延迟时不能盲目切换主库,必须先确认从库是否追平了 binlog。
备份与恢复认知。故障处理里最容易慌的就是“要不要回滚数据”。Agent 必须知道当前集群是否有最近的全备和 binlog,知道备份文件存放在哪个区域,知道恢复一个表需要大概多长时间。这些问题如果回答不了,它在紧急情况下就只是个“会说话的告警提示器”。
我把这类能力称为“数据库故障处理基础套餐”。如果一个 Agent 连这些都不知道,它不可能承担真正的应急操作,只能做一些文档问答。
3. 一次完整的数据库故障处理:Agent 应该怎么做
3.1 步骤一:故障采集与现象收敛
回到那次故障。在确定了“连接数持续上涨,锁等待增多”后,我们希望 Agent 能自动执行一套采集动作,而不是等工程师去手工敲命令。设计上,Agent 收到告警后,会并行启动几个只读巡检任务,全部基于一次快照采集:
| 采集项 | 对应命令/信息来源 | 解决什么问题 |
|---|---|---|
| 活跃会话和来源 | information_schema.processlist聚合查询 | 连接打满还是会话堆积 |
| 锁等待关系 | sys.innodb_lock_waits | 谁在等谁,阻塞源头在哪 |
| 当前事务详情 | performance_schema.data_locks | 识别长事务和未提交事务 |
| InnoDB 引擎状态 | SHOW ENGINE INNODB STATUS | 死锁、信号量、恢复状态 |
| 复制延迟 | MGR 视图 /SHOW REPLICA STATUS | 集群是否健康 |
| 慢 SQL 统计 | performance_schema.events_statements_summary_by_digest | 哪些 SQL 消耗高 |
这里有一个很容易忽略的细节:采集一定要“一次性快照”而不是“逐条命令慢慢查”。如果 Agent 先查 processlist,再查锁等待,中间隔了好几秒,连接情况可能已经变了,前后的数据没法对齐。我们最后用 Python 脚本在同一个事务里对这些系统表做多表关联查询,这样能拿到一个相对一致的现场。
采集完成后,Agent 的“感知层”会输出一份结构化现象描述。当时的关键输出是:
- 活跃连接中,来自应用 “order-api-v3” 的连接占 402 个,其中
Sleep状态超过 60 秒的有 233 个; - 出现锁等待的 SQL 集中在一张订单明细表上,被阻塞会话数为 86;
- 持有锁的事务来自 IP 10.20.31.18,事务启动时间为 23:19:40,至今未提交;
- MGR 状态正常,但从节点由于回放积压导致查询延迟。
有了这份“现象收敛结果”,Agent 才真正从“它知道有问题”进入到“它知道哪里有问题”。
3.2 步骤二:根因分析与假设排序
拿到现象后,Agent 不能直接跳到结论。我们给它的判断层设计了一套“假设-验证”循环,先枚举最可能的根因,再逐条验证:
- 连接池泄漏:表现为连接数持续上涨、但活跃查询不多、Sleep 连接占大多数;
- 长事务未提交引发行锁堆积:表现为大量写操作阻塞、锁等待次数升高、活跃事务数增加;
- 慢查询拖垮 CPU:表现为单条 SQL 执行时间很长、扫描行数巨大、CPU 和 IO 同时高;
- 硬件或存储故障:表现为 IO 延迟很高、磁盘繁忙、日志报错。
Agent 按照“影响面优先”的顺序做排序。虽然当时 CPU 使用率 98% 最刺眼,但它应该先回答“CPU 是被 SQL 打高,还是被锁等待堆积的副作用打高”。判断方法很简单:看processlist里处于Query的会话多不多,如果大量会话都在Statistics或Waiting for lock状态,说明 CPU 可能是在空转,真正的问题是锁。
实际诊断 SQL 类似这样:
SELECT id, user, host, db, command, time, state, LEFT(info, 120) AS current_sql FROM information_schema.processlist WHERE command <> 'Sleep' ORDER BY time DESC LIMIT 20;这个查询会把当前非 Sleep 的最长会话捞出来。当时的输出里,排在第一位的是SELECT ... FROM order_detail WHERE order_id = ? FOR UPDATE,state 是Waiting for lock,已经等待了 79 秒。紧随其后的是一堆INSERT语句,全部卡在行锁等待上。这就基本确认了“锁等待”是主矛盾,而锁的源头是那个 23:19 开始、至今未提交的事务。
Agent 想要进一步确认,可以查sys.innodb_lock_waits:
SELECT r.trx_id AS waiting_trx_id, r.trx_mysql_thread_id AS waiting_thread, TIMESTAMPDIFF(SECOND, r.trx_started, NOW()) AS waiting_age, b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_thread, b.trx_started FROM sys.innodb_lock_waits w JOIN information_schema.innodb_trx r ON w.waiting_trx_id = r.trx_id JOIN information_schema.innodb_trx b ON w.blocking_trx_id = b.trx_id;查询结果非常清楚:阻塞者线程是 9909,事务从 23:19:40 开始,持续了 10 分钟以上;等待者是一大批来自订单写服务的连接。根因假设“长事务未提交导致行锁堆积”得到确认,Agent 也同时收集到了执行动作所需的全部上下文。
3.3 步骤三:执行动作与人工审批
根因确认后,Agent 能给出的处理手段不止一种。我们先说最安全的动作,再说需要更强权限的动作。
最安全的是“回收空闲连接”。对应命令是:
-- 找出空闲超过 60 秒的连接,生成 kill 语句 SELECT CONCAT('KILL ', id, ';') AS kill_statement, user, host, db, time, state FROM information_schema.processlist WHERE command = 'Sleep' AND time > 60 LIMIT 200;但这里必须谨慎:不能把所有 Sleep 连接都杀掉,因为有些连接是连接池里的保活连接,被杀后虽然应用会自动重连,但短时间内会引发连接风暴。更安全的做法是先按来源 IP 和用户维度做统计,确认哪些 IP 下的连接数异常,再针对这些连接执行清理。
针对阻塞源头,最终要处理的是线程 9909 所在的未提交事务。Agent 不能直接执行KILL 9909,因为如果这个事务里还有未提交的业务逻辑,强杀可能会导致部分数据回滚,业务侧可能需要感知。所以我们的流程是:Agent 生成操作建议,先发到审批单上,由当班 DBA 确认,同时 Agent 通过运维平台给业务负责人发通知。
最终审批通过后,执行了:
-- 终止阻塞会话 KILL 9909;执行完成后,Agent 自动进入“验证阶段”:再次查询sys.innodb_lock_waits,确认锁等待记录已经清空;然后观察活跃连接数是否在回落。我这里拿到的结果:执行 kill 后 30 秒,锁等待次数从每秒 40+ 降到了 0,活跃连接数从 852 降到 560,业务连接池开始自动回收释放连接,大约 7 分钟后系统恢复正常。
这里想强调一个原则:Agent 可以提方案、生成命令、调用系统 API,但最终执行前必须有人工授权。即便要追求全自动,也应该先在一个受限环境里跑足够长的时间,而且每一次执行动作都要有回滚方案。数据库不是普通的 IT 资源,一旦误操作,恢复成本很高。
3.4 步骤四:故障复盘与知识沉淀
故障恢复不等于处理结束。后面更重要的一件事是,把这次故障变成 Agent 下一次遇到类似问题的“反射”。
复盘中我们梳理了三个导致故障的深层原因:
- 业务应用 order-api-v3 使用了旧版数据库连接池,未设置
maxLifetime和空闲超时释放,导致大量空闲连接长期占用; - 订单详情查询语句在事务内先
SELECT ... FOR UPDATE锁行了记录,又执行了远程接口调用,使得事务时间被拉长到一个不合理范围; - 数据库侧的锁等待监控没有配置对应告警,直到连接数打满才触发,错过了最早的干预窗口。
Agent 在复盘层的输出不是一篇给领导看的 Word 文档,而是一个可以嵌入知识库的结构化记录,包括故障现象特征、根因假设、证据链、执行动作、恢复时间、后续改进项。我们的做法是把这些信息抽取成 JSON 字段,再写入向量数据库,同时挂到对应预案标签下。
举个例子。如果后续某天又出现“连接数上涨 + 锁等待 + 活跃事务多”的组合,Agent 在做假设排序时,会把“长事务未提交”的概率提到很高的位置,并第一时间去检查innodb_trx表和锁等待关联,而不是先反复分析慢日志。这就是知识沉淀带来的直接价值。运维 Agent 的价值,不是体现在它背下来多少文档,而是体现在它在故障发生时能更快、更准确地找到证据和做出行动。
4. 搭建 Agent 处理数据库故障时,需要避开的坑
4.1 坑一:把向量数据库检索当成故障诊断的全部
现在很多 Agent 项目都会接向量数据库,把操作手册、历史工单、故障报告切片后塞进去。这个思路本身没有问题,问题在于把向量检索当成唯一能力。我调研过一些团队做的运维 Agent,它们本质上就是“查询增强生成”的套壳:你问“数据库死锁怎么处理”,它把文档里的“死锁产生的原因”背出来,但如果当前库里已经真的发生了死锁,它并不知道。
原因很简单:向量数据库存的是“语义碎片”,不是“实时状态”。当你问“现在这台数据库死锁怎么处理”,Agent 需要先查询当前的死锁记录、等待关系、事务状态,也就是用 SQL 去查系统表,再用检索到的文档辅助判断。正确做法是让结构化查询和语义检索各司其职:监控数据、系统状态、锁关系通通走 SQL;历史案例、操作规范、踩坑经验走向量数据库。两个结果合并后,再交给大模型做推理。
我们在设计时做了一个很关键的小改动:如果 Agent 的答案没有引用任何“实时采集指标”,系统会直接标记为“未验证建议”,不能自动执行。这个机制能挡住很多看似正确但实际没有任何用处的回答。
4.2 坑二:权限边界没设计好
让 Agent 去执行数据库命令,权限给多大是个棘手问题。给大了,一个误判就可能把整个集群搞挂;给小了,Agent 什么也干不了,又回到“只会回答”的状态。
我建议按下面这个矩阵拆权限:
| 操作类型 | 示例 | 权限要求 |
|---|---|---|
| 只读巡检 | 查询 processlist、查看锁等待、读监控 | Agent 可直接执行,无需人工审批 |
| 轻量变更 | kill 空闲超过阈值的连接,清理临时会话 | Agent 可发起,需当班 DBA 一键审批 |
| 重型变更 | kill 持有长事务的会话、重启实例、切换主库 | 必须双人审批,且 Agent 需提供证据链 |
| 破坏性变更 | drop 数据、truncate 表、格式化存储 | 默认禁止,必须走完整变更流程 |
还有一个容易被忽略的细节:Agent 申请执行高危命令时,不能只说一句“我要执行 KILL”。它需要把“杀哪个连接、这个连接在跑什么事务、影响哪些业务、回滚方案是什么”全部列出来。这个要求不是刁难,而是迫使 Agent 在执行前真正理解自己要做的事。我们第一次踩坑时,就是因为 Agent 直接给了一个KILL 9909的结论,但说不清楚这个连接到底在做什么,后来改成模板化审批单才解决。
4.3 坑三:缺少“回答必须可验证”的机制
Agent 给出的结论一定要能验证。我见过不少团队在评估 Agent 效果时,只看“回答是否专业”“步骤是否齐全”,却忽略了一个核心问题:这些回答放到真实故障现场,有没有用?
我们内部把验证机制分成三层:
第一层是证据完整性:每条根因判断都要附上对应的数据证据。说“连接池泄漏”,必须给出同一来源 IP 的连接数变化曲线;说“锁等待严重”,必须给出sys.innodb_lock_waits的查询结果。
第二层是操作可回滚性:Agent 每次执行动作前,要生成一个“执行前状态快照”和“回滚脚本”。执行完后再对比快照,判断动作是否真的起了作用。
第三层是复盘一致性:故障结束后,Agent 自己要对整个处理过程打分,看预判的根因和最终根因是否一致。如果 Agent 一开始判断错了,系统会把错误链路记录下来,作为后续模型训练和规则修正的样本。
有了这三层,“Agent 不会乱说话”就不是靠提示词约束,而是靠流程约束。很多 AI 项目的失败,不是模型能力不够,而是没有用工程手段把模型限制在“可验证”的边界里。
5. 这类 Agent 到底要学哪些东西:给运维和开发同学的能力清单
5.1 数据库基本功:建议同时掌握传统关系库和国产库
想做出能真正处理数据库故障的 Agent,开发者和运维同学首先要过数据库基本功这一关。我的建议是,不要只盯着 MySQL 一门课死磕,最好按照“一套传统关系库 + 一套国产库”的组合来学。现在企业里 Oracle、MySQL 还有大量存量,达梦、Doris 这类国产或大数据分析型数据库也越来越多。Agent 能连的库种类越多,适用面越广。
学习路径可以从“安装-增删改查-事务-锁-集群-备份恢复”这样走:
- 先手动安装一遍 MySQL 和达梦数据库,搞懂客户端连接、用户权限、配置文件里的关键参数;
- 再练习数据库增删改查,重点理解事务隔离级别和锁机制;
- 然后用
SHOW ENGINE INNODB STATUS和系统视图模拟锁等待、死锁; - 最后搭一套主从或集群环境,练习切换、延迟排查、备份恢复。
这个过程听着像数据库课程设计,但非常值得。因为你只有亲手踩过锁等待的坑,写 Agent 的规则时才知道data_lock_waits里每一列代表什么;只有亲自把备份恢复到另一个实例,才知道 Agent 报出的恢复时间大概有多大的误差。
5.2 给 Agent 增加“操作技能”:从生成 SQL 到执行动作
在这个项目里,我们并没有用一个特别复杂的 Agent 框架,而是先把“单步能力”做扎实。核心思路是让 Agent 可以连接数据库执行只读诊断,并把结果交给上层做判断。一个简单的例子是用 Python 连接 MySQL,拉取当前 processlist 信息:
import pymysql import json def collect_processlist(host, user, password, port=3306): conn = pymysql.connect( host=host, user=user, password=password, port=port, connect_timeout=5 ) with conn.cursor() as cur: cur.execute(""" SELECT id, user, host, db, command, time, state, LEFT(info, 200) AS sql_text FROM information_schema.processlist WHERE command <> 'Sleep' ORDER BY time DESC LIMIT 50 """) rows = cur.fetchall() cols = [desc[0] for desc in cur.description] conn.close() return [dict(zip(cols, row)) for row in rows] if __name__ == "__main__": result = collect_processlist( "127.0.0.1", "monitor", "your_password" ) print(json.dumps(result, ensure_ascii=False, indent=2))这段代码是 Agent 的“感知层”入口。拿到返回结果后,再交给判断层或大模型做结构化总结。如果要让 Agent 执行KILL,我们不会让它直接用这个账号去操作,而是通过运维平台的 API 提交一个工单,带上目标线程 ID 和执行理由。这样既能执行动作,又能留痕和审批。
至于 Agent 的编排框架,用简单的if-else或者像 LangGraph 这类带状态流转的工具都可以。重点是准备好这些可以被调用的原子动作,例如collect_processlist,check_lock_wait,get_replication_status,kill_session_with_approval。没有这些原子动作,Agent 就只能“说”,不能“做”。
5.3 一个最小可用的故障处理 Agent 实现思路
考虑到很多人想快速跑通一个 Demo,我分享一下我们的最小实现思路。它不需要复杂的模型训练,核心逻辑非常简单:
def handle_database_fault(alert): if alert.metric != "connection_usage": return "暂不支持的告警类型" # 1. 感知:拉取现场数据 snapshot = collect_snapshot(alert.instance_id) # 2. 判断:根据规则做候选根因排序 hypotheses = rank_hypotheses(snapshot) # 3. 决策:如果规则置信度低,再调大模型辅助 if hypotheses[0].confidence < 0.7: hypotheses = llm_analyze(snapshot, hypotheses) # 4. 执行:先申请审批,审批通过后执行动作 action = generate_action(hypotheses[0], snapshot) approval = request_approval(action) if approval.passed: execute(action, snapshot) # 5. 复盘:执行后重新拉取现场数据,确认是否缓解 verify_and_report(action)这段伪代码已经把前面说的“感知-判断-执行-复盘”闭环串起来了。实际生产环境里,rank_hypotheses可能是一组规则加统计模型,llm_analyze才会用到 Agent 的语言能力,request_approval对接审批系统,execute对接运维平台 API。整体上,你可以把它理解成一个“带大脑的自动化运维脚本”,大模型负责把规则覆盖不到的场景总结出来,但核心控制权仍然掌握在可控、可回滚的工程代码里。
6. 现场实录:从“答非所问”到“稳定处置”
6.1 第一次实践时的失败记录
这个系统不是一开始就跑得这么顺。最早我们做的 v1 版本,真的差点把生产环境搞出更大的事。
当时 Agent 接到一个和本次场景很像的告警,它给出的建议是“直接重启数据库实例”。理由是知识库里有这样一条历史工单:连接数打满、CPU 高,重启后恢复。它就这样原封不动地复述了出来。幸好当班 DBA 没有按下执行按钮,而是手工复查了一遍事务状态,发现这库上有两个已经运行了 20 多分钟的大事务,如果按 Agent 建议强制重启,数据库启动后会进入崩溃恢复流程,binlog 回放和 undo 清理会让恢复时间从预计的 5 分钟拉到 40 分钟以上,业务损失会更大。
复盘这次失败,问题不在于大模型不会推理,而在于我们没给它足够的“现场约束”。它没有在回答问题前先拉取innodb_trx,没有检查是否有大事务,也没有把“重启可能引发崩溃恢复”这一风险写进决策条件。这就像一个人没有任何乐器知识,只听别人说“弹钢琴时按白色按键就行”,然后就在演出前乱按一通。
从那以后,我们把“采集现状”作为所有建议的前置条件,并且加入了一条硬规则:没有拿到实时数据之前,Agent 禁止给出高风险的处置动作建议。这条规则虽然简单,但立刻让 Agent 的建议质量提高了一个档次。
6.2 调整后成功的操作复盘
到这次“长事务阻塞 + 连接数打满”的故障时,Agent 的表现已经比较接近我理想中的状态了。
故障开始后,Agent 自动执行了以下步骤:
- 收到“连接数持续上升”的告警,触发
collect_snapshot采集脚本; - 通过
processlist聚合发现order-api-v3的连接数异常,且大量连接处于 Sleep; - 通过
sys.innodb_lock_waits找到阻塞源头是线程 9909,事务已运行 10 分 40 秒; - 生成了两个处置建议:清理空闲连接、终止线程 9909;
- 将操作建议钉到审批流,附上了锁等待查询结果和影响分析;
- 经 DBA 审批通过后,执行
KILL 9909,并自动重新采集锁等待数据; - 确认锁等待清空、连接数回落,输出结构化故障报告并写入知识库。
整个过程从告警到最终恢复大约 24 分钟,其中人工审批等待占了一部分时间,真正执行和处理只用了不到 10 分钟。相比过去人工翻监控、写 SQL、等确认,效率提升非常明显。
我更看重的,是 Agent 在这件事里证明了它能提供“证据链”:它不是因为“猜”而做出决策,而是因为看到了锁等待关系、看到了未提交事务、看到了连接来源,才有信心提出处理方案。企业运维 Agent 的价值,恰恰就在这些看得见摸得着的细节里。
说回我自己,我现在做运维 Agent 时,总会提醒团队三句话:先采集再说话,所有动作都要有审批和回滚,没有可视化证据的回答不要自动执行。这三条看起来很朴素,但每一条都是用真实故障换来的。Agent 的前景不在“会聊天”,而在“能扛事”,能把一次数据库故障从头到尾扛下来,才算真正迈过了企业运维的第一道门槛。