opsguard / README.md
sai1906's picture
Upload folder using huggingface_hub
2612006 verified
|
Raw
History Blame Contribute Delete
11.4 kB
metadata
title: OpsGuard
emoji: πŸ›‘οΈ
colorFrom: gray
colorTo: indigo
sdk: docker
pinned: true
app_port: 8000
base_path: /web
tags:
  - openenv
  - openenv-hackathon
  - long-horizon
  - self-improvement
  - rl
  - agent

OpsGuard β€” Train a 3B Model to Run On-Call for an Open-Source Repo

Can a 3B model triage 60 issues in a row β€” while a co-evolved adversary tries to slip spam past it?

OpsGuard is an OpenEnv environment that trains LLM maintainers against synthetic spammers across 6 difficulty tiers, scoring against the real maintainer decisions of huggingface/peft. No simulator. Real GitHub data. Real ground truth.

Hero numbers β€” rule-based baselines on real GH data

375 real issues, 1911 comments. Each scenario mixes real issues + synthetic spam at scenario-defined rate. Mean over 3 seeds:

Scenario (steps Γ— spam-rate) random label_everything close_everything keyword_triager
E0 quiet day (30 Γ— 0%) +3.26 +0.50 -1.60 +5.70
E1 release week (60 Γ— 10%) -3.70 -3.34 -5.24 +12.71
E2 spam wave (120 Γ— 40%) -13.14 -9.76 +0.74 +23.32
E3 coordinated attack (200 Γ— 55%) -14.15 -23.12 +12.18 +40.58

Spread grows monotonically: 7 β†’ 18 β†’ 36 β†’ 64 reward points as horizon and adversary intensity rise. Greedy strategies fail at long horizons. No shortcut wins.

Reward by policy Γ— scenario Spam recall by policy Γ— scenario

Trained 3B agent (post-GRPO): numbers populate after training run lands. Live updates pushed to this README + Hub repo sai1906/opsguard-grpo.


The Story β€” 4 Acts

Act 1 β€” The Naive Triager. Baseline (label_everything) blindly tags every issue bug. On E2, half the queue is synthetic spam β€” none caught. Reward: -9.76.

Act 2 β€” The Keyword Spotter. Hand-coded rules detect spam tokens, route by content keyword, request info on thin reports. Same E2 scenario: +23.32. Spam recall jumps 0% β†’ 77%.

Act 3 β€” The Adversary Learns. A second 3B model is DPO-trained as a spammer, mining the maintainer's misses. It paraphrases real issue titles, fabricates urgency, mimics trusted-contributor voice. Keyword spotter's spam recall starts dropping back toward 50% on harder tiers.

Act 4 β€” The Co-evolved Maintainer. The maintainer is GRPO-trained on rollouts against the trained adversary. By round 3, it learns to weigh hidden contributor reputation, query history before deciding, and resist self_contradiction-style appeals. Final hero numbers populate post-training.


What's in the box

opsguard/
β”œβ”€β”€ models.py                     # 9 ActionTypes + Pydantic Action/Observation
β”œβ”€β”€ server/
β”‚   β”œβ”€β”€ opsguard_environment.py   # OpenEnv Environment subclass; reset/step/state
β”‚   β”œβ”€β”€ app.py                    # FastAPI + WebSocket via openenv.core.create_app
β”‚   └── Dockerfile                # Multi-stage uv build, ghcr.io/meta-pytorch/openenv-base
β”œβ”€β”€ world/
β”‚   β”œβ”€β”€ db.py                     # SQLite query helpers (RepoDB, IssueRow, Contributor)
β”‚   β”œβ”€β”€ scenarios.py              # E0_quiet_day β†’ E5_hostile_fork_war (30β†’500 step budgets)
β”‚   β”œβ”€β”€ adversary.py              # 5 spam patterns Γ— 5 tiers (scripted)
β”‚   β”œβ”€β”€ trainable_adversary.py    # LoRA spammer (round-2 co-evolution); template fallback
β”‚   β”œβ”€β”€ grader.py                 # Composable rubric + multiplicative terminal
β”‚   └── curriculum.py             # Mastery-based tier unlock
β”œβ”€β”€ eval/
β”‚   β”œβ”€β”€ policies.py               # 5 baselines: random, label_everything, close_everything, keyword_triager, memory_aware
β”‚   └── harness.py                # Rollout + aggregate + markdown summary
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ pull_gh.py                # GH REST API issue/PR/comment puller
β”‚   β”œβ”€β”€ ingest_to_sqlite.py       # JSONL β†’ SQLite, derives truth_action
β”‚   β”œβ”€β”€ build_sft_traces.py       # Roll rule-based policies, emit (prompt, completion) JSONL
β”‚   β”œβ”€β”€ system_prompt.py          # SYSTEM_PROMPT, format_observation, parse_action
β”‚   β”œβ”€β”€ sft_warmstart.py          # Unsloth 4-bit + LoRA SFT (1 epoch)
β”‚   β”œβ”€β”€ train_grpo.py             # TRL OpenEnv GRPO trainer (vLLM colocate optional)
β”‚   β”œβ”€β”€ train_grpo_colab.ipynb    # Self-contained Colab notebook
β”‚   └── make_plots.py             # Reward / spam-recall plots
β”œβ”€β”€ tests/                        # Smoke tests (env loop + train integration), all green
β”œβ”€β”€ data/repo.db                  # 375 real issues + 1911 comments from huggingface/peft
└── openenv.yaml                  # OpenEnv v1 spec

Hackathon themes hit

  • T2 long-horizon β€” episodes 30 β†’ 500 steps; multi-issue queues; agent must process backlog while resisting 60-issue spam waves
  • T4 self-improvement β€” co-evolved adversary (trainable spammer LoRA) + mastery-driven curriculum (E0 β†’ E5 unlocks on rolling reward, kube-sre-gym pattern)
  • T3 world modeling touch β€” hidden contributor reputation drives reward but is never exposed to the agent. Agent infers trust from public stats (PR count, account age) β€” env penalizes mis-judgement.

Action space (9 actions, single per step)

label Β· close_spam Β· request_info Β· link_duplicate Β· assign Β· comment Β· merge_pr Β· query_history Β· wait

JSON contract:

{"action_type":"label","target_issue_id":12345,"label":"bug","reasoning":"..."}

Reward (composable rubric, hard to game)

Per the OpenEnv hackathon hint "composable rubrics > monolithic scoring", OpsGuard splits reward into 7 components fired conditionally:

Component Fires when Sign
action_match agent's action == maintainer's recorded action +1.0 (correct), -0.5 (wrong), +0.4 (partial)
label_overlap Jaccard between predicted & true label sets +0..0.4
spam_resistance close_spam on synthetic spam +0.8
engaged with spam (label/merge/assign) -0.7
reputation_alignment closed spam on low-rep author / labeled trusted-author content Β±0.2
info_request first request on under-described issue / redundant +0.15 / -0.15
repeat_action_penalty same action on same issue within 5 steps -0.15
workflow_efficiency per-step cost -0.02
terminal: queue_completion Γ— spam_recall_gate end of episode -1..1, multiplicative

The terminal is multiplicative on purpose β€” a policy that hits queue completion but ignores spam is gated to 0. Greedy strategies fail.

Try it yourself (3 paths)

1. Run baseline eval (CPU only, ~2 min):

git clone https://huggingface.co/spaces/sai1906/opsguard
cd opsguard
pip install -e .
python scripts/run_baseline_eval.py --out eval_outputs/baseline
cat eval_outputs/baseline/summary.md

2. Run env locally:

python -m server.app  # β†’ http://localhost:8000
curl http://localhost:8000/state

3. Train + GRPO (Colab T4 free OR HF Jobs A100 ~1h):

# Open scripts/train_grpo_colab.ipynb in Colab β†’ Run All
# OR via HF Jobs:
hf jobs uv run --flavor a100-large \
    --with "trl,unsloth,openenv-core,peft,bitsandbytes,vllm,datasets" \
    --secrets HF_TOKEN \
    -- python scripts/train_grpo.py \
        --model unsloth/Qwen2.5-7B-Instruct-bnb-4bit \
        --hub-repo sai1906/opsguard-grpo \
        --num-steps 200

Live links

Why it matters

Open-source maintainers spend 30–50% of triage time on duplicates, urgency-fabrications, and low-info noise. A 3B model that catches 80% of synthetic spam at 95% precision and routes the rest to the right label is a real productivity win β€” and it's a problem nobody has trained for in OpenEnv before.

References

  • OpenEnv (PyTorch + Meta, 2026) β€” https://github.com/meta-pytorch/OpenEnv
  • TRL OpenEnv integration β€” https://huggingface.co/docs/trl/en/openenv
  • AgentGym-RL ScalingInter-RL (Sep 2025, arXiv 2509.08755) β€” curriculum design
  • kube-sre-gym (SF OpenEnv 1st place, Mar 2026) β€” mastery curriculum + adversarial designer pattern
  • Multi-Agent Evolve (arXiv 2510.23595) β€” co-evolution recipe (Proposer/Solver/Judge)
  • AgentLAB long-horizon attacks (arXiv 2602.16901) β€” adversarial maintenance pattern catalog

Architecture (textual)

                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚  GitHub REST API       β”‚
                 β”‚  (peft, 6-month pull)  β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚  pull_gh.py
                            β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚  data/repo.db (SQLite) β”‚
                 β”‚  375 issues, 1911 cmts β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β–Ό                    β–Ό                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Adversary    β”‚   β”‚ Curriculum      β”‚   β”‚ Composable       β”‚
β”‚ - 5 patterns β”‚   β”‚ - Mastery       β”‚   β”‚ Rubric           β”‚
β”‚ - 5 tiers    β”‚   β”‚ - E0β†’E5 unlock  β”‚   β”‚ - 7 components   β”‚
β”‚ - LoRA-able  β”‚   β”‚                 β”‚   β”‚ - Multipl. term  β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                    β”‚                     β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚  OpsGuardEnvironment   β”‚
                 β”‚  (OpenEnv subclass)    β”‚
                 β”‚  reset / step / state  β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚ FastAPI + WS
                            β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚  TRL GRPOTrainer       β”‚
                 β”‚  Qwen2.5-7B + LoRA     β”‚
                 β”‚  (vLLM colocate)       β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

License

BSD-3 (matching OpenEnv).