Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ dist/
build/
missionctrl_checkpoints/
reward_curve.png
.codex
AGENTS.md
graphify-out
221 changes: 221 additions & 0 deletions colab_notebook.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"gpuType": "A100",
"name": "MissionCtrl_Training.ipynb"
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# MissionCtrl — One-Click Training Notebook\n",
"\n",
"**OpenEnv Hackathon Round 2**\n\n",
"This notebook trains an OverseerAgent to detect hallucinations in a multi-agent fleet using GRPO + Unsloth.\n\n",
"**Runtime required**: A100 GPU (HuggingFace compute credits)\n",
"**Expected training time**: ~2.5 hours\n",
"**Expected final reward**: 0.80+"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 1: Install dependencies ──────────────────────────────────────────────\n",
"!pip install unsloth trl openenv transformers datasets accelerate matplotlib --quiet\n",
"!pip install --upgrade bitsandbytes --quiet\n",
"print('✅ Dependencies installed')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 2: Clone / upload project files ─────────────────────────────────────\n",
"# Option A: Clone from your repo\n",
"# !git clone https://github.com/your-username/missionctrl .\n",
"\n",
"# Option B: Upload environment.py, reward_model.py, train.py manually\n",
"# (Use the Files panel on the left in Colab)\n",
"\n",
"# Verify files are present\n",
"import os\n",
"required = ['environment.py', 'reward_model.py', 'train.py']\n",
"for f in required:\n",
" status = '✅' if os.path.exists(f) else '❌ MISSING'\n",
" print(f' {status} {f}')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 3: Verify GPU ────────────────────────────────────────────────────────\n",
"import torch\n",
"print(f'GPU: {torch.cuda.get_device_name(0)}')\n",
"print(f'VRAM: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB')\n",
"assert torch.cuda.is_available(), 'No GPU detected — switch runtime to A100'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 4: Smoke-test the environment ───────────────────────────────────────\n",
"from environment import MissionCtrlEnv, OverseerAction\n",
"from reward_model import compute_reward, reward_breakdown\n",
"\n",
"env = MissionCtrlEnv(difficulty='medium', num_tasks=3, seed=42)\n",
"obs, info = env.reset()\n",
"\n",
"print('Environment smoke test:')\n",
"print(f' Tasks loaded: {len(obs[\"task_board\"])}')\n",
"print(f' Agent messages: {len(obs[\"recent_messages\"])}')\n",
"\n",
"# Test a FLAG action\n",
"first_task = obs['task_board'][0]['task_id']\n",
"action = OverseerAction('FLAG', task_id=first_task, evidence='fabricated citation detected')\n",
"obs2, reward, terminated, truncated, info = env.step(action)\n",
"print(f' Step reward: {reward:.3f}')\n",
"print(f' Info: {info}')\n",
"print('✅ Environment working correctly')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 5: Run pre-training baseline ────────────────────────────────────────\n",
"from train import run_baseline\n",
"\n",
"baseline_reward = run_baseline()\n",
"print(f'\\n🎯 Baseline established: {baseline_reward:.3f}')\n",
"print('This is your starting floor. Training target: 0.75+')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 6: Set HuggingFace credentials ──────────────────────────────────────\n",
"from huggingface_hub import login\n",
"# Either paste your token or use the Colab secrets panel (recommended)\n",
"login(token='YOUR_HF_TOKEN_HERE') # or: login() # interactive prompt\n",
"\n",
"# Set your repo name in train.py before running Cell 7\n",
"import train\n",
"train.HF_REPO = 'your-hf-username/missionctrl-overseer' # ← change this\n",
"print(f'Will push to: {train.HF_REPO}')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 7: TRAIN ─────────────────────────────────────────────────────────────\n",
"# Full 3-phase curriculum with reward-gated advancement.\n",
"# Watch the reward climb from ~0.31 → 0.80+\n",
"from train import train\n",
"\n",
"history = train()\n",
"print('\\n🏆 Training complete!')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 8: Display reward curve ─────────────────────────────────────────────\n",
"from IPython.display import Image\n",
"Image('./missionctrl_checkpoints/reward_curve.png')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 9: Before/After demo comparison ─────────────────────────────────────\n",
"# Load trained model and compare with baseline behavior\n",
"from unsloth import FastLanguageModel\n",
"from environment import MissionCtrlEnv, parse_action\n",
"from train import build_user_prompt, SYSTEM_PROMPT\n",
"import torch\n",
"\n",
"model, tokenizer = FastLanguageModel.from_pretrained(\n",
" './missionctrl_checkpoints/final',\n",
" max_seq_length=4096,\n",
" load_in_4bit=True,\n",
")\n",
"FastLanguageModel.for_inference(model)\n",
"\n",
"# Use a known hallucinated episode (seed 0, hard difficulty)\n",
"env = MissionCtrlEnv(difficulty='hard', num_tasks=4, seed=0)\n",
"obs, _ = env.reset()\n",
"\n",
"prompt = tokenizer.apply_chat_template(\n",
" [\n",
" {'role': 'system', 'content': SYSTEM_PROMPT},\n",
" {'role': 'user', 'content': build_user_prompt(obs)},\n",
" ],\n",
" tokenize=False,\n",
" add_generation_prompt=True,\n",
")\n",
"inputs = tokenizer(prompt, return_tensors='pt', truncation=True, max_length=3584).to(model.device)\n",
"\n",
"with torch.no_grad():\n",
" out = model.generate(**inputs, max_new_tokens=256, temperature=0.1, do_sample=True)\n",
"\n",
"completion = tokenizer.decode(out[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True)\n",
"\n",
"print('=== TRAINED MODEL OUTPUT ===')\n",
"print(completion)\n",
"print(f'\\nParsed action: {parse_action(completion)}')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ── Cell 10: Final evaluation run ────────────────────────────────────────────\n",
"from train import evaluate\n",
"\n",
"final_reward, metrics = evaluate(model, tokenizer, difficulty='hard', num_tasks=4, n_episodes=20)\n",
"\n",
"print('\\n=== FINAL EVALUATION SUMMARY ===')\n",
"print(f' Overall reward: {metrics[\"mean_reward\"]:.3f} ± {metrics[\"std_reward\"]:.3f}')\n",
"print(f' Detection rate: {metrics[\"mean_detect_rate\"]:.1%}')\n",
"print(f' False positive rate: {metrics[\"mean_fp_rate\"]:.1%}')"
]
}
]
}
Loading