链路故障根因分析系统设计
提炼自一个多级数据传输链路的根因分析系统(FastAPI + MySQL + LLM 对话诊断)。场景:观测数据从采集端经多级平台传输到中心节点,任一环节故障都表现为"下游收不到数据",需要自动定位故障环节并给出处置建议。已做脱敏,只保留通用模式。 最新更新: 2026-07-20
核心结论
- 根因分析的本质是把链路建模成有序节点序列,用"收到-处理-转发"三态做短路式定位:按顺序找第一个失败节点
- 规则引擎负责"查得准",LLM 负责"问得懂"——两者共享同一数据服务层,LLM 通过 Function Calling 调用规则引擎的能力,而不是替代它
- 定位逻辑必须有降级链:精确状态表 → 上游 API 反推 → 静态配置推断,三级兜底保证"总能给出结论+建议"而不是报错
- 给 LLM 用的工具返回排版好的纯文本报告而不是裸 JSON,把多工具协作步骤写进工具 description,比堆系统提示词有效
- 监控类系统最大的敌人是数据质量:状态码语义不统一、脏数据、字段命名漂移,每一层都要防御
一、链路分段模型与故障定位
分段建模
把传输链抽象为五段有序节点,每段维护三样东西:
采集端 → 接入平台 → 汇聚平台 → 传输链路 → 中心节点- 上下游映射表:硬编码每段的 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 行,结构比长度重要)
- 角色定义 + 领域术语规范表(强制说"资料"不说"产品",附正误对照)
- 核心诊断流程(字段传递链画出来)
- 时间参数填充规则(用户没提时间就不填参数,走默认 24h)
- 防幻觉匹配:找不到匹配就明说"没有这个资料"并列出相近可选项,禁止乱匹配
- 查询红线:严禁查整张表,废弃的全量查询工具直接从 schema 移除
- 端到端 few-shot 示例 + 五类定位结论的解读模板
SSE 流式三坑
- 每次 yield 后必须
await asyncio.sleep(0)主动让出事件循环,否则输出不实时 - 响应头要加
X-Accel-Buffering: no防 Nginx 缓冲 - 模型偶尔把内部函数调用标记漏进正文,需逐 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 不知道先查哪个;线性流程每步产出下一步的键,可解释性强 |
六、经验教训清单
- 状态码语义不统一(0=正常与 1=正常两套并存)是持续的坑,只能逐表写死判异条件并给 LLM 附映射字典
- 脏数据防御要做两层:SQL 里过滤 + 代码里再过滤一遍
- LLM 防滥用要靠"物理隔离":全量查询工具直接从 schema 移除,比提示词里写"不要全表查"可靠
- 会话记忆无淘汰策略、密钥明文进配置文件,都是要还的技术债
- f-string 拼 SQL 与参数化查询混用,是注入隐患也是维护隐患——风格必须统一
- 演进过程中废弃的工具 schema 注释保留并标注"已废弃、用什么替代",是很好的活文档
相关笔记
- 监控告警:指标与告警体系
- AI 工作流工程化经验:同样的"规则兜底 + LLM 增强"思想
- 大模型应用开发 L4: Agent 与工具调用:Function Calling 基础