我把日常排障的经验,沉淀成了一组 AI 技能

本文是系列第一篇,只介绍日常查问题过程中沉淀的技能,以及它们如何协同。Dify 与 adb-gateway 的接入、异常自动诊断和代码自愈将分篇展开,不在本文一次写完。

这些技能不是为了做一个“会聊天的排障机器人”。

最初要解决的问题很朴素:同一类排查工作,换一个问题、换一个环境,就要把同样的动作重新做一遍。

先查二次开发代码,再查平台反编译代码;找到入口后追调用链、数据库表和数据流;静态分析不够,再查运行日志和真实数据;需要动态验证时,还要找到合适的类和方法设置断点。

真正耗时间的,往往不是某个动作有多难,而是动作分散、顺序依赖经验、环境约束容易遗漏。

时间窗可能算错,LIMIT 不能阻止全表扫描,反编译代码的行号不能信,某些查询通道在客户端超时后,服务端语句还可能继续执行。AI 可以帮忙分析,但没有必要每次都重新踩一遍这些坑。

于是,我把稳定的排查流程写成 Skill,把安全约束装进脚本,把不同环境的访问方式固定成路由,逐渐形成了现在这套组合:

代码定位 → 调用链分析 → 日志与数据取证 → 动态验证 → 结构化结论

它目前服务于辅助排障,也为后续逐步实现异常自动诊断提供基础能力。

一、auto-debug:排障流程的总控技能

auto-debug 不负责某一项单独操作,它负责决定:拿到一条线索后,下一步应该找什么证据。

支持哪些输入

它可以识别十一类线索:

  • 异常堆栈
  • 接口路径
  • 数据库表名
  • 流程编码
  • 业务数据标识
  • 配置项
  • 定时任务
  • 枚举或状态值
  • 事件或消息
  • 日志关键字
  • 普通功能描述

不需要用户先整理成标准格式。一句功能描述、一段堆栈,甚至一个表名,都可以作为入口。

核心工作流程

  1. 双源码定位
    同时搜索二次开发源码和平台反编译代码,避免只看到自己的扩展代码,却漏掉平台底层实现。

  2. 代码调用链分析
    从入口类继续追踪服务、引擎、数据访问和外部调用,并标明代码来源。

  3. 数据库表定位
    结合实体注解、数据访问层和 SQL,识别涉及的表及读写方式。

  4. 数据流分析
    判断入参去了哪里,哪些数据被读取或修改,是否发布事件、发送消息或调用外部服务。

  5. 业务场景还原
    分析分支条件、状态枚举和权限判断,解释什么情况下会走到这段逻辑。

  6. 按需补充实证
    静态代码不足以解释问题时,再调用日志或数据库查询技能,而不是一开始就全套执行。

  7. 可选动态验证
    在开发工具可用时设置方法级断点;只需要分析时,可以使用只报告模式,不操作开发工具。

输出什么

最终形成四维报告:

  • 代码调用链
  • 涉及的数据库表
  • 数据流和副作用
  • 业务触发条件与分支场景

如果使用了日志或数据库验证,还应把运行证据与静态推断区分开。

关键边界

  • 静态调用链是候选路径,不等于实际运行路径。
  • 堆栈顶部的业务帧是优先排查点,不一定就是最终根因。
  • 反编译代码行号可能与运行时不一致,因此只建议方法级断点。
  • 找不到源码或无法操作开发工具时,要明确给出人工排查指引,不能假装已经完成验证。

二、stack-trace:异常堆栈的专用入口

stack-trace 是 auto-debug 的堆栈特化入口,不是另一套独立分析引擎。

它主要完成几件事:

  1. 从整段堆栈中提取业务代码帧。
  2. 过滤开发框架、代理类和运行库产生的噪声。
  3. 还原代理类背后的真实业务类。
  4. 逐个定位源码,读取方法上下文。
  5. 按异常抛出点到上层入口的顺序整理调用关系。
  6. 给出优先排查位置和可选的方法级断点。

它解决的不是“把堆栈翻译成人话”,而是把一长串 at ... 转成可以继续验证的源码路径。

三、decompile-web-api:建立可搜索的平台代码底座

二次开发只能看到扩展代码,但很多问题的关键逻辑位于平台产品包中。这个技能负责把产品包转化为可搜索、可阅读的 Java 代码。

配套脚本做了什么

反编译脚本将原来一串手工操作串成了一条流水线:

  1. 自动寻找反编译工具。
  2. 按“命令行参数、环境变量、项目版本配置”的顺序确定产品版本。
  3. 指定版本不存在时,回退到可用的最新产品包。
  4. 解压应用包,处理主程序类和业务相关的内嵌依赖。
  5. 执行批量反编译。
  6. 查找匹配的源码包,用原始源码覆盖反编译产物。
  7. 检查生成的 Java 文件数量,输出处理结果。
  8. 正常完成后清理临时文件。

源码包优先是一个重要细节。相比反编译结果,原始源码通常保留更准确的变量名、注释和泛型信息,可以减少误判。

使用边界

  • 分析前必须确认代码版本与运行环境一致。
  • 已有有效产物时可以复用,不必每次重新反编译。
  • 反编译结果仍可能丢失注释、泛型或原始结构,需要交叉验证。
  • 重建产物会替换旧结果,自动化执行时应明确输出版本,避免误删仍在使用的分析材料。

四、jar-decompile-analysis:把反编译代码变成调用链证据

如果说上一个技能负责“把代码拿出来”,这个技能负责“把代码看明白”。

它沉淀了一套针对第三方平台代码的分析方法:

  • 用语义搜索寻找相关模块。
  • 用精确搜索定位类名、常量、枚举和关键文本。
  • 读取完整类和方法,避免只凭搜索片段下结论。
  • 结合代码导航追踪接口、实现类和引用关系。
  • 从界面文案、配置项、消息类型等表象反向定位实现。
  • 通过实体注解、常量和 SQL 识别数据库表映射。

输出内容包括触发场景、处理流程、影响对象、涉及数据表和关键代码位置。

配套参考资料还整理了部分平台核心模块、典型调用链和常用搜索词,减少每次从陌生包结构开始摸索的成本。

这个技能没有独立的执行脚本,价值主要在于分析方法和已有模块知识。对不确定的反编译逻辑,它要求明确标注“推测”,而不是把代码看似合理当成事实。

五、SLS 日志查询:为静态分析补充运行时证据

SLS 日志查询技能负责从日志平台取出与故障时刻对应的应用日志,并把原始返回整理成可供后续分析的运行证据。它不直接猜测根因,只解决三个问题:查哪个环境、查哪段时间、如何用有限样本证明查询结果确实覆盖了目标时刻。

在完整排障链路中,auto-debug 负责判断是否需要运行日志,日志技能负责构造查询并解释结果,adb-gateway 负责动态签名、凭据管理、参数校验和日志平台调用。三者边界固定,日志技能也可以脱离完整排障流程单独使用。有时只是想查几行日志,没必要先召开一次四维分析会议。

为什么需要一个网关

日志平台的开发接口需要动态签名,普通工作流的 HTTP 节点不方便直接完成签名计算。

因此增加了一层轻量网关,由确定性程序负责:

  • 调用日志平台开发接口;
  • 管理访问凭据;
  • 校验查询参数;
  • 将结果转换成结构化数据;
  • 向 AI 工作流提供普通 HTTP 调用方式。

模型负责决定查什么,网关负责保证怎么查。签名、白名单和时间窗这些确定性工作,不适合交给模型现场发挥。

技能文档沉淀的查询流程

  1. 先做健康检查,确认日志配置可用。
  2. 构造查询时间窗,并反向换算一次,核对是否落在目标时间。
  3. 先抽取少量样本,确认该时段确实有日志。
  4. 再按类名、接口名或错误词进行单条件检索。
  5. 关键词没有结果时,可以拉取小范围样本后在本地过滤。
  6. 较长时间范围按小时切窗,最后汇总。
  7. 解读前检查返回日志的时间分布,避免样本只覆盖窗口开头,就误判目标时刻没有日志。

这些步骤来自实际使用中的易错点。尤其是时间窗和样本覆盖问题,看起来不像技术难题,却很容易让后续分析整体跑偏。

网关代码增加的保护

  • 日志库白名单,防止跨范围查询。
  • 单次查询窗口不超过一小时。
  • 单次返回数量有上限。
  • 查询语句长度和时间戳合法性校验。
  • 支持固定凭据、实例角色和密钥管理等凭据来源。
  • 凭据被服务端拒绝时,可以刷新后重试一次。
  • 返回统一的成功状态、日志数量和结构化日志内容。

当前边界

按照现有技能文档,远程日志直查目前只在测试环境打通,不能默认其他环境也具备同样能力。

网关部分接口已经支持令牌校验,但不同接口的保护范围并不完全一致。扩大使用范围前,需要逐接口核对鉴权、访问白名单、查询审计和日志脱敏,不能把“内网可用”直接等同于“可以长期开放”。

它能提供运行证据,但“查到一条异常日志”仍然不等于“已经找到根因”。

六、数据库查询技能:验证代码判断是否符合真实现场

数据库查询分为测试、预发和生产三个技能,目标相同:

在确有必要时,用真实数据验证表结构、状态值和业务现场,而不是为了查库而查库。

三者共同沉淀了以下约束:

  • 只允许 SELECT 或 WITH 开头的单条查询。
  • 拒绝多语句、注释绕过、写操作关键字和危险函数。
  • 没有分页限制时自动补充返回上限。
  • 防止无条件全表计数、前置通配模糊查询和无条件全表排序。
  • 确需进行大范围扫描时必须显式确认,且只能豁免扫描保护,不能豁免只读校验。
  • 查询结果可能包含个人信息,进入报告前必须脱敏。
  • 查询结果与代码分析冲突时,要展示分歧,不能悄悄选择一个更顺眼的结论。

1. test-db-query:测试环境直连只读查询

测试环境采用数据库直连方式,脚本流程比较简单:

本地校验 → 建立只读会话 → 执行查询 → 返回结构化结果

除了本地校验,还增加了两层运行保护:

  • 数据库会话强制只读;
  • 会话级查询超时,超时后由数据库取消语句。

返回内容包括是否成功、实际返回行数、列名、行数据,以及是否自动补充分页限制。

它主要用于确认真实列名、字段存储值和测试业务数据状态。

2. uat-db-query:预发环境直连与备用通道

预发环境的主脚本与测试环境类似,同样采用本地校验、数据库只读会话和查询超时保护,日常排查优先使用直连方式。

另外保留了一个业务集成通道备用脚本,适用于无法直连数据库的网络环境。

备用脚本的流程更复杂:

  1. 校验主查询和统计查询。
  2. 获取访问令牌。
  3. 读取专用查询通道的原始配置。
  4. 临时写入经过校验的查询。
  5. 执行查询并返回结果。
  6. 在结束流程中恢复原始配置。

这里体现了一个重要原则:使用备用通道,不仅要考虑能不能查,还要考虑用完以后现场能不能恢复。

3. prod-db-query:生产环境受控查询

生产环境不允许直接连接数据库,而是通过专用业务集成通道执行。

标准脚本负责:

  • 在发起任何请求前校验主查询和统计查询;
  • 使用参数绑定传递查询条件;
  • 固定查询返回类型;
  • 只操作专用查询方法;
  • 执行结束后恢复默认安全查询;
  • 对高风险扫描模式进行额外拦截。

另外还有一个长等待脚本,用于少数已经确认必要的长耗时查询。它延长的是等待时间,不是放宽只读限制;涉及大范围扫描时仍需显式确认,非必要不使用。

这里必须说明一个容易混淆的边界:

数据库数据查询是只读的,但生产通道的执行过程涉及临时配置更新,不能宣传成“全程零写入”。

因此,生产使用不能只看 SQL 是否以 SELECT 开头,还要考虑通道权限、操作审计、恢复失败处理和异常中断后的现场检查,更不能把平台自身的关键字拦截当作唯一防线。

七、这些技能如何组合工作

以一条异常堆栈为例,完整链路可以是:

  1. stack-trace 或 auto-debug 提取业务帧。
  2. 在二次开发源码和对应版本的反编译代码中定位实现。
  3. 还原调用链、数据表、状态变化和分支条件。
  4. 静态分析不足时,查询目标时间窗内的运行日志。
  5. 仍需确认业务现场时,按环境调用对应数据库技能。
  6. 输出代码证据、日志证据、数据证据和待验证假设。
  7. 必要时给出方法级断点或人工复现步骤。

但不是每个问题都要把流程全部跑完。

代码已经能够解释,就不必查库;日志已经能够证实,就不必额外增加动态验证。技能组合的意义是减少盲目操作,不是让 AI 更忙。

八、当前进展与下一步

这套技能目前仍然属于辅助排障,不等于已经完成异常自动诊断,更不等于生产代码自愈。

从现有网关代码看,实现已经开始从单项查询向自动取证演进:网关可以提供证据收集接口,一次调用聚合适当版本的源码上下文和异常链路日志;源码或日志某一环节失败时,另一类证据仍可独立返回。调用方只需要提供堆栈、链路标识和异常时刻,帧处理、日志窗口和上下文长度控制由网关完成。

这只是自动诊断的第一步。后续还需要分别完成:

  • 使用 Dify 编排证据收集与诊断流程;
  • 明确模型、确定性程序和人工审核的职责;
  • 用历史问题验证诊断结论是否可靠;
  • 在具备测试、审批、灰度和回滚条件后,再讨论限定场景的修复自动化。

这些内容将按实际实现步骤分别记录,不在本文提前画完整蓝图。

结语

这些 Skill 真正沉淀下来的,不是一组查询命令,而是一套排障秩序:

先定位,再取证;先区分推断和事实,再讨论修复;先能够验证和回滚,再谈自动化。

下一步的重点,不是让模型直接给出根因,而是先通过 Dify 与 adb-gateway,把取证过程稳定地接入真实工作流程。

0
所有评论 0