👉 Try the demo: https://github.com/LM-Kit/lm-kit-net-samples/tree/main/console_net/model-optimization/fine-tuning/text_to_sql_fine_tuning
Text-to-SQL Fine-Tuning for C# .NET Applications
🎯 Purpose of the Demo
This demo fine-tunes a small local model on a dataset file so it writes correct SQLite for YOUR database schema, without the schema pasted into every prompt. It measures held-out quality before and after training (is the reply bare SQL, does it hit the right tables, does every identifier exist in the schema), then merges the adapter into a single deployable GGUF model and proves the artifact answers on its own.
👥 Who Should Use This Demo (Target Audience)
- .NET developers building natural-language query features over a known schema.
- Teams whose training data already exists as JSONL/ShareGPT/Alpaca files and who want a measurable, local training pipeline from file to artifact.
🚀 What Problem It Solves
A general model does not know your table and column names: it invents
order_date, stock_quantity, customer_name. The usual workaround, pasting
the schema into every prompt, costs tokens and latency on every request.
Fine-tuning bakes the schema in once: prompts carry only the question, replies
reference only real identifiers. Everything runs locally, so the schema never
leaves the machine.
💻 Demo Application Overview
The sample loads qwen3.5:0.8b, evaluates ten held-out questions against the
base model, loads a 68-conversation chat JSONL dataset with
AddDatasetFile (format auto-detected), checks dataset statistics and the
chat-template mask (UnmaskedSampleCount), trains with rank 16 adapters on
attention and feed-forward modules under a cosine schedule with warmup and a
validation split, re-evaluates, then merges the adapter into a standalone
model with LoraMerger (EnableQuantization keeps the artifact at the base
precision) and runs a query on the merged file.
✨ Key Features
- File-based training data: chat JSONL in the repo, ShareGPT/Alpaca/text/ZIP load the same way.
- A verifiable metric: schema-correct SQL on held-out questions, printed per question before and after.
- Validation loss reported per epoch through
FinetuningProgress. - Two artifacts from one run: a 25 MB adapter and a merged, re-quantized GGUF.
Example Output
Before fine-tuning:
[err] SELECT * FROM VeloShop WHERE Category = 'Road Bike' AND Price < 800;
[err] SELECT * FROM orders ORDER BY order_date DESC LIMIT 3;
BASE: schema-correct SQL 2/10
Dataset: 68 conversations, 47 to 88 tokens per sample.
Training (rank 16, 8 epochs, attention + feed-forward)...
epoch 8/8 validation loss 0.2588
After fine-tuning:
[ok ] SELECT * FROM products WHERE category = 'road' AND price_cents < 80000;
[ok ] SELECT SUM(total_cents) FROM orders WHERE status = 'shipped';
TUNED: schema-correct SQL 8/10
Merged model: veloshop-sql-merged.gguf (442 MB)
Merged model answers "How many orders are pending?":
SELECT COUNT(*) FROM orders WHERE status = 'pending';
🏗️ Architecture
data/nl2sql.jsonl (questions -> SQL over the VeloShop schema)
|
v
LoraFinetuning.AddDatasetFile --> dataset statistics + mask check
|
v
TrainToAdapter --(FinetuningProgress: loss, validation)--> veloshop-sql.gguf
| |
v v
ApplyLoraAdapter -> held-out eval LoraMerger -> veloshop-sql-merged.gguf
|
v
standalone model answers SQL
⚙️ Getting Started
Prerequisites
- .NET 8.0 SDK or later.
- First run downloads
qwen3.5:0.8b(about 600 MB). - A CUDA GPU makes training an order of magnitude faster; CPU works.
Download
Clone the samples repository and open the demo folder
console_net/model-optimization/fine-tuning/text_to_sql_fine_tuning.
Run
dotnet run -c Release
🔧 Troubleshooting
- Out of memory during training: lower
MicroBatchSize, reduce the rank, or target attention modules only. - Held-out score plateaus: add paraphrases per question family; raise epochs and watch the validation loss for the point of diminishing returns.
UnmaskedSampleCountwarning: the dataset roles do not render cleanly through the model's chat template; fix the dataset before training.
🚀 Extend the Demo
- Replace
data/nl2sql.jsonlwith question-to-SQL pairs over your real schema; keep the system prompt identical between training and inference. - Ship the 25 MB adapter instead of the merged model when one base serves several tasks (see the LoRA Adapter Hot-Swap demo).
- Add execution-based evaluation against a real database for a stricter metric.
📚 Additional Resources
- Fine-Tune a Model with LoRA
- Prepare Training Datasets for LoRA Fine-Tuning
- LM-Kit.NET documentation: https://docs.lm-kit.com