""" inference.py — SQL Debugger & Optimizer Agent =============================================== Runs an LLM against all 3 tasks. Emits mandatory [START]/[STEP]/[END] logs. Env vars: API_BASE_URL LLM endpoint (default: https://router.huggingface.co/v1) MODEL_NAME Model name (default: Qwen/Qwen2.5-72B-Instruct) HF_TOKEN API key """ from __future__ import annotations import json, os, textwrap from typing import Dict, List, Optional from openai import OpenAI from sql_debugger_env import Action, SQLDebuggerEnv API_KEY = os.getenv("HF_TOKEN") or os.getenv("API_KEY", "") API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1") MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct") BENCHMARK = "sql-debugger-agent" TASKS = ["easy", "medium", "hard"] client = OpenAI(api_key=API_KEY, base_url=API_BASE_URL) SYSTEM_PROMPT = textwrap.dedent(""" You are an expert SQL debugger and optimizer. You will be given a broken SQL query, the database schema, and a description of what the query SHOULD do. Your job is to fix ALL bugs. Always respond with ONLY a JSON object — no markdown, no explanation outside JSON: { "challenge_id": "", "fixed_sql": "", "explanation": "", "detected_issues": ["issue1", "issue2"] } Common bug types to look for: - Syntax typos (SELCT, FORM, WHER) - Missing GROUP BY when using aggregate functions with non-aggregate columns - Wrong JOIN type (INNER vs LEFT) - Wrong column in ORDER BY (ordering by raw column instead of aggregate alias) - Subquery referencing wrong scope (AVG of all rows instead of filtered group) - SQL injection (string concatenation of user input — fix with parameterized form) - N+1 correlated subqueries (rewrite as JOIN with subquery or CTE) Output ONLY the JSON. Nothing else. """).strip() def build_prompt(obs_dict: dict) -> str: c = obs_dict["challenge"] return textwrap.dedent(f""" TASK: {obs_dict['task']} INSTRUCTIONS: {obs_dict['instructions']} DATABASE SCHEMA: {obs_dict['schema_info']} CHALLENGE ID: {c['id']} GOAL: {c['description']} DIFFICULTY: {c['difficulty']} KNOWN BUGS (hints): {chr(10).join('- ' + b for b in c['bugs'])} HINT: {c['hint']} BROKEN SQL TO FIX: {c['broken_sql']} Output only JSON with keys: challenge_id, fixed_sql, explanation, detected_issues """).strip() def run_task(task_name: str) -> dict: env = SQLDebuggerEnv(task=task_name) obs_obj = env.reset() obs = obs_obj.model_dump() step_num = 0 rewards: List[float] = [] done = False last_error = None print(f"[START] task={task_name} env={BENCHMARK} model={MODEL_NAME}", flush=True) while not done: prompt = build_prompt(obs) try: resp = client.chat.completions.create( model=MODEL_NAME, messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": prompt}, ], max_tokens=600, temperature=0.1, ) raw = resp.choices[0].message.content or "" raw = raw.strip().strip("```json").strip("```").strip() action_dict = json.loads(raw) action = Action(**action_dict) last_error = None except Exception as e: last_error = str(e)[:100] cid = obs["challenge"]["id"] action = Action( challenge_id=cid, fixed_sql=obs["challenge"]["broken_sql"], explanation="parse error fallback", detected_issues=[], ) obs_obj, reward, done, info = env.step(action) obs = obs_obj.model_dump() step_num += 1 rewards.append(reward) action_str = f"fix(id={action.challenge_id},issues={len(action.detected_issues)})" print( f"[STEP] step={step_num} action={action_str} " f"reward={reward:.2f} done={str(done).lower()} " f"error={last_error if last_error else 'null'}", flush=True, ) score = env.episode_score() rewards_str = ",".join(f"{r:.2f}" for r in rewards) print( f"[END] success={str(score >= 0.5).lower()} steps={step_num} " f"score={score:.2f} rewards={rewards_str}", flush=True, ) env.close() return {"task": task_name, "score": score, "steps": step_num} def main(): print(f"# SQL Debugger & Optimizer — Baseline Inference", flush=True) print(f"# Model: {MODEL_NAME} API: {API_BASE_URL}\n", flush=True) results = [] for task in TASKS: result = run_task(task) results.append(result) print(f"# Task '{task}' → score: {result['score']:.4f}\n", flush=True) avg = sum(r["score"] for r in results) / len(results) print("# === FINAL SUMMARY ===", flush=True) for r in results: print(f"# {r['task']:8s}: {r['score']:.4f}", flush=True) print(f"# AVERAGE : {avg:.4f}", flush=True) if __name__ == "__main__": main()