Calcifer Calcifer 2
Teg

用飞书机器人+本地大模型+MCP打造智能告警分析助手

2026/03/13 03:07 26 次阅读 王梓
打赏
✸ ✸ ✸

飞书机器人 + 本地大模型 + MCP

打造智能告警分析助手

📝 今天这篇文章有点长,但全是干货,建议先收藏再看!

💡 读完你就能亲手打造一个自动分析告警的AI助手!


🚀 智能告警分析助手 飞书机器人 + 本地大模型 + MCP 🤖 飞书Bot 🧠 本地大模型 🔧 MCP工具

飞书机器人 + 本地大模型 + MCP:智能告警分析助手架构与实践

💼 下午三点,你正忙着写代码,突然飞书弹出一条消息:
📱 "【告警】服务A 500错误率激增!"

你赶紧放下手头工作,打开监控平台——
⏱ 花了 12分钟 查日志、翻链路、看堆栈
🔍 终于发现:原来是下游服务B超时导致的

等你准备好分析报告发群里时,发现:
👨‍💻 同事小王已经在处理了,而且他的分析结果和你一模一样!

💡 如果有一个智能助手,能在告警发生的第一时间自动完成这一切呢?
本文就教你如何用 飞书机器人 + 本地大模型 + MCP,打造这样一个智能告警分析助手!

🎯 一、背景:告警处理的痛点,你中了几个?

⬇️ 看看这是不是你的日常 ⬇️

作为SRE,日常工作中最繁琐的任务之一就是处理告警。一次典型的告警处理流程是这样的:

⚙️ 传统告警处理流程 1. 收到通知 📱 钉钉/飞书/邮件 2. 查看详情 📊 监控平台 3. 查询日志 📄 日志系统 4. 分析根因 🧠 依赖经验 5. 建议 💬 转交处理 ⏱ 耗时 5-15 分钟 | 🧠 高度依赖个人经验 | 😫 深夜告警苦不堪言 同类型告警反复出现,每次重复上述流程

能否让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 工作流示意 开始 解析告警 查询日志 分析错误 生成报告 结束,返回结果

使用 LangGraph 的好处:

  • 可视化:工作流程一目了然
  • 可维护:每个节点独立开发测试
  • 可扩展:新增步骤只需加节点
  • 可回溯:支持断点续传、错误重试

2.9 MultiAgent - 多个 Agent 协同工作

🤔 想象一下:一个复杂的告警分析可能涉及多种能力——解析日志、分析错误、查询链路、提取堆栈。如果让一个 Agent 全部搞定,可能会比较慢或者不够专业。

MultiAgent(多智能体)架构:就像一个公司有不同的部门,每个部门(Agent)负责自己的专业领域,有一个协调者来分配任务。

MultiAgent 协作示意 协调者 日志分析 Agent 查日志、聚合错误 链路分析 Agent 查 OTEL、构建调用链 堆栈分析 Agent 提取业务代码位置 协调者汇总结果,生成最终报告

在我们的系统中,虽然目前主要使用单 Agent(MultiAgentSystem),但它内部已经实现了类似多 Agent 的工具调度能力——根据任务需要调用不同的 MCP 工具。

🚀 三、思路演进:罗马不是一天建成的

💡 从v1到v4,看看我们踩了多少坑才找到最优解!

罗马不是一天建成的,这个系统也是经过多个版本迭代才最终定型的。下面是我们的迭代过程:

方案迭代过程 v1: 关键词匹配 if "timeout" → 查网络 规则引擎 Hardcode ❌ 效果差 v2: LLM 直接分析 告警文本 → LLM 不查实时日志 ⚠️ 效果一般 v3: LLM + MCP LLM 决定调用 MCP 实时查询日志 ✅ 效果不错 v4: 双模式架构(最终) 告警 → MultiAgent 直接处理 对话 → LLM + MCP ✅ 效果最好 ✨ 💡 核心改进 告警场景不再依赖 LLM 决策,直接调度 MCP 工具,更稳定可靠 不同问题走不同处理路径,告警快准狠,对话智能灵活

🏗️ 四、最终架构:一张图看懂整个系统

🎨 精心设计的架构图,保存下来可以直接用!

经过多次迭代,最终的架构是这样的:

智能告警分析助手架构 用户 SRE/运维 飞书 Bot (WebSocket) 消息分类器 告警 对话 MultiAgent 系统 告警专用,直接调度 MCP LLM + 知识库 通用对话,MCP 工具调用 MCP Server (4个工具) OpenSearch 日志系统 业务日志 + 链路追踪索引 🔄 双模式处理流程 告警模式 MultiAgent 直接调度 → 调用 MCP 工具 MCP 工具 alarm_analyze query_by_trace/url/time 对话模式 LLM + LiteLLM → LLM 决策调用 MCP ✅ 持续运行 | 本地 Mac 部署 | 无需公网域名

🔧 五、核心组件:每个零件都很重要

🧩 拆解开来,其实每个模块都不难理解!

5.1 飞书 Bot 入口

使用飞书SDK的WebSocket模式,长连接接收消息。为什么选WebSocket?

  • 🌐 无需公网域名:WebSocket可以穿透内网,不需要暴露HTTPS端口
  • ⚡ 实时性好:消息推送实时到达,无需轮询
  • 💻 本地可运行:可以在Mac/PC上持续运行

5.2 本地大模型

模型选型对比:

模型大小Tools支持推荐场景
qwen3:14b9.3GB✅ 支持推荐
qwq:32b19GB✅ 支持内存够用时
deepseek-r1:14b9GB❌ 不支持纯推理

5.3 MCP 工具层

我们的4把"工具":

MCP 工具矩阵 alarm_analyze 🔍 告警解析 输入:告警文本 输出:服务/接口/traceId alarm_query_by_trace 🔗 链路追踪 输入:traceId 输出:完整调用链 alarm_query_by_url 📄 URL查询 输入:服务+URL 输出:错误日志 alarm_query_by_time ⏰ 时间查询 输入:服务+时间 输出:ERROR日志

⚡ 六、关键技术点:这些细节决定成败

🔍 划重点!这些坑我都替你踩过了!

6.1 时间范围处理

这是最容易出错的地方。告警中的"last 5 mins"表示check_time前5分钟,不是当前时间往前5分钟!

时间范围处理 check_time - 5min 查询起始 check_time 告警时间 当前时间 ❌ 别用这个 ❌ now() - 5min 查不到历史告警! ✅ check_time - 5min 按告警时间查询!

6.2 错误聚合统计

当告警包含大量错误时,需要将相似错误聚合统计,帮助快速识别主要问题:

错误聚合流程 原始ERROR日志 [ERROR] 连接超时... [ERROR] 连接超时... 分组处理 按消息前150字符 进行分组统计 聚合结果 🔴 连接超时 (2次) 🟡 数据库异常 (1次) 💡 聚合算法 对每条ERROR日志,提取message字段的前150字符作为分组key 相同key的日志累加计数,生成类似"错误消息 (出现N次)"的聚合结果

6.3 OpenTelemetry 链路分析

📡 等等,什么是 OpenTelemetry?

想象一下:你的系统有 10 个服务相互调用,用户一个请求经过 gateway → service-A → service-B → service-C,最后报错了。你知道问题出在哪吗?

OpenTelemetry(简称 OTEL)就是来解决这个问题的:它会给每个请求分配一个唯一的 ID(traceId),并记录每个服务的调用信息。这样我们就能看到完整的调用链,知道问题出在哪一步。

通过traceId查询完整的调用链,精确定位问题发生在哪个服务:

OTEL 链路追踪 1. 日志中提取 traceId 2. 查询 OTEL 索引 3. 构建调用链 📍 调用链示例 gateway service-A service-B ❌ 异常 返回500 ⚠️ 部分服务可能未接入 OTEL,需要从日志中提取服务调用作为备选

6.4 业务堆栈提取

对于业务代码的异常,需要提取特定的堆栈信息帮助定位问题代码位置:

业务堆栈提取 ERROR 日志 包含完整堆栈信息 com.example.biz.xxx 正则匹配 at\s+([a-z][a-z0-9_]* \.[A-Z][a-zA-Z0-9_]+) 过滤业务包名 只保留特定域名的堆栈 如: com.example.biz.* 📋 堆栈提取示例 at com.example.biz.order.service.OrderService.createOrder(OrderService.java:45) at com.example.biz.order.controller.OrderController.handle(OrderController.java:102) ... org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:897)

🎬 七、系统运行示意:看它是如何工作的

👀 直观演示,看完就懂!

让我们来看一下这个智能助手是如何在实际中运行的:

🎬 系统运行演示 1️⃣ 告警触发 监控系统发现服务异常 500错误率激增! 2️⃣ 飞书Bot接收 WebSocket长连接接收消息 去重检查,避免重复处理 3️⃣ MultiAgent处理 直接调度MCP工具 无需LLM决策,速度更快 🔧 MCP 工具调用 alarm_analyze query_by_trace query_by_url query_by_time 4️⃣ 查询数据 OpenSearch + OTEL索引 获取日志、链路、堆栈 5️⃣ 分析报告 错误聚合 + 根因分析 结构化输出,易于阅读 6️⃣ 发送结果 ✅ 飞书群自动回复 全程仅需 30-60 秒! 🚀 全程自动化:从告警到分析报告,无需人工干预 ⏱ 仅需30-60秒 | 💪 解放运维双手

✨ 八、效果展示:看看实际效果有多牛

🎉 前方高能!实际运行效果展示!

输入告警:

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. 检查数据库连接池配置

💥 九、踩坑记录:这些坑我都替你踩过了

😂 血泪史!看完能帮你少走很多弯路!

整个实现过程中踩了无数坑,这里记录几个最典型的:

🛠️ 踩坑记录 🔥 坑 1:时间范围错误 最初用 now() - 15min 查询 历史告警查不到日志 ✅ 改用 check_time - 5min 🔥 坑 2:must_not 过滤错误 must_not 错误排除了日志 导致查询返回0条 ✅ 移除 must_not 过滤 🔥 坑 3:OTEL 无数据 部分服务未接入 OTEL trace 查询返回 0 条 ✅ 添加日志 fallback 方案 🔥 坑 4:服务名映射错误 映射表不完整 某些服务查不到日志 ✅ 补充映射关系 🔥 坑 5:重复回复 飞书重复推送消息 用户收到多次回复 ✅ 消息内容哈希去重 🔥 坑 6:断线重连后重复处理 WebSocket 断开重连后 飞书重新推送离线消息 服务重启后内存缓存清空 ✅ 使用 msg_id 去重 🔥 坑 7:回答旧问题 对话历史太长 LLM 混淆历史问题 ✅ 限制只保留最近1轮

🔌 十、飞书 WebSocket 重复消息问题详解

📖 这是一个真实踩过的坑,一定要看!

🤔 这是什么问题?

飞书机器人使用 WebSocket 长连接接收消息。当网络不稳定导致断开后,机器人会自动重连。但重连后,飞书服务器会重新推送断开期间的离线消息,导致同一条消息被处理多次。

问题场景

典型问题时间线 09:00 用户发送消息 09:05 处理成功 09:10 断线重连 09:10 飞书重新推送离线消息 机器人收到 09:00 的消息,再次处理 ❌ 用户收到重复回复!

根本原因

根据飞书 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 数据流向

数据流向 飞书服务器 Bot 服务 本地模型 不联网 OpenSearch 内网地址 知识库 本地文件

10.2 安全措施

  • 不监听外网端口:只使用 WebSocket 被动接收
  • 本地模型不联网:Ollama 完全离线运行
  • OpenSearch 使用内网地址:无法从外部访问
  • 消息去重:基于内容哈希避免重复处理
  • 对话历史有限保留:只保留最近1轮,避免信息泄露

📋 十一、系统涉及的核心概念一览

🧠 怕忘记?一张表格帮你总结所有知识点!

看了这么多概念,可能你已经有点晕了。没关系,让我们用一个表格来汇总本文涉及的所有概念:

概念在本系统中的作用通俗理解
飞书 Bot消息入口,接收告警消息前台接待,负责收发消息
WebSocket长连接通信保持常开的"电话线"
LLM (大模型)理解用户意图,生成回答大脑,负责思考和推理
Ollama本地运行 LLM本地 AI 服务,不联网
LiteLLM统一调用不同 LLM翻译器,统一 API 接口
MCP大模型调用外部工具的标准工具箱的"使用说明书"
Tools (工具)具体的日志查询、链路追踪功能具体的每一把"工具"
Agent自动化处理告警的智能程序有思考能力的"工程师"
MultiAgent协调多个 Agent 协同工作团队的"项目经理"
LangGraphAgent 工作流的编排框架工作流的"流水线"
RAG检索企业知识辅助回答给 AI 看"企业手册"
Skills特定的 AI 能力AI 的"专业技能"
OpenSearch存储和查询日志日志数据库
OpenTelemetry分布式链路追踪请求的"GPS 定位"

11.1 概念之间的关系

概念关系图 用户 / SRE 飞书 Bot MultiAgent / Agent 核心处理逻辑 LLM + Ollama MCP Tools RAG / 知识库 OpenSearch / OTEL 数据流:用户 → 飞书Bot → Agent → LLM + MCP Tools → 知识库 + OpenSearch

📊 十二、技术选型总结

🎯 一张表格告诉你为什么选这些技术!

组件选型理由
入口飞书 WebSocket实时性好,无需轮询,无需公网域名
大模型qwen3:14b (本地)支持 Tools,便宜,完全离线
日志查询OpenSearch内网,高性能,支持复杂查询
链路追踪OpenTelemetry标准化的分布式追踪
工具协议MCP标准化的工具调用

🚀 十三、进阶方向:未来还能怎么玩?

💡 思路给你了,剩下的靠你发挥!

  • 📚 自动知识更新:从成功分析的案例中自动提取新知识
  • 🌐 多服务支持:扩展到更多服务的告警处理
  • 🔎 向量检索:升级为 Embedding + 向量知识库
  • 🤖 Agent 决策:使用 LangGraph 实现多 Agent 协作
  • 📊 告警收敛:相同根因的告警合并处理
  • 🎫 自动创建工单:根据分析结果自动创建运维工单

🎉 恭喜你看完了!

💡 这篇文章是不是很有收获?

👍 觉得有用的话,别忘了 点赞 + 在看 + 转发 三连哦!

🔔 还没关注的朋友,赶紧 点个关注,后续更多干货等着你!


✸ ✸ ✸

📜 版权声明

本文作者:王梓 | 原文链接:https://www.bthlt.com/note/369772863-Teg用飞书机器人+本地大模型+MCP打造智能告警分析助手

出处:葫芦的运维日志 | 转载请注明出处并保留原文链接

📜 留言板

留言提交后需管理员审核通过才会显示