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, 可观测性, 向量检索, 安全防御评估, 测试用例, 版权保护, 自动化运维, 自定义请求头, 逆向工具