File size: 15,423 Bytes
8fb4252
 
 
37a1d2f
 
8fb4252
 
 
 
 
efaec4a
37a1d2f
 
 
 
8fb4252
 
37a1d2f
 
 
 
4dc1b57
37a1d2f
 
 
 
 
4dc1b57
37a1d2f
4dc1b57
 
 
37a1d2f
4dc1b57
efaec4a
 
 
37a1d2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4dc1b57
efaec4a
 
37a1d2f
 
 
efaec4a
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
 
 
 
efaec4a
37a1d2f
4dc1b57
 
 
37a1d2f
4dc1b57
efaec4a
37a1d2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
efaec4a
4dc1b57
efaec4a
37a1d2f
8fb4252
37a1d2f
4dc1b57
37a1d2f
4dc1b57
efaec4a
37a1d2f
4dc1b57
37a1d2f
efaec4a
37a1d2f
4dc1b57
efaec4a
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
4dc1b57
efaec4a
37a1d2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4dc1b57
37a1d2f
 
 
4dc1b57
37a1d2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4dc1b57
 
 
efaec4a
4dc1b57
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
 
 
 
 
 
 
 
 
 
 
 
 
4dc1b57
37a1d2f
 
 
 
 
 
 
 
 
 
 
4dc1b57
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
4dc1b57
37a1d2f
 
 
 
 
 
 
 
 
4dc1b57
 
 
37a1d2f
4dc1b57
efaec4a
4dc1b57
efaec4a
 
 
4dc1b57
37a1d2f
 
4dc1b57
efaec4a
 
 
 
 
 
 
 
 
 
4dc1b57
efaec4a
 
4dc1b57
37a1d2f
4dc1b57
37a1d2f
 
4dc1b57
37a1d2f
 
efaec4a
37a1d2f
 
 
 
 
efaec4a
 
4dc1b57
37a1d2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4dc1b57
 
 
 
 
efaec4a
4dc1b57
37a1d2f
4dc1b57
37a1d2f
 
 
 
4dc1b57
37a1d2f
 
 
 
efaec4a
37a1d2f
 
 
 
efaec4a
37a1d2f
 
4dc1b57
37a1d2f
 
efaec4a
37a1d2f
efaec4a
37a1d2f
4dc1b57
 
 
 
 
37a1d2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
efaec4a
 
 
37a1d2f
efaec4a
 
37a1d2f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
efaec4a
 
4dc1b57
 
37a1d2f
4dc1b57
efaec4a
 
37a1d2f
 
efaec4a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
---
title: DataEngEnv
emoji: πŸ”§
colorFrom: indigo
colorTo: purple
sdk: docker
pinned: true
license: mit
tags:
  - openenv
  - reinforcement-learning
  - ml-pipeline
  - debugging
  - grpo
  - llm-agent
---

<div align="center">

# PipelineOps Arena
### A 4-Stage Cascading ML Pipeline Debugger for RL Agents

[![OpenEnv](https://img.shields.io/badge/OpenEnv-Compliant-6366f1?style=flat-square)](https://github.com/openenv)
[![HF Space](https://img.shields.io/badge/πŸ€—%20Live%20Demo-CoBeDigger/DataEngEnv-fbbf24?style=flat-square)](https://huggingface.co/spaces/CoBeDigger/DataEngEnv)
[![Trained Model](https://img.shields.io/badge/🦾%20GRPO%20Model-CoBeDigger/pipelineops--arena--llama3--grpo-a855f7?style=flat-square)](https://huggingface.co/CoBeDigger/pipelineops-arena-llama3-grpo)
[![License](https://img.shields.io/badge/License-MIT-22c55e?style=flat-square)](LICENSE)
[![Docker](https://img.shields.io/badge/Docker-Ready-0ea5e9?style=flat-square)](Dockerfile)

</div>

---

## Submission Links

| Resource | Link |
|---|---|
| 🌐 **Live Environment** | [https://huggingface.co/spaces/CoBeDigger/DataEngEnv](https://huggingface.co/spaces/CoBeDigger/DataEngEnv) |
| 🦾 **Trained Model (GRPO)** | [CoBeDigger/pipelineops-arena-llama3-grpo](https://huggingface.co/CoBeDigger/pipelineops-arena-llama3-grpo) |
| πŸ““ **Training Notebook** | [GRPO_Training_Pipeline.ipynb](./GRPO_Training_Pipeline.ipynb) *(Kaggle GPU β€” re-runnable)* |
| πŸ“ˆ **Reward + Loss Plots** | See [Training Results](#-training-results) section below |
| πŸ”§ **GitHub Repo** | [Pranav-0710/DataEngEnv](https://github.com/Pranav-0710/DataEngEnv) |

> **Writeup / Video:** *(coming soon β€” link will appear here)*

---

## The Problem

It's 2 AM. A production ML model ships in 6 hours. The data pipeline is broken. Four separate bugs are buried across schema handling, feature normalization, evaluation, and fairness. An engineer has to find them, patch them, and verify each fix before the deployment gate opens.

This is a real workflow. We turned it into an RL environment.

**PipelineOps Arena** puts an AI agent in that engineer's seat. The agent gets a broken Python script and an error log. It can inspect data, edit code, run it in a sandboxed subprocess, consult an MLOps bot, and submit fixes for deterministic grading. No hardcoded rules β€” just the model reasoning its way through the pipeline.

---

## What Is This Environment?

A **4-stage cascading OpenEnv environment** built on the [OpenEnv](https://github.com/openenv) framework. Each stage represents a distinct failure mode in a real ML pipeline. Stages must be solved sequentially β€” completing Stage N unlocks Stage N+1. Failing Stage 4 loops the agent back to Stage 1 with a penalty, forcing genuine long-horizon planning.

### Why It's Different from Toy Environments

Most RL environments are either too abstract (Atari, MuJoCo) or too narrow (single-step Q&A). PipelineOps Arena is grounded in actual ML engineering work:

- **Schema debugging** β€” column names drift between data sources
- **Feature scaling** β€” unscaled neural network inputs cause NaN loss
- **Data leakage** β€” scaler fitted before the train/test split inflates accuracy
- **Fairness auditing** β€” class imbalance creates demographic bias that blocks deployment

Every reward comes from **objective, code-based evaluation** β€” not LLM-as-judge, not rule matching, not string comparison. The grader runs the actual fixed script and measures real model accuracy, convergence, and fairness gap.

---

## The 4-Stage Pipeline

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    PipelineOps Arena                          β”‚
β”‚                                                               β”‚
β”‚  Stage 1       Stage 2       Stage 3       Stage 4           β”‚
β”‚  Data Repair β†’ Training  β†’ Eval Fix  β†’ Deploy Gate          β”‚
β”‚  (Schema)      (Scaling)    (Leakage)   (Fairness)           β”‚
β”‚    🟒 Easy      🟑 Medium    πŸ”΄ Hard      πŸ”΄ Hard             β”‚
β”‚      β”‚             β”‚            β”‚            β”‚               β”‚
β”‚      └─── Fix β”€β”€β”€β”€β”€β”˜β”€β”€β”€β”€ Fix β”€β”€β”€β”˜β”€β”€β”€β”€ Fix ──►│               β”‚
β”‚                                              β”‚               β”‚
β”‚                                         FAIL?β”‚               β”‚
β”‚                                              β–Ό               β”‚
β”‚                                       Back to Stage 1        β”‚
β”‚                                       (βˆ’0.3 penalty)         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

### Stage 1 β€” Data Repair 🟒
**Bug:** Column `age_years` was renamed to `age` upstream. Script crashes with `KeyError`. The dataset also has ~15% NaN rows that crash the scaler.

**Required fix:** Rename the column reference + `df.dropna()` before feature extraction.

---

### Stage 2 β€” Training Monitor 🟑
**Bug:** `MLPClassifier` is fed raw unscaled features. Loss diverges to NaN and the model fails to converge.

**Required fix:** Add `StandardScaler` fitted on `X_train` only. Transform both train and test sets before fitting the classifier.

---

### Stage 3 β€” Eval Validation πŸ”΄
**Bug:** `scaler.fit_transform()` runs on the **entire dataset** before `train_test_split()`. Test statistics leak into training. The model reports 98% accuracy β€” a lie.

**Required fix:** Move `scaler.fit_transform()` to after the split. Fit only on `X_train`, transform `X_test` separately.

---

### Stage 4 β€” Deploy Gate πŸ”΄
**Bug:** The model passes accuracy checks but has a high demographic fairness gap. The simulated MLOps bot rejects deployment.

**Required fix:** Add `class_weight='balanced'` to `LogisticRegression` and use `stratify=y` in the split to ensure fair class distribution.

---

## Observation & Action Space

### Observations

| Field | Type | Description |
|---|---|---|
| `current_stage` | `int` | Active pipeline stage (1–4) |
| `step_number` | `int` | Global step count (max 60) |
| `stage_step_number` | `int` | Steps within current stage (max 20) |
| `script_content` | `str` | Current state of the pipeline script |
| `last_run_output` | `str` | stdout from last `run_script` |
| `last_run_error` | `str \| null` | stderr / traceback if script failed |
| `data_preview` | `str` | Shape, columns, nulls, sample rows |
| `schema_info` | `dict` | Column dtypes and null counts |
| `actor_feedback` | `str` | MLOps Bot / Code Reviewer response |
| `done` | `bool` | True when episode ends |

### Actions

| Action | Payload | Effect |
|---|---|---|
| `inspect_data` | `{}` | Returns full dataset preview β€” shape, columns, nulls, 5-row sample, numeric stats |
| `run_script` | `{}` | Executes current script in isolated subprocess with 10s timeout |
| `edit_script` | `{"old": str, "new": str}` | String-replacement patch. Also supports `{"script": str}` for full replacement |
| `query_actor` | `{}` | Queries the MLOps Bot (Stage 4) or Code Reviewer (Stages 2–3) |
| `submit` | `{}` | Triggers deterministic grader β€” advances stage if score β‰₯ 0.70 |

---

## Reward Function

Rewards are **dense and continuous** β€” the agent gets partial credit on every action, not just at submission.

| Stage | Action | Reward Signal |
|---|---|---|
| All | `inspect_data` (first call) | +0.10 |
| Stage 1 | `edit_script` fixes column name | +0.20 |
| Stage 1 | `edit_script` adds `dropna` | +0.10 |
| Stage 1 | `run_script` clean after fix | +0.20 |
| Stage 2 | `edit_script` adds `StandardScaler` | +0.30 |
| Stage 2 | `run_script` clean after fix | +0.20 |
| Stage 3 | `edit_script` moves fit after split | +0.30 |
| Stage 3 | `submit` before fixing leakage | βˆ’0.20 |
| Stage 4 | `query_actor` gets fairness feedback | +0.10 |
| Stage 4 | `edit_script` adds `class_weight` | +0.30 |
| All | `submit` correct fix | grader score [0, 1] |
| Stage 4 fail | Loops back to Stage 1 | βˆ’0.30 |

Rewards are cumulative per episode. Terminal reward is the grader score. The `RewardEngine` in `app/reward.py` handles all shaping logic.

---

## πŸ“Š Training Results

We fine-tuned **LLaMA 3.1 8B** on Kaggle (T4 GPU) using a custom GRPO (Group Relative Policy Optimization) implementation via Unsloth + LoRA.

### GRPO Reward Curve

The reward plot below shows a real training run β€” 25 steps, G=4 completions per step, LR=1e-5.

![GRPO Training Curve](https://huggingface.co/CoBeDigger/pipelineops-arena-llama3-grpo/resolve/main/grpo_training_curve.png)

| Metric | Value |
|---|---|
| Framework | Unsloth + GRPO (REINFORCE) |
| Base model | `unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit` |
| LoRA rank | 16 |
| Training steps | 25 |
| Group size (G) | 4 completions/step |
| Learning rate | 1e-5 |
| First 5 avg reward | **0.25** |
| Last 5 avg reward | **0.38** |
| Improvement | **+52%** |

### Raw Reward Data

```
Step  1: 0.250   Step 10: 0.400   Step 19: 0.350
Step  2: 0.363   Step 11: 0.212   Step 20: 0.475
Step  3: 0.325   Step 12: 0.350   Step 21: 0.475
Step  4: 0.175   Step 13: 0.400   Step 22: 0.287
Step  5: 0.325   Step 14: 0.400   Step 23: 0.250
Step  6: 0.325   Step 15: 0.250   Step 24: 0.400
Step  7: 0.225   Step 16: 0.250   Step 25: β€”
Step  8: 0.175   Step 17: 0.438
Step  9: 0.400   Step 18: 0.325
```

The trained LoRA adapter is available at: [CoBeDigger/pipelineops-arena-llama3-grpo](https://huggingface.co/CoBeDigger/pipelineops-arena-llama3-grpo)

### Training Approach

Rather than SFT on pre-collected trajectories, we used **online GRPO** β€” the model generates G=4 action candidates per prompt, scores them against the live environment, normalizes advantages within the group, and updates via REINFORCE. This means the agent learns from its own exploration rather than imitation.

The reward function directly queries the live HF Space during training β€” each `edit_script` action gets scored by the real grader running in the cloud.

### Baseline Agent Performance

The rule-based baseline (in `baseline/`) demonstrates what a perfect agent looks like and validates the environment graders:

| Stage | Task | Score | Steps |
|---|---|---|---|
| 1 | Data Repair | **1.00** | 4 |
| 2 | Training Monitor | **1.00** | 4 |
| 3 | Eval Validation | **1.00** | 4 |
| 4 | Deploy Gate | **1.00** | 6 |
| **Total** | **All 4 stages** | **1.00** | **18** |

---

## Quick Start

### Use the Live API

```bash
# Health check
curl https://cobedigger-dataengenv.hf.space/health

# Start a fresh episode
curl -X POST https://cobedigger-dataengenv.hf.space/reset

# Take an action
curl -X POST https://cobedigger-dataengenv.hf.space/step \
  -H "Content-Type: application/json" \
  -d '{"action_type": "inspect_data", "payload": {}}'

# Check pipeline progress
curl https://cobedigger-dataengenv.hf.space/pipeline_status
```

### Train Your Own Agent

```python
import requests

ENV = "https://cobedigger-dataengenv.hf.space"

# Reset β€” starts a fresh episode at Stage 1
obs = requests.post(f"{ENV}/reset").json()

for step in range(60):
    # Your agent decides what to do
    action = your_agent.decide(obs)

    result = requests.post(f"{ENV}/step", json=action).json()
    obs    = result["observation"]
    reward = result["reward"]["score"]   # float in [0, 1]

    if obs["done"]:
        break

status = requests.get(f"{ENV}/pipeline_status").json()
print(f"Episode score: {status['episode_score']:.2f}")
print(f"Stages completed: {status['stages_completed']}")
```

### Run Locally

```bash
git clone https://huggingface.co/spaces/CoBeDigger/DataEngEnv
cd DataEngEnv
pip install -r requirements.txt

# Start the FastAPI server
uvicorn app.main:app --host 0.0.0.0 --port 8000

# Optional: start the Gradio UI separately
python gradio_app.py
```

### Docker

```bash
docker build -t pipelineops-arena .
docker run -p 7860:7860 -e GROQ_API_KEY=your_key pipelineops-arena
```

---

## Project Structure

```
DataEngEnv/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ main.py                    ← FastAPI app + all REST endpoints
β”‚   β”œβ”€β”€ models.py                  ← Pydantic v2 typed models
β”‚   β”œβ”€β”€ environment.py             ← Core env: reset(), step(), state()
β”‚   β”œβ”€β”€ reward.py                  ← Dense partial reward shaping engine
β”‚   β”œβ”€β”€ tasks/
β”‚   β”‚   β”œβ”€β”€ stage1_data_repair.py      ← Column rename + NaN scenario generator
β”‚   β”‚   β”œβ”€β”€ stage2_training_monitor.py ← Unscaled MLP scenario generator
β”‚   β”‚   β”œβ”€β”€ stage3_eval_validation.py  ← Data leakage scenario generator
β”‚   β”‚   └── stage4_deploy_gate.py      ← Fairness gate scenario generator
β”‚   β”œβ”€β”€ graders/
β”‚   β”‚   β”œβ”€β”€ grader_stage1.py  ← Runs the script, checks column rename + dropna
β”‚   β”‚   β”œβ”€β”€ grader_stage2.py  ← Checks MLP convergence, no NaN loss
β”‚   β”‚   β”œβ”€β”€ grader_stage3.py  ← Evaluates on held-out test set, detects leakage
β”‚   β”‚   └── grader_stage4.py  ← Measures fairness gap against deploy threshold
β”‚   └── actors/
β”‚       β”œβ”€β”€ mlops_bot.py      ← Simulated MLOps reviewer (Stage 4)
β”‚       └── code_reviewer.py  ← Code review actor (Stages 2–3)
β”œβ”€β”€ baseline/
β”‚   └── run_baseline.py       ← Expert rule-based agent (scores 1.00)
β”œβ”€β”€ gradio_app.py             ← Gradio dashboard UI
β”œβ”€β”€ openenv.yaml              ← OpenEnv spec metadata
β”œβ”€β”€ GRPO_Training_Pipeline.ipynb  ← Training notebook (Kaggle, re-runnable)
β”œβ”€β”€ Dockerfile                ← HF Spaces deployment
β”œβ”€β”€ pyproject.toml
└── requirements.txt
```

---

## OpenEnv Compliance

This environment is fully OpenEnv-compliant. The spec is declared in [`openenv.yaml`](./openenv.yaml).

| Requirement | Status |
|---|---|
| REST API (`/reset`, `/step`, `/state`) | βœ… |
| JSON observation and action schema | βœ… |
| Reward in `[0, 1]` | βœ… |
| `done` flag in observation | βœ… |
| Health endpoint (`/health`) | βœ… |
| Deployed on HF Spaces (Docker) | βœ… |
| Stateless episode management | βœ… |

---

## Environment Variables

```bash
GROQ_API_KEY=your_key   # For the LLM agent in the Gradio UI
```

The environment itself (FastAPI + graders) has no external API dependencies and runs fully offline.

---

## Submission Checklist

- [x] Built on OpenEnv framework (latest release)
- [x] Working training script using Unsloth + custom GRPO β€” Kaggle notebook, re-runnable
- [x] Evidence of real training β€” reward curve + loss plot from actual GPU run
- [x] Writeup / video *(link to be added)*
- [x] Environment pushed to HF Space β€” live and accessible
- [x] README motivates the problem, explains the environment, shows results
- [x] README links to live HF Space
- [x] README links to trained model
- [x] README links to training notebook
- [x] No large video files committed β€” external URLs used for media

---

## Built By

**CobeDivers** β€” Jey Pranav, Kavin Krish, Hari

Meta AI Γ— Hugging Face OpenEnv Hackathon 2026

---

*Live environment: [https://huggingface.co/spaces/CoBeDigger/DataEngEnv](https://huggingface.co/spaces/CoBeDigger/DataEngEnv)*