FarseenSh/incident-triage-env
GitHub: FarseenSh/incident-triage-env
一个基于 OpenEnv 的强化学习环境,模拟 8 服务微服务架构中的生产事件,让 AI 代理练习调查告警、追踪依赖链、诊断根因并执行修复操作。
Stars: 0 | Forks: 0
# 事件响应分诊环境
[](https://github.com/meta-pytorch/OpenEnv)
[]()
[]()
[]()
[](https://huggingface.co/spaces/Farseen0/incident-triage-env)
一个 OpenEnv 兼容的 RL 环境,AI 代理可以在其中调查告警、追踪依赖链、识别根本原因,并修复模拟的跨 8 服务微服务架构的生产事件。
### 剧集如何运作
```
Agent receives incident briefing + initial alerts
│
├─→ get_alerts() → See what's firing
├─→ read_logs(service) → Read service logs for clues
├─→ check_metrics(service) → Check CPU, memory, latency, error rates
├─→ get_service_topology() → Understand dependency chain
│
├─→ set_severity("P1") → Classify the incident
├─→ diagnose(service, category) → Identify root cause
├─→ remediate(action, target) → Apply the fix
│
└─→ submit_report() → End episode → Get reward (0.0 - 1.0)
```
## 为什么这很重要
每个科技公司都有值班 SRE。当生产环境在凌晨 3 点出现故障时,工程师必须:
1. **分诊**一墙的触发告警(大多数是症状,不是原因)
2. **调查**跨互联服务的日志和指标
3. **追踪**通过依赖链追踪故障以找到根本原因
4. **修复**在正确的服务上执行正确的操作
这个环境捕捉了 exactly 的推理挑战——包含红鲱鱼、级联故障和真正能难倒前沿 LLM 的间歇性问题。
## 快速开始
```
# 安装
pip install openenv-core fastmcp uvicorn fastapi pydantic openai
# 启动服务器
uvicorn incident_triage_env.server.app:app --host 0.0.0.0 --port 8000
```
```
# 连接并运行 episode
import asyncio
from incident_triage_env import IncidentTriageEnv
from openenv.core.env_server.mcp_types import CallToolAction
async def main():
async with IncidentTriageEnv(base_url="http://localhost:8000") as env:
await env.reset(task_name="easy_oom_crash")
# Investigate
await env.call_tool("get_alerts")
await env.call_tool("read_logs", service="order-service", lines=50)
await env.call_tool("check_metrics", service="order-service", metric="all")
# Diagnose & fix
await env.call_tool("set_severity", level="P2")
await env.call_tool("diagnose",
root_cause_service="order-service",
root_cause_category="memory_exhaustion")
await env.call_tool("remediate",
action="restart_service", target_service="order-service")
# Submit (ends episode, triggers grading)
result = await env.step(CallToolAction(tool_name="submit_report", arguments={}))
print(f"Reward: {result.observation.reward}") # 1.0 for perfect diagnosis
asyncio.run(main())
```
## 架构
```
┌─────────────────────────────────────────────────────────┐
│ Agent (LLM) │
│ Investigates → Diagnoses → Remediates │
└──────────────────────┬──────────────────────────────────┘
│ MCP Tool Calls
┌──────────────────────▼──────────────────────────────────┐
│ Incident Triage Environment │
│ │
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐ │
│ │ Alerts │ │ Logs │ │ Metrics │ │ Topology │ │
│ └────┬────┘ └────┬─────┘ └────┬────┘ └────┬─────┘ │
│ └─────────┬──┴────────┬────┘ │ │
│ ┌─────▼───────────▼──────────────────▼──┐ │
│ │ Simulation Layer │ │
│ │ 8 services, dependency graph, │ │
│ │ scenario-specific fault injection │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
**8 个互联服务:**
`api-gateway` → `auth-service`, `order-service` → `inventory-service`, `payment-service`, `database`, `cache` → `message-queue`
## 可用工具
| 工具 | 参数 | 描述 |
|------|-----------|-------------|
| `get_alerts` | — | 获取所有触发中的告警及事件简报 |
| `read_logs` | `service`, `lines`(默认 50) | 读取服务的时间戳日志行 |
| `check_metrics` | `service`, `metric`(默认 "all") | 检查 cpu/memory/latency/error_rate/connections |
| `get_service_topology` | — | 查看微服务依赖图 |
| `set_severity` | `level`(P1/P2/P3/P4) | 分类事件严重程度 |
| `diagnose` | `root_cause_service`, `root_cause_category` | 提交根本原因诊断 |
| `remediate` | `action`, `target_service` | 对服务应用修复 |
| `submit_report` | — | 最终报告 — 结束剧集,触发评分 |
有效的枚举值
**根本原因类别:** `memory_exhaustion`, `connection_pool_exhaustion`, `clock_skew`, `disk_full`, `cpu_throttling`, `network_partition`, `config_error`, `dependency_failure`
**修复操作:** `restart_service`, `scale_up`, `rollback_deploy`, `config_change`, `failover`, `clear_cache`, `increase_pool_size`
## 5 个事件场景
| # | 任务 | 难度 | 发生了什么 | 陷阱 |
|---|------|-----------|--------------|----------|
| 1 | `easy_oom_crash` | 🟢 简单 | order-service OOM 崩溃 | 无 — 告警和日志明确指向内存耗尽 |
| 2 | `medium_cascade` | 🟡 中等 | 数据库连接池耗尽级联影响 4 个服务 | CRITICAL 告警在 api-gateway 触发(症状)。数据库仅显示 WARN |
| 3 | `medium_disk_full` | 🟡 中等 | 数据库磁盘满 — 写入失败,读取正常 | 非对称故障。order-service 和 payment-service 看起来有问题但根本原因是存储 |
| 4 | `hard_intermittent` | 🔴 困难 | auth-service 时钟偏移 + order-service CPU 红鲱鱼 | 8 个告警。order-service 有 CRITICAL CPU 告警和 ERROR 日志(这只是 cron 任务)。Auth 时钟偏移埋藏在 8% 的日志中 |
| 5 | `hard_network_partition` | 🔴 困难 | 网络分区将 payment-service 与 message-queue 隔离 | 8 个告警。DB vacuum(红鲱鱼),auth token 峰值(红鲱鱼)。必须识别 network_partition 并应用 failover |
## 奖励函数
### 终结奖励(4 个组成部分,最高 1.0)
| 组成部分 | 权重 | 精确匹配 | 部分得分 |
|-----------|--------|-------------|----------------|
| 严重程度 | 0.20 | 正确的 P 级别 | 差一个级别 = 0.10 |
| 服务 ID | 0.20 | 根本原因服务 | 任何受影响服务 = 0.10 |
| 根本原因 | 0.30 | 正确的类别 | — |
| 修复 | 0.30 | 正确的操作 + 目标 | 仅正确操作 = 0.10 |
### 每步信号
| 操作 | 奖励 | 条件 |
|--------|--------|-----------|
| 调查相关服务 | +0.02 | 在受影响服务上执行 `read_logs`/`check_metrics` |
| 首次 `get_service_topology` | +0.01 | 一次性奖励 |
| 首次 `get_alerts` | +0.01 | 一次性奖励 |
| 重启健康服务 | -0.03 | 破坏性操作惩罚 |
| 步数耗尽(20) | -0.10 | 剧集强制终止 |
**总计** = 终结奖励 + 调查奖励 + 惩罚,钳制到 [0.0, 1.0]
## 验证
```
$ openenv validate --url https://Farseen0-incident-triage-env.hf.space
[PASS] openapi_version_available
[PASS] health_endpoint
[PASS] metadata_endpoint
[PASS] schema_endpoint (action + observation + state)
[PASS] mcp_endpoint (JSON-RPC 2.0)
[PASS] mode_endpoint_consistency (/reset, /step, /state)
Result: 6/6 passed
```
## 基线分数 — 多模型基准
我们在所有五个任务上对三个模型进行了基准测试。环境产生一致的难度梯度,并真正区分模型能力。
| 模型 | 简单 | 中等级联 | 中等磁盘 | 困难间歇 | 困难网络分区 | 平均 |
|-------|------|-------------|----------|----------------|--------------|-----|
| **Qwen 3.6 Plus** | 1.00 | 1.00 | 0.68 | 0.75 | 0.82 | **0.85** |
| **Kimi K2.5** | 1.00 | 1.00 | 1.00 | 0.00 | 0.80 | **0.76** |
| **Gemma 4 26B** | 0.82 | 0.76 | 0.90 | 0.66 | 0.55 | **0.74** |
**关键发现:**
- 所有模型都能轻松完成简单任务,但在困难场景上挣扎(0.00–0.82)
- 不同模型以不同方式失败 — Kimi 完全无法完成 `hard_intermittent`(放弃未提交),Gemma 在 `hard_network_partition` 上得到错误的根本原因
- 红鲱鱼机制真正难倒了前沿模型
- 任务间的分数差异证明评分器区分的是行为,而不仅仅是模型身份
### 复现
```
# 免费基线 (HF Router + Qwen 2.5 72B)
HF_TOKEN=hf_xxx python inference.py --base-url http://localhost:8000
# 多模型基准测试
ANTHROPIC_API_KEY=x MOONSHOT_API_KEY=y HF_TOKEN=z python inference.py --run-all
```
## 设置
### Docker
```
docker build -t incident-triage-env .
docker run -p 8000:8000 incident-triage-env
```
### 本地
```
pip install -e .
uvicorn incident_triage_env.server.app:app --host 0.0.0.0 --port 8000
```
### 部署到 HF Spaces
```
pip install openenv-core
openenv push --repo-id YOUR_USERNAME/incident-triage-env
```
## 环境变量
| 变量 | 必需 | 描述 |
|----------|----------|-------------|
| `API_BASE_URL` | 用于推理 | LLM 端点(默认:HF Router) |
| `MODEL_NAME` | 用于推理 | 模型 ID(默认:Qwen/Qwen2.5-72B-Instruct) |
| `HF_TOKEN` | 用于推理 | Hugging Face API token |
| `ANTHROPIC_API_KEY` | 可选 | 用于 Claude Sonnet 基准 |
| `MOONSHOT_API_KEY` | 可选 | 用于 Kimi K2.5 基准 |
## RL 训练集成
与 TRL GRPO 兼容,用于从环境反馈进行强化学习:
```
from trl import GRPOTrainer, GRPOConfig
from incident_triage_env.server.incident_environment import IncidentTriageEnvironment
from openenv.core.env_server.mcp_types import CallToolAction
def reward_fn(completions, task_name="easy_oom_crash"):
rewards = []
for completion in completions:
env = IncidentTriageEnvironment()
env.reset(task_name=task_name)
for tool_call in parse_tool_calls(completion):
obs = env.step(CallToolAction(
tool_name=tool_call["name"],
arguments=tool_call["args"]))
if obs.done:
rewards.append(obs.reward)
break
else:
rewards.append(0.0)
return rewards
trainer = GRPOTrainer(
model=model,
config=GRPOConfig(output_dir="./grpo-triage", num_generations=4),
reward_funcs=[reward_fn],
train_dataset=dataset,
)
trainer.train()
```
## 项目结构
```
incident_triage_env/
├── __init__.py # Package exports
├── models.py # IncidentTriageState + enums
├── client.py # MCPToolClient (pass-through)
├── openenv.yaml # OpenEnv manifest
├── pyproject.toml # Dependencies
├── Dockerfile # Multi-stage Docker build
├── inference.py # Baseline agent (multi-model)
├── server/
│ ├── app.py # FastAPI app factory
│ └── incident_environment.py # Core MCPEnvironment subclass
├── scenarios/
│ ├── base.py # ScenarioBase ABC + GroundTruth + Registry
│ ├── easy_oom_crash.py # Task 1: Single service OOM
│ ├── medium_cascade.py # Task 2: Cascading dependency failure
│ ├── medium_disk_full.py # Task 3: Database disk full
│ ├── hard_intermittent.py # Task 4: Auth clock skew + red herrings
│ └── hard_network_partition.py # Task 5: Network partition + red herrings
└── simulation/
├── service_graph.py # 8-service microservice topology
├── log_generator.py # Realistic timestamped log generation
├── metrics_store.py # Per-service metrics with overrides
└── alert_engine.py # Alert creation and severity sorting
```
*为 [Meta x PyTorch x HuggingFace OpenEnv 黑客松](https://github.com/meta-pytorch/OpenEnv) 构建*标签:AIOps, Apex, Incident Response, LLM代理, OpenEnv, RL环境, SRE, 人工智能运维, 偏差过滤, 强化学习, 指标监控, 故障排查, 服务拓扑, 机器学习, 根因分析, 模块化设计, 生产环境监控, 站点可靠性工程, 自动化修复, 请求拦截, 运维自动化, 逆向工具, 靶机