Spaces:
Sleeping
Sleeping
| """Benchmark: 3 tasks × (standard, adversarial) × 5 runs each + naive baseline.""" | |
| import collections | |
| import json | |
| import math | |
| import os | |
| import subprocess | |
| import sys | |
| import time | |
| import requests | |
| from environment import IncidentResponseEnvironment | |
| from task_definitions import ACTIONS, ADVERSARIAL_OVERLAYS, TASKS | |
| from inference import run_groq_agent | |
| SERVER_PORT = 7860 | |
| SERVER_URL = f"http://localhost:{SERVER_PORT}" | |
| RUNS = 5 | |
| CORRECT_ACTION = { | |
| "task_easy": "rollback_deployment", | |
| "task_medium": "rollback_deployment", | |
| "task_hard": "rotate_db_credentials", | |
| } | |
| def start_server() -> subprocess.Popen: | |
| app_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "app.py") | |
| return subprocess.Popen( | |
| [sys.executable, app_path], | |
| stdout=subprocess.DEVNULL, | |
| stderr=subprocess.DEVNULL, | |
| ) | |
| def wait_for_health(timeout: int = 30) -> None: | |
| deadline = time.time() + timeout | |
| while time.time() < deadline: | |
| try: | |
| if requests.get(f"{SERVER_URL}/health", timeout=2).status_code == 200: | |
| print(f" Server healthy at {SERVER_URL}") | |
| return | |
| except requests.exceptions.ConnectionError: | |
| pass | |
| time.sleep(0.5) | |
| raise RuntimeError(f"Server did not become healthy within {timeout}s") | |
| def naive_action_for(task_id: str, adversarial: bool) -> str: | |
| """Return the ACTIONS name most frequently mentioned in the (possibly adversarial) chat.""" | |
| chat = ( | |
| ADVERSARIAL_OVERLAYS[task_id] | |
| if adversarial and task_id in ADVERSARIAL_OVERLAYS | |
| else TASKS[task_id]["observation"]["chat_history"] | |
| ) | |
| counts: collections.Counter = collections.Counter() | |
| for msg in chat: | |
| text = msg["msg"].lower() | |
| for action in ACTIONS: | |
| if action in text: | |
| counts[action] += 1 | |
| return counts.most_common(1)[0][0] if counts else ACTIONS[0] | |
| def run_once( | |
| env: IncidentResponseEnvironment, | |
| task_id: str, | |
| adversarial: bool, | |
| action: str, | |
| ) -> float: | |
| episode_id, obs = env.reset(task_id=task_id, adversarial=adversarial) | |
| # Use log index 0 as evidence — always in-bounds | |
| env.step(episode_id, {"action": action, "evidence": 0}) | |
| return env.grade(episode_id)["score"] | |
| def collect(env, task_id, adversarial, action): | |
| return [run_once(env, task_id, adversarial, action) for _ in range(RUNS)] | |
| def stats(scores: list[float]) -> tuple[float, float]: | |
| avg = sum(scores) / len(scores) | |
| std = math.sqrt(sum((s - avg) ** 2 for s in scores) / len(scores)) | |
| return round(avg, 4), round(std, 4) | |
| def render_table(rows: list[dict]) -> None: | |
| cols = ["task", "mode", "model", "avg_score", "std_dev"] | |
| widths = {c: max(len(c), max(len(str(r[c])) for r in rows)) for c in cols} | |
| header = "| " + " | ".join(c.ljust(widths[c]) for c in cols) + " |" | |
| sep = "| " + " | ".join("-" * widths[c] for c in cols) + " |" | |
| print(header) | |
| print(sep) | |
| for r in rows: | |
| print("| " + " | ".join(str(r[c]).ljust(widths[c]) for c in cols) + " |") | |
| def main() -> None: | |
| groq_available = bool(os.environ.get("GROQ_API_KEY", "")) | |
| print("Starting server...") | |
| proc = start_server() | |
| try: | |
| wait_for_health() | |
| if groq_available: | |
| print(" GROQ_API_KEY found — llama-3.3-70b will run live") | |
| else: | |
| print(" GROQ_API_KEY not set — llama-3.3-70b will use deterministic fallback") | |
| env = IncidentResponseEnvironment() | |
| rows: list[dict] = [] | |
| for task_id in TASKS: | |
| for adversarial in (False, True): | |
| mode = "adversarial" if adversarial else "standard" | |
| # Oracle: always the known-correct action | |
| oracle_scores = collect(env, task_id, adversarial, CORRECT_ACTION[task_id]) | |
| avg, std = stats(oracle_scores) | |
| rows.append({ | |
| "task": task_id, "mode": mode, "model": "oracle", | |
| "avg_score": avg, "std_dev": std, | |
| }) | |
| # Naive baseline: pick action most mentioned in chat | |
| naive = naive_action_for(task_id, adversarial) | |
| naive_scores = collect(env, task_id, adversarial, naive) | |
| avg_n, std_n = stats(naive_scores) | |
| rows.append({ | |
| "task": task_id, "mode": mode, "model": f"naive({naive})", | |
| "avg_score": avg_n, "std_dev": std_n, | |
| }) | |
| # Groq LLM agent | |
| groq_scores = [run_groq_agent(task_id, adversarial) for _ in range(RUNS)] | |
| avg_g, std_g = stats(groq_scores) | |
| rows.append({ | |
| "task": task_id, "mode": mode, "model": "llama-3.3-70b", | |
| "avg_score": avg_g, "std_dev": std_g, | |
| }) | |
| print("\n## Benchmark Results\n") | |
| render_table(rows) | |
| with open("benchmark_results.json", "w") as f: | |
| json.dump(rows, f, indent=2) | |
| print("\nSaved -> benchmark_results.json") | |
| finally: | |
| proc.terminate() | |
| proc.wait() | |
| print("Server stopped.") | |
| if __name__ == "__main__": | |
| main() | |