Instructions to use maxdemarzi/black-swan-sql3b-lora with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use maxdemarzi/black-swan-sql3b-lora with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-Coder-3B-Instruct") model = PeftModel.from_pretrained(base_model, "maxdemarzi/black-swan-sql3b-lora") - Notebooks
- Google Colab
- Kaggle
black-swan SQL 3B (LoRA)
Writes DuckDB SQL from a schema and a question. Half of a two-stage text-to-PyRel pipeline: this adapter emits SQL, and a deterministic transpiler converts it to PyRel. Trained by the Black Swan project.
r=32, alpha=64, LoRA over Qwen/Qwen2.5-Coder-3B-Instruct.
The prompt is part of the model
Generation must use ARCTIC_SYSTEM, shipped here as system_prompt.txt:
You are a data science expert. Below, you are provided with a database schema and a natural language question. Your task is to understand the schema and generate a valid SQL query to answer the question.
with the Arctic user template (engine, db_details, question, output_format),
output_format = the terse fenced-SQL block, not the <think>/<answer>
reasoning scaffold. The rung is duckdb-values: evidence, comments and sample
values on, reasoning off.
A different system prompt is not a small degradation. The sibling PyRel adapter records that dropping its own system message makes the model emit a different language entirely, which reads as a broken model rather than a missing message.
| decoding | greedy, temperature=0 |
max_new_tokens |
4096 at evaluation β median output is 165 characters, but the long tail reached 13,598 |
| extractor | first ```sql fence, then strip the leading sql tag |
Because reasoning is off there is exactly one fence, so first and last coincide. That distinction matters for reasoning models on this same pipeline, where taking the first fence scores a draft the model went on to correct.
Measured
BIRD holdout, 428 scoreable questions, paired against the same 3B fine-tuned to emit PyRel directly:
| arm | correct | paired vs PyRel | |
|---|---|---|---|
| 3B β PyRel direct | 165/428 | 38.6% | β |
| 3B β SQL β transpiler (this adapter) | 179/428 | 41.8% | +60/β46, p = 0.21 |
| routed: SQL where it fires, PyRel where it declines | 206/428 | 48.1% | +60/β19, p = 4.2e-06 |
The head-to-head is not significant. This adapter is not measurably better than emitting PyRel directly; the gain is in routing, because the two arms fail on different questions. Deploy it as one arm of a pair, or accept 41.8% knowing 33% of questions get no program at all.
Decomposition: SQL accuracy 44.3% Γ transpiler carry 94.2% = 41.7% against a measured 41.8%. Zero malformed outputs in 445 generations.
The transpiler declines a third of the time
Re-running all 445 predictions through synthesize_ast:
302 admitted (ast_join 165, ast_single 54, ast_join_n 36, ast_bound 26, +6 patterns)
143 no template
0 raised
no template is a transpiler gap, not a model error β the SQL may be perfectly
correct. Each one is a deterministic, permanently fixable Python bug, which is the
improvement path this arm has and a direct-to-PyRel model does not.
sqlglot is a hard dependency and its absence is silent. synthesize_ast
catches the ImportError and returns None, which is also how it signals a
decline β so a deployment without sqlglot declines 100% of requests and looks like
a transpiler that cannot handle your queries. Verified: it returned 60 of 60
no template on a machine that was simply missing the package.
Provenance
Trained on BIRD train only. Evaluated on the four BIRD dev databases held out from
training (california_schools, debit_card_specializing, superhero,
thrombosis_prediction).
The recipe is pinned to an RTX 5090 deliberately: an identical recipe on different hardware has moved an adapter by 11 questions on this project, which is larger than the effect being measured here.
- Downloads last month
- 12