File size: 6,070 Bytes
ede2fa4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
"""
Baseline inference script for the SQL Query Environment.

Uses the OpenAI-compatible API to run an LLM agent against all 3 tasks.
Reads credentials from environment variables:
  - API_BASE_URL: The API endpoint for the LLM
  - MODEL_NAME:   The model identifier to use
  - HF_TOKEN:     Your Hugging Face / API key

Usage:
    API_BASE_URL=https://router.huggingface.co/v1 \
    MODEL_NAME=Qwen/Qwen2.5-72B-Instruct \
    HF_TOKEN=hf_xxx \
    python inference.py
"""

import os
import sys
import json
import time
import requests

from openai import OpenAI

# ── Configuration ──
API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
API_KEY = os.getenv("HF_TOKEN") or os.getenv("API_KEY") or os.getenv("OPENAI_API_KEY", "")
MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct")

# Environment URL (local or HF Space)
ENV_URL = os.getenv("ENV_URL", "http://localhost:7860")

MAX_ATTEMPTS = 3  # Max steps per task
TASKS = ["task_1", "task_2", "task_3"]


def call_environment(endpoint: str, payload: dict = None) -> dict:
    """Call the environment's HTTP API."""
    url = f"{ENV_URL.rstrip('/')}/{endpoint.lstrip('/')}"
    if payload is not None:
        resp = requests.post(url, json=payload, timeout=30)
    else:
        resp = requests.get(url, timeout=30)
    resp.raise_for_status()
    return resp.json()


def generate_sql(client: OpenAI, schema: str, question: str, history: str = "") -> str:
    """Ask the LLM to generate a SQL query."""
    system_prompt = (
        "You are an expert SQL query writer. Given a database schema and a "
        "natural language question, write a single SQLite-compatible SQL query "
        "that answers the question.\n\n"
        "RULES:\n"
        "- Return ONLY the SQL query, nothing else.\n"
        "- Do NOT include markdown code fences, explanations, or comments.\n"
        "- Use proper SQLite syntax.\n"
        "- Pay attention to column names and table relationships.\n"
        "- When asked to round values, use ROUND(value, decimal_places).\n"
        "- Use single quotes for string literals.\n"
    )

    user_prompt = f"DATABASE SCHEMA:\n{schema}\n\nQUESTION: {question}"
    if history:
        user_prompt += f"\n\nPREVIOUS ATTEMPTS AND FEEDBACK:\n{history}"
        user_prompt += "\n\nPlease fix your query based on the feedback above."

    try:
        completion = client.chat.completions.create(
            model=MODEL_NAME,
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_prompt},
            ],
            temperature=0.1,
            max_tokens=500,
        )
        response = completion.choices[0].message.content or ""
        # Clean up: remove markdown fences if present
        response = response.strip()
        if response.startswith("```sql"):
            response = response[6:]
        if response.startswith("```"):
            response = response[3:]
        if response.endswith("```"):
            response = response[:-3]
        return response.strip()
    except Exception as e:
        print(f"  LLM API error: {e}")
        return "SELECT 1"


def run_task(client: OpenAI, task_id: str) -> float:
    """Run the agent on a single task. Returns the best reward achieved."""
    print(f"\n{'='*60}")
    print(f"TASK: {task_id.upper()}")
    print(f"{'='*60}")

    # Reset environment for this task
    reset_resp = call_environment("/reset", {"task_id": task_id})
    obs = reset_resp["observation"]

    print(f"Question: {obs['task_description']}")
    print(f"Difficulty: {obs['difficulty']}")

    best_reward = 0.0
    history = ""

    for attempt in range(1, MAX_ATTEMPTS + 1):
        print(f"\n--- Attempt {attempt}/{MAX_ATTEMPTS} ---")

        # Generate SQL query
        sql = generate_sql(
            client,
            schema=obs["schema_description"],
            question=obs["task_description"],
            history=history,
        )
        print(f"SQL: {sql[:200]}{'...' if len(sql) > 200 else ''}")

        # Submit to environment
        step_resp = call_environment("/step", {
            "task_id": task_id,
            "sql_query": sql,
        })
        obs = step_resp["observation"]
        reward = step_resp["reward"]
        done = step_resp["done"]

        print(f"Reward: {reward:.2f}")
        print(f"Feedback: {obs['feedback']}")

        best_reward = max(best_reward, reward)

        # Track history for retry
        history += f"\nAttempt {attempt}: SQL: {sql}\n"
        history += f"  Reward: {reward}, Feedback: {obs['feedback']}\n"
        if obs.get("query_error"):
            history += f"  Error: {obs['query_error']}\n"

        if done:
            break

    print(f"\nBest reward for {task_id}: {best_reward:.2f}")
    return best_reward


def main():
    """Run the baseline agent on all tasks and report scores."""
    print("=" * 60)
    print("SQL Query Environment - Baseline Inference")
    print("=" * 60)
    print(f"API URL:  {API_BASE_URL}")
    print(f"Model:    {MODEL_NAME}")
    print(f"Env URL:  {ENV_URL}")
    print()

    # Verify environment is up
    try:
        health = call_environment("/health")
        print(f"Environment health: {health}")
    except Exception as e:
        print(f"ERROR: Cannot reach environment at {ENV_URL}: {e}")
        print("Make sure the environment server is running.")
        sys.exit(1)

    # Create OpenAI client
    client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)

    # Run all tasks
    results = {}
    total_score = 0.0

    for task_id in TASKS:
        score = run_task(client, task_id)
        results[task_id] = score
        total_score += score

    # Summary
    print("\n" + "=" * 60)
    print("FINAL RESULTS")
    print("=" * 60)
    for task_id, score in results.items():
        print(f"  {task_id:8s}: {score:.2f}")
    avg_score = total_score / len(TASKS)
    print(f"  {'AVERAGE':8s}: {avg_score:.2f}")
    print("=" * 60)

    return results


if __name__ == "__main__":
    main()