aman-source/incident-env

GitHub: aman-source/incident-env

一个用于训练和评估 AI 智能体在生产环境中进行事件响应分诊的模拟环境,让智能体扮演值班 SRE 在时间压力下诊断和修复微服务故障。

Stars: 0 | Forks: 0

## 标题: IncidentEnv emoji: 🚨 colorFrom: red colorTo: yellow sdk: docker pinned: false app_port: 7860 # IncidentEnv -- 事件响应分诊环境 一个 **OpenEnv 兼容环境**,用于模拟生产环境的事件响应,以训练和评估 AI 智能体。智能体扮演值班 SRE 工程师的角色:接收告警、调查微服务架构中的日志和指标、通过依赖图谱追踪故障、诊断根本原因并执行纠正措施——所有这一切都在现实的时间压力和级联系统降级的情况下进行。IncidentEnv 具有一种新颖的多维奖励函数,结合了时间衰减评分、级联故障惩罚、调查效率跟踪和感知爆炸半径的附带损害评分,产生的评估信号能够敏锐地区分复杂的推理与暴力探索。 为 **Scaler x Meta x Hugging Face OpenEnv 黑客马拉松**(印度版,70K+ 参与者)构建。 ## 为什么选择事件响应? 事件响应是软件工程中认知要求最高的任务之一——也是 Meta、Hugging Face 以及每家主要科技公司的每位工程师在值班轮换期间都要执行的任务。尽管它对生产可靠性至关重要,但 **OpenEnv 生态系统中不存在事件响应环境**。IncidentEnv 填补了这一空白。 此环境评估的技能正是定义专家 SRE 工作的那些技能: - **日志分析** —— 从包含现实时间戳、堆栈跟踪和交错条目的冗长、嘈杂的生产日志中提取信号 - **依赖追踪** —— 通过相互关联的服务追踪故障链,其中症状距离根本原因有多个跃点 - **时间关联** —— 跨时间链接事件(部署、配置更改、错误发生窗口)以识别因果关系 - **排除干扰项** —— 忽略与根本原因无关的误导性信号(排队导致的 CPU 升高、不相关的警告日志、表面性的配置更改) - **在不确定情况下采取果断行动** —— 在存在多种选项时选择正确的纠正措施,每种措施具有不同的影响范围 - **升级判断** —— 知道何时呼叫人类团队以及以何种优先级进行 奖励设计确实新颖。与二元的通过/失败评分器不同,IncidentEnv 通过五个正交维度对智能体进行评分,并结合时间压力衰减、级联故障状态变化和防止幸运猜测的最低调查门槛。这创造了前沿模型感到真正具有挑战性的评估信号——即使是 70B 参数模型在困难任务上也只能得分 0.72。 ## 任务 | 任务 | ID | 难度 | 服务数 | 最大步数 | 时间预算 | 测试内容 | |------|----|------------|----------|-----------|-------------|---------------| | 单服务 OOM 崩溃 | `easy_oom` | 简单 | 5 | 15 | 100s | 日志读取、单跳诊断、基本纠正措施 | | 级联 DB 连接池耗尽 | `medium_db_pool` | 中等 | 9 | 15 | 100s | 多跳依赖追踪、排除干扰项、连接池推理 | | 间歇性金丝雀部署 + OAuth 提供商故障 | `hard_canary` | 困难 | 15 | 15 | 100s | 时间关联、间歇性错误分析、金丝雀识别、多层干扰项 | ### 任务 1:简单 —— 单服务 OOM 崩溃 **场景**:`user-service` 返回 HTTP 503 错误。日志清楚地显示带有堆栈跟踪的 `java.lang.OutOfMemoryError: Java heap space` 条目,指向 `InMemoryStore.put()`。内存指标确认利用率为 98%。两小时前部署的 v2.4.1 引入了一个内存密集型内存缓存层,但没有调整堆限制。 **智能体必须做什么**: 1. 调查 `user-service` 日志 —— 观察堆耗尽的 OOM 错误 2. 调查 `user-service` 指标 —— 确认内存为 98%,与部署关联 3. 调查 `user-service` 部署 —— 确定 v2.4.1 为触发变更 4. 诊断:“由内存密集型部署 v2.4.1 引起的 OOM” 5. 行动:将 user-service `rollback` 到以前的版本 **为何简单**:具有一个服务的单一因果链。根本原因距离告警只有一跳。日志明确指出了错误。没有干扰项。此任务验证智能体可以读取日志、与部署历史记录关联并采取基本的纠正措施。 ### 任务 2:中等 —— 级联 DB 连接池耗尽 **场景**:`payment-service` 在事务处理上超时。但根本原因在两跳之外:`user-service` 在其用户查找路径中存在未关闭的数据库连接,导致连接池泄漏。这耗尽了共享的 `database` 连接池,进而导致 `payment-service`(也依赖于数据库)在事务提交上失败。 **干扰项**: - 昨天的 `payment-service` 部署 (v3.1.0) —— 看起来可疑但无关 - 基础设施日志中的 DNS 解析短暂故障 —— 已自动解决,无影响 - `api-gateway` 延迟升高 —— 下游故障的后果,而非原因 **智能体必须做什么**:从 payment-service 症状追踪到数据库连接耗尽,再到作为泄漏源的 user-service。至少需要 4 次调查才能建立因果链。智能体必须抵制责怪 payment-service 最近部署的诱惑,转而遵循连接池证据找到 user-service。 **为何中等**:根本原因距离呈现的症状有 2 跳。多个服务显示降级。两个不同的干扰项争夺智能体的注意力。需要理解连接池机制和依赖排序。 ### 任务 3:困难 —— 间歇性金丝雀部署伴随 OAuth 提供商故障 **场景**:多个服务中间歇性出现 HTTP 5xx 错误(约 10% 的请求),没有明显的模式。根本原因:`auth-service` v2.1.0-canary 的金丝雀部署引入了一个 claims-validator 错误,该错误仅在处理来自 OAuth provider-B 的令牌时失败(provider-A 令牌工作正常)。由于只有金丝雀 Pod 受到影响,且只有 provider-B 令牌触发该错误,因此错误稀疏且间歇性。 **干扰项**(4 层): - `recommendation-service` CPU 峰值 —— 合法但无关的批处理 - `config-service` 最近的更新 —— 例行配置轮换,无功能影响 - `database` 慢查询日志 —— 偶尔的长运行分析查询,预先存在 - 基础设施中的证书更新活动 —— 已成功完成,无错误 **为何困难**: - **间歇性信号**:第一次日志检查显示大部分是干净的输出 —— 30+ 个成功请求中只有 2 行隐藏的错误行。任何给定检查中错误仅出现约 30% 的时间。 - **15 个服务**:搜索空间大,有许多潜在嫌疑对象 - **金丝雀特殊性**:必须确定只有金丝雀 Pod(而非完整部署)是问题所在 - **提供商关联**:必须在稀疏的错误消息中注意到 provider-B 模式 - **时间压力**:100 秒预算,最多 15 步,意味着每次调查都必须有价值 ## 基准测试结果 在所有三个任务中运行基线智能体的得分: | 模型 | 简单 | 中等 | 困难 | 平均 | |-------|------|--------|------|---------| | **Llama 3.3 70B Instruct** | 0.95 | 0.76 | 0.72 | **0.81** | | **Llama 4 Scout 17B** | 0.96 | 0.70 | 0.20 | **0.62** | | **Llama 3.1 8B Instruct** | 0.86 | 0.70 | 0.53 | **0.70** | **主要观察结果**: - 简单任务可以被所有模型尺寸可靠地解决,验证了它是一个合理的基线。 - 中等任务显示约 0.70-0.76 的一致性能,差异来自调查效率和时间因子。 - 困难任务**真正挑战了所有模型**。即使是 Llama 3.3 70B 也只能得分 0.72,而 Scout 17B 降至 0.20 —— 在时间关联和间歇性错误模式方面挣扎。值得注意的是,8B 在困难任务上优于 Scout 17B(0.53 对 0.20),表明该任务测试的是推理深度而非原始参数数量。 - 简单和困难分数之间的差距(70B 为 0.95 到 0.72,Scout 为 0.96 到 0.20)展示了有意义的难度递进。 ## 动作空间 所有动作都以具有四个字段的 JSON 对象提交: ``` { "action_type": "", "target": "", "command": "", "parameters": {} } ``` ### `investigate` —— 查询系统信息 | 命令 | 描述 | 示例 | |---------|-------------|---------| | `logs` | 查看服务的近期日志条目 | `{"action_type": "investigate", "target": "auth-service", "command": "logs"}` | | `metrics` | 查看当前性能指标 | `{"action_type": "investigate", "target": "database", "command": "metrics"}` | | `deployments` | 查看最近的部署历史 | `{"action_type": "investigate", "target": "payment-service", "command": "deployments"}` | | `dependencies` | 查看上游/下游服务映射 | `{"action_type": "investigate", "target": "api-gateway", "command": "dependencies"}` | | `config` | 查看当前服务配置 | `{"action_type": "investigate", "target": "cache", "command": "config"}` | | `overview` | 系统范围的健康摘要 | `{"action_type": "investigate", "target": "system", "command": "overview"}` | | `recent_changes` | 所有服务的最近变更 | `{"action_type": "investigate", "target": "system", "command": "recent_changes"}` | ### `diagnose` —— 提交根本原因诊断 ``` { "action_type": "diagnose", "target": "auth-service", "command": "Claims-validator bug in v2.1.0-canary causing provider-B OAuth token failures" } ``` `target` 标识智能体认为是根本原因的服务。`command` 字段包含自由文本诊断。评分器使用针对预期根本原因的关键词匹配来对诊断准确性进行评分。 ### `act` —— 采取纠正措施 | 命令 | 描述 | 何时使用 | |---------|-------------|-------------| | `restart` | 重启服务 | OOM、挂起的进程 | | `rollback` | 回滚到以前的版本 | 错误的部署 | | `scale_up` | 添加更多实例 | 资源耗尽 | | `scale_down` | 移除实例 | 过度配置 | | `flush_cache` | 清除服务缓存 | 陈旧/损坏的缓存 | | `drain_connections` | 排空并重置连接池 | 连接池耗尽 | | `kill_canary` | 终止金丝雀部署 | 错误的金丝雀发布 | ``` { "action_type": "act", "target": "auth-service", "command": "kill_canary", "parameters": {} } ``` ### `escalate` —— 呼叫人类团队 | 团队 | 处理内容 | |------|---------| | `backend` | 应用程序级别的问题 | | `infrastructure` | 基础设施、网络、DNS | | `database` | 数据库性能、复制、连接池 | | `security` | 认证失败、可疑活动 | | `management` | 面向客户的升级 | ``` { "action_type": "escalate", "target": "database", "command": "page", "parameters": {"priority": "p1"} } ``` 优先级:`p1`(严重,立即响应),`p2`(高,15 分钟内),`p3`(中,1 小时内)。 ## 观察空间 每次调用 `reset()` 或 `step()` 都会返回一个具有以下字段的观察结果: | 字段 | 类型 | 描述 | |-------|------|-------------| | `message` | `str` | 当前状态或动作结果的可读描述 | | `alert_summary` | `dict` | 当前告警详情:`service`、`symptom`、`severity`、`triggered_at` | | `system_status` | `dict` | 服务名称到 `{health, latency_ms, error_rate_5xx, cpu_pct, memory_pct}` 的映射 | | `investigation_result` | `str` | 最近调查的详细输出(日志、指标、部署历史) | | `available_actions` | `list[str]` | 当前状态下的有效动作类型 | | `action_result` | `str` | 最近纠正措施的结果(如果有) | | `time_elapsed` | `int` | Episode 中已消耗的模拟秒数 | | `time_budget` | `int` | 此任务的最大模拟秒数 | | `hint` | `str` | 可选提示(在简单任务的早期步骤中提供) | | `done` | `bool` | Episode 是否已结束 | | `reward` | `float` | 步骤级奖励信号 | | `metadata` | `dict` | 附加上下文:`scenario_id`、`task_id`、`cascade_events`、`steps_taken` | ### 示例观察结果(调查日志后) ## 奖励函数 IncidentEnv 使用一个**多维奖励函数**,捕捉真实事件响应的细微差别。智能体是根据其调查、诊断和行动的*方式*进行评分的——而不仅仅是它们是否最终偶然发现了答案。 ### 步骤级奖励 每一步的小奖励或惩罚引导智能体并提供学习信号: | 动作 | 条件 | 奖励 | |--------|-----------|--------| | `investigate` | 目标与事件链相关 | +0.05 | | `investigate` | 目标无关(健康、不相关的服务) | 0.00 | | `investigate` | 重复之前的调查 | -0.02 | | `diagnose` | 正确的根本原因(3+ 个匹配关键词) | +0.10 | | `diagnose` | 部分正确(正确的服务或部分关键词) | +0.05 | | `diagnose` | 不正确 | -0.05 | | `diagnose` | 在满足最低调查次数之前提交 | 拒绝(不评分) | | `act` | 对正确服务采取正确的纠正措施 | +0.10 | | `act` | 错误的动作或错误的目标 | -0.05 | | `escalate` | 正确的团队和适当的优先级 | +0.05 | | `escalate` | 错误的团队或不适当的优先级 | -0.05 | ### 最终得分(评分器) 当 Episode 完成时,确定性评分器计算加权最终得分: ``` final_score = ( diagnosis_accuracy * 0.30 + resolution_quality * 0.25 + investigation_efficiency * 0.20 + time_factor * 0.15 + collateral_avoidance * 0.10 ) ``` 每个组件在 [0.0, 1.0] 范围内评分: | 组件 | 权重 | 评分逻辑 | |-----------|--------|---------------| | **诊断准确性** | 30% | 0.0 = 无诊断,0.4 = 仅服务正确,0.7 = 部分关键词匹配(1-2 个关键词),1.0 = 完全匹配(与预期根本原因有 3+ 个关键词) | | **解决质量** | 25% | 1.0 = 对正确服务的最佳操作,0.5 = 次优但有帮助的操作,0.0 = 未采取行动,对有害操作给予负惩罚 | | **调查效率** | 20% | `relevant_investigations / total_investigations` —— 奖励有针对性、高效的证据收集 | | **时间因子** | 15% | `max(0.0, 1.0 - time_elapsed / (time_budget * 0.83))` —— 当消耗 83% 的预算时衰减至 0 | | **附带损害避免** | 10% | 从 1.0 开始,每个有害动作(错误重启、不必要的升级等)减少 0.15 | 最终得分限制在 **[0.0, 1.0]** 范围内。 ### 新颖机制 **带衰减的时间压力**:时间因子创造紧迫感,但不会使缓慢但正确的解决方案变得毫无价值。在 3 步内解决的智能体获得高时间奖励;花费 12 步的智能体在诊断和解决方面仍然获得满分,只是时间组件减少。速度很重要,但正确性更重要。 **级联故障**:如果智能体花费太长时间,模拟系统会进一步降级。依赖服务开始失败,错误率增加,并出现新的误导性症状。每次级联事件都使环境更难推理,并降低了最大可实现的附带损害避免得分。 **间歇性错误**:困难任务的日志在任何给定检查中仅约 30% 的时间显示错误。第一次调查可能返回大部分干净的输出,其中只有 2 行错误埋在 30+ 个成功请求中。这测试智能体是否可以检测稀疏信号,还是在一次看起来干净的日志检查后将服务视为健康。 **最低调查门槛**:环境强制智能体在提交诊断之前收集最低限度的证据。这防止了幸运猜测,并确保高分反映真正的推理,而非随机探索。 ## 设置与用法 ### 前置条件 - Python 3.11+ - Docker(用于容器化部署) - OpenAI 兼容的 API 密钥(用于运行基线智能体) ### Docker(推荐) ``` docker build -t incident-env -f incident_env/server/Dockerfile . docker run -p 7860:7860 incident-env ``` 服务器将在 `http://localhost:7860` 可用。验证方式: ``` curl http://localhost:7860/health # {"status": "healthy"} ``` ### 本地开发 ``` pip install -e . uvicorn incident_env.server.app:app --host 0.0.0.0 --port 7860 ``` ### 运行基线智能体 ``` export OPENAI_API_KEY=sk-... python -m incident_env.baseline.run_baseline ``` 脚本连接到运行中的服务器,在所有三个任务上运行智能体,并打印每个任务的得分及最终平均值。 ### 使用 Python 客户端 ``` from incident_env.client import IncidentEnv from incident_env.models import IncidentAction env = IncidentEnv(url="http://localhost:7860") # 重置特定任务 obs = env.reset(task_id="easy_oom") # 调查 action = IncidentAction( action_type="investigate", target="user-service", command="logs" ) result = env.step(action) print(result.observation.message) print(result.observation.investigation_result) # 诊断 action = IncidentAction( action_type="diagnose", target="user-service", command="OOM from v2.4.1 memory-intensive caching deployment" ) result = env.step(action) # 操作 action = IncidentAction( action_type="act", target="user-service", command="rollback", parameters={"version": "2.4.0"} ) result = env.step(action) print(f"Reward: {result.reward}, Done: {result.done}") ``` ## API 端点 | 端点 | 方法 | 描述 | |----------|--------|-------------| | `/` | `GET` | 根端点。返回环境名称和版本。 | | `/health` | `GET` | 健康检查。返回 `200 OK` 和 `{"status": "healthy"}`。 | | `/tasks` | `GET` | 列出所有任务,包含 ID、难度级别、描述和完整动作模式。 | | `/reset` | `POST` | 重置环境并开始新的 Episode。接受 `{"task_id": "easy_oom"}`。 | | `/step` | `POST` | 提交动作并接收观察结果。接受 `IncidentAction` JSON 主体。 | | `/state` | `GET` | 检索当前环境状态(Episode ID、步数、任务 ID)。 | | `/schema` | `GET` | `IncidentAction` 和 `IncidentObservation` 模型的完整 JSON 模式。 | | `/grader` | `POST` | 计算已完成 Episode 的评分器得分。接受 `{"task_id": "...", "episode_id": "..."}`。 | | `/baseline` | `POST` | 触发基线推理。返回每个任务的得分和平均值。 | | `/ws` | `WebSocket` | 用于持久、有状态智能体会话的 WebSocket 端点。 | | `/docs` | `GET` | 自动生成的 Swagger/OpenAPI 文档(FastAPI 内置)。 | ### 示例:GET /tasks ``` { "tasks": [ { "id": "easy_oom", "name": "Single Service OOM Crash", "difficulty": "easy", "max_steps": 15, "description": "user-service is returning 503 errors due to an OutOfMemoryError from a recent deployment" }, { "id": "medium_db_pool", "name": "Cascading Database Connection Pool Exhaustion", "difficulty": "medium", "max_steps": 15, "description": "payment-service timeouts caused by database connection pool exhaustion from user-service leak" }, { "id": "hard_canary", "name": "Intermittent Canary Deployment with OAuth Provider Failures", "difficulty": "hard", "max_steps": 15, "description": "Intermittent 5xx errors from auth-service canary deployment affecting provider-B OAuth tokens" } ], "action_schema": { "action_type": {"type": "string", "enum": ["investigate", "diagnose", "act", "escalate"]}, "target": {"type": "string", "description": "Service name or team name"}, "command": {"type": "string", "description": "Specific command for the action type"}, "parameters": {"type": "object", "description": "Additional parameters (optional)"} } } ``` ### 示例:POST /grader **请求:** ``` {"task_id": "easy_oom", "episode_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"} ``` **响应:** ``` { "task_id": "easy_oom", "episode_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "score": 0.85, "breakdown": { "diagnosis_accuracy": 0.95, "resolution_quality": 1.0, "investigation_efficiency": 0.67, "time_factor": 0.73, "collateral_avoidance": 1.0 } } ``` ## 项目结构 ``` incident_env/ ├── __init__.py # Package exports ├── models.py # IncidentAction, IncidentObservation (Pydantic) ├── client.py # IncidentEnv(EnvClient) typed client ├── openenv.yaml # Environment manifest ├── pyproject.toml # Package configuration ├── README.md # This file ├── scenarios/ │ ├── __init__.py │ ├── easy.py # Single Service OOM scenario data │ ├── medium.py # Cascading DB Pool Exhaustion scenario data │ └── hard.py # Intermittent Canary + OAuth scenario data ├── graders/ │ ├── __init__.py │ └── grader.py # Deterministic grading logic (5-component scoring) ├── baseline/ │ ├── __init__.py │ └── run_baseline.py # OpenAI API baseline agent loop └── server/ ├── __init__.py ├── incident_environment.py # Core Environment subclass (reset/step/state) ├── app.py # FastAPI app + /tasks, /grader, /baseline endpoints ├── requirements.txt # Server dependencies └── Dockerfile # Container image for HF Spaces deployment ``` ## 设计原则 ### 确定性场景 给定相同的任务 ID 和种子,环境会产生相同的场景,具有相同的日志、指标和系统状态。相同的动作序列总是产生相同的奖励。这确保了可重复的评估和智能体之间的公平比较。 ### 丰富的文本观察 日志消息以真实的生产输出为模型,具有现实的时间戳、日志级别、Java/Python 类名和堆栈跟踪。指标名称遵循行业约定(`p99_latency_ms`、`error_rate_5xx`、`cpu_utilization_pct`)。服务名称是现实的(`api-gateway`、`auth-service`、`payment-service`)。智能体必须解析生产级文本,而不是简化的玩具格式。 ### 多维评分 二元的正确/错误评分器无法区分系统性调查和随机猜测。五组件评分器捕捉调查策略、诊断准确性、动作质量、速度和安全性——所有在真实事件响应中重要的维度,并为智能体改进创造丰富的训练信号。 ### 模拟时间(非墙钟时间) 每个动作消耗模拟时间单位。这使得评估具有确定性和可重复性,无论网络延迟或计算速度如何。`time_elapsed / time_budget` 比率驱动时间压力奖励组件。 ### 级联系统模型 在真实的生产系统中,故障会传播。数据库连接池耗尽不会保持隔离——它会波及每一个依赖它的服务。IncidentEnv 对这种传播进行建模,创建系统随时间恶化的动态场景。这奖励果断行动的智能体,并惩罚那些无休止调查而不采取行动的智能体。 ### 运行时无外部依赖 环境服务器具有零外部 API 调用。所有系统模拟都在容器内部本地运行。只有基线推理脚本(单独的评估工具)调用外部 LLM API。 ## 验证 ``` $ openenv validate [OK] incident: Ready for multi-mode deployment ``` 环境通过所有 OpenEnv 验证检查: - 服务器启动并响应健康检查 - `reset()` 产生具有有效观察结果的干净状态 - `step()` 接受有效动作并返回格式良好的观察结果 - 评分器在 [0.0, 1.0] 范围内产生确定性得分 - 所有自定义端点(`/tasks`、`/grader`、`/baseline`)正确响应 - Docker 容器构建并运行无误 ## 许可证 MIT
标签:AIOps, BurpSuite集成, DLL 劫持, Docker, HuggingFace, Meta, OpenEnv, Petitpotam, Scaler, SRE, 人工智能体, 代码推理, 仿真环境, 依赖追踪, 偏差过滤, 分布式系统, 响应大小分析, 大语言模型, 安全防御评估, 微服务架构, 故障诊断, 时间压力模拟, 智能运维, 根因分析, 站点可靠性工程, 系统稳定性, 级联故障, 训练环境, 请求拦截, 运维演练, 运维自动化, 逆向工具, 黑客松