当时钟拨过一个不眠的故障夜,业务恢复后最“扎心”的事往往不是修复过程,而是还要坐在电脑前,把零散的监控截图、告警消息、操作记录、会议纪要,整理成一份逻辑通顺、时间线清晰、结论明确的故障复盘报告。手动整理一份复杂故障复盘,短则四十分钟,长则两三个小时,其中大量时间花在“重新梳理事件顺序”和“组织语言”上,而这部分工作恰恰是 AI 最擅长的。
本文会从一个可以落地的角度出发,讲清楚如何基于 LLM(大语言模型)能力,把故障事件数据自动变成结构化复盘报告。我们会从核心概念讲起,再逐步拆解提示词工程与 Agent 流程,最后给出一套完整的 Python 实战代码。对 AI 应用开发、AI 工程实践感兴趣的开发者,以及被复盘报告困扰的后端、运维、SRE 同学,都可以直接参考这套思路。
1. 背景与核心概念
1.1 为什么故障复盘成了团队负担
故障复盘,也叫事后分析(Postmortem)、事故复盘,是稳定性保障流程里不可或缺的一环。它的价值在于:把一次故障的起因、经过、影响、恢复动作和后续改进项沉淀下来,避免同一个坑踩第二次。
但真正落地的过程中,复盘报告的质量经常取决于整理者的表达能力和耐心。一个复杂故障可能跨越多个系统,涉及应用、数据库、网关、消息队列、云服务等多个组件,监控告警可能有几十条,值班同学的排查动作也可能有十几次。把这些碎片信息拼成一个完整故事,本身就是一个高强度的信息整理任务。
手动整理报告时常见的问题:
- 时间线对不齐:多个系统的时间戳格式不一致,排序时容易错乱。
- 信息遗漏:故障跨度长,中间有些不起眼的操作,恰恰是恢复的关键节点。
- 结论模糊:只写了“某服务异常”,没说清楚影响范围、恢复手段和后续改进。
- 模板不统一:每个人写出来的格式差异很大,不利于事后检索和统计分析。
AI 生成故障报告,并不是要替代工程师做根因分析,而是把“信息整理 + 结构化表达”这部分人力从繁重的手工劳动中解放出来,让工程师把精力放在真正需要判断力的根因定位上。
1.2 AI 生成故障报告:它能做什么、不能做什么
用 AI 辅助生成故障复盘报告,通常包含下面几种能力:
- 事件时间线重排:把不同来源的事件按时间排序,形成秒级时间轴。
- 影响范围归纳:从告警和监控数据中提取受影响的业务、接口、地域和用户范围。
- 关键动作抽取:从操作记录中筛选出恢复动作、止损动作和验证动作。
- 报告文本生成:按团队模板生成背景、时间线、根因分析、恢复过程、改进措施等章节。
- 根因参考建议:基于历史故障库或知识库,给出可能的根因方向和排查建议。
需要注意的是,AI 不能自动保证“事实正确”。如果喂给模型的事件数据本身有误,AI 写出来的报告就会存在事实偏差,这也是业内常说的“AI 幻觉”问题。所以在工程落地时,不能把 AI 输出直接当成最终结论,必须设计“人工审核”环节,同时尽量让 AI 基于结构化数据推理,而不是让模型凭空想象。
1.3 适合谁来用,用在什么场景
这套方案适合以下几类人群:
- 后端开发工程师:负责业务系统,需要编写应用故障复盘。
- 运维 / SRE:需要处理大量监控告警和系统级故障。
- 质量保障人员:线上问题复盘中需要梳理测试遗漏和改进项。
- 研发效能工程师:希望把故障复盘流程集成到内部平台,减少人工成本。
典型使用场景包括:
- 每次故障恢复后,自动生成初稿,负责人只做修订和确认。
- 周报 / 月报中自动汇总多次故障的关键信息和改进项。
- 结合监控平台、告警平台、ChatOps 机器人,在故障恢复后自动推送报告草稿。
2. 环境准备与版本说明
2.1 技术栈与运行环境
本文示例以 Python 3 环境为基础,核心依赖如下:
- Python 3.9 及以上版本。
openai或其他兼容 LLM API 的 SDK。pandas:用于处理事件表格。jinja2:用于格式化输出模板。- 一个可用的 LLM API 服务,例如 OpenAI 兼容接口。
需要说明的是,大语言模型相关 SDK 的版本迭代比较快,不同版本的参数名称和调用方式会有差异。本文重点讲清楚实现思路和代码逻辑,你拿到项目里需要根据实际使用的模型服务做小幅调整。
如果你还没有可用的模型 API,也可以用本地方案,比如通过 Ollama 部署开源大模型,然后把调用地址改成http://localhost:11434即可。关键不在于用哪家模型,而在于提示词结构、数据整理流程和人工审核机制。
2.2 示例项目结构
实战代码我们按下面结构组织:
ai_incident_review/ ├── data/ │ ├── events.json # 故障事件原始数据 │ └── incidents.json # 故障基础信息 ├── templates/ │ └── report_template.md # 复盘报告 Markdown 模板 ├── src/ │ ├── data_prepare.py # 数据清洗与特征提取 │ ├── prompt_builder.py # 提示词构建 │ ├── llm_client.py # LLM 调用封装 │ └── report_generator.py # 报告生成主流程 ├── output/ │ └── incident_report.md # 生成的复盘报告 └── requirements.txt这个结构把数据准备、提示词、模型调用、报告生成四层分开,方便在真实项目中替换监控数据源和报告模板。
3. 核心原理拆解
3.1 事件数据的结构化提取
要稳定生成高质量故障报告,第一步不是写提示词,而是把散乱的事件整理成结构化数据。常见的事件来源包括:监控告警平台、日志平台、变更平台、值班操作记录、聊天群消息。
事件数据通常需要包含以下字段:
| 字段名 | 含义 | 示例 |
|---|---|---|
| event_time | 事件发生时间 | 2025-06-20 14:03:12 |
| event_type | 事件类型 | alarm / operation / deployment |
| source | 事件来源 | 监控平台 / 变更平台 |
| component | 组件或系统名 | order-service |
| message | 事件描述 | 订单接口超时率超过 50% |
| operator | 操作人(可选) | zhangsan |
| severity | 严重程度 | P1 / P2 / P3 |
清洗时要重点解决三类问题:
- 时间格式统一。所有事件时间必须统一成同一个时区和时间格式,推荐使用
YYYY-MM-DD HH:mm:ss。 - 字段缺失补全。没有操作人的事件可以标记为
system。 - 去重。同一时间同一组件同一告警内容的重复事件,要合并成一条。
只有数据干净了,AI 生成的时间线和影响范围才有意义。
3.2 提示词工程:让 AI 输出专业复盘
提示词是 AI 输出质量的分水岭。很多新手直接把所有事件描述丢给模型,说“帮我写个复盘报告”,得到的结果往往像流水账。
更稳妥的做法是给模型提供三个层次的信息:
- 角色和任务。
- 结构化事件数据和基础信息。
- 输出约束和模板要求。
例如:
你是一名资深 SRE 工程师,擅长编写故障复盘报告。 请根据以下故障基础信息和事件数据,输出一份结构完整、结论清晰的复盘报告。 故障基础信息: {incident_basic} 事件数据: {events_table} 输出要求: 1. 按照时间线顺序梳理事件经过。 2. 区分告警事件与操作事件,标注关键恢复节点。 3. 根因分析部分要求基于事件数据,不要编造数据。 4. 改进措施要求具体、可执行。 5. 使用 Markdown 格式输出。这里有一个经验:不要急着让 AI 一次生成所有内容。建议拆分成“先按时间线梳理事件 → 再归纳影响范围 → 最后生成报告正文”三个步骤。这样每一轮生成的内容都基于上一轮结果,逻辑更连贯,也更容易检查错误。
3.3 Agent 流程设计:从数据到报告的流水线
所谓的 AI Agent,在这里并不神秘。它就是把大模型能力封装进一个有输入、有处理、有输出的流程中。
我们可以把故障复盘生成流程拆成下面几步:
读取故障数据 ↓ 数据清洗与时间线排序 ↓ 调用 LLM 生成事件摘要 ↓ 调用 LLM 生成根因分析与改进建议 ↓ 组装 Markdown 报告 ↓ 输出草稿(人工审核)每一步都是独立函数,中间用 JSON 传递数据。这样做的好处是:
- 单步失败可以重试,不用重新跑完整流程。
- 每一轮 LLM 的输入输出都可以留日志,便于排查质量问题和审计。
- 后续可以替换某一步的实现,比如把“事件摘要”换成规则引擎。
4. 完整实战案例
下面我们来看一个可以直接运行的示例。为了便于理解,我们使用简化的数据结构和代码,重点展示流程思路。
4.1 创建项目结构
在本地执行:
mkdir -p ai_incident_review/{data,templates,src,output} cd ai_incident_review4.2 准备故障事件数据
创建data/events.json:
[ { "event_time": "2025-06-20 14:01:00", "event_type": "alarm", "source": "monitor", "component": "order-service", "message": "order-service 接口超时率超过 30%", "severity": "P1" }, { "event_time": "2025-06-20 14:03:00", "event_type": "alarm", "source": "monitor", "component": "mysql-master", "message": "MySQL 主库 CPU 使用率达到 95%", "severity": "P1" }, { "event_time": "2025-06-20 14:05:00", "event_type": "operation", "source": "ops", "component": "order-service", "message": "运维紧急扩容 order-service 实例", "operator": "wangwu", "severity": "P1" }, { "event_time": "2025-06-20 14:08:00", "event_type": "alarm", "source": "monitor", "component": "mysql-master", "message": "MySQL 主库 CPU 使用率下降至 60%", "severity": "P2" } ]创建data/incidents.json:
{ "incident_id": "INC-20250620-001", "title": "订单服务接口超时率升高", "start_time": "2025-06-20 14:01:00", "end_time": "2025-06-20 14:30:00", "level": "P1", "business_impact": "订单接口超时率升高,部分用户无法正常提交订单" }4.3 编写核心代码
4.3.1 数据清洗模块
创建src/data_prepare.py:
# -*- coding: utf-8 -*- import json from datetime import datetime def load_json(file_path): with open(file_path, "r", encoding="utf-8") as f: return json.load(f) def normalize_events(events): """统一时间格式并按时间排序""" for event in events: # 统一解析时间字符串,转换后重新格式化 dt = datetime.strptime(event["event_time"], "%Y-%m-%d %H:%M:%S") event["event_time"] = dt.strftime("%Y-%m-%d %H:%M:%S") events.sort(key=lambda x: x["event_time"]) return events def build_events_table(events): """把事件列表转成适合给 LLM 看的文本表格""" header = "| 时间 | 类型 | 来源 | 组件 | 事件描述 | 严重级别 |" separator = "| --- | --- | --- | --- | --- | --- |" rows = [] for e in events: row = ( f"| {e['event_time']} | {e['event_type']} | {e['source']} " f"| {e['component']} | {e['message']} | {e.get('severity', '')} |" ) rows.append(row) return "\n".join([header, separator] + rows)4.3.2 提示词构建模块
创建src/prompt_builder.py:
# -*- coding: utf-8 -*- SYSTEM_PROMPT = ( "你是一名资深 SRE 工程师,擅长编写故障复盘报告。" "你的任务是基于结构化事件数据,生成逻辑清晰、内容准确的复盘报告。" "你只能使用提供的数据进行推理,不能编造任何未出现的事实。" ) def build_incident_prompt(incident_basic: dict, events_table: str) -> str: user_prompt = f""" 故障基础信息: {json.dumps(incident_basic, ensure_ascii=False, indent=2)} 按时间排序后的事件数据: {events_table} 请按照下面结构生成复盘报告: 1. 故障概述 2. 故障时间线 3. 影响范围 4. 根因分析 5. 恢复过程 6. 改进措施 要求: - 时间线必须按照事件顺序展开,并标注关键恢复节点。 - 根因分析必须引用事件数据,不能编造。 - 改进措施要具体可落地。 - 使用 Markdown 格式输出。 """ return user_prompt注意json模块需要在这里导入。修改后:
# -*- coding: utf-8 -*- import json SYSTEM_PROMPT = ( "你是一名资深 SRE 工程师,擅长编写故障复盘报告。" "你的任务是基于结构化事件数据,生成逻辑清晰、内容准确的复盘报告。" "你只能使用提供的数据进行推理,不能编造任何未出现的事实。" ) def build_incident_prompt(incident_basic: dict, events_table: str) -> str: user_prompt = f""" 故障基础信息: {json.dumps(incident_basic, ensure_ascii=False, indent=2)} 按时间排序后的事件数据: {events_table} 请按照下面结构生成复盘报告: 1. 故障概述 2. 故障时间线 3. 影响范围 4. 根因分析 5. 恢复过程 6. 改进措施 要求: - 时间线必须按照事件顺序展开,并标注关键恢复节点。 - 根因分析必须引用事件数据,不能编造。 - 改进措施要具体可落地。 - 使用 Markdown 格式输出。 """ return user_prompt4.3.3 LLM 调用封装
创建src/llm_client.py:
# -*- coding: utf-8 -*- from openai import OpenAI def create_client(api_key: str, base_url: str) -> OpenAI: """创建 LLM 客户端,兼容 OpenAI 格式的接口""" return OpenAI(api_key=api_key, base_url=base_url) def chat_completion(client: OpenAI, system_prompt: str, user_prompt: str, model: str) -> str: """调用对话模型,返回纯文本结果""" response = client.chat.completions.create( model=model, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], temperature=0.3, ) return response.choices[0].message.content.strip()4.3.4 报告生成主流程
创建src/report_generator.py:
# -*- coding: utf-8 -*- import os from data_prepare import load_json, normalize_events, build_events_table from prompt_builder import SYSTEM_PROMPT, build_incident_prompt from llm_client import create_client, chat_completion def main(): # 读取数据 incidents = load_json("data/incidents.json") events = load_json("data/events.json") events = normalize_events(events) events_table = build_events_table(events) # 构建提示词 user_prompt = build_incident_prompt(incidents, events_table) # 调用 LLM api_key = os.getenv("LLM_API_KEY", "your-api-key") base_url = os.getenv("LLM_BASE_URL", "https://api.openai.com/v1") model = os.getenv("LLM_MODEL", "gpt-4o-mini") client = create_client(api_key, base_url) report_md = chat_completion(client, SYSTEM_PROMPT, user_prompt, model) # 保存报告 os.makedirs("output", exist_ok=True) with open("output/incident_report.md", "w", encoding="utf-8") as f: f.write(report_md) print("报告已生成:output/incident_report.md") if __name__ == "__main__": main()4.4 运行与验证
安装依赖:
pip install openai pandas jinja2在项目根目录执行:
export LLM_API_KEY="你的Key" export LLM_BASE_URL="https://api.openai.com/v1" export LLM_MODEL="gpt-4o-mini" python src/report_generator.py如果使用本地 Ollama 部署,可以改成:
export LLM_BASE_URL="http://localhost:11434/v1" export LLM_MODEL="qwen2.5:7b" python src/report_generator.py4.5 结果说明
运行成功后,output/incident_report.md里会生成一份包含六个章节的 Markdown 报告。由于不同模型的输出略有差异,这里不再贴一份“固定答案”,你需要重点关注报告中的时间线是否与输入事件一致、根因分析是否引用了事件数据、改进措施是否具备可执行性。
如果个别章节质量不满足要求,可以考虑三种优化方向:
- 调整提示词中的输出约束。
- 把单次生成拆成多轮生成,先生成时间线,再基于时间线生成根因分析。
- 在事件数据中加入更多上下文,比如变更记录、依赖关系、历史故障记录。
5. 常见问题与排查思路
在实际使用过程中,比较容易遇到几个问题。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 报告时间线与原始数据不一致 | 事件数据未按时间排序,或模型自行重排了顺序 | 在数据清洗阶段强制排序,并在提示词中注明“严格按提供顺序输出” |
| 根因分析出现编造内容 | 模型缺少足够上下文,自动脑补了故障原因 | 增加“只能引用事件数据”的约束,引入知识库或历史故障库补充上下文 |
| 输出的 Markdown 格式错乱 | 模型输出中包含多余空格或特殊字符 | 增加格式解析函数,提取代码块中的内容;在后处理阶段清洗 |
| 一次调用超时或返回截断 | 事件数据过长,单次 token 超限 | 拆分事件数据,分多轮生成再合并;或提高 max_tokens |
| 生成的改进措施太泛泛 | 提示词约束不足 | 在提示词中要求改进项必须对应具体事件,并给出责任人和时间范围 |
| 报告风格不符合团队规范 | 提示词缺少模板输入 | 把团队复盘模板放入提示词,要求逐段填充 |
排查这类问题的基本思路是:先检查进入模型的数据是否干净,再检查提示词是否准确表达了约束,最后检查模型输出是否经过了合理的后处理。数据决定事实,提示词决定结构,后处理决定格式,三者都要盯。
6. 最佳实践与工程建议
6.1 数据安全与最小权限
故障数据往往包含业务敏感信息。在设计系统时需要注意:
- 调用 LLM 前先做数据脱敏,把用户名、手机号、订单号等个人信息替换成占位符。
- 尽量使用私有化部署或经过合规审批的外部服务,避免敏感数据直接发送到未授权的第三方。
- API Key 必须通过环境变量或密钥管理系统注入,禁止硬编码在代码仓库里。
6.2 从“一次生成”走向“多轮 Agent 协作”
单次生成适合快速出稿,但在复杂故障场景中,建议拆成多个子任务:
- 第一轮:事件时间线与关键节点提取。
- 第二轮:影响范围与恢复动作归纳。
- 第三轮:根因分析与改进建议。
- 第四轮:按团队模板组装成完整报告。
每一轮都是独立的 LLM 调用,中间结果可以被人工检查,也能在出错时单独重跑。
6.3 引入人工审核与版本管理
AI 生成的报告本质上是“草稿”,不能直接发出去。最好设计一个审批流程:AI 生成初稿 → 责任人修改确认 → 归档到知识库。有条件的话,把报告纳入 Git 管理,方便追溯每次修改。
6.4 知识库注入减少幻觉
想让 AI 的根因分析更专业,可以维护一个“历史故障知识库”,里面保存过去的故障原因、处理过程、改进方案。调用模型时,把相似历史故障作为参考上下文注入提示词,模型就能给出更贴合实际情况的分析,而不是泛泛而谈。
6.5 可观测性与成本控制
每次 LLM 调用都要记录输入输出 token 数、响应耗时和报错信息。上线初期建议在测试环境用假数据验证,再逐步接入真实故障数据。批量生成报告时,要考虑限流和预算控制,避免故障高发期产生高额调用费用。
7. 总结与学习路线
通过本文的梳理,我们已经完成了从“手动整理故障复盘”到“AI 自动生成报告”的核心路径拆解。需要记住的关键点有四个:第一,事件数据的质量决定报告的天花板;第二,提示词决定了 AI 是否能按团队规范输出;第三,多轮小任务比一次性大任务更稳定可靠;第四,人工审核和知识库收集是故障复盘系统长期运行的基础设施。
如果你准备在自己的团队落地这套能力,建议按这个顺序推进:先拿最近一次真实故障数据做验证,写一份不含敏感信息的脱敏样本;然后把报告模板放入提示词,跑通最小闭环;再逐步加入知识库、多轮生成和告警平台自动触发能力。AI 应用开发最忌讳一上来就追求“全自动、零人工”,从辅助生成初稿开始,让工程师切身体会到效率提升,再继续迭代才是更稳妥的路径。
如果这篇文章对你有帮助,可以收藏备用。接下来可以继续研究 AI Agent 开发中的工具调用编排,比如让 AI 自动查询监控系统、拉取日志、关联变更记录,进一步把故障复盘从“半自动”推向“高度自动化”。