Text Generation
Transformers
Safetensors
English
qwen3_5
image-text-to-text
text-to-sql
sql
bird
spider
agentic
qwen3.5
conversational
Instructions to use feyninc/sqrl-9b with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use feyninc/sqrl-9b with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="feyninc/sqrl-9b") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("feyninc/sqrl-9b") model = AutoModelForMultimodalLM.from_pretrained("feyninc/sqrl-9b", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use feyninc/sqrl-9b with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "feyninc/sqrl-9b" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "feyninc/sqrl-9b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/feyninc/sqrl-9b
- SGLang
How to use feyninc/sqrl-9b with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "feyninc/sqrl-9b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "feyninc/sqrl-9b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "feyninc/sqrl-9b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "feyninc/sqrl-9b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use feyninc/sqrl-9b with Docker Model Runner:
docker model run hf.co/feyninc/sqrl-9b
File size: 9,174 Bytes
48ffb67 654a17a 48ffb67 654a17a 48ffb67 654a17a 48ffb67 | 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 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | ---
license: apache-2.0
base_model: Qwen/Qwen3.5-9B
language:
- en
pipeline_tag: text-generation
tags:
- text-to-sql
- sql
- bird
- spider
- agentic
- qwen3.5
library_name: transformers
---
# sqrl-9b
**sqrl-9b** is a 9B-parameter agentic text-to-SQL model built on
[Qwen/Qwen3.5-9B](https://huggingface.co/Qwen/Qwen3.5-9B). It answers natural-language
questions over SQLite databases by optionally *probing the database first* — running
read-only exploration queries to check value formats, join paths, and filters — before
committing to a final SQL answer. It is the larger sibling of
[feyninc/sqrl-4b](https://huggingface.co/feyninc/sqrl-4b), trained with the same recipe.
Training stages:
1. **SFT distillation** — fine-tuned on ~10.2k execution-verified agentic trajectories
sampled from a much stronger RL-trained 35B teacher (Qwen3.6-35B-A3B, 70.3% BIRD-dev EX)
on cleaned BIRD-train + Spider-train questions. Only trajectories whose final SQL
execution-matched the gold answer were kept.
2. **CISPO RL** — online reinforcement learning (group-relative advantage, group size 8)
with execution-match reward on the same cleaned BIRD+Spider question pool, with
async dynamic sampling. Best checkpoint at step 60.
## Results
All BIRD-dev numbers measured on the full 1534-question set at temperature 0.7 with the
agentic harness (execution-clustered majority vote = sample 8 candidates, group them by
identical execution result set, return the largest cluster's query).
| Benchmark | Metric | Score |
|---|---|---|
| BIRD-dev | pass@1 (avg over 8 samples) | **66.6%** EX |
| BIRD-dev | vote-of-8 (execution-clustered) | **69.8%** EX |
Family comparison on identical seeds (pass@1 / vote@8):
[sqrl-4b](https://huggingface.co/feyninc/sqrl-4b) 64.6 / 68.8 ·
[sqrl-9b](https://huggingface.co/feyninc/sqrl-9b) 66.6 / 69.8 ·
[sqrl-35b-a3b](https://huggingface.co/feyninc/sqrl-35b-a3b) 68.7 / 70.6.
Notes from the measurement campaign:
- **sqrl-9b vote-of-8 (69.8%) is the family's cost/performance sweet spot** — within
0.8 pts of anything the whole family achieves under any sampling/voting scheme,
including the 35B. vote-of-4 captures ~85% of the voting gain at half the cost.
- Vote unanimity is a strong free confidence signal: when all 8 samples agree (~60% of
questions) the answer is right ~87% of the time; narrow/tied votes are right ~19-43% —
useful for routing or escalation.
- The pre-RL SFT checkpoint scores 64.0% pass@1 on the same harness; base Qwen3.5-9B
scores ~56%.
## How it works — the agentic protocol
The model emits **exactly one action block per turn**, after a brief reasoning summary:
- `<sql> SELECT ... </sql>` — a read-only *exploration* query. Execute it against the
database and feed the result back as a user turn wrapped in `<observation>` tags.
The model continues (up to a step budget).
- `<answer> SELECT ... </answer>` — the final SQL. Execute and return.
Many questions are answered directly (zero exploration turns); the model learned to
explore only when seeing real data would change its answer (value-format checks,
ambiguous joins).
## Usage
### Serve with vLLM
```bash
vllm serve feyninc/sqrl-9b --served-model-name sqrl-9b \
--data-parallel-size 4 --gpu-memory-utilization 0.90 --max-model-len 32768
```
> **Important:** do **not** enable a reasoning parser (e.g. `--reasoning-parser qwen3`).
> The model's post-`</think>` content carries the action protocol; stripping/rerouting
> the think block breaks it. Parse `message.content` — if it contains a `</think>`,
> take everything after it.
Recommended sampling: `temperature 0.7, top_p 0.95` (matches training); greedy also works.
### Prompt format
System prompt (fill `{schema}`, `{evidence}`, `{max_steps}`):
````text
<role>
You are an expert data analyst, fluent in SQL, with a meticulous eye for
matching a question's intent to the exact tables, columns, and stored value formats of
a database.
</role>
<task>
Translate the user's natural-language question into a SQL query that answers
it, using the database schema in <schema> and any domain hints in <evidence>. You can
run read-only queries against the database to inspect it before giving your final
answer.
</task>
<database_engine>
SQLite
</database_engine>
<schema>
{schema}
</schema>
<evidence>
{evidence}
</evidence>
<protocol>
Think through the problem internally first. Then, in your response, write a
BRIEF summary of your reasoning — 2-4 sentences stating which tables and columns are
relevant, the joins and filters, and any exact value-format detail. Be decisive: state
the plan once, do not second-guess or restate. End your message with EXACTLY ONE action
block (and nothing after it):
<sql> a read-only query to inspect the database </sql>
Use this when uncertain and you want to see real data before answering — e.g.
confirm a value's exact stored format, check a filter actually matches rows,
sanity-check an intermediate result, or verify a join. You will see the result
rows and then continue.
<answer> your final SQL query </answer>
Use this once you are confident. It is executed and scored, and the task ends.
Examples:
I'll check the exact county value before filtering, since the format may vary.
<sql> SELECT DISTINCT `County Name` FROM frpm LIMIT 10 </sql>
The schools are in the frpm table; I'll select `School Name` and filter `County Name`
to 'Alameda'. The schema is clear, so I can answer directly.
<answer> SELECT `School Name` FROM frpm WHERE `County Name` = 'Alameda' </answer>
</protocol>
<rules>
- Use only the tables and columns defined in <schema>.
- Quote identifiers containing spaces or special characters with backticks.
- Return exactly the columns the question asks for — no more, no fewer.
- Use the hints in <evidence> to resolve ambiguous terms and value encodings.
- If you already know the correct query, go straight to <answer> — investigating is
optional; only run <sql> when seeing the data would actually change your answer.
- The action block must be the LAST thing in your message; do not discuss the tags
themselves in your reasoning.
- You have at most {max_steps} <sql> steps; after that you must give <answer>.
</rules>
````
First user turn:
```text
Question: {question}
Reason about it, then give <sql> to investigate or <answer> to finish.
```
After executing an exploration `<sql>`, feed the result back as a **user** message:
```text
<observation>
{tab-separated result rows, or the error message}
</observation>
Continue with <sql> or <answer>.
```
`{schema}` is a readable dump of the SQLite schema (CREATE-TABLE-like listing of
tables/columns/types). `{evidence}` is the BIRD external-knowledge hint, or
`(none provided)`. `max_steps=5` was used in training. When the step budget is
exhausted, send `You must finish now. Give your <answer>.` as a user turn.
### Minimal driver loop
```python
import re
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
messages = [{"role": "system", "content": system_prompt},
{"role": "user", "content": user0}]
for step in range(6):
r = client.chat.completions.create(model="sqrl-9b", messages=messages,
temperature=0.7, top_p=0.95, max_tokens=8192)
content = r.choices[0].message.content
if "</think>" in content: # strip inline think scratchpad
content = content.split("</think>")[-1].strip()
messages.append({"role": "assistant", "content": content})
ans = re.findall(r"<answer>(.*?)</answer>", content, re.S)
if ans:
final_sql = ans[-1].strip(); break
sql = re.findall(r"<sql>(.*?)</sql>", content, re.S)
if not sql:
break
obs = run_readonly(sql[-1].strip()) # your sqlite executor
messages.append({"role": "user",
"content": f"<observation>\n{obs}\n</observation>\n"
"Continue with <sql> or <answer>."})
```
## Checkpoint notes
- This repo contains the **full merged HF checkpoint** (LoRA rank 32 merged into the
base). Qwen3.5-9B has untied embeddings, so the merge is direct: the trained head
lands in `lm_head`, `embed_tokens` is untouched. Loads with standard `transformers` /
vLLM — no custom code beyond `trust_remote_code` if your transformers version
requires it for Qwen3.5.
- The vision tower is inherited from the base model unchanged. The model is usable as a
standard VL checkpoint, but SQL training was text-only.
- Text-to-SQL training data: BIRD-train and Spider-train, execution-filtered and
semantically cleaned (3-model LLM-judge panel). BIRD-dev and Spider-test were never
trained on.
## Intended use & limitations
Built for SQLite text-to-SQL with schema + optional evidence in context. Works best
with the exact prompt protocol above (it was both SFT'd and RL'd under it). Not tuned
for other SQL dialects; identifier quoting follows SQLite backtick conventions. As with
all text-to-SQL models, execute generated SQL read-only and validate before acting on
results.
|