MohitSalvi16/devops-incident-response-openenv
GitHub: MohitSalvi16/devops-incident-response-openenv
一个基于 OpenEnv 的 AI 代理训练与评测环境,用于解决 DevOps 与 SRE 场景下的实战事件响应问题。
Stars: 1 | Forks: 0
title: DevOps 事件响应
emoji: 🚨
colorFrom: red
colorTo: indigo
sdk: docker
app_port: 7860
pinned: false
license: mit
short_description: 用于 AI agents 的 OpenEnv SRE 事件响应环境
tags:
- openenv
- rl
- agents
- devops
- sre
- incident-response
# DevOps 事件响应 — OpenEnv 环境
[](https://github.com/meta-pytorch/OpenEnv)
[]()
[]()
## 为什么存在这个环境
生产环境事件导致公司平均每分钟的停机时间损失 **$5,600**(Gartner)。值班工程师必须快速切换上下文、阅读密集的日志、关联跨服务的故障,并应用精确的修复——通常是在凌晨 3 点进行。这个环境提供了一个现实的、确定性的测试平台,用于评估 AI agents 是否能处理该工作流:
- 跨多个服务的**日志分析**
- 在模糊条件下的**根因诊断**
- 带有评分器验证修复的**代码与配置修复**
- 针对级联故障的**多服务关联**
- 通过模拟 shell 命令进行**恢复验证**
这是我们未曾见过的在任何现有 OpenEnv 环境中进行过建模的领域,并且对 RL / agent 社区具有直接价值:训练 agents 进行事件响应可直接缩短平均解决时间(MTTR)并提高系统可靠性。
## 快速开始
### 运行服务器(本地)
```
pip install -r requirements.txt
python -m server.app # listens on 0.0.0.0:${PORT:-7860}
```
### 运行服务器(Docker)
```
docker build -t devops-incident-env .
docker run -p 7860:7860 -e PORT=7860 devops-incident-env
curl http://localhost:7860/health # → {"status":"healthy"}
curl -X POST -H 'Content-Type: application/json' \
-d '{}' http://localhost:7860/reset # → initial observation
```
Dockerfile 会识别 `$PORT`(Hugging Face Spaces 会注入它),因此同一个镜像可以在 HF Spaces 和本地保持不变地运行。
### 运行 baseline agent
```
export API_BASE_URL=https://api.openai.com/v1
export MODEL_NAME=gpt-4o-mini
export HF_TOKEN=sk-...
python inference.py
```
如果未设置 `HF_TOKEN` / `OPENAI_API_KEY`,`inference.py` 将回退到确定性的启发式 baseline,以便脚本始终产生可复现的分数。
### 运行本地提交前验证器
```
bash scripts/pre_validate.sh # full
SKIP_DOCKER=1 bash scripts/pre_validate.sh # skip docker build
```
## OpenEnv 合约
此环境使用 `openenv.core.env_server.http_server.create_app`,因此所有标准 endpoint 都会自动连接:
| Method | Path | Purpose |
|--------|----------------|-----------------------------------------------|
| GET | `/health` | 用于存活探针的 `{"status":"healthy"}` |
| GET | `/metadata` | 环境名称 + 描述 + 版本 |
| GET | `/schema` | `action`、`observation`、`state` 的 JSON schema |
| GET | `/openapi.json`| OpenAPI 3.x spec(由 `openenv validate` 使用) |
| POST | `/reset` | 重置并返回初始 observation |
| POST | `/step` | 执行 action,返回 observation |
| GET | `/state` | 当前 `episode_id` + `step_count` |
| POST | `/mcp` | JSON-RPC MCP endpoint |
| WS | `/ws` | 持久 WebSocket session |
`openenv validate` 通过:
```
[OK] Meta_Hackathon: Ready for multi-mode deployment
```
## Action 空间
agent 在每步发出一个 `DevOpsAction`(`openenv.core.env_server.types.Action` 的子类):
| `action_type` | `target` | `content` |
|----------------|--------------------------|---------------------------------------------|
| `read_log` | 日志文件名 | _空_ |
| `read_file` | 文件路径 | _空_ |
| `diagnose` | _空_ | 根因假设 |
| `edit_file` | 文件路径 | **完整**替换文件内容 |
| `run_command` | _空_ | shell 命令(例如 `nginx -s reload`) |
| `submit_fix` | _空_ | 修复内容总结 |
## Observation 空间
`DevOpsObservation`(`openenv.core.env_server.types.Observation` 的子类):
| Field | Type | Description |
|----------------------|------------------|----------------------------------------------|
| `step` | `int` | 当前步数 |
| `max_steps` | `int` | Episode 步数限制 |
| `task_id` | `str` | 活动任务标识符 |
| `task_description` | `str` | 人类可读的目标 |
| `alert_message` | `str` | PagerDuty 风格告警(仅首步) |
| `logs` | `dict[str,str]` | 以文件名为键的日志文件内容 |
| `files` | `dict[str,str]` | 以路径为键的源代码/配置文件 |
| `command_output` | `str` | 上次 `run_command` 的输出 |
| `system_status` | `str` | `up` / `degraded` / `down` |
| `diagnosis_feedback` | `str` | 关于上次 `diagnose` action 的反馈 |
| `error` | `str` | 上次 action 无效时的错误 |
| `cumulative_reward` | `float` | 累计 reward |
| `final_score` | `float` | 归一化的 [0,1] 分数(在 `done` 时设置) |
| `done` | `bool` | Episode 已终止 |
| `reward` | `float` | 该步的 reward |
## Reward 函数
每一步都会产生密集的 reward(没有稀疏的 episode 结束 reward)。
| Component | Reward | Trigger |
|-----------------------|-----------------|---------------------------------------------|
| 信息收集 | +0.02 | 首次读取每个日志/文件/命令 |
| 部分诊断 | +0.05 – 0.15 | 识别出部分根因 |
| 完整诊断 | +0.20 – 0.30 | 识别出所有根因 |
| 部分修复 | +0.05 – 0.25 | 修复部分文件 |
| 完整修复 | +0.40 – 0.50 | 所有文件均被正确修复 |
| 成功解决 | +0.20 | `system_status == "up"` 时 `submit_fix` |
| 效率奖励 | +0.00 – 0.10 | 步数越少 → 奖励越高 |
| 重复动作 | −0.05 × 次数 | 对循环的逐步升级惩罚 |
| 错误提交 | −0.10 × 次数 | 系统仍宕机时 `submit_fix` |
| **裸提交** | **−0.20 × 次数** | 没有任何事先 `edit_file` 的 `submit_fix`(防漏洞利用) |
| Episode 超时 | −0.10 | 达到最大步数且系统仍宕机 |
评分器将累计 reward 归一化为 `final_score ∈ [0, 1]`。**没有任何评分器返回常数分数** —— 每个任务都会根据 agent 的质量产生明显不同的分数(已通过 `tests/test_tasks.py::test_grader_score_bounds` 参数化测试验证)。
## 任务
| ID | 难度 | 最大步数 | 根因 |
|---------------------------------|------------|-----------|-------------|
| `easy_port_misconfiguration` | easy | 15 | 1 |
| `medium_database_connection` | medium | 20 | 2 |
| `medium_kubernetes_crashloop` | medium | 22 | 2 |
| `hard_microservice_cascade` | hard | 25 | 5 |
### Easy — 端口配置错误
Nginx 被配置为 `listen 8080;`,但负载均衡器期望使用端口 80。端口 8080 被监控 agent 占用。**一个**根因;主要测试日志读取和基本配置编辑能力。
### Medium — 数据库连接池耗尽
应用程序在负载下返回 503 错误。**两个**相互作用的故障:连接池大小设置为 2(必须 ≥ 10),并且应用程序代码从不将连接释放回池中。agent 必须同时编辑 `database.yml` 和 `user_service.py`。
### Medium — Kubernetes CrashLoopBackOff
`payment-service` 的所有 3 个副本都处于 CrashLoopBackOff 状态。**两个**相互作用的故障:(1) Secret `payment-secrets` 缺少 `database_url` 键,并且 (2) 存活探针路径为 `/health`,但服务仅暴露了 `/healthz`。agent 必须检查 kubectl 事件、Deployment YAML 和 Secret YAML,并修补这两者。
### Hard — 微服务级联故障
跨越 `api-gateway`、`order-service`、`inventory-service` 和 Redis 的 SEV-1 级联宕机。**五个**相互作用的根因:禁用的断路器、重试风暴、缺失的服务间超时、未处理的 Redis `WatchError`,以及具有 `noeviction` 策略的 Redis OOM。真正挑战前沿模型 —— 每次修复都会获得部分积分。
## Baseline 分数
可通过 `python inference.py` 复现:
| Task | 启发式 agent | `mistral-small-latest`¹ |
|-----------------------------------|-----------------|--------------------------|
| `easy_port_misconfiguration` | **0.99** | **0.99** (10 步) |
| `medium_database_connection` | 0.01 | 0.01 |
| `medium_kubernetes_crashloop` | **0.99** | **0.99** (11 步) |
| `hard_microservice_cascade` | 0.01 | 0.01 |
| **平均** | **0.50** | **0.50** |
| **通过的任务 (≥0.5)** | **2/4** | **2/4** |
¹ 代表性运行于 2026-04-12 通过 Mistral La Plateforme API 针对 `mistral-small-latest` 进行,`temperature=0`。托管的 LLM API 即使在零温度下也表现出残余的非确定性;在 3 次独立运行中,该模型的平均分数范围在 **0.23 – 0.50** 之间,这正是 Phase 2 评估所寻找的那种方差类型(跨运行的恒定分数是一票否决标准)。启发式 baseline 是完全确定性的。“medium-DB”和“hard-cascade”仍然无法被小型开放模型解决 —— 它们需要多文件协调编辑和级联根因分析,这真正挑战了前沿模型。**这个差距就是 agent 评估信号**:更强的模型(GPT-4.1、Claude Opus、Llama-3.1-405B、Nemotron 3 Super)预计在中等/困难任务上得分会显著更高,从而在评估准则中产生有意义的分数方差。
推理脚本使用扁平化(系统 + 一次用户回合)的提示策略,因此每次调用的上下文保持在 ~1.5k token 以下,使得小型模型(≤8B 参数)能够在不触及上下文长度错误的情况下完成整个轨迹。
## 项目布局
```
.
├── openenv.yaml # OpenEnv manifest (spec_version: 1)
├── pyproject.toml # project + [project.scripts] server entry
├── uv.lock # locked deps (required by openenv validate)
├── Dockerfile # python:3.10-slim + uvicorn
├── .dockerignore
├── README.md # this file
├── requirements.txt # pip-style deps mirroring pyproject.toml
├── inference.py # baseline agent (LLM + heuristic fallback)
├── models.py # OpenEnv-typed Action / Observation / State
├── server/
│ ├── __init__.py
│ ├── app.py # create_app(...) + main()
│ └── devops_environment.py # Environment subclass wrapping the inner env
├── env/
│ ├── env.py # core stateful env (reset/step/state)
│ ├── grader.py # dense reward computation
│ ├── models.py # internal action/observation
│ └── tasks/
│ ├── base_task.py
│ ├── task_registry.py
│ ├── easy_port_misconfiguration.py
│ ├── medium_database_connection.py
│ ├── medium_kubernetes_crashloop.py # ← 4th task
│ └── hard_microservice_cascade.py
├── tests/ # 24 unit tests
│ ├── test_tasks.py
│ └── test_env.py
└── scripts/
└── pre_validate.sh # local pre-submission validator
```
## License
MIT
标签:AI智能体, SRE, 人工智能, 仿真环境, 偏差过滤, 强化学习, 故障排查, 用户模式Hook绕过, 运维