standing-on-giants/Data-Pipeline-Incident-Response
GitHub: standing-on-giants/Data-Pipeline-Incident-Response
一个用于评估和基准测试智能体 LLM 动态诊断与修复数据管道故障能力的强化学习环境。
Stars: 0 | Forks: 0
title: 数据管道故障响应 — OpenEnv
colorFrom: red
colorTo: orange
sdk: docker
app_port: 7860
tags:
- openenv
- data-engineering
- rl-environment
- agentic
license: MIT
# 数据管道故障响应 — OpenEnv
一个 RL 环境,其中 agent 作为值班数据工程师,诊断损坏的 pipeline,调查数据质量问题,并应用根因修复。
## 动机
数据团队每天都在处理损坏的 pipeline。供应商静默更改了 API 导出格式,关键源表中突然出现 null 值,或者重复的行导致下游财务聚合数据虚高。解决这些问题需要的不仅仅是代码生成——它需要**动态地调查数据**。
在这个环境中,agent 会收到包含 DAG 中失败断言的警报。它必须查询数据(`read_data_sample`、`check_schema`)以查明出了什么问题,应用正确的转换补丁(`add_data_filter`、`patch_transformation`),通过重新运行 pipeline 来验证修复,并知道何时将真正损坏的数据上报给上游。
该环境在需要**数据驱动推理**、**迭代调试**以及区分本地可修复 bug 和上游数据损坏的任务上对 agentic LLM 进行基准测试。
## 项目结构
```
data_pipeline_env/
├── Dockerfile
├── openenv.yaml
├── requirements.txt
├── new_inference.py Agent loop, prompt builder, action parser (local use)
└── src/
├── __init__.py
├── environment.py OpenEnv-compliant env (reset / step / state)
├── pipeline_runner.py Simulates DAG execution and data transformations
├── assertions.py Deterministic data quality grader
├── tasks.py Task definitions (DAGs, faults, schemas)
├── models.py Pydantic models (PipelineAction, PipelineObservation, …)
└── server.py FastAPI REST wrapper
```
# 数据管道故障响应 — OpenEnv
一个用于 agent 诊断和修复损坏数据管道的 RL 环境。
**真实世界任务**:每个数据团队都会在夜间处理 pipeline 故障。agent 作为值班数据工程师:它读取失败的断言报告,检查原始数据,确定根本原因,并应用修复——这正是人类在凌晨 3 点会做的事情。
## 快速开始
```
docker build -t data-pipeline-env .
docker run -p 7860:7860 data-pipeline-env
```
### 本地 (Python conda/venv)
```
# 安装依赖
pip install -r requirements.txt
# 对所有 3 个任务运行 inference(需要 API key)
export API_BASE_URL="https://router.huggingface.co/v1"
export MODEL_NAME="meta-llama/Llama-3.3-70B-Instruct"
export HF_TOKEN="your_token_here"
Push this repo to a Hugging Face Space with `sdk: docker` in the README frontmatter. The Space builds and serves automatically.
```bash
git clone https://huggingface.co/spaces//data-pipeline-incident-response
cp -r . data-pipeline-incident-response/
cd data-pipeline-incident-response
git add . && git commit -m "initial" && git push
python inference.py
python inference.py --task easy # single task
python inference.py --task hard --steps 25
```
## 环境概述
这些仅在本地运行 `new_inference.py` 时需要。Space 本身没有模型依赖——它只提供环境 API。
| 变量 | 必需 | 默认 | 描述 |
|---|---|---|---|
| `GEMINI_API_KEY` | 是 (本地) | — | 用于 Gemini 推理的 API key |
| `MODEL_NAME` | 否 | `gemini-2.5-flash` | 模型覆盖 |
| `MAX_STEPS` | 否 | `20` | 每 episode 的最大步数 |
| `TEMPERATURE` | 否 | `0.1` | 采样温度 |
| `MAX_TOKENS` | 否 | `1024` | 每次 LLM 调用的最大 token 数 |
## 用法
### REST API
```
# 健康检查
curl http://localhost:7860/health
# 列出任务
curl http://localhost:7860/tasks
# 启动 session
curl -X POST http://localhost:7860/reset \
-H "Content-Type: application/json" \
-d '{"task_id": "easy", "max_steps": 20}'
# → {"session_id": "easy_...", "observation": {...}}
# 执行一步
curl -X POST http://localhost:7860/step \
-H "Content-Type: application/json" \
-d '{
"session_id": "",
"action": {
"action_type": "read_data_sample",
"params": {"table": "raw_orders", "n_rows": 20}
}
}'
# 获取 session 状态
curl "http://localhost:7860/state?session_id="
```
### 本地 agent 运行器
```
pip install openai python-dotenv # in addition to requirements.txt
# 在 .env 文件中设置你的 GEMINI_API_KEY
python new_inference.py # all three tasks
python new_inference.py --task easy
python new_inference.py --task hard --steps 25
python new_inference.py --quiet # suppress per-step output
```
## 环境描述
```
from src.environment import DataPipelineEnv
from src.models import PipelineAction
env = DataPipelineEnv(task_id="easy") # "easy" | "medium" | "hard"
obs = env.reset() # → PipelineObservation
result = env.step(action) # → StepResult
state = env.state() # → Dict
```
当所有断言通过(`pipeline_passed=True`)或步数预算耗尽时,Episode 结束。
## 观察空间
`PipelineObservation` 字段:
| 字段 | 类型 | 描述 |
|---|---|---|
| `task_id` | `str` | `"easy"`、`"medium"` 或 `"hard"` |
| `difficulty` | `str` | 人类可读的难度标签 |
| `description` | `str` | 任务上下文(什么坏了) |
| `max_steps` | `int` | 步数预算 |
| `dag_structure` | `List[DAGNode]` | pipeline 图(步骤 + schema) |
| `failed_assertions` | `List[AssertionResult]` | 当前失败的数据质量检查 |
| `passed_assertions` | `List[AssertionResult]` | 当前通过的数据质量检查 |
| `historical_runs` | `List[HistoricalRun]` | 跨越数天的 pipeline 历史记录 |
| `data_sample` | `Optional[List[Dict]]` | 调用 `read_data_sample` 时填充 |
| `current_schema` | `Optional[Dict]` | 调用 `check_schema` 时填充 |
| `historical_schema` | `Optional[Dict]` | 调用 `compare_schema` 时填充 |
| `actions_taken` | `List[str]` | 最近的操作历史 |
| `last_action_result` | `str` | 上一个操作的文本结果 |
| `step_number` | `int` | 当前步数 |
| `pipeline_passed` | `bool` | 当所有断言通过时为 `True` |
### 问题所在
数据管道在夜间运行。它:
1. 从上游源(Salesforce、供应商、CRM)中**提取**数据
2. 对其进行**转换**(清理、连接、聚合)
3. 将其**加载**到仪表板和 ML 模型使用的下游表中
**数据质量断言**检查如下内容:
- `user_id IS NOT NULL`
- `order_item_id is UNIQUE`
- `revenue is numeric and in [0, 1,000,000]`
当断言失败时,pipeline 会停止。agent 的工作是找出原因并修复它。
## 任务
| 任务 | 故障 | 表 | 断言 | 难度 |
|--------|-------------------------------------|--------|------------|------------|
| easy | 来自上游的 5 个 null user_id | 2 | 3 | Easy |
| medium | 20 个重复的 order_item_id | 3 | 4 | Medium |
| hard | 收入格式更改 + N/A 行 | 4 | 6 | Hard |
## 动作空间
| 动作 | 参数 | 目的 |
|---|---|---|
| `read_data_sample` | `table`, `n_rows` | 通过检查实际行进行诊断 |
| `check_schema` | `table` | 通过检查当前列 dtypes 进行诊断 |
| `compare_schema` | `table` | 对比当前与历史 schema 以发现漂移 |
| `add_data_filter` | `step_id`, `filter_condition` | 修复:删除坏记录(例如 `user_id IS NOT NULL`) |
| `patch_transformation` | `step_id`, `patch_type`, `column` | 修复:原地清理数据(`coalesce`、`dedup`、`parse_currency`) |
| `run_pipeline` | *(无)* | 重新编译并触发 DAG,生成新的断言状态 |
| `alert_upstream_team` | `team`, `issue_description` | 正确上报无法修复的上游损坏 |
| `mark_acceptable` | `assertion_id`, `reason` | *(反模式)* 将失败的断言标记为忽略 |
**奖励:** 检查数据会因刷接口受到轻微惩罚(`-0.05`),盲目操作(未读取数据就添加过滤器)会受到严重惩罚(`-0.5`),正确上报无法修复的数据可获得 `+0.5`,修复 pipeline 会根据新断言通过或失败的情况获得分数。通过完整的 pipeline 可获得 `+1.0` 奖励。
## 任务描述
### easy — Null 值
| 问题 | 详细信息 |
|---|---|
| **故障** | 上游表添加了 `discount_code` 列,意外地导致 5 个随机行的 `user_id` 变为 null。 |
| **症状** | 在 `orders_clean.user_id` 上 `NOT NULL` 断言失败。 |
| **解决方案** | `add_data_filter` (`user_id IS NOT NULL`) |
| 动作 | 描述 |
|------------------------|------------------------------------------------------|
| `read_data_sample` | 查看表的前 N 行 |
| `check_schema` | 查看当前列类型 |
| `compare_schema` | 对比当前 schema 与历史 |
| `run_quality_assertion`| 重新运行特定断言 |
| `add_data_filter` | 向 pipeline 步骤添加 WHERE 子句 |
| `patch_transformation` | 应用列修复 (cast, dedup, parse_currency) |
| `backfill_partition` | 重新运行特定日期的 pipeline |
| `alert_upstream_team` | 将无法修复的问题上报给数据源所有者 |
| `mark_acceptable` | 接受已知问题(如果错误将被惩罚) |
| `run_pipeline` | 重新执行完整 pipeline 并检查所有断言 |
## 奖励设计
| 事件 | 奖励 |
|---------------------------------------------------|-----------|
| 断言从失败 → 通过(每次运行) | +0.4 |
| 断言从通过 → 失败(每次运行) | −0.5 |
| 所有断言通过(终止) | +1.0 |
| 未先读取数据就应用修复 | −0.5 |
| 正确的上游警报(hard 任务) | +0.5 |
| 对确实失败的断言使用 `mark_acceptable` | −1.0 |
## 运行服务器 (Docker)
```
# 构建
docker build -t data-pipeline-env .
# 运行
docker run -p 8001:8001 data-pipeline-env
# 健康检查
curl http://localhost:8001/health
# WebSocket endpoint: ws://localhost:8001/ws
```
### medium — 重复行
| 问题 | 详细信息 |
|---|---|
| **故障** | 供应商为昨天的数据发送了 20 个重复的订单项。 |
| **症状** | `order_item_id` 上的唯一约束失败,并且 `order_summary` 行数虚高。 |
| **解决方案** | 在 `transform_items` 步骤上执行 `patch_transformation` (type=`dedup`, column=`order_item_id`)。 |
### hard — Meta Ads 与 Conversions Pipeline(级联故障)
| 问题 | 详细信息 |
|---|---|
| **故障 1** | Graph API v19.0 将 `spend` 更改为 `"$1,234.56"` 字符串。由于 API 中断,约 10 行包含 `"N/A"`。 |
| **故障 2** | `impressions` 包含 `"N/A"` 值;将其合并为 0 会导致 CTR 除以零 (Inf/NaN)。 |
| **故障 3** | Conversions API 重试失败的 payload → 约 37 行重复的 `event_id` (15%)。 |
| **故障 4** | conversions 中的 `campaign_id` 带有 `"CMP_"` 前缀;insights 使用 int → ROAS join 丢失了 90%+ 的行。 |
| **症状** | 3 个输出表中共有 8 个断言失败:`spend` 上的类型/范围,`ctr` 上的范围,conversions 上的唯一性/行数,`roas_summary` 上的行数/范围。 |
| **解决方案** | 顺序执行:在 `spend` 上执行 `parse_currency` + `coalesce`,在 `impressions` 上执行 `parse_currency` + `coalesce(1)`,在 `event_id` 上执行 `dedup`,在 conversions `campaign_id` 上执行 `strip_prefix` + `cast_column`,+ `alert_upstream_team(meta_ads_api_team)`。 |
## 基准分数
模型:`gemini-2.5-pro`。`MAX_STEPS=20`,`TEMPERATURE=0.1`。
| 任务 | 得分 | 奖励 | 步数 | 断言通过数 | 是否通过 |
|---|---|---|---|---|---|
| easy | 1.00 | +1.35 | 3 | 3 / 3 | 是 |
| medium | 1.00 | +1.75 | 3 | 4 / 4 | 是 |
| hard | — | — | — | — / 8 | 待定 |
| **平均** | **—** | **—** | **—** | — | **—** |
### WebSocket 协议
```
// Reset
{"action": "reset", "task_id": "easy"}
// Step
{"action": {"action_type": "read_data_sample",
"params": {"table": "raw_orders", "n_rows": 20}}}
// Get state
{"action": "state"}
```
## 评分
评分器是完全确定性的:
```
score = assertions_passing / assertions_total ∈ [0.0, 1.0]
```
Hard 任务要求同时满足:
- 应用正确的数据修复(C1, C2, C3, C4, C6 通过)
- 针对损坏的行向正确的上游团队报警
## 项目结构
```
data_pipeline_env/
├── inference.py ← Baseline LLM agent
├── openenv.yaml ← OpenEnv spec metadata
├── requirements.txt
├── Dockerfile
└── src/
├── __init__.py
├── models.py ← Pydantic Observation / Action / StepResult
├── environment.py ← DataPipelineEnv (reset / step / state)
├── tasks.py ← Easy / Medium / Hard task definitions
├── assertions.py ← Deterministic assertion checker
├── pipeline_runner.py← Pandas-based pipeline executor
└── server.py ← FastAPI WebSocket server (OpenEnv spec)
```
标签:AI智能体, LLM评测, 强化学习环境, 数据工程, 数据质量, 模块化设计, 自动化修复, 请求拦截, 逆向工具