dide1/incident-response-agent

GitHub: dide1/incident-response-agent

基于 Claude 的自主事件响应 Agent,在模拟微服务环境中实现从告警检测、根因诊断、影响评估到 Slack 通知与复盘报告生成的全流程自动化。

Stars: 0 | Forks: 0

# 自主事件响应 Agent 这是一个作品集项目,它在一个 Docker 化的微服务环境中模拟生产环境故障,通过真实的 Prometheus/Alertmanager 告警进行检测,并使用由 Claude 驱动的 LLM Agent 自主诊断根本原因,通过向量相似度搜索检索相关的 runbook,从实时 Prometheus 指标估算用户影响,发布 Slack 简报,并生成完整的复盘报告(postmortem)—— 所有过程均无需人工干预。 ## 功能说明 当告警触发时,Agent 会执行以下操作: 1. **识别错误提交** — 查询部署跟踪器,获取近期每次提交的 diff,并推理出是哪次更改导致了告警 2. **检索正确的 runbook** — 对事件描述进行向量化,并在存储于 pgvector 的 11 个 runbook 中执行余弦相似度搜索 3. **估算实际影响** — 查询 Prometheus 获取实时的错误率和请求率,使用与事件持续时间匹配的时间窗口 4. **发布 Slack 简报** — 发送包含严重程度、影响指标、归因提交和即时行动方案的 Block Kit 消息 5. **生成复盘报告** — 当告警解除时,生成一份结构化的 Markdown 文档,其中包含执行摘要、时间线、根本原因、行动计划(及负责人)、促成因素和经验教训 ## 架构 ``` ┌──────────────────────────────────────────────────────┐ │ Mock Production Environment │ │ │ │ api-gateway :8080 ──► order-service :8081 │ │ │ └──► payments-service :8082 │ │ │ │ │ Each service exposes GET /metrics (Prometheus fmt) │ └──────────────────────────────────────────────────────┘ │ scrape every 15s ▼ ┌─────────────────────┐ alert fires ┌─────────────────────┐ │ Prometheus :9090 │ ───────────────► │ Alertmanager :9093 │ │ alert_rules.yml │ │ routes to agent │ └─────────────────────┘ └──────────┬──────────┘ │ POST /webhook ▼ ┌───────────────────────────┐ │ agent-backend :9000 │ │ │ │ FastAPI + Claude agent │ │ ┌─────────────────────┐ │ │ │ Tools │ │ │ │ • get_recent_deploys│ │ │ │ • get_commit_diff │ │ │ │ • search_runbooks │ │ │ │ • query_prometheus │ │ │ └─────────────────────┘ │ │ │ │ pgvector (runbook RAG) │ │ fastembed BAAI/bge-small │ │ Slack Block Kit notifier │ │ Postmortem generator │ └───────────────────────────┘ │ ┌───────────────┴───────────────┐ │ │ ▼ ▼ Slack channel Postgres :5432 • incident brief • deploy_tracker • resolved notice • commit_diffs • postmortem preview • runbooks (vector) • postmortems ``` ## 技术栈 | 组件 | 技术 | |-----------|-----------| | 微服务 | Python / FastAPI / uvicorn | | 可观测性 | Prometheus + Alertmanager | | Agent | 通过 Anthropic tool use API 调用 Claude (`claude-sonnet-4-6`) | | 向量搜索 | pgvector (HNSW index) + fastembed `BAAI/bge-small-en-v1.5` (384维, ONNX) | | 数据库 | PostgreSQL 15 (`pgvector/pgvector:pg15`) | | 通知 | Slack Incoming Webhooks + Block Kit | | 基础设施 | Docker Compose | ## 项目布局 ``` . ├── docker-compose.yml ├── .env # ANTHROPIC_API_KEY, SLACK_WEBHOOK_URL, fault mode vars ├── agent-backend/ │ ├── main.py # FastAPI app, webhook handler, endpoints │ ├── agent.py # Claude tool-use agentic loop │ ├── tools.py # Tool definitions + dispatch │ ├── db.py # Postgres: deploys, diffs, runbooks, postmortems │ ├── embedder.py # fastembed singleton │ ├── prometheus_client.py # PromQL HTTP client │ ├── slack_notifier.py # Block Kit formatter + webhook poster │ ├── postmortem.py # Claude postmortem generator │ └── requirements.txt ├── runbooks/ # 11 Markdown runbooks (ingested into pgvector) │ ├── api-latency-spike.md │ ├── bad-deploy-rollback.md │ ├── db-connection-pool-exhaustion.md │ ├── downstream-service-failure.md │ ├── high-error-rate-investigation.md │ ├── missing-retry-logic.md │ ├── n-plus-one-query.md │ ├── payment-gateway-timeout.md │ ├── rate-limiting-ddos.md │ ├── service-memory-leak.md │ └── unhandled-exception-triage.md ├── services/ │ ├── api-gateway/ │ ├── order-service/ # fault: N+1 query → HighLatency │ └── payments-service/ # fault: unhandled exception → HighErrorRate ├── prometheus/ │ ├── prometheus.yml │ └── alert_rules.yml # HighErrorRate (>50% errors, 30s) + HighLatency (P99>2s, 30s) ├── alertmanager/ │ └── alertmanager.yml └── scripts/ ├── generate_traffic.sh # continuous request loop for Prometheus rate data ├── inject_fault.sh # sets FAULT_MODE, restarts service, seeds bad commit ├── heal.sh # clears fault, restores service ├── record_bad_commit.py # called by inject_fault.sh to seed deploy tracker ├── ingest_runbooks.py # POST /admin/ingest-runbooks ├── probe_similarity.py # adversarial retrieval quality check (7 queries) ├── test_phase2.py ├── test_phase3.py ├── test_phase4.py └── test_phase5.py ``` ## 快速开始 ### 前置条件 - Docker Desktop (Compose v2) - Python 3.11+(用于在容器外运行的测试脚本) - 一个 [Anthropic API key](https://console.anthropic.com/) - 一个 Slack Incoming Webhook URL(可选 — 如果未设置,简报将输出到 stdout) ### 1. 配置环境 ``` cp .env.example .env # or create .env manually ``` `.env` 最低配置: ``` ANTHROPIC_API_KEY=sk-ant-... SLACK_WEBHOOK_URL=https://hooks.slack.com/services/... # optional ORDER_FAULT_MODE=false PAYMENT_FAULT_MODE=false API_FAULT_MODE=false ``` ### 2. 启动技术栈 ``` docker compose up --build -d ``` 等待约 30 秒,直到所有服务变为健康状态: ``` curl http://localhost:9000/health # agent-backend curl http://localhost:8080/health # api-gateway curl http://localhost:9090/-/ready # prometheus ``` ### 3. 将 runbook 导入 pgvector ``` python3 scripts/ingest_runbooks.py # → 11 个 runbook 已嵌入(BAAI/bge-small-en-v1.5,384 dims)并存储 ``` ### 4. 启动流量生成器 在一个单独的终端中运行 — 这是 Prometheus 计算错误率和延迟率所必需的: ``` ./scripts/generate_traffic.sh ``` ### 5. 注入故障 ``` # HighErrorRate:payments-service 在约 80% 的请求上抛出 PaymentProcessorException ./scripts/inject_fault.sh payments-service # HighLatency:order-service N+1 query 回归,P99 飙升至约 2s ./scripts/inject_fault.sh order-service ``` 大约 2 分钟内,Alertmanager 将触发 webhook,Agent 开始运行,你将看到: - 你的频道中出现一份 Slack 简报 - Agent 日志:`docker compose logs -f agent-backend` - Prometheus 告警:`http://localhost:9090/alerts` ### 6. 触发复盘报告 ``` ./scripts/heal.sh payments-service ``` 当解除状态的 webhook 到达时(约 5 分钟),Agent 将生成并存储复盘报告: ``` curl http://localhost:9000/postmortems/latest | python3 -m json.tool ``` ## 告警规则 | 告警 | 条件 | 时间窗口 | |-------|-----------|--------| | `HighErrorRate` | 每个 job 的 5xx 错误率 > 总请求量的 50% | `for: 30s` | | `HighLatency` | 每个 job 的 P99 延迟 > 2秒 | `for: 30s` | ## Agent 工具 | 工具 | 功能说明 | |------|-------------| | `get_recent_deploys` | 返回过去 N 分钟内部署到某个服务的所有提交 | | `get_commit_diff` | 获取特定 SHA 存储的 diff | | `search_runbooks` | 对查询进行向量化,并在 pgvector 中执行余弦相似度搜索 (HNSW) | | `query_prometheus` | 对 Prometheus 执行 PromQL 查询;使用根据告警开始时间计算的 `{window}` 占位符,以避免因包含事件发生前的基准数据而稀释影响指标 | ## 核心 API 端点 | 方法 | 路径 | 描述 | |--------|------|-------------| | `POST` | `/webhook` | Alertmanager webhook 接收器(触发 + 解除) | | `POST` | `/deploys` | 记录一次部署及其可选的 diff | | `GET` | `/incidents/latest` | 获取最近完成的 Agent 分析结果 | | `GET` | `/postmortems/latest` | 获取最近生成的复盘报告 | | `POST` | `/admin/ingest-runbooks` | 从 `/runbooks/` 目录对所有 runbook 进行向量化并插入/更新 | | `POST` | `/runbooks/search` | 直接执行向量搜索(用于调试检索过程) | | `DELETE` | `/admin/clear-deploys` | 清空部署记录表(用于测试初始化) | ## 运行测试 每个测试都是独立的,并在执行后自动清理环境: ``` python3 scripts/test_phase2.py # commit correlation + confidence calibration python3 scripts/test_phase3.py # runbook ingestion, similarity, agent e2e python3 scripts/test_phase4.py # Prometheus impact, Slack brief structure + webhook python3 scripts/test_phase5.py # postmortem generation on alert resolution ``` 阶段 4 会在内部运行 `generate_traffic.sh` 脚本 90 秒后再注入故障,以便 Prometheus 拥有基准数据。所有四个测试套件的预期总运行时间:约 8 分钟。 ## 设计说明 **为什么选择 fastembed 而不是 OpenAI embeddings?** 无需外部 API 调用,没有按 token 计算的成本,在容器中运行速度约为 10ms/embed。`BAAI/bge-small-en-v1.5`(384维,ONNX runtime)足以处理 11 个关键字丰富的 runbook,并且对抗性检索的区分度很高 —— db-connection-pool-exhaustion 和 downstream-service-failure 能够分别解析为不同的 top-1 结果,两者的余弦相似度分别为 0.763 和 0.798。 **为什么选择 HNSW 而不是 IVFFLAT?** 当 `lists=10` 时,IVFFLAT 至少需要约 30 个训练向量;而由于只有 11 个 runbook,7 个对抗性查询中有 2 个返回了空结果。HNSW 没有最小数据集大小的要求,并且在此数据规模下能提供精确结果。 **为什么在 PromQL 中使用动态的 `{window}`?** 对于持续 90 秒的事件,固定使用 `[2m]` 的时间窗口会用事件发生前约 30 秒的正常流量数据稀释错误率。Agent 会传入 `since=starts_at`,而 Prometheus 客户端会计算 `window = elapsed + 30s`,从而确保该速率能够完整捕捉到整个峰值。 **不使用 register_vector 的向量序列化:** `psycopg2.extras.RealDictCursor` 与 `pgvector` 的 `register_vector()` 不兼容(因为后者在内部对字典调用了 `row[0]`)。因此,向量被作为 `'[f1,f2,...]'::vector` 字符串字面量进行传递 —— 无需适配器。
标签:AIOps, API集成, Docker, LLM Agent, 可观测性, 向量检索, 安全防御评估, 测试用例, 版权保护, 自动化运维, 自定义请求头, 逆向工具