拓冰建站拓冰建站
首页 / 资讯中心 / 正文

AI驱动的故障复盘报告自动生成:最小可运行服务实现

在运维和研发工作中系统故障结束后最耗人的往往不是恢复而是整理故障复盘报告。一次复杂故障涉及事件时间线、监控指标、变更记录、根因分析和后续行动项手动把这些信息拼接成一份结构完整的报告通常要花几个小时甚至更长。AI 辅助自动生成复杂故障报告正好能把这部分重复劳动压缩到分钟级同时把人留在“信息核对、根因判定、行动项决策”这些机器做不了的位置上。下面要实现的是一个最小可运行的 AI 故障复盘报告生成服务。它接收一份结构化的故障数据 JSON调用大模型接口生成一份结构化复盘报告再做 JSON 校验、字段补全和 Markdown 渲染。整个过程适合 SRE、DevOps、后端开发和团队技术负责人参考也适合想用大模型落地内部工具但不能直接照抄公开项目的人。1. 为什么故障复盘报告值得交给 AI 来写1.1 手动整理复盘报告的三个硬伤第一是时间开销大。一次 P1 故障往往跨多个系统包含多条告警、多段变更、多轮排查操作。复盘时要翻聊天记录、看工单系统、导监控数据、回忆操作时间光是把时间线对齐就可能花掉半天。第二是报告质量不稳定。不同人写的复盘结构差异很大有人写不出根因链有人把影响范围写得很模糊有人漏掉监控告警这一段导致后续改进没有依据。第三是信息容易失真。故障结束后参与人员的记忆会随时间衰减甚至不自觉补充“事后才知道”的原因最终报告会偏离事件真实过程。这三类问题本质上都不是“不会写”而是“信息整理成本太高”和“模板一致性难以保证”。AI 恰恰擅长在约束明确的场景下做信息重排和文本生成这是它介入复盘报告最合适的理由。1.2 AI 能做什么、不能做什么AI 在故障复盘这件事上的能力边界必须一开始就划清它能做的是把结构化时间线排序总结、把监控指标变化转成趋势描述、按固定模板归纳影响范围、给行动项生成初稿、统一措辞风格。它不能做的是验证某个时间点是否真实、确认真正的根因、决定由哪个团队负责。所以正确做法不是让模型“自由发挥写一篇复盘”而是给它结构化的故障数据、固定的输出 JSON Schema、以及禁止编造的约束让它在数据范围内补全和润色。模型生成的内容全部是“待审核草稿”必须有人工确认环节尤其是根因分析和行动项部分。1.3 设计原则结构化输入、模板约束、人工兜底整个系统按三条原则设计。结构化输入故障数据必须先整理成 JSON包括故障编号、标题、影响范围、时间线、变更记录、监控指标。数据越规范模型输出越稳定。模板约束报告结构提前定义好模型只负责按字段生成内容不负责决定报告长什么样。人工兜底任何自动生成报告都必须经过负责人审核后才能归档或推送模型不承担事实责任。用这套原则可以避免最常见的翻车场景模型一本正经地编造根因而团队成员因为“AI 写的”就放松了核对。2. 先理解复盘报告的生成链路2.1 一份复杂故障报告应该包含哪些部分不同团队的报告模板会不一样但复杂的生产故障报告通常至少包含下面这些模块。报告模块主要内容常见数据来源事件基本信息故障编号、标题、严重等级、起止时间工单系统、告警平台影响范围影响用户数、受影响接口、持续时间监控系统、业务方反馈时间线告警触发、排查动作、恢复操作的时间点聊天记录、操作审计、工单根因分析直接原因、深层原因、是否与变更相关开发排查结论触发条件什么条件让潜在问题暴露出来架构分析、日志分析恢复动作从发现问题到恢复服务的关键操作运维命令记录监控与告警告警是否及时、是否有漏告和误告监控平台关联变更故障前是否有发布、配置调整、扩容操作发布平台、变更系统行动项负责人、待办内容、截止时间复盘会议结论复盘结论本次故障的核心教训人工总结AI 生成报告的输入就应该尽量覆盖这些模块的数据。数据没有覆盖到的模块在提示词中明确要求模型标成“未知”而不是靠上下文猜测。2.2 整体生成链路一个最小可用链路可以设计成下面这样数据采集 → 数据规整 → 构建提示词 → 调用大模型 → 解析校验 → 渲染 Markdown → 人工审核 → 归档推送。数据采集这一步可以由人工导出监控截图、工单信息、变更记录也可以直接读取监控系统或工单系统的 API。数据规整是把零散信息转换成统一的 JSON 结构这一步是整个链路里最影响质量的地方。构建提示词和调用模型是核心代码后面会给出实现。解析校验阶段要做两条检查返回内容是不是合法 JSON、必填字段是否齐全。渲染成 Markdown 后再交给人工审核审核通过后进入归档或推送流程。2.3 技术选型权衡这个流程本身不强依赖特定技术栈。最简单的方案是用 Python 写一个小服务通过 HTTP 调用 OpenAI 兼容接口。如果团队以 Java 为主可以用 Spring AI 把同样的提示词和校验逻辑封装成服务底层换成 Spring 的 RestClient。如果对数据安全要求高可以把模型部署在内网只对内部服务开放接口。是否引入 Agent 编排要看场景。单次报告生成用“请求-响应”就够了不需要 Agent。但如果要做一个更完整的智能复盘工具可以把它扩展成 Agent 工作流自动读取告警事件、查询最近变更、拉取监控指标、生成报告、推送群消息和工单。每一步都是一个独立工具调用一个编排器负责串联。3. 环境准备与依赖配置3.1 运行环境要求这个示例项目需要以下环境Python 3.10 或更高版本pip 和虚拟环境工具一个可以用 HTTP 访问的大模型接口接口格式需要兼容/chat/completions本机能访问该接口接口地址可以是一个部署好的模型服务如果还没有一个可用的模型接口可以先准备一个本地部署的模型服务或者申请企业内部提供的模型平台接入地址。实际落地前要确认三件事接口地址、认证方式、模型名称三者只要有一个不对后续调用都会失败。3.2 项目结构建议先按下面这个目录结构创建项目ai-incident-report/ ├── .env ├── requirements.txt ├── llm_client.py ├── report_generator.py ├── main.py └── examples/ └── incident_example.jsonllm_client.py负责调用大模型接口。report_generator.py负责构建提示词、解析返回结果、生成 Markdown。main.pyFastAPI 服务入口接收故障数据并返回报告。examples/incident_example.json一份示例故障数据。3.3 依赖安装先创建虚拟环境并激活python -m venv .venv source .venv/bin/activate然后创建requirements.txt内容如下fastapi uvicorn[standard] httpx pydantic python-dotenv安装依赖pip install -r requirements.txt这里刻意不写死版本号。落地时建议在虚拟环境中执行pip freeze requirements-lock.txt把实际安装版本固定下来方便回滚和复现。不同版本的 FastAPI 和 Pydantic 在模型定义和model_dump的调用方式上有差异锁版本能减少环境问题。3.4 环境变量配置创建.env文件内容按实际环境调整LLM_API_BASEhttp://127.0.0.1:8000/v1 LLM_API_KEYsk-local LLM_MODELlocal-model LLM_TIMEOUT60这四个环境变量的含义如下环境变量含义示例LLM_API_BASE大模型接口基础地址最后要能拼出/chat/completionshttps://model.example.com/v1LLM_API_KEY调用接口的认证密钥sk-xxxxLLM_MODEL模型名称必须和部署方提供的名称一致deepseek-chat、gpt-4o等LLM_TIMEOUT单次调用超时时间单位秒603.5 连通性快速验证在写业务代码之前先用小脚本验证接口能通避免后面把所有问题都堆在一起排查。python -c from llm_client import LLMClient; c LLMClient(api_basehttp://127.0.0.1:8000/v1, api_keysk-local, modellocal-model); print(c.chat([{role:user,content:你好}]))如果这一步能返回模型文本说明接口可用。如果报连接错误、401 或模型不存在先处理网络、密钥和模型名问题再进入下一步。4. 实现一个最小可运行的故障报告生成服务4.1 准备一份结构化故障数据创建一个examples/incident_example.json文件内容是一份模拟的故障记录。下面的数据都是演示用的实际项目里需要替换成真实数据。{ incident_id: INC-2025-03-14-001, title: 订单支付服务超时率上升, start_time: 2025-03-14 10:05:00, end_time: 2025-03-14 11:20:00, severity: P1, impact: 支付超时率从 0.2% 上升到 12%持续 75 分钟影响下单用户约 3 万。, related_systems: [order-service, payment-service, mysql-main, redis-cache], timeline: [ {time: 2025-03-14 10:05:00, event: 监控告警支付超时率超过 3%}, {time: 2025-03-14 10:12:00, event: 运维确认 payment-service CPU 使用率异常}, {time: 2025-03-14 10:30:00, event: 开发排查到慢 SQL疑似索引失效}, {time: 2025-03-14 11:10:00, event: 执行索引重建后超时率开始下降}, {time: 2025-03-14 11:20:00, event: 超时率恢复至 0.2%事件关闭} ], change_records: [ {time: 2025-03-13 22:00:00, content: 发布 order-service v2.8.1包含支付回调逻辑调整} ], monitor_metrics: { before: 超时率 0.2%QPS 1200, during: 超时率 12%QPS 1100, after: 超时率 0.2%QPS 1250 } }这里的关键是把“时间点”和“事件”拆成数组而不是写成一整段描述。这样模型更容易理解事件顺序也更容易按模板输出。4.2 编写大模型调用模块创建llm_client.py封装对大模型接口的调用。from typing import Dict, List import httpx class LLMClient: def __init__(self, api_base: str, api_key: str, model: str, timeout: int 60): self.api_base api_base.rstrip(/) self.api_key api_key self.model model self.timeout timeout def chat( self, messages: List[Dict[str, str]], temperature: float 0.2, max_tokens: int 2048, ) - str: url f{self.api_base}/chat/completions headers { Authorization: fBearer {self.api_key}, Content-Type: application/json, } payload { model: self.model, messages: messages, temperature: temperature, max_tokens: max_tokens, } resp httpx.post(url, headersheaders, jsonpayload, timeoutself.timeout) resp.raise_for_status() data resp.json() return data[choices][0][message][content]这个模块的核心是拼装请求和读取choices[0].message.content。如果你的模型服务使用了自定义 API Key 头或自定义错误字段需要调整headers和异常处理逻辑。temperature设置成 0.2目的是让输出更稳定减少随机发散故障复盘这类文本不追求创造性追求的是可复现。4.3 编写提示词构建和结果解析模块创建report_generator.py这一部分直接决定生成报告的质量。import json import re from typing import Dict, List from llm_client import LLMClient OUTPUT_SCHEMA { incident_id: 故障编号必须与输入一致, title: 复盘标题, impact_summary: 影响范围概述只总结输入中的数据, timeline_summary: 时间线关键节点归纳, root_cause_analysis: 根因分析输入中没有提到就写未知, trigger_conditions: 触发条件分析输入中没有就写未知, recovery_actions: 恢复动作归纳, monitor_and_alert: 监控告警情况分析, preventive_actions: [预防措施1, 预防措施2], action_items: [ {owner: 负责人/团队, action: 待办事项, deadline: 截止时间} ], unknown_items: [数据缺失且被标注未知的信息] } SYSTEM_PROMPT ( 你是一名资深的 SRE 故障复盘报告撰写助理。 你的任务是根据用户提供的结构化故障数据生成复盘内容的 JSON 而不是直接写一篇自由格式文章。 你只能使用用户数据中出现的信息不得编造时间、数字、影响范围、负责人或根因。 如果某个信息在数据中缺失必须写“未知”或“数据未提供”。 输出必须是合法的 JSON不要包含任何 JSON 以外的解释文字。 ) USER_PROMPT_TEMPLATE 请根据以下结构化故障数据生成故障复盘报告所需的 JSON 内容。 故障数据 json {incident_json}输出的 JSON 结构必须严格符合下面的要求 {output_schema}额外要求所有内容使用中文action_items 至少 2 条不要修改 incident_id不要输出 JSON 以外的内容。 REQUIRED_FIELDS [ incident_id, title, impact_summary, timeline_summary, root_cause_analysis, recovery_actions, action_items, ]def build_messages(incident: Dict) - List[Dict[str, str]]: user_content USER_PROMPT_TEMPLATE.format( incident_jsonjson.dumps(incident, ensure_asciiFalse, indent2), output_schemaOUTPUT_SCHEMA, ) return [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_content}, ]def parse_report(content: str) - Dict: text content.strip() if text.startswith(): text re.sub(r^(?:json)?\s*, , text) text re.sub(r\s*$, , text)try: data json.loads(text) except json.JSONDecodeError: return {ok: False, reason: invalid_json, raw: content} if not isinstance(data, dict): return {ok: False, reason: not_object, raw: content} missing [key for key in REQUIRED_FIELDS if key not in data] if missing: return {ok: False, reason: missing_fields, missing: missing, raw: content} return {ok: True, data: data}def generate_report_with_retry( client: LLMClient, incident: Dict, max_retry: int 2, ) - Dict: messages build_messages(incident) last_result None for attempt in range(max_retry): content client.chat(messages, temperature0.2) result parse_report(content) if result[ok]: return result last_result result return last_resultdef render_markdown(report: Dict) - str: lines [ f# {report.get(title, 故障复盘报告)}, , ## 事件基本信息, f- 故障编号{report.get(incident_id, 未知)}, f- 影响概述{report.get(impact_summary, 未知)}, , ## 时间线归纳, report.get(timeline_summary, 未知), , ## 根因分析, report.get(root_cause_analysis, 未知), , ## 恢复动作, report.get(recovery_actions, 未知), , ## 监控告警, report.get(monitor_and_alert, 未知), , ## 预防措施, ] for item in report.get(preventive_actions, []): lines.append(f- {item}) lines.append() lines.append(## 行动项) for item in report.get(action_items, []): owner item.get(owner, 待定) action item.get(action, ) deadline item.get(deadline, 待定) lines.append(f- [{deadline}] {action}责任人{owner}) if report.get(unknown_items): lines.append() lines.append(## 数据缺失项) for item in report[unknown_items]: lines.append(f- {item}) return \n.join(lines)提示词里的 OUTPUT_SCHEMA 看起来像 JSON但其实是一段字段说明。它既让模型理解输出结构又不会因为字段名和输入冲突导致混乱。parse_report 做了三层保护去掉 Markdown 代码块围栏、解析 JSON、检查必填字段。只要有一层不过就返回失败原因而不是直接抛异常。 ### 4.4 编写 FastAPI 接口 创建 main.py把上面的模块串起来。 python import os from typing import Dict, List from dotenv import load_dotenv from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field from llm_client import LLMClient from report_generator import generate_report_with_retry, render_markdown load_dotenv() LLM_API_BASE os.getenv(LLM_API_BASE, http://127.0.0.1:8000/v1) LLM_API_KEY os.getenv(LLM_API_KEY, sk-local) LLM_MODEL os.getenv(LLM_MODEL, local-model) LLM_TIMEOUT int(os.getenv(LLM_TIMEOUT, 60)) class TimelineItem(BaseModel): time: str event: str class IncidentRequest(BaseModel): incident_id: str Field(..., description故障编号) title: str Field(..., description故障标题) start_time: str Field(..., description故障开始时间) end_time: str Field(..., description故障结束时间) severity: str Field(..., description严重等级例如 P1) impact: str Field(default, description影响范围描述) related_systems: List[str] Field(default_factorylist, description关联系统) timeline: List[TimelineItem] Field(default_factorylist, description时间线) change_records: List[Dict] Field(default_factorylist, description变更记录) monitor_metrics: Dict Field(default_factorydict, description监控指标) app FastAPI(titleAI 故障复盘报告生成服务) app.post(/reports/generate) def generate_report(request: IncidentRequest): client LLMClient( api_baseLLM_API_BASE, api_keyLLM_API_KEY, modelLLM_MODEL, timeoutLLM_TIMEOUT, ) incident request.model_dump() result generate_report_with_retry(client, incident, max_retry2) if not result[ok]: raise HTTPException(status_code500, detailresult) return {ok: True, report: result[data], markdown: render_markdown(result[data])}IncidentRequest用 Pydantic 做了请求体校验。实际业务中如果故障数据是从监控平台直接推过来的可能字段更多可以随时在模型里追加字段不用一开始就设计成最完整的大表。4.5 启动服务并验证启动 FastAPI 服务uvicorn main:app --reload --port 8000另开一个终端用curl提交故障数据curl -X POST http://127.0.0.1:8000/reports/generate \ -H Content-Type: application/json \ --data examples/incident_example.json正常响应会返回一个对象
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门