案例背景
我们维护一个中型电商微服务集群——12 个核心服务(订单、支付、库存、履约、通知、网关等),部署在 K8s 上,日均订单量 35 万单。日志通过 Fluentd 采集到 ELK,每天产生 50GB 日志(含 Nginx access log、应用业务 log、慢查询 log、审计 log)。
过去的 P0 故障排查流程:
告警触发(Prometheus + Grafana)
↓
值班工程师打开 Kibana → 搜索相关服务日志
↓
在几十万条日志中肉眼找异常 → 检查服务依赖链路
↓
定位根因 → 写复盘文档
↓
平均耗时:2 小时(最快的 40 分钟,最慢的 6 小时)
痛点不在"搜索"而在"理解":日志之间有因果链路(网关超时 → 订单服务重试 → 库存锁冲突 → 支付回调延迟),ELK 能搜到每条日志,但无法自动建立这个因果链。工程师 80% 的时间花在"把散落在不同服务、不同时间戳的日志拼成一条因果链"。
我们决定用 GPT-6 Astra 来做这件事。GPT-6 Astra 的 105 万 Token 上下文窗口是关键——可以把一个故障时间窗口内所有相关服务的日志全部塞进去,让模型"一眼看全局"。
工具组合与分工
| 工具 | 分工 | 为什么这样选 |
|---|---|---|
| GPT-6 Astra | 主推理引擎 | 105 万 Token 上下文可吞下一个时间窗口内全部日志;多步推理能力可建立因果链 |
| 自定义日志分析 MCP | 结构化提取日志元数据 | 直接读 ELK API 拿日志,做字段对齐和时间线归并,输出标准化 JSON |
| Slack MCP | 告警通知 | 分析完成后自动发 Slack 卡片消息,值班工程师 30 秒内收到根因摘要 |
| Puppeteer MCP | 辅助验证 | 自动打开 Grafana 截取对应时间的监控图表,附在告警消息中 |
关键设计原则:MCP 做"数据搬运工",GPT 做"逻辑推理师",人只做"决策执行者"。
系统架构
Prometheus 告警 → 触发分析任务
│
▼
┌──────────────────────┐
│ 日志分析 MCP │
│ 1. 查询 ELK 获取日志 │
│ 2. 按 trace_id 归并 │
│ 3. 按时间线排序 │
│ 4. 字段标准化 │
│ 5. 脱敏处理 │
└──────────┬───────────┘
│ JSON(结构化日志)
▼
┌──────────────────────┐
│ GPT-6 Astra │
│ 1. 因果链分析 │
│ 2. 异常模式识别 │
│ 3. 根因定位 │
│ 4. 影响面评估 │
│ 5. 修复建议生成 │
└──────────┬───────────┘
│ 分析报告
▼
┌──────────────────────┐
│ Slack MCP │
│ 发送告警卡片 │
│ + Grafana 截图 │
└──────────────────────┘
实施步骤
第一步:自定义日志分析 MCP
我们用 TypeScript 写了一个 MCP Server,核心提供三个工具:
// 日志分析 MCP 核心工具
const tools = {
// 工具1:按时间窗口和 trace_id 查询日志
query_logs_by_trace: {
description: "按 trace_id 查询跨服务日志链路",
inputSchema: {
trace_id: "string",
time_range: { start: "ISO8601", end: "ISO8601" }
}
},
// 工具2:查询异常级别日志
query_error_logs: {
description: "查询指定服务在时间窗口内的 ERROR/WARN 级别日志",
inputSchema: {
service: "string[]", // 支持多服务
level: "string[]", // ["ERROR", "WARN"]
time_range: { start: "ISO8601", end: "ISO8601" }
}
},
// 工具3:获取服务依赖链路
get_service_topology: {
description: "获取服务之间的调用依赖关系拓扑图",
inputSchema: {}
}
};
关键设计:MCP 不返回原始日志文本,而是返回结构化 JSON——字段对齐、时间戳统一为 ISO8601、trace_id 关联的日志聚合为一个数组。这样可以大幅减少 GPT 需要处理的 Token 量。
第二步:日志脱敏中间件
日志里经常包含用户手机号、订单金额、支付卡号等敏感信息。在 MCP 层做正则替换:
function desensitize(log: string): string {
// 手机号:138****1234
log = log.replace(/1[3-9]\d{9}/g, (m) => m.slice(0,3) + '****' + m.slice(-4));
// 金额:保留整数部分
log = log.replace(/amount[":\s]+(\d+\.\d{2})/g, 'amount: [REDACTED]');
// 卡号:保留后4位
log = log.replace(/\d{16,19}/g, (m) => '****' + m.slice(-4));
return log;
}
第三步:根因分析 Prompt 模板
这是整个系统最核心的部分——给 GPT-6 Astra 的 Prompt:
你是一位资深 SRE 工程师。以下是微服务集群在一次告警时间窗口内的结构化日志数据。
## 服务拓扑
{{service_topology}}
## 异常日志(按时间排序)
{{error_logs_json}}
## Trace 链路
{{trace_logs_json}}
## 分析任务
请按以下框架分析:
### 1. 因果链重建
从日志中重建事件的时间线和因果关系:
- 最早异常出现在哪个服务、什么时间?
- 异常如何从上游传播到下游?
- 哪些服务的异常是"果"而非"因"?
### 2. 根因定位
区分"表面症状"和"根本原因":
- 表面症状:告警触发的直接原因(如 HTTP 502)
- 根本原因:导致表面症状的最早异常(如数据库连接池耗尽)
- 给出置信度(高/中/低)和依据
### 3. 影响面评估
- 受影响的业务范围(哪些 API、哪些用户操作)
- 是否有数据一致性问题(如订单状态不一致)
- 是否需要回滚
### 4. 修复建议
- 立即止损操作(如重启、扩容、降级)
- 根因修复操作(如改配置、改代码)
- 验证方法(如何确认已修复)
## 输出格式
请在 500 字以内输出分析报告,使用以下结构:
🔴 根因:[一句话描述]
📊 置信度:[高/中/低]
🔗 因果链:A → B → C
⚠️ 影响面:[受影响的服务和用户操作]
🚑 止损建议:[立即可执行的 1-3 步操作]
🔧 根因修复:[代码或配置层面的修复建议]
第四步:Slack 告警集成
分析完成后,通过 Slack MCP 发送格式化告警:
触发条件:GPT 分析完成
消息类型:Slack Block Kit 卡片
包含内容:
- 根因摘要(一句话)
- 置信度
- 因果链(可视化文本)
- Grafana 监控截图(Puppeteer 自动截取)
- 止损操作按钮(一键执行预设的 K8s 命令)
三个关键踩坑
坑一:Token 消耗爆炸 → 分层分析
最初我们把 50GB 日志全塞给 GPT-6 Astra,一次分析消耗 $12(120 万 Token 输入)。一天触发 5 次告警就是 $60,一个月 $1800。
解决方案:分层分析。第一层只给 GPT 异常级别日志的摘要(每个服务 5 条 ERROR 日志的代表),让模型判断"哪个服务是根因"。第二层只拉取根因服务的完整 trace 日志做深度分析。Token 消耗降至 $0.8/次。
坑二:误报过滤 → 阈值策略
GPT-6 Astra 偶尔会把"正常的 WARN 日志"误判为根因。例如慢查询日志里的 200ms 查询,模型会标记为"数据库性能问题",但实际 200ms 对我们的业务来说是正常的。
解决方案:在 Prompt 中加入基线数据——告诉模型每个服务的正常指标范围。同时设置置信度阈值:只有"高置信度"的分析才自动告警,"中/低置信度"的只记日志不推送 Slack。
坑三:trace_id 缺失 → 启发式关联
约 15% 的日志缺失 trace_id(老代码没接入链路追踪)。这些日志的因果关系无法通过 trace_id 直接关联。
解决方案:在 MCP 层做启发式关联——同一服务在 ±2 秒内的 ERROR 日志,即使没有 trace_id,也关联为同一事件。准确率约 75%,但总比丢掉好。后续推动这些老服务接入 OpenTelemetry。
效果对比
| 指标 | 改造前 | 改造后 | 改善 |
|---|---|---|---|
| P0 故障定位时间 | 2 小时 | 3 分钟 | 97.5% ↓ |
| 值班工程师需要介入 | 每次 | 30% 的告警 | 70% ↓ |
| 根因准确率 | ~80%(人工) | ~88%(AI) | +8% |
| 月度 Token 成本 | $0 | ~$120 | — |
| 工程师满意度 | 3/10 | 8/10 | — |
总结
日志分析场景的核心价值不在于"AI 能读日志"——ELK 也能读。真正的价值在于 AI 能理解日志之间的因果关系,把"几十万条散落在不同服务、不同时间戳的日志"自动拼成一条"根因→症状→影响"的因果链。105 万 Token 的上下文窗口是这一切的前提——没有这么大的窗口,你无法把一个故障时间窗口的所有相关日志一次性塞给模型。
一个忠告:不要一上来就全量自动化。我们的策略是前两个月只做"分析建议"不自动执行止损操作,让模型的分析结果和工程师的人工判断对比,收集误报案例持续优化 Prompt。两个月后根因准确率从 65% 提升到 88%,才开始让高置信度分析自动触发止损。