Skip to content

链路故障根因分析系统设计

提炼自一个多级数据传输链路的根因分析系统(FastAPI + MySQL + LLM 对话诊断)。场景:观测数据从采集端经多级平台传输到中心节点,任一环节故障都表现为"下游收不到数据",需要自动定位故障环节并给出处置建议。已做脱敏,只保留通用模式。 最新更新: 2026-07-20


核心结论

  1. 根因分析的本质是把链路建模成有序节点序列,用"收到-处理-转发"三态做短路式定位:按顺序找第一个失败节点
  2. 规则引擎负责"查得准",LLM 负责"问得懂"——两者共享同一数据服务层,LLM 通过 Function Calling 调用规则引擎的能力,而不是替代它
  3. 定位逻辑必须有降级链:精确状态表 → 上游 API 反推 → 静态配置推断,三级兜底保证"总能给出结论+建议"而不是报错
  4. 给 LLM 用的工具返回排版好的纯文本报告而不是裸 JSON,把多工具协作步骤写进工具 description,比堆系统提示词有效
  5. 监控类系统最大的敌人是数据质量:状态码语义不统一、脏数据、字段命名漂移,每一层都要防御

一、链路分段模型与故障定位

分段建模

把传输链抽象为五段有序节点,每段维护三样东西:

采集端 → 接入平台 → 汇聚平台 → 传输链路 → 中心节点
  • 上下游映射表:硬编码每段的 upstream/downstream,用于告警关联分析(找上游、下游、同类事件)
  • 错误模式表:每段的 错误关键词 → 可能原因列表(如接入平台段:超时 → 数据库慢查询/连接池耗尽/服务负载高)
  • 根因五分类CODE / CONFIG / RESOURCE / NETWORK / DATA,由错误关键词字典映射(超时→RESOURCE、连接失败→NETWORK、认证失败→CONFIG、进程崩溃→CODE)

短路式定位(核心算法)

数据接收状态表中每条记录带多个节点的状态字段(接入平台收到 / 汇聚平台收到 / 传输成功)。定位就是按链路顺序找第一个 FAILED 的节点

状态组合定位结论
接入平台 FAILED故障在采集或接入环节
接入 OK、汇聚 FAILED故障在接入→汇聚的传输环节
汇聚 OK、转发 FAILED故障在汇聚→传输平台的转发环节
全部 OK 但仍有告警故障在下游接收环节,或偶发接口异常

两个实用技巧:

  • 观测不到的节点用推断:采集端本身没有状态上报,但"接入平台收到了数据"就能推断"采集端发出了数据"
  • 每种定位结论配一句 reason + 一句可执行的 action(具体检查什么),action 置顶在建议列表第一条

三级降级链

1. 首选:数据接收状态表(精确到节点的三态)
2. 该数据类型未配置监控 → 调上游平台开放接口,用"下游收到没有"反推:
   下游正常 = 上游告警是偶发/状态不准;下游也没收到 = 定位到数据源环节
3. 查询出错 → 按静态配置的流向字段(该数据本应流向哪个下游)推断归因段

置信度计算

简单加权就够用:基础 0.5,发生次数多加分(>10 次 +0.2),相关事件多加分(>5 条 +0.2),封顶 0.99。配合按告警类型模板化生成描述(如"成功率 <50% → 严重故障,可能是服务进程异常/转换逻辑错误")。


二、多维检查与数据质量防御

五个检查维度,每个对应一张监控表和一个判异条件:

维度判异条件数据质量坑
上游代码报错状态 != 正常错误信息字段常为空,输出兜底文案"无详细错误信息",防 LLM 编造
数据完整性应收 vs 实收 + 状态异常名称字段是"资料名+编码"拼接,必须 LIKE 模糊匹配;脏数据(NULL/空串/字符串"None")要 SQL 层 + 代码层双重过滤
传输节点状态状态 != 正常此表 1=正常,别的表 0=正常——状态码语义不统一
服务器状态状态 != 0状态码 -1未监控/0正常/1次要/2主要/3严重,输出时附映射字典帮 LLM 解读
进程状态运行数 < 部署数"异常接口"会返回正常进程,需二次过滤;要排除测试环境

通用约定:时间参数缺省 = 最近 24 小时;所有工具输出限条数(前 N 条 + "还有 X 条未显示");每个工具 try/except 返回错误文本,保证 Function Calling 循环不中断。

5 步线性链式诊断

最终版流程强调"这不是 5 个并行维度,而是一个连续流程"——每步产出下一步的查询键:

步骤1 监控配置表(系统/模块名) → 得到 step_id 集合
步骤2 传输节点表 WHERE id IN (...) → 提取 ip 集合 + 进程名集合 + 传输异常
步骤3 完整性表 WHERE step_id IN (...) AND 异常 → 完整性异常
步骤4 服务器表 WHERE ip IN (...) → 服务器异常
步骤5 进程表 WHERE process IN (...) → 进程异常
汇总  各维度异常计数 + 综合定位

容错设计:任一步失败流程继续(输出 [错误]/[警告]/[跳过] 标记),最终综合判断。


三、LLM 对话诊断工程

架构选择:原生 SDK Function Calling,不用框架

早期版本用 LangChain + 独立进程(通过 HTTP 调规则引擎的 REST 接口当工具),后来重构为原生 OpenAI 兼容 SDK + 单体合并——工具函数直接调数据服务层,少一跳 HTTP,代码也更可控。

多轮循环结构(设 max_iterations=10 防死循环):

messages = [system_prompt] + 历史 + user
loop:
  stream = client.chat.completions.create(..., tools, tool_choice="auto", stream=True)
  分三路收集: tool_calls 增量 / reasoning(thinking) / content
  有 tool_calls -> 逐个执行本地函数 -> 以 role:"tool" 回填 -> continue
  无 tool_calls 有 content -> 最终答案, 存会话, 结束

流式 tool_calls 的坑:arguments 是分片到达的,必须按 index 累积拼接完才能解析 JSON。

工具设计模式

  • 工具即格式化报告生成器:每个工具查库后返回排版好的纯文本(标题、编号列表、状态标记),而不是裸 JSON——LLM 理解和转述都更稳
  • 目录检索型工具:把全量监控配置连同一段"使用说明"一起返回,让 LLM 自己做口语→标准名的语义匹配("自动站实况"→标准模块名),替代传统模糊搜索
  • 编排步骤写进 description:"使用步骤:1.先调目录工具;2.筛选;3.构造参数;4.调本工具"——把多工具协作流程编码进 schema,比只写在系统提示词里遵循率高
  • 给 LLM 时间锚点get_current_time 工具 + 提示词里写清"昨天/最近X天"的计算规则,相对时间问题先调时间工具

提示词组织(约 500 行,结构比长度重要)

  1. 角色定义 + 领域术语规范表(强制说"资料"不说"产品",附正误对照)
  2. 核心诊断流程(字段传递链画出来)
  3. 时间参数填充规则(用户没提时间就不填参数,走默认 24h)
  4. 防幻觉匹配:找不到匹配就明说"没有这个资料"并列出相近可选项,禁止乱匹配
  5. 查询红线:严禁查整张表,废弃的全量查询工具直接从 schema 移除
  6. 端到端 few-shot 示例 + 五类定位结论的解读模板

SSE 流式三坑

  1. 每次 yield 后必须 await asyncio.sleep(0) 主动让出事件循环,否则输出不实时
  2. 响应头要加 X-Accel-Buffering: no 防 Nginx 缓冲
  3. 模型偶尔把内部函数调用标记漏进正文,需逐 chunk 清洗特殊标签

消息用 type 字段区分 thinking / info / tool_result / content / done / error,前端用 fetch + ReadableStream 手动解析(比 EventSource 灵活,能带 POST body)。


四、对接上游平台开放接口的模式

  • 纯拉取轮询,无 webhook:诊断时按需实时调用,告警拉取窗口固定最近 2 小时
  • 同一平台多种认证形态并存:URL 参数 apikey / 三元组(apikey + 接口专属 ID+Key,逐接口绑定)/ 先登录换 token 放 Cookie——客户端封装层统一处理
  • 防御性解析:上游返回可能是裸数组、{records:[...]}{data:[...]} 三种形态,逐一尝试;时间入参有的要字符串有的要毫秒时间戳
  • 失败一律返回 None/[] 由上层降级(吞异常打日志),只有关键业务接口按业务状态码主动 raise
  • 数据归一化:上游告警字段映射为本系统统一告警模型,生成本地 alert_id

五、版本演进的三次跃迁

跃迁动机
架构规则引擎 + AI 助手双进程(HTTP 互调)单体合并,工具直调数据层少一跳、部署简单
数据源查本地同步表调上游开放接口实时拉取拿到真实报错堆栈,数据不滞后
诊断流程5 个并行维度各查各的data_step 双路径 → 5 步线性链式并行维度让 LLM 不知道先查哪个;线性流程每步产出下一步的键,可解释性强

六、经验教训清单

  1. 状态码语义不统一(0=正常与 1=正常两套并存)是持续的坑,只能逐表写死判异条件并给 LLM 附映射字典
  2. 脏数据防御要做两层:SQL 里过滤 + 代码里再过滤一遍
  3. LLM 防滥用要靠"物理隔离":全量查询工具直接从 schema 移除,比提示词里写"不要全表查"可靠
  4. 会话记忆无淘汰策略、密钥明文进配置文件,都是要还的技术债
  5. f-string 拼 SQL 与参数化查询混用,是注入隐患也是维护隐患——风格必须统一
  6. 演进过程中废弃的工具 schema 注释保留并标注"已废弃、用什么替代",是很好的活文档

相关笔记

基于 VitePress 构建