飞书机器人 + 本地大模型 + MCP
打造智能告警分析助手
📝 今天这篇文章有点长,但全是干货,建议先收藏再看!
💡 读完你就能亲手打造一个自动分析告警的AI助手!
飞书机器人 + 本地大模型 + MCP:智能告警分析助手架构与实践
💼 下午三点,你正忙着写代码,突然飞书弹出一条消息:
📱 "【告警】服务A 500错误率激增!"
你赶紧放下手头工作,打开监控平台——
⏱ 花了 12分钟 查日志、翻链路、看堆栈
🔍 终于发现:原来是下游服务B超时导致的
等你准备好分析报告发群里时,发现:
👨💻 同事小王已经在处理了,而且他的分析结果和你一模一样!
💡 如果有一个智能助手,能在告警发生的第一时间自动完成这一切呢?
本文就教你如何用 飞书机器人 + 本地大模型 + MCP,打造这样一个智能告警分析助手!
🎯 一、背景:告警处理的痛点,你中了几个?
⬇️ 看看这是不是你的日常 ⬇️
作为SRE,日常工作中最繁琐的任务之一就是处理告警。一次典型的告警处理流程是这样的:
能否让AI来自动完成这个工作?答案是肯定的。下面我将详细介绍整个实现过程。
📚 二、别怕!核心概念大白话解释
🤔 技术名词看不懂?没关系,我用讲故事的方式讲给你听!
在开始实现之前,我们需要先了解几个关键技术概念。放心,我会用通俗易懂的方式来解释。
2.1 MCP - 大模型的"工具箱"
🤔 想象一下:你有一个非常聪明的助手(相当于大模型),他懂很多知识,但如果你问他"帮我查一下今天服务器的报错日志",他肯定做不到,因为他没有手、没有眼睛,无法操作电脑。
MCP 就是来解决这个问题的:它是一套标准,让大模型可以"调用"外部工具。就像给聪明助手配了一双手、一副眼镜,他就能帮你查日志、执行命令了。
# MCP 就像给大模型定义了一套"工具说明书"
# 工具定义示例
{
"name": "查询日志",
"description": "根据时间和服务名查询错误日志",
"parameters": {
"service": "服务名",
"start_time": "开始时间"
}
}
# 大模型看到这些工具后,会思考:
# "用户要查日志,我需要调用 '查询日志' 这个工具"
2.2 Tools - 具体的工具
如果说 MCP 是"工具箱的设计图",那 Tools 就是具体的每一把"工具"。
在我们的系统中,有4把"工具":
- 🔍 alarm_analyze - 告警解析器:帮大模型理解告警在说什么
- 🔗 alarm_query_by_trace - 链路追踪器:根据traceId查完整调用链
- 📄 alarm_query_by_url - URL查询器:根据接口地址查错误日志
- ⏰ alarm_query_by_time - 时间查询器:根据时间范围查日志
2.3 RAG - 让AI记住"企业知识"
🤔 问题来了:大模型虽然懂很多,但不懂你们公司特有的"黑话"。比如你问"那个GATEWAY_ERROR怎么排查",他可能答不上来,因为这是你们内部的错误码。
RAG(检索增强生成)就是来解决这个问题的:我们提前把企业的知识文档(排查手册、错误码表等)准备好。当用户问问题时,先从知识库中找到相关的内容,然后一起送给大模型。这样大模型就能"参考"企业知识来回答了。
2.4 Skills - 给AI的"技能包"
Skills 是更高级的"能力"。如果说 Tools 是让AI"能做事",那 Skills 就是让AI"会做事"。
比如:
- 📝 写报告技能 - 把分析结果整理成清晰的报告格式
- 🎯 根因分析技能 - 从一堆错误中识别出真正的问题
- 📊 数据分析技能 - 统计错误频率、生成趋势图
2.5 LiteLLM - 大模型的"统一翻译器"
🤔 问题来了:如果你想用不同的AI模型(比如 OpenAI GPT、Anthropic Claude、还有本地的 Qwen3),每个模型的 API 调用方式都不同,是不是很麻烦?
LiteLLM 就是来解决这个问题:它像是一个"统一翻译器",不管底层用哪个模型,对外都提供统一的 API 接口。这样你想换模型时,只需要改一行配置,无需修改代码。
# 用 LiteLLM 调用不同模型,API 都是一样的!
response = litellm.completion(
model="gpt-4", # 换成 claude-3 或 qwen3 都可以
messages=[{"role": "user", "content": "你好"}]
)
2.6 Ollama - 在本地跑大模型
🤔 想象一下:你想用大模型来处理公司内部的敏感数据,但又不想把数据上传到云端(担心安全问题)。怎么办?
Ollama 就是来解决这个问题的:它是一个在本地运行大模型的工具。你可以把它理解为一个"本地 AI 服务",不需要联网,所有数据都留在本地。
# 安装 Ollama 后,一行命令就能跑模型
ollama run qwen3:14b
# 还可以用 API 调用
curl http://localhost:11434/api/generate -d '{
"model": "qwen3:14b",
"prompt": "你好"
}'
在我们的系统中,使用 Ollama 运行 qwen3:14b 模型,既保证了数据安全,又节省了云端调用成本。
2.7 Agent - 会"思考"的 AI 程序
🤔 想象一下:普通的大模型就像一个"知识渊博但只会回答问题的教授"——你问什么,他答什么。但如果你让他处理一个复杂的任务,比如"帮我分析这个告警",他可能会懵。
Agent(智能体)就不一样了:它不仅有知识,还会规划、执行、反思。想象一个经验丰富的工程师:
- 🧠 规划:拿到任务后,会先分析"我需要做什么"
- 🔧 执行:调用合适的工具来完成每一步
- 🔍 反思:检查结果,如果不对就调整策略
- 📝 记忆:记住之前的操作,避免重复犯错
在我们的系统中,MultiAgentSystem 就是一个专门处理告警的 Agent:
# Agent 处理告警的流程 agent = MultiAgentSystem() # 1. 接收告警 alarm_text = "服务A报错了,500错误" # 2. Agent 自动执行: # - 解析告警信息(服务、时间、错误数) # - 查询相关日志 # - 分析错误类型 # - 提取链路追踪信息 # - 生成分析报告 result = agent.analyze_alarm(alarm_text) # 3. 返回结构化结果 print(result.summary) # 告警概要 print(result.cause) # 根因分析 print(result.action) # 建议措施
2.8 LangGraph - Agent 的"流水线"
🤔 想象一下:一个复杂的 Agent 要处理很多步骤——解析告警、查日志、分析错误、提取堆栈、生成报告。如果这些步骤都写在一个函数里,代码会变得非常混乱,难以维护。
LangGraph 就是来解决这个问题的:它把 Agent 的工作流程建模成一个图(Graph),每个节点是一个具体的操作,边是节点之间的流转关系。
使用 LangGraph 的好处:
- ✅ 可视化:工作流程一目了然
- ✅ 可维护:每个节点独立开发测试
- ✅ 可扩展:新增步骤只需加节点
- ✅ 可回溯:支持断点续传、错误重试
2.9 MultiAgent - 多个 Agent 协同工作
🤔 想象一下:一个复杂的告警分析可能涉及多种能力——解析日志、分析错误、查询链路、提取堆栈。如果让一个 Agent 全部搞定,可能会比较慢或者不够专业。
MultiAgent(多智能体)架构:就像一个公司有不同的部门,每个部门(Agent)负责自己的专业领域,有一个协调者来分配任务。
在我们的系统中,虽然目前主要使用单 Agent(MultiAgentSystem),但它内部已经实现了类似多 Agent 的工具调度能力——根据任务需要调用不同的 MCP 工具。
🚀 三、思路演进:罗马不是一天建成的
💡 从v1到v4,看看我们踩了多少坑才找到最优解!
罗马不是一天建成的,这个系统也是经过多个版本迭代才最终定型的。下面是我们的迭代过程:
🏗️ 四、最终架构:一张图看懂整个系统
🎨 精心设计的架构图,保存下来可以直接用!
经过多次迭代,最终的架构是这样的:
🔧 五、核心组件:每个零件都很重要
🧩 拆解开来,其实每个模块都不难理解!
5.1 飞书 Bot 入口
使用飞书SDK的WebSocket模式,长连接接收消息。为什么选WebSocket?
- 🌐 无需公网域名:WebSocket可以穿透内网,不需要暴露HTTPS端口
- ⚡ 实时性好:消息推送实时到达,无需轮询
- 💻 本地可运行:可以在Mac/PC上持续运行
5.2 本地大模型
模型选型对比:
| 模型 | 大小 | Tools支持 | 推荐场景 |
|---|---|---|---|
| qwen3:14b | 9.3GB | ✅ 支持 | 推荐 |
| qwq:32b | 19GB | ✅ 支持 | 内存够用时 |
| deepseek-r1:14b | 9GB | ❌ 不支持 | 纯推理 |
5.3 MCP 工具层
我们的4把"工具":
⚡ 六、关键技术点:这些细节决定成败
🔍 划重点!这些坑我都替你踩过了!
6.1 时间范围处理
这是最容易出错的地方。告警中的"last 5 mins"表示check_time前5分钟,不是当前时间往前5分钟!
6.2 错误聚合统计
当告警包含大量错误时,需要将相似错误聚合统计,帮助快速识别主要问题:
6.3 OpenTelemetry 链路分析
📡 等等,什么是 OpenTelemetry?
想象一下:你的系统有 10 个服务相互调用,用户一个请求经过 gateway → service-A → service-B → service-C,最后报错了。你知道问题出在哪吗?
OpenTelemetry(简称 OTEL)就是来解决这个问题的:它会给每个请求分配一个唯一的 ID(traceId),并记录每个服务的调用信息。这样我们就能看到完整的调用链,知道问题出在哪一步。
通过traceId查询完整的调用链,精确定位问题发生在哪个服务:
6.4 业务堆栈提取
对于业务代码的异常,需要提取特定的堆栈信息帮助定位问题代码位置:
🎬 七、系统运行示意:看它是如何工作的
👀 直观演示,看完就懂!
让我们来看一下这个智能助手是如何在实际中运行的:
✨ 八、效果展示:看看实际效果有多牛
🎉 前方高能!实际运行效果展示!
输入告警:
PROJECT SERVICE XXX STATUS 500 ALARM(last 5 mins) check_time:2026-03-11 21:21:00 error_count:5 URL:/api/v1/xxx/xxx
智能分析输出:
## 📊 告警概要 - 服务: xxx-service - 告警类型: HTTP 500 错误 - 接口: /api/v1/xxx/xxx - 错误数: 5 ## 🔍 错误聚合分析 ❌ Connection timeout to downstream service (3次) - 首次出现: 21:18:24 - 原因: 调用下游服务超时 ❌ Database connection pool exhausted (2次) - 首次出现: 21:19:05 - 原因: 数据库连接池耗尽 ## 🔗 OTEL 链路追踪 调用链: gateway → xxx-service → downstream-service → ❌ 超时 ## 📍 业务堆栈位置 at com.example.biz.xxx.service.OrderService.createOrder(OrderService.java:45) at com.example.biz.xxx.controller.OrderController.handle(OrderController.java:102) ## 🎯 根因定位 主要问题: 下游服务 downstream-service 响应超时 ## 📋 排查建议 1. 检查 downstream-service 服务的响应时间和可用性 2. 考虑增加连接超时时间配置 3. 检查数据库连接池配置
💥 九、踩坑记录:这些坑我都替你踩过了
😂 血泪史!看完能帮你少走很多弯路!
整个实现过程中踩了无数坑,这里记录几个最典型的:
🔌 十、飞书 WebSocket 重复消息问题详解
📖 这是一个真实踩过的坑,一定要看!
🤔 这是什么问题?
飞书机器人使用 WebSocket 长连接接收消息。当网络不稳定导致断开后,机器人会自动重连。但重连后,飞书服务器会重新推送断开期间的离线消息,导致同一条消息被处理多次。
问题场景
根本原因
根据飞书 SDK 官方文档的分析,WebSocket 重复消息有以下原因:
- 📡 网络波动:飞书服务器没收到确认,超时重发
- 🔄 服务重启:内存缓存清空,之前的事件又来了
- 🔌 断线重连:WebSocket 重连后重新推送离线消息
- 👥 多实例运行:多个实例同时收到同一事件
解决方案
我们使用消息 ID(msg_id)进行去重,这是飞书消息的唯一标识:
# 之前(不可靠)
msg_key = hashlib.md5(f"{user_id}:{text}".encode()).hexdigest()
# 问题:服务重启后字典被清空,重复消息无法识别
# 现在(可靠)
msg_key = msg_id # 飞书消息的唯一ID
# 优点:每个msg_id只处理一次,即使服务重启也不影响
三层防护架构(进阶方案)
如果需要更完善的去重机制,可以参考飞书官方推荐的三层防护:
| 防护层 | 去重依据 | 防护位置 |
|---|---|---|
| 协议层 | SeqID(消息序列号) | 网络层面 |
| 分发层 | EventID(事件ID) | 飞书服务器重发 |
| 应用层 | msg_id(消息ID) | 业务逻辑层面 |
对于单机运行的飞书机器人,使用 msg_id 去重(应用层)已经足够。
10.1 数据流向
10.2 安全措施
- ✅ 不监听外网端口:只使用 WebSocket 被动接收
- ✅ 本地模型不联网:Ollama 完全离线运行
- ✅ OpenSearch 使用内网地址:无法从外部访问
- ✅ 消息去重:基于内容哈希避免重复处理
- ✅ 对话历史有限保留:只保留最近1轮,避免信息泄露
📋 十一、系统涉及的核心概念一览
🧠 怕忘记?一张表格帮你总结所有知识点!
看了这么多概念,可能你已经有点晕了。没关系,让我们用一个表格来汇总本文涉及的所有概念:
| 概念 | 在本系统中的作用 | 通俗理解 |
|---|---|---|
| 飞书 Bot | 消息入口,接收告警消息 | 前台接待,负责收发消息 |
| WebSocket | 长连接通信 | 保持常开的"电话线" |
| LLM (大模型) | 理解用户意图,生成回答 | 大脑,负责思考和推理 |
| Ollama | 本地运行 LLM | 本地 AI 服务,不联网 |
| LiteLLM | 统一调用不同 LLM | 翻译器,统一 API 接口 |
| MCP | 大模型调用外部工具的标准 | 工具箱的"使用说明书" |
| Tools (工具) | 具体的日志查询、链路追踪功能 | 具体的每一把"工具" |
| Agent | 自动化处理告警的智能程序 | 有思考能力的"工程师" |
| MultiAgent | 协调多个 Agent 协同工作 | 团队的"项目经理" |
| LangGraph | Agent 工作流的编排框架 | 工作流的"流水线" |
| RAG | 检索企业知识辅助回答 | 给 AI 看"企业手册" |
| Skills | 特定的 AI 能力 | AI 的"专业技能" |
| OpenSearch | 存储和查询日志 | 日志数据库 |
| OpenTelemetry | 分布式链路追踪 | 请求的"GPS 定位" |
11.1 概念之间的关系
📊 十二、技术选型总结
🎯 一张表格告诉你为什么选这些技术!
| 组件 | 选型 | 理由 |
|---|---|---|
| 入口 | 飞书 WebSocket | 实时性好,无需轮询,无需公网域名 |
| 大模型 | qwen3:14b (本地) | 支持 Tools,便宜,完全离线 |
| 日志查询 | OpenSearch | 内网,高性能,支持复杂查询 |
| 链路追踪 | OpenTelemetry | 标准化的分布式追踪 |
| 工具协议 | MCP | 标准化的工具调用 |
🚀 十三、进阶方向:未来还能怎么玩?
💡 思路给你了,剩下的靠你发挥!
- 📚 自动知识更新:从成功分析的案例中自动提取新知识
- 🌐 多服务支持:扩展到更多服务的告警处理
- 🔎 向量检索:升级为 Embedding + 向量知识库
- 🤖 Agent 决策:使用 LangGraph 实现多 Agent 协作
- 📊 告警收敛:相同根因的告警合并处理
- 🎫 自动创建工单:根据分析结果自动创建运维工单
🎉 恭喜你看完了!
💡 这篇文章是不是很有收获?
👍 觉得有用的话,别忘了 点赞 + 在看 + 转发 三连哦!
🔔 还没关注的朋友,赶紧 点个关注,后续更多干货等着你!