Commit ·
bfbbcd1
1
Parent(s): f8cae2a
Fix duplicate WebSocket log output; update benchmark numbers to latest run (avg 75.9%, ~10min)
Browse files- README.md +4 -4
- inference.py +16 -4
- scripts/test_local.py +2 -2
- server/app.py +17 -16
README.md
CHANGED
|
@@ -72,7 +72,7 @@ export MODEL_NAME="meta-llama/Llama-3.1-8B-Instruct"
|
|
| 72 |
export HF_TOKEN="hf_your_token_here"
|
| 73 |
export ENV_BASE_URL="https://therubberduckdebuggers-cascade-containment.hf.space"
|
| 74 |
|
| 75 |
-
# Full LLM+GRPO evaluation (~
|
| 76 |
python inference.py
|
| 77 |
|
| 78 |
# Local validation + greedy benchmark
|
|
@@ -214,9 +214,9 @@ Results from `baseline/run.py` (Llama 3.3 70B via Groq, runtime ~19.8 minutes):
|
|
| 214 |
| Task | Greedy (D0) | LLM+GRPO | Lift |
|
| 215 |
| --- | --- | --- | --- |
|
| 216 |
| Easy | 42.8% (breach 60%) | **90.8%** | +48pp |
|
| 217 |
-
| Medium | 42.7% (breach 80%) | **
|
| 218 |
-
| Hard | 33.0% (breach 100%) | **
|
| 219 |
-
| **Average** | **39.5%** | **
|
| 220 |
|
| 221 |
The greedy baseline (always allocates to D0) scores 33–43% with 60–100% hospital breach rates — no trivial exploit path. LLM+GRPO reaches 66–91% with zero breaches, demonstrating that genuine triage reasoning is required and rewarded.
|
| 222 |
|
|
|
|
| 72 |
export HF_TOKEN="hf_your_token_here"
|
| 73 |
export ENV_BASE_URL="https://therubberduckdebuggers-cascade-containment.hf.space"
|
| 74 |
|
| 75 |
+
# Full LLM+GRPO evaluation (~10 minutes, emits [START][STEP][END] logs)
|
| 76 |
python inference.py
|
| 77 |
|
| 78 |
# Local validation + greedy benchmark
|
|
|
|
| 214 |
| Task | Greedy (D0) | LLM+GRPO | Lift |
|
| 215 |
| --- | --- | --- | --- |
|
| 216 |
| Easy | 42.8% (breach 60%) | **90.8%** | +48pp |
|
| 217 |
+
| Medium | 42.7% (breach 80%) | **78.0%** | +35pp |
|
| 218 |
+
| Hard | 33.0% (breach 100%) | **61.1%** | +28pp |
|
| 219 |
+
| **Average** | **39.5%** | **75.9%** | **+36pp** |
|
| 220 |
|
| 221 |
The greedy baseline (always allocates to D0) scores 33–43% with 60–100% hospital breach rates — no trivial exploit path. LLM+GRPO reaches 66–91% with zero breaches, demonstrating that genuine triage reasoning is required and rewarded.
|
| 222 |
|
inference.py
CHANGED
|
@@ -73,6 +73,8 @@ def run_rollout(
|
|
| 73 |
rewards = []
|
| 74 |
|
| 75 |
log_start(task=f"{task_name}-r{rollout_idx}", env=BENCHMARK, model=MODEL_NAME)
|
|
|
|
|
|
|
| 76 |
|
| 77 |
try:
|
| 78 |
while not done:
|
|
@@ -85,7 +87,9 @@ def run_rollout(
|
|
| 85 |
result = env.step(action)
|
| 86 |
except Exception as e:
|
| 87 |
log_step(step=step + 1, action=action_str, reward=0.0, done=True, error=str(e)[:80])
|
| 88 |
-
|
|
|
|
|
|
|
| 89 |
return total_reward, step, trajectory, 0.0
|
| 90 |
|
| 91 |
next_obs = result.observation
|
|
@@ -96,7 +100,11 @@ def run_rollout(
|
|
| 96 |
|
| 97 |
rewards.append(reward)
|
| 98 |
trajectory.append({"obs": obs, "action": action, "reward": reward})
|
| 99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
obs = next_obs
|
| 102 |
if done:
|
|
@@ -114,10 +122,14 @@ def run_rollout(
|
|
| 114 |
success = score >= 0.40
|
| 115 |
|
| 116 |
except Exception:
|
| 117 |
-
|
|
|
|
|
|
|
| 118 |
return total_reward, step, trajectory, 0.0
|
| 119 |
|
| 120 |
-
|
|
|
|
|
|
|
| 121 |
return total_reward, step, trajectory, score
|
| 122 |
|
| 123 |
|
|
|
|
| 73 |
rewards = []
|
| 74 |
|
| 75 |
log_start(task=f"{task_name}-r{rollout_idx}", env=BENCHMARK, model=MODEL_NAME)
|
| 76 |
+
seen_steps: set = set() # deduplicate WebSocket replay artefacts
|
| 77 |
+
end_logged: bool = False
|
| 78 |
|
| 79 |
try:
|
| 80 |
while not done:
|
|
|
|
| 87 |
result = env.step(action)
|
| 88 |
except Exception as e:
|
| 89 |
log_step(step=step + 1, action=action_str, reward=0.0, done=True, error=str(e)[:80])
|
| 90 |
+
if not end_logged:
|
| 91 |
+
end_logged = True
|
| 92 |
+
log_end(success=False, steps=step, score=0.0, rewards=rewards)
|
| 93 |
return total_reward, step, trajectory, 0.0
|
| 94 |
|
| 95 |
next_obs = result.observation
|
|
|
|
| 100 |
|
| 101 |
rewards.append(reward)
|
| 102 |
trajectory.append({"obs": obs, "action": action, "reward": reward})
|
| 103 |
+
|
| 104 |
+
# Only log each step number once — WebSocket can replay buffered responses
|
| 105 |
+
if step not in seen_steps:
|
| 106 |
+
seen_steps.add(step)
|
| 107 |
+
log_step(step=step, action=action_str, reward=reward, done=done, error=None)
|
| 108 |
|
| 109 |
obs = next_obs
|
| 110 |
if done:
|
|
|
|
| 122 |
success = score >= 0.40
|
| 123 |
|
| 124 |
except Exception:
|
| 125 |
+
if not end_logged:
|
| 126 |
+
end_logged = True
|
| 127 |
+
log_end(success=False, steps=step, score=0.0, rewards=rewards)
|
| 128 |
return total_reward, step, trajectory, 0.0
|
| 129 |
|
| 130 |
+
if not end_logged:
|
| 131 |
+
end_logged = True
|
| 132 |
+
log_end(success=success, steps=step, score=score, rewards=rewards)
|
| 133 |
return total_reward, step, trajectory, score
|
| 134 |
|
| 135 |
|
scripts/test_local.py
CHANGED
|
@@ -11,8 +11,8 @@ from server.grader import grade_trajectory
|
|
| 11 |
# LLM+GRPO reference scores — update this dict after each baseline/run.py session.
|
| 12 |
GRPO_SCORES = {
|
| 13 |
"easy": {"score": 0.8848, "containment": 1.000, "hospital": 0.996, "efficiency": 0.900},
|
| 14 |
-
"medium": {"score": 0.
|
| 15 |
-
"hard": {"score": 0.
|
| 16 |
}
|
| 17 |
|
| 18 |
|
|
|
|
| 11 |
# LLM+GRPO reference scores — update this dict after each baseline/run.py session.
|
| 12 |
GRPO_SCORES = {
|
| 13 |
"easy": {"score": 0.8848, "containment": 1.000, "hospital": 0.996, "efficiency": 0.900},
|
| 14 |
+
"medium": {"score": 0.7798, "containment": 0.533, "hospital": 0.974, "efficiency": 0.960},
|
| 15 |
+
"hard": {"score": 0.6110, "containment": 0.420, "hospital": 0.940, "efficiency": 0.520},
|
| 16 |
}
|
| 17 |
|
| 18 |
|
server/app.py
CHANGED
|
@@ -525,7 +525,7 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 525 |
<div class="brand-icon">🦠</div>
|
| 526 |
<div>
|
| 527 |
<div class="brand-name">Cascade Containment</div>
|
| 528 |
-
<div class="brand-sub">OpenEnv Benchmark · Meta PyTorch Hackathon × SST 2026 · LLM avg 75.
|
| 529 |
</div>
|
| 530 |
</div>
|
| 531 |
<div class="header-right">
|
|
@@ -568,7 +568,7 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 568 |
</div>
|
| 569 |
<div class="hero-stats">
|
| 570 |
<div class="hs-item"><div class="hs-val">3</div><div class="hs-label">Task levels</div></div>
|
| 571 |
-
<div class="hs-item"><div class="hs-val">75.
|
| 572 |
<div class="hs-item"><div class="hs-val">+36pp</div><div class="hs-label">vs greedy</div></div>
|
| 573 |
</div>
|
| 574 |
</div>
|
|
@@ -766,7 +766,8 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 766 |
Llama 3.3 70B via Groq, with GRPO-style episodic memory across 2–3 rollouts per task.
|
| 767 |
Each rollout injects advantage-gated memory from prior rollouts into the prompt.
|
| 768 |
Reproduced by running <code style="color:var(--text);">python baseline/run.py</code>.
|
| 769 |
-
|
|
|
|
| 770 |
</div>
|
| 771 |
<div class="grid-3" style="margin-bottom:1rem;">
|
| 772 |
<div class="card-sm" style="border-top:2px solid var(--green);">
|
|
@@ -781,7 +782,7 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 781 |
</div>
|
| 782 |
<div class="card-sm" style="border-top:2px solid var(--amber);">
|
| 783 |
<div style="font-size:0.62rem;letter-spacing:0.08em;text-transform:uppercase;color:var(--amber);margin-bottom:0.5rem;">Medium · 3 rollouts</div>
|
| 784 |
-
<div style="font-family:var(--serif);font-size:2rem;font-weight:700;color:#fff;line-height:1;">
|
| 785 |
<div style="font-size:0.68rem;color:var(--muted);margin-top:0.25rem;">Best of 4 · no breach</div>
|
| 786 |
<div style="margin-top:0.75rem;display:flex;flex-direction:column;gap:0.3rem;">
|
| 787 |
<div style="display:flex;justify-content:space-between;font-size:0.68rem;"><span style="color:var(--muted);">Containment</span><span>42%</span></div>
|
|
@@ -791,7 +792,7 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 791 |
</div>
|
| 792 |
<div class="card-sm" style="border-top:2px solid var(--red);">
|
| 793 |
<div style="font-size:0.62rem;letter-spacing:0.08em;text-transform:uppercase;color:var(--red);margin-bottom:0.5rem;">Hard · 3 rollouts</div>
|
| 794 |
-
<div style="font-family:var(--serif);font-size:2rem;font-weight:700;color:#fff;line-height:1;">
|
| 795 |
<div style="font-size:0.68rem;color:var(--muted);margin-top:0.25rem;">Best of 4 · no breach</div>
|
| 796 |
<div style="margin-top:0.75rem;display:flex;flex-direction:column;gap:0.3rem;">
|
| 797 |
<div style="display:flex;justify-content:space-between;font-size:0.68rem;"><span style="color:var(--muted);">Containment</span><span>51%</span></div>
|
|
@@ -811,13 +812,13 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 811 |
</tr>
|
| 812 |
<tr>
|
| 813 |
<td><span class="badge badge-amber">Medium</span></td>
|
| 814 |
-
<td>
|
| 815 |
-
<td><strong style="color:var(--amber);">
|
| 816 |
</tr>
|
| 817 |
<tr>
|
| 818 |
<td><span class="badge badge-red">Hard</span></td>
|
| 819 |
-
<td>
|
| 820 |
-
<td><strong style="color:var(--red);">
|
| 821 |
</tr>
|
| 822 |
</table>
|
| 823 |
</div>
|
|
@@ -848,21 +849,21 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 848 |
</tr>
|
| 849 |
<tr>
|
| 850 |
<td><span class="badge badge-amber">Medium</span></td>
|
| 851 |
-
<td style="color:var(--muted);">42.7%</td><td><strong>
|
| 852 |
-
<td class="pos">+
|
| 853 |
<td><span class="badge badge-green">Strong</span></td>
|
| 854 |
<td><span class="badge badge-green">None — 8% eff, 80% breach</span></td>
|
| 855 |
</tr>
|
| 856 |
<tr>
|
| 857 |
<td><span class="badge badge-red">Hard</span></td>
|
| 858 |
-
<td style="color:var(--muted);">33.0%</td><td><strong>
|
| 859 |
-
<td class="pos">+
|
| 860 |
<td><span class="badge badge-green">Strong</span></td>
|
| 861 |
<td><span class="badge badge-green">None — 0% eff, 100% breach</span></td>
|
| 862 |
</tr>
|
| 863 |
<tr style="border-top:1px solid var(--border2);">
|
| 864 |
<td><strong>Average</strong></td>
|
| 865 |
-
<td style="color:var(--muted);">39.5%</td><td><strong>75.
|
| 866 |
<td class="pos"><strong>+36pp</strong></td>
|
| 867 |
<td><span class="badge badge-green">Strong</span></td>
|
| 868 |
<td><span class="badge badge-green">No exploits found</span></td>
|
|
@@ -883,7 +884,7 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 883 |
<div style="display:flex;flex-direction:column;gap:0.45rem;">
|
| 884 |
<div><div style="display:flex;justify-content:space-between;font-size:0.68rem;margin-bottom:0.2rem;"><span style="color:var(--muted);">Greedy (D0)</span><span>43%</span></div><div class="bar-track" style="height:8px;"><div class="bar-fill" style="width:43%;background:var(--dim);"></div></div></div>
|
| 885 |
<div><div style="display:flex;justify-content:space-between;font-size:0.68rem;margin-bottom:0.2rem;"><span style="color:var(--amber);">LLM+GRPO</span><span>75%</span></div><div class="bar-track" style="height:8px;"><div class="bar-fill" style="width:75%;background:var(--amber);"></div></div></div>
|
| 886 |
-
<div style="font-size:0.68rem;color:var(--muted);">Lift: <span style="color:var(--amber);font-weight:700;">+
|
| 887 |
</div>
|
| 888 |
</div>
|
| 889 |
<div class="card-sm">
|
|
@@ -891,7 +892,7 @@ body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:1
|
|
| 891 |
<div style="display:flex;flex-direction:column;gap:0.45rem;">
|
| 892 |
<div><div style="display:flex;justify-content:space-between;font-size:0.68rem;margin-bottom:0.2rem;"><span style="color:var(--muted);">Greedy (D0)</span><span>33%</span></div><div class="bar-track" style="height:8px;"><div class="bar-fill" style="width:33%;background:var(--dim);"></div></div></div>
|
| 893 |
<div><div style="display:flex;justify-content:space-between;font-size:0.68rem;margin-bottom:0.2rem;"><span style="color:var(--red);">LLM+GRPO</span><span>63%</span></div><div class="bar-track" style="height:8px;"><div class="bar-fill" style="width:63%;background:var(--red);"></div></div></div>
|
| 894 |
-
<div style="font-size:0.68rem;color:var(--muted);">Lift: <span style="color:var(--red);font-weight:700;">+
|
| 895 |
</div>
|
| 896 |
</div>
|
| 897 |
</div>
|
|
|
|
| 525 |
<div class="brand-icon">🦠</div>
|
| 526 |
<div>
|
| 527 |
<div class="brand-name">Cascade Containment</div>
|
| 528 |
+
<div class="brand-sub">OpenEnv Benchmark · Meta PyTorch Hackathon × SST 2026 · LLM avg 75.9%</div>
|
| 529 |
</div>
|
| 530 |
</div>
|
| 531 |
<div class="header-right">
|
|
|
|
| 568 |
</div>
|
| 569 |
<div class="hero-stats">
|
| 570 |
<div class="hs-item"><div class="hs-val">3</div><div class="hs-label">Task levels</div></div>
|
| 571 |
+
<div class="hs-item"><div class="hs-val">75.9%</div><div class="hs-label">LLM+GRPO avg</div></div>
|
| 572 |
<div class="hs-item"><div class="hs-val">+36pp</div><div class="hs-label">vs greedy</div></div>
|
| 573 |
</div>
|
| 574 |
</div>
|
|
|
|
| 766 |
Llama 3.3 70B via Groq, with GRPO-style episodic memory across 2–3 rollouts per task.
|
| 767 |
Each rollout injects advantage-gated memory from prior rollouts into the prompt.
|
| 768 |
Reproduced by running <code style="color:var(--text);">python baseline/run.py</code>.
|
| 769 |
+
Llama 3.3 70B via Groq, with GRPO-style episodic memory across 2–3 rollouts per task.
|
| 770 |
+
Total runtime: <strong style="color:var(--text);">~10 minutes</strong>.
|
| 771 |
</div>
|
| 772 |
<div class="grid-3" style="margin-bottom:1rem;">
|
| 773 |
<div class="card-sm" style="border-top:2px solid var(--green);">
|
|
|
|
| 782 |
</div>
|
| 783 |
<div class="card-sm" style="border-top:2px solid var(--amber);">
|
| 784 |
<div style="font-size:0.62rem;letter-spacing:0.08em;text-transform:uppercase;color:var(--amber);margin-bottom:0.5rem;">Medium · 3 rollouts</div>
|
| 785 |
+
<div style="font-family:var(--serif);font-size:2rem;font-weight:700;color:#fff;line-height:1;">78.0%</div>
|
| 786 |
<div style="font-size:0.68rem;color:var(--muted);margin-top:0.25rem;">Best of 4 · no breach</div>
|
| 787 |
<div style="margin-top:0.75rem;display:flex;flex-direction:column;gap:0.3rem;">
|
| 788 |
<div style="display:flex;justify-content:space-between;font-size:0.68rem;"><span style="color:var(--muted);">Containment</span><span>42%</span></div>
|
|
|
|
| 792 |
</div>
|
| 793 |
<div class="card-sm" style="border-top:2px solid var(--red);">
|
| 794 |
<div style="font-size:0.62rem;letter-spacing:0.08em;text-transform:uppercase;color:var(--red);margin-bottom:0.5rem;">Hard · 3 rollouts</div>
|
| 795 |
+
<div style="font-family:var(--serif);font-size:2rem;font-weight:700;color:#fff;line-height:1;">61.1%</div>
|
| 796 |
<div style="font-size:0.68rem;color:var(--muted);margin-top:0.25rem;">Best of 4 · no breach</div>
|
| 797 |
<div style="margin-top:0.75rem;display:flex;flex-direction:column;gap:0.3rem;">
|
| 798 |
<div style="display:flex;justify-content:space-between;font-size:0.68rem;"><span style="color:var(--muted);">Containment</span><span>51%</span></div>
|
|
|
|
| 812 |
</tr>
|
| 813 |
<tr>
|
| 814 |
<td><span class="badge badge-amber">Medium</span></td>
|
| 815 |
+
<td>56.3%</td><td>78.0%</td><td>64.0%</td>
|
| 816 |
+
<td><strong style="color:var(--amber);">78.0%</strong></td>
|
| 817 |
</tr>
|
| 818 |
<tr>
|
| 819 |
<td><span class="badge badge-red">Hard</span></td>
|
| 820 |
+
<td>61.1%</td><td>57.7%</td><td>60.3%</td>
|
| 821 |
+
<td><strong style="color:var(--red);">61.1%</strong></td>
|
| 822 |
</tr>
|
| 823 |
</table>
|
| 824 |
</div>
|
|
|
|
| 849 |
</tr>
|
| 850 |
<tr>
|
| 851 |
<td><span class="badge badge-amber">Medium</span></td>
|
| 852 |
+
<td style="color:var(--muted);">42.7%</td><td><strong>78.0%</strong></td>
|
| 853 |
+
<td class="pos">+35pp</td>
|
| 854 |
<td><span class="badge badge-green">Strong</span></td>
|
| 855 |
<td><span class="badge badge-green">None — 8% eff, 80% breach</span></td>
|
| 856 |
</tr>
|
| 857 |
<tr>
|
| 858 |
<td><span class="badge badge-red">Hard</span></td>
|
| 859 |
+
<td style="color:var(--muted);">33.0%</td><td><strong>61.1%</strong></td>
|
| 860 |
+
<td class="pos">+28pp</td>
|
| 861 |
<td><span class="badge badge-green">Strong</span></td>
|
| 862 |
<td><span class="badge badge-green">None — 0% eff, 100% breach</span></td>
|
| 863 |
</tr>
|
| 864 |
<tr style="border-top:1px solid var(--border2);">
|
| 865 |
<td><strong>Average</strong></td>
|
| 866 |
+
<td style="color:var(--muted);">39.5%</td><td><strong>75.9%</strong></td>
|
| 867 |
<td class="pos"><strong>+36pp</strong></td>
|
| 868 |
<td><span class="badge badge-green">Strong</span></td>
|
| 869 |
<td><span class="badge badge-green">No exploits found</span></td>
|
|
|
|
| 884 |
<div style="display:flex;flex-direction:column;gap:0.45rem;">
|
| 885 |
<div><div style="display:flex;justify-content:space-between;font-size:0.68rem;margin-bottom:0.2rem;"><span style="color:var(--muted);">Greedy (D0)</span><span>43%</span></div><div class="bar-track" style="height:8px;"><div class="bar-fill" style="width:43%;background:var(--dim);"></div></div></div>
|
| 886 |
<div><div style="display:flex;justify-content:space-between;font-size:0.68rem;margin-bottom:0.2rem;"><span style="color:var(--amber);">LLM+GRPO</span><span>75%</span></div><div class="bar-track" style="height:8px;"><div class="bar-fill" style="width:75%;background:var(--amber);"></div></div></div>
|
| 887 |
+
<div style="font-size:0.68rem;color:var(--muted);">Lift: <span style="color:var(--amber);font-weight:700;">+35pp</span></div>
|
| 888 |
</div>
|
| 889 |
</div>
|
| 890 |
<div class="card-sm">
|
|
|
|
| 892 |
<div style="display:flex;flex-direction:column;gap:0.45rem;">
|
| 893 |
<div><div style="display:flex;justify-content:space-between;font-size:0.68rem;margin-bottom:0.2rem;"><span style="color:var(--muted);">Greedy (D0)</span><span>33%</span></div><div class="bar-track" style="height:8px;"><div class="bar-fill" style="width:33%;background:var(--dim);"></div></div></div>
|
| 894 |
<div><div style="display:flex;justify-content:space-between;font-size:0.68rem;margin-bottom:0.2rem;"><span style="color:var(--red);">LLM+GRPO</span><span>63%</span></div><div class="bar-track" style="height:8px;"><div class="bar-fill" style="width:63%;background:var(--red);"></div></div></div>
|
| 895 |
+
<div style="font-size:0.68rem;color:var(--muted);">Lift: <span style="color:var(--red);font-weight:700;">+28pp</span></div>
|
| 896 |
</div>
|
| 897 |
</div>
|
| 898 |
</div>
|