Compact Russian text-to-SQL model: a full-parameter SFT of
techwithsergiu/Qwen3.5-text-0.8B
— a text-only slice of Qwen/Qwen3.5-0.8B with the vision tower removed
(0.77B actual parameters) — trained to answer Russian natural-language
questions over a database schema with step-by-step reasoning that ends in a final
SQLite query (OmniSQL-style CoT).
Performance Evaluation
Execution accuracy (predicted SQL executed against SQLite, result-set comparison)
on the held-out eval split — the same 2,729 questions in every row (EN vs RU
are the same items, English question vs its translation), greedy decoding:
Model
Questions
n
EX accuracy
Base (zero-shot)
EN
2,729
16.0%
Base (zero-shot)
RU
2,729
13.9%
RUSQL (this model)
RU
2,729
58.4%
Fine-tuning lifts execution accuracy from 13.9% to 58.4% — about 4.2× the base
model, and above its English-question ceiling (16.0%).
Breakdown by SQL complexity (RU questions):
Complexity
n
Base EX
RUSQL EX
Simple
259
28.6%
75.7%
Moderate
858
14.7%
70.3%
Complex
973
12.3%
55.1%
Highly Complex
639
9.2%
40.5%
All three rows are scored on the exact same 2,729 items (the QE-filtered held-out
split), so the numbers are directly comparable. Greedy decoding. The base model also
fails to produce a parseable SQL block on ~12% of items (331/2,729 for RU, 322 for EN);
after fine-tuning this drops to 13.
Chat-format packing, full supervision on the assistant turn incl. <|im_end|>
Only the question is translated to Russian; schema (DDL), external knowledge and
the gold SQL stay in English — matching the real-world setting where databases are
English-named but users ask in Russian.
Training set: ~444k filtered examples (+2,729 held-out eval); filter drop rate ~13.8%
Instruction Prompt
The model is trained (and must be used) with this exact chat format:
System:
You are a text-to-SQL assistant. Given a database schema and a question, reason step by step and finish with the final SQLite query in a ```sql code block.
User:
Database schema:
{DDL}
External knowledge:
{optional, may be omitted}
Question: {вопрос на русском}
Assistant: free-form chain-of-thought ending with the final query in a
```sql ... ``` block. Qwen thinking mode is disabled (enable_thinking=False) —
reasoning is plain response text, OmniSQL style.
Training Configuration
Base model
techwithsergiu/Qwen3.5-text-0.8B (text-only slice of Qwen3.5-0.8B, 0.77B params)
Method
Full fine-tune (no LoRA), bf16, single consumer GPU with 8 GB VRAM
AdamW 8-bit, lr 1.5e-5, warmup 3%, weight decay 0.01
Epochs
1 (+ incremental continuation on new data chunks)
Max sequence
4,096 tokens
Usage
python
1from transformers import AutoModelForCausalLM, AutoTokenizer
2import re, torch
34model_id ="MaXoN654/RUSQL-0.8B-Text2SQL"5tok = AutoTokenizer.from_pretrained(model_id)6model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.bfloat16, device_map="auto")78# schema = "\n\n".join of CREATE TABLE statements, SynSQL style9# (quoted identifiers, inline /* ... */ column comments)10schema ="""CREATE TABLE "employees" (
11 "employee_id" INTEGER /* Unique identifier for each employee */,
12 "name" TEXT /* Full name of the employee */,
13 "salary" REAL /* Annual salary in USD */,
14 "department_id" INTEGER /* Reference to the department */,
15 PRIMARY KEY ("employee_id"),
16 CONSTRAINT fk_employees_department_id FOREIGN KEY ("department_id") REFERENCES departments ("department_id")
17)
1819CREATE TABLE "departments" (
20 "department_id" INTEGER /* Unique identifier for each department */,
21 "department_name" TEXT /* Name of the department */,
22 PRIMARY KEY ("department_id")
23)"""24question ="Покажи трёх сотрудников с самой высокой зарплатой в отделе продаж"2526external_knowledge =None# optional hint text; omitted from the prompt when empty2728defbuild_user(schema, question, external_knowledge=None):29 parts =[f"Database schema:\n{schema}"]30if external_knowledge and external_knowledge.strip():31 parts.append(f"External knowledge:\n{external_knowledge.strip()}")32 parts.append(f"Question: {question}")33return"\n\n".join(parts)3435messages =[36{"role":"system","content":"You are a text-to-SQL assistant. Given a database schema and a question, reason step by step and finish with the final SQLite query in a ```sql code block."},37{"role":"user","content": build_user(schema, question, external_knowledge)},38]39inputs = tok.apply_chat_template(messages, add_generation_prompt=True,40 enable_thinking=False, return_tensors="pt").to(model.device)41out = model.generate(inputs, max_new_tokens=1024, temperature=0.0, do_sample=False)42text = tok.decode(out[0][inputs.shape[1]:], skip_special_tokens=True)4344sql = re.findall(r"```sql\s*(.*?)```", text, re.S | re.I)[-1].strip()45print(sql)
Limitations
SELECT-only — SynSQL-2.5M contains no DML/DDL, so the model was never trained on
INSERT/UPDATE/DELETE. Asked to modify data, it does not refuse — it silently reformulates
the request into a related SELECT. Do not use it to generate data-modifying queries.
SQLite dialect only — queries may not be valid PostgreSQL/MySQL without adaptation.
Schema and gold SQL are English; questions in other languages than Russian/English are untested.
Training questions are machine-translated — residual translation artifacts are possible despite QE filtering.
Pipeline
The full data pipeline (sampling → translation → QE filtering → SFT → execution-accuracy eval)
is implemented in the rusql project and runs entirely on a single consumer GPU.