Instructions to use j2521402/SQL-R1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use j2521402/SQL-R1 with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Upload folder using huggingface_hub
Browse files- .gitattributes +3 -0
- README.md +171 -1
- grpo-hard/README.md +116 -0
- grpo-hard/adapter_config.json +48 -0
- grpo-hard/adapter_model.safetensors +3 -0
- grpo-hard/chat_template.jinja +85 -0
- grpo-hard/tokenizer.json +3 -0
- grpo-hard/tokenizer_config.json +30 -0
- grpo/README.md +157 -0
- grpo/adapter_config.json +48 -0
- grpo/adapter_model.safetensors +3 -0
- grpo/chat_template.jinja +85 -0
- grpo/tokenizer.json +3 -0
- grpo/tokenizer_config.json +30 -0
- sft/README.md +144 -0
- sft/adapter_config.json +48 -0
- sft/adapter_model.safetensors +3 -0
- sft/chat_template.jinja +85 -0
- sft/tokenizer.json +3 -0
- sft/tokenizer_config.json +30 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
grpo/tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
grpo-hard/tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
sft/tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,3 +1,173 @@
|
|
| 1 |
---
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
base_model: Qwen/Qwen3-4B-Base
|
| 3 |
+
library_name: peft
|
| 4 |
+
pipeline_tag: text-generation
|
| 5 |
+
language:
|
| 6 |
+
- en
|
| 7 |
+
tags:
|
| 8 |
+
- base_model:adapter:Qwen/Qwen3-4B-Base
|
| 9 |
+
- peft
|
| 10 |
+
- lora
|
| 11 |
+
- text-to-sql
|
| 12 |
+
- sql
|
| 13 |
+
- sft
|
| 14 |
+
- grpo
|
| 15 |
+
- rlvr
|
| 16 |
+
- trl
|
| 17 |
---
|
| 18 |
+
|
| 19 |
+
# SQL-R1
|
| 20 |
+
|
| 21 |
+
SQL-R1 trains Qwen3-4B-Base for complex Text-to-SQL through completion-only
|
| 22 |
+
supervised fine-tuning and GRPO with verifiable SQLite execution feedback.
|
| 23 |
+
|
| 24 |
+
This repository contains three LoRA adapters:
|
| 25 |
+
|
| 26 |
+
| Subfolder | Stage | Intended use |
|
| 27 |
+
|---|---|---|
|
| 28 |
+
| `sft` | Completion-only SFT | Supervised baseline |
|
| 29 |
+
| `grpo` | SFT + execution-feedback GRPO | Recommended main checkpoint |
|
| 30 |
+
| `grpo-hard` | Hard-sample curriculum GRPO | Ablation and analysis |
|
| 31 |
+
|
| 32 |
+
All three adapters require
|
| 33 |
+
[`Qwen/Qwen3-4B-Base`](https://huggingface.co/Qwen/Qwen3-4B-Base).
|
| 34 |
+
|
| 35 |
+
## Results
|
| 36 |
+
|
| 37 |
+
Execution accuracy (EX) and execution-valid rate were evaluated on the complete
|
| 38 |
+
public BIRD Dev and Spider Dev splits using a consistent greedy-decoding and
|
| 39 |
+
SQLite-execution pipeline.
|
| 40 |
+
|
| 41 |
+
| Checkpoint | BIRD Dev EX | BIRD execution-valid | Spider Dev EX | Spider execution-valid |
|
| 42 |
+
|---|---:|---:|---:|---:|
|
| 43 |
+
| Qwen3-4B-Base | 23.21% | 55.61% | 55.51% | 77.66% |
|
| 44 |
+
| `sft` | 42.37% | 87.29% | 77.27% | 96.62% |
|
| 45 |
+
| **`grpo`** | **42.37%** | 87.35% | **79.59%** | 97.00% |
|
| 46 |
+
| `grpo-hard` | 42.50% | **88.79%** | 78.92% | **97.20%** |
|
| 47 |
+
|
| 48 |
+
The `grpo` checkpoint improves Spider Dev EX by 2.32 percentage points over
|
| 49 |
+
SFT while preserving BIRD Dev EX. The curriculum ablation improves BIRD
|
| 50 |
+
execution validity but shows mild Spider forgetting.
|
| 51 |
+
|
| 52 |
+
These are project-side development-set measurements rather than hidden-test
|
| 53 |
+
leaderboard submissions. Systems using database-content retrieval,
|
| 54 |
+
self-consistency, reranking, or larger proprietary models are not directly
|
| 55 |
+
comparable.
|
| 56 |
+
|
| 57 |
+
## Training overview
|
| 58 |
+
|
| 59 |
+
### SFT
|
| 60 |
+
|
| 61 |
+
- Training records: 12,976
|
| 62 |
+
- Validation records: 608
|
| 63 |
+
- Completion-only loss: prompt tokens are masked and loss is computed only on
|
| 64 |
+
the target SQL
|
| 65 |
+
- LoRA rank/alpha/dropout: 32 / 64 / 0.05
|
| 66 |
+
- Trainable parameters: 66.1M (1.62%)
|
| 67 |
+
- Precision: BF16
|
| 68 |
+
|
| 69 |
+
### GRPO
|
| 70 |
+
|
| 71 |
+
- RL training records: 12,885
|
| 72 |
+
- Optimization steps: 300
|
| 73 |
+
- Candidates per prompt: 4
|
| 74 |
+
- Approximate generated rollouts: 1,200
|
| 75 |
+
- Reward signals: SQL validity, read-only safety, executability, and execution
|
| 76 |
+
result equivalence
|
| 77 |
+
- Parallel read-only SQLite rollout validation
|
| 78 |
+
|
| 79 |
+
Gold SQL and execution results are available only to the reward function and
|
| 80 |
+
are never included in the model prompt.
|
| 81 |
+
|
| 82 |
+
### Hard-sample curriculum ablation
|
| 83 |
+
|
| 84 |
+
- Curriculum records: 2,522
|
| 85 |
+
- BIRD moderate/challenging focus records: 1,891
|
| 86 |
+
- Stratified replay records: 631
|
| 87 |
+
- Optimization steps: 300
|
| 88 |
+
- Validation database overlap: 0
|
| 89 |
+
|
| 90 |
+
## Usage
|
| 91 |
+
|
| 92 |
+
Choose one of `sft`, `grpo`, or `grpo-hard`. The recommended default is `grpo`.
|
| 93 |
+
|
| 94 |
+
```python
|
| 95 |
+
import torch
|
| 96 |
+
from peft import PeftModel
|
| 97 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 98 |
+
|
| 99 |
+
base_model_id = "Qwen/Qwen3-4B-Base"
|
| 100 |
+
repo_id = "j2521402/SQL-R1"
|
| 101 |
+
adapter_subfolder = "grpo"
|
| 102 |
+
|
| 103 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 104 |
+
repo_id,
|
| 105 |
+
subfolder=adapter_subfolder,
|
| 106 |
+
)
|
| 107 |
+
base_model = AutoModelForCausalLM.from_pretrained(
|
| 108 |
+
base_model_id,
|
| 109 |
+
torch_dtype=torch.bfloat16,
|
| 110 |
+
device_map="auto",
|
| 111 |
+
)
|
| 112 |
+
model = PeftModel.from_pretrained(
|
| 113 |
+
base_model,
|
| 114 |
+
repo_id,
|
| 115 |
+
subfolder=adapter_subfolder,
|
| 116 |
+
).eval()
|
| 117 |
+
|
| 118 |
+
messages = [
|
| 119 |
+
{
|
| 120 |
+
"role": "system",
|
| 121 |
+
"content": (
|
| 122 |
+
"You are a Text-to-SQL assistant. Given a SQLite database schema, "
|
| 123 |
+
"optional evidence, and a question, return exactly one read-only "
|
| 124 |
+
"SQLite query. Do not include explanations or Markdown fences."
|
| 125 |
+
),
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"role": "user",
|
| 129 |
+
"content": (
|
| 130 |
+
'Database schema:\nTABLE "singer" ("Singer_ID" INT, "Name" TEXT);\n\n'
|
| 131 |
+
"Question:\nHow many singers do we have?"
|
| 132 |
+
),
|
| 133 |
+
},
|
| 134 |
+
]
|
| 135 |
+
|
| 136 |
+
inputs = tokenizer.apply_chat_template(
|
| 137 |
+
messages,
|
| 138 |
+
add_generation_prompt=True,
|
| 139 |
+
return_tensors="pt",
|
| 140 |
+
return_dict=True,
|
| 141 |
+
).to(model.device)
|
| 142 |
+
|
| 143 |
+
with torch.inference_mode():
|
| 144 |
+
output = model.generate(
|
| 145 |
+
**inputs,
|
| 146 |
+
max_new_tokens=256,
|
| 147 |
+
do_sample=False,
|
| 148 |
+
eos_token_id=tokenizer.eos_token_id,
|
| 149 |
+
pad_token_id=tokenizer.pad_token_id,
|
| 150 |
+
)
|
| 151 |
+
|
| 152 |
+
completion = output[0, inputs["input_ids"].shape[1]:]
|
| 153 |
+
print(tokenizer.decode(completion, skip_special_tokens=True).strip())
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
Each subfolder also contains its tokenizer configuration and detailed model
|
| 157 |
+
card.
|
| 158 |
+
|
| 159 |
+
## Limitations
|
| 160 |
+
|
| 161 |
+
- Training and evaluation focus on English Text-to-SQL and SQLite.
|
| 162 |
+
- Prompts contain database schemas and optional evidence but do not
|
| 163 |
+
automatically retrieve database contents.
|
| 164 |
+
- Execution equivalence is a strong but imperfect correctness signal.
|
| 165 |
+
- Generated SQL may still be wrong or expensive. Execute it only in a
|
| 166 |
+
read-only sandbox with time and row limits.
|
| 167 |
+
- SQL-R1 is a direct Text-to-SQL model, not a general tool-calling agent.
|
| 168 |
+
|
| 169 |
+
## Code
|
| 170 |
+
|
| 171 |
+
Data processing, SFT, GRPO reward, training, and evaluation code:
|
| 172 |
+
[j2521402/SQL-R1](https://github.com/j2521402/SQL-R1).
|
| 173 |
+
|
grpo-hard/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
base_model: Qwen/Qwen3-4B-Base
|
| 3 |
+
library_name: peft
|
| 4 |
+
pipeline_tag: text-generation
|
| 5 |
+
language:
|
| 6 |
+
- en
|
| 7 |
+
tags:
|
| 8 |
+
- base_model:adapter:Qwen/Qwen3-4B-Base
|
| 9 |
+
- peft
|
| 10 |
+
- lora
|
| 11 |
+
- text-to-sql
|
| 12 |
+
- sql
|
| 13 |
+
- grpo
|
| 14 |
+
- rlvr
|
| 15 |
+
- curriculum-learning
|
| 16 |
+
- trl
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
# SQL-R1-GRPO-Hard
|
| 20 |
+
|
| 21 |
+
SQL-R1-GRPO-Hard is a curriculum-learning ablation of SQL-R1. It continues
|
| 22 |
+
GRPO training from SQL-R1-GRPO on BIRD moderate and challenging examples mixed
|
| 23 |
+
with stratified replay data.
|
| 24 |
+
|
| 25 |
+
This repository contains a LoRA adapter for
|
| 26 |
+
[`Qwen/Qwen3-4B-Base`](https://huggingface.co/Qwen/Qwen3-4B-Base).
|
| 27 |
+
For the best overall balance across BIRD and Spider, use SQL-R1-GRPO; this
|
| 28 |
+
checkpoint is published primarily for analysis and reproducibility.
|
| 29 |
+
|
| 30 |
+
## Curriculum data
|
| 31 |
+
|
| 32 |
+
- Total records: 2,522
|
| 33 |
+
- BIRD moderate/challenging focus records: 1,891
|
| 34 |
+
- Stratified replay records: 631
|
| 35 |
+
- Spider replay records: 316
|
| 36 |
+
- Validation database overlap: 0
|
| 37 |
+
|
| 38 |
+
The replay subset preserves easier examples and cross-dataset coverage while
|
| 39 |
+
the curriculum emphasizes harder BIRD queries.
|
| 40 |
+
|
| 41 |
+
## Training
|
| 42 |
+
|
| 43 |
+
- Starting checkpoint: SQL-R1-GRPO
|
| 44 |
+
- Optimization steps: 300
|
| 45 |
+
- Candidates per prompt: 4
|
| 46 |
+
- Approximate generated rollouts: 1,200
|
| 47 |
+
- Learning rate: 2e-6
|
| 48 |
+
- Precision: BF16
|
| 49 |
+
- Reward: SQL validity, read-only safety, executability, and result equivalence
|
| 50 |
+
under parallel SQLite execution
|
| 51 |
+
|
| 52 |
+
Gold SQL is used only to compute verifiable execution rewards and is never
|
| 53 |
+
included in the model prompt.
|
| 54 |
+
|
| 55 |
+
## Evaluation
|
| 56 |
+
|
| 57 |
+
| Checkpoint | BIRD Dev EX | BIRD execution-valid | Spider Dev EX | Spider execution-valid |
|
| 58 |
+
|---|---:|---:|---:|---:|
|
| 59 |
+
| SQL-R1-GRPO | 42.37% | 87.35% | **79.59%** | 97.00% |
|
| 60 |
+
| **SQL-R1-GRPO-Hard** | **42.50%** | **88.79%** | 78.92% | **97.20%** |
|
| 61 |
+
|
| 62 |
+
Hard-sample curriculum training slightly improves BIRD execution accuracy and
|
| 63 |
+
execution validity, but Spider EX decreases mildly. This result illustrates the
|
| 64 |
+
specialization–retention trade-off and motivates the replay ablation.
|
| 65 |
+
|
| 66 |
+
These are project-side measurements on the complete public development splits,
|
| 67 |
+
not hidden-test leaderboard submissions.
|
| 68 |
+
|
| 69 |
+
## Usage
|
| 70 |
+
|
| 71 |
+
```python
|
| 72 |
+
import torch
|
| 73 |
+
from peft import PeftModel
|
| 74 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 75 |
+
|
| 76 |
+
base_model_id = "Qwen/Qwen3-4B-Base"
|
| 77 |
+
repo_id = "j2521402/SQL-R1"
|
| 78 |
+
adapter_subfolder = "grpo-hard"
|
| 79 |
+
|
| 80 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 81 |
+
repo_id,
|
| 82 |
+
subfolder=adapter_subfolder,
|
| 83 |
+
)
|
| 84 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 85 |
+
base_model_id,
|
| 86 |
+
torch_dtype=torch.bfloat16,
|
| 87 |
+
device_map="auto",
|
| 88 |
+
)
|
| 89 |
+
model = PeftModel.from_pretrained(
|
| 90 |
+
model,
|
| 91 |
+
repo_id,
|
| 92 |
+
subfolder=adapter_subfolder,
|
| 93 |
+
)
|
| 94 |
+
model.eval()
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
Use the same SQL-only ChatML prompt format documented in the
|
| 98 |
+
[SQL-R1 repository](https://github.com/j2521402/SQL-R1).
|
| 99 |
+
|
| 100 |
+
## Limitations
|
| 101 |
+
|
| 102 |
+
- This checkpoint deliberately specializes toward harder BIRD examples and
|
| 103 |
+
shows mild Spider forgetting.
|
| 104 |
+
- Training and evaluation focus on English Text-to-SQL and SQLite.
|
| 105 |
+
- Database contents are not automatically retrieved for the prompt.
|
| 106 |
+
- Generated SQL should be executed only in a read-only sandbox with resource
|
| 107 |
+
limits.
|
| 108 |
+
- This is an ablation checkpoint rather than the recommended general model.
|
| 109 |
+
|
| 110 |
+
## Project
|
| 111 |
+
|
| 112 |
+
Training, curriculum-data construction, reward, and evaluation code:
|
| 113 |
+
[j2521402/SQL-R1](https://github.com/j2521402/SQL-R1).
|
| 114 |
+
|
| 115 |
+
Core libraries: PyTorch 2.8.0, Transformers 5.14.1, PEFT 0.19.1,
|
| 116 |
+
TRL 1.8.0, Datasets 5.0.0, and Accelerate 1.14.0.
|
grpo-hard/adapter_config.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"alora_invocation_tokens": null,
|
| 3 |
+
"alpha_pattern": {},
|
| 4 |
+
"arrow_config": null,
|
| 5 |
+
"auto_mapping": null,
|
| 6 |
+
"base_model_name_or_path": "Qwen/Qwen3-4B-Base",
|
| 7 |
+
"bias": "none",
|
| 8 |
+
"corda_config": null,
|
| 9 |
+
"ensure_weight_tying": false,
|
| 10 |
+
"eva_config": null,
|
| 11 |
+
"exclude_modules": null,
|
| 12 |
+
"fan_in_fan_out": false,
|
| 13 |
+
"inference_mode": true,
|
| 14 |
+
"init_lora_weights": true,
|
| 15 |
+
"layer_replication": null,
|
| 16 |
+
"layers_pattern": null,
|
| 17 |
+
"layers_to_transform": null,
|
| 18 |
+
"loftq_config": {},
|
| 19 |
+
"lora_alpha": 64,
|
| 20 |
+
"lora_bias": false,
|
| 21 |
+
"lora_dropout": 0.05,
|
| 22 |
+
"lora_ga_config": null,
|
| 23 |
+
"megatron_config": null,
|
| 24 |
+
"megatron_core": "megatron.core",
|
| 25 |
+
"modules_to_save": null,
|
| 26 |
+
"peft_type": "LORA",
|
| 27 |
+
"peft_version": "0.19.1",
|
| 28 |
+
"qalora_group_size": 16,
|
| 29 |
+
"r": 32,
|
| 30 |
+
"rank_pattern": {},
|
| 31 |
+
"revision": null,
|
| 32 |
+
"target_modules": [
|
| 33 |
+
"down_proj",
|
| 34 |
+
"up_proj",
|
| 35 |
+
"o_proj",
|
| 36 |
+
"q_proj",
|
| 37 |
+
"k_proj",
|
| 38 |
+
"v_proj",
|
| 39 |
+
"gate_proj"
|
| 40 |
+
],
|
| 41 |
+
"target_parameters": null,
|
| 42 |
+
"task_type": "CAUSAL_LM",
|
| 43 |
+
"trainable_token_indices": null,
|
| 44 |
+
"use_bdlora": null,
|
| 45 |
+
"use_dora": false,
|
| 46 |
+
"use_qalora": false,
|
| 47 |
+
"use_rslora": false
|
| 48 |
+
}
|
grpo-hard/adapter_model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:438f3b22fb4c1ac3a2ef0b416378b9196350c702a343be836c59906e6e74c782
|
| 3 |
+
size 264308896
|
grpo-hard/chat_template.jinja
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- if tools %}
|
| 2 |
+
{{- '<|im_start|>system\n' }}
|
| 3 |
+
{%- if messages[0].role == 'system' %}
|
| 4 |
+
{{- messages[0].content + '\n\n' }}
|
| 5 |
+
{%- endif %}
|
| 6 |
+
{{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
|
| 7 |
+
{%- for tool in tools %}
|
| 8 |
+
{{- "\n" }}
|
| 9 |
+
{{- tool | tojson }}
|
| 10 |
+
{%- endfor %}
|
| 11 |
+
{{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
|
| 12 |
+
{%- else %}
|
| 13 |
+
{%- if messages[0].role == 'system' %}
|
| 14 |
+
{{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
|
| 15 |
+
{%- endif %}
|
| 16 |
+
{%- endif %}
|
| 17 |
+
{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
|
| 18 |
+
{%- for message in messages[::-1] %}
|
| 19 |
+
{%- set index = (messages|length - 1) - loop.index0 %}
|
| 20 |
+
{%- if ns.multi_step_tool and message.role == "user" and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
|
| 21 |
+
{%- set ns.multi_step_tool = false %}
|
| 22 |
+
{%- set ns.last_query_index = index %}
|
| 23 |
+
{%- endif %}
|
| 24 |
+
{%- endfor %}
|
| 25 |
+
{%- for message in messages %}
|
| 26 |
+
{%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
|
| 27 |
+
{{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
|
| 28 |
+
{%- elif message.role == "assistant" %}
|
| 29 |
+
{%- set content = message.content %}
|
| 30 |
+
{%- set reasoning_content = '' %}
|
| 31 |
+
{%- if message.reasoning_content is defined and message.reasoning_content is not none %}
|
| 32 |
+
{%- set reasoning_content = message.reasoning_content %}
|
| 33 |
+
{%- else %}
|
| 34 |
+
{%- if '</think>' in message.content %}
|
| 35 |
+
{%- set content = message.content.split('</think>')[-1].lstrip('\n') %}
|
| 36 |
+
{%- set reasoning_content = message.content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
|
| 37 |
+
{%- endif %}
|
| 38 |
+
{%- endif %}
|
| 39 |
+
{%- if loop.index0 > ns.last_query_index %}
|
| 40 |
+
{%- if loop.last or (not loop.last and reasoning_content) %}
|
| 41 |
+
{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
|
| 42 |
+
{%- else %}
|
| 43 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 44 |
+
{%- endif %}
|
| 45 |
+
{%- else %}
|
| 46 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 47 |
+
{%- endif %}
|
| 48 |
+
{%- if message.tool_calls %}
|
| 49 |
+
{%- for tool_call in message.tool_calls %}
|
| 50 |
+
{%- if (loop.first and content) or (not loop.first) %}
|
| 51 |
+
{{- '\n' }}
|
| 52 |
+
{%- endif %}
|
| 53 |
+
{%- if tool_call.function %}
|
| 54 |
+
{%- set tool_call = tool_call.function %}
|
| 55 |
+
{%- endif %}
|
| 56 |
+
{{- '<tool_call>\n{"name": "' }}
|
| 57 |
+
{{- tool_call.name }}
|
| 58 |
+
{{- '", "arguments": ' }}
|
| 59 |
+
{%- if tool_call.arguments is string %}
|
| 60 |
+
{{- tool_call.arguments }}
|
| 61 |
+
{%- else %}
|
| 62 |
+
{{- tool_call.arguments | tojson }}
|
| 63 |
+
{%- endif %}
|
| 64 |
+
{{- '}\n</tool_call>' }}
|
| 65 |
+
{%- endfor %}
|
| 66 |
+
{%- endif %}
|
| 67 |
+
{{- '<|im_end|>\n' }}
|
| 68 |
+
{%- elif message.role == "tool" %}
|
| 69 |
+
{%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
|
| 70 |
+
{{- '<|im_start|>user' }}
|
| 71 |
+
{%- endif %}
|
| 72 |
+
{{- '\n<tool_response>\n' }}
|
| 73 |
+
{{- message.content }}
|
| 74 |
+
{{- '\n</tool_response>' }}
|
| 75 |
+
{%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
|
| 76 |
+
{{- '<|im_end|>\n' }}
|
| 77 |
+
{%- endif %}
|
| 78 |
+
{%- endif %}
|
| 79 |
+
{%- endfor %}
|
| 80 |
+
{%- if add_generation_prompt %}
|
| 81 |
+
{{- '<|im_start|>assistant\n' }}
|
| 82 |
+
{%- if enable_thinking is defined and enable_thinking is false %}
|
| 83 |
+
{{- '<think>\n\n</think>\n\n' }}
|
| 84 |
+
{%- endif %}
|
| 85 |
+
{%- endif %}
|
grpo-hard/tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:be75606093db2094d7cd20f3c2f385c212750648bd6ea4fb2bf507a6a4c55506
|
| 3 |
+
size 11422650
|
grpo-hard/tokenizer_config.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": false,
|
| 3 |
+
"backend": "tokenizers",
|
| 4 |
+
"bos_token": null,
|
| 5 |
+
"clean_up_tokenization_spaces": false,
|
| 6 |
+
"eos_token": "<|endoftext|>",
|
| 7 |
+
"errors": "replace",
|
| 8 |
+
"extra_special_tokens": [
|
| 9 |
+
"<|im_start|>",
|
| 10 |
+
"<|im_end|>",
|
| 11 |
+
"<|object_ref_start|>",
|
| 12 |
+
"<|object_ref_end|>",
|
| 13 |
+
"<|box_start|>",
|
| 14 |
+
"<|box_end|>",
|
| 15 |
+
"<|quad_start|>",
|
| 16 |
+
"<|quad_end|>",
|
| 17 |
+
"<|vision_start|>",
|
| 18 |
+
"<|vision_end|>",
|
| 19 |
+
"<|vision_pad|>",
|
| 20 |
+
"<|image_pad|>",
|
| 21 |
+
"<|video_pad|>"
|
| 22 |
+
],
|
| 23 |
+
"is_local": true,
|
| 24 |
+
"local_files_only": false,
|
| 25 |
+
"model_max_length": 131072,
|
| 26 |
+
"pad_token": "<|endoftext|>",
|
| 27 |
+
"split_special_tokens": false,
|
| 28 |
+
"tokenizer_class": "Qwen2Tokenizer",
|
| 29 |
+
"unk_token": null
|
| 30 |
+
}
|
grpo/README.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
base_model: Qwen/Qwen3-4B-Base
|
| 3 |
+
library_name: peft
|
| 4 |
+
pipeline_tag: text-generation
|
| 5 |
+
language:
|
| 6 |
+
- en
|
| 7 |
+
tags:
|
| 8 |
+
- base_model:adapter:Qwen/Qwen3-4B-Base
|
| 9 |
+
- peft
|
| 10 |
+
- lora
|
| 11 |
+
- text-to-sql
|
| 12 |
+
- sql
|
| 13 |
+
- grpo
|
| 14 |
+
- rlvr
|
| 15 |
+
- trl
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
# SQL-R1-GRPO
|
| 19 |
+
|
| 20 |
+
SQL-R1-GRPO is the main SQL-R1 checkpoint: a LoRA adapter trained on
|
| 21 |
+
Qwen3-4B-Base with completion-only supervised fine-tuning followed by GRPO
|
| 22 |
+
using verifiable SQLite execution feedback.
|
| 23 |
+
|
| 24 |
+
The model receives a database schema, optional evidence, and a natural-language
|
| 25 |
+
question, then generates one read-only SQLite query. This repository contains
|
| 26 |
+
the adapter only; load it together with
|
| 27 |
+
[`Qwen/Qwen3-4B-Base`](https://huggingface.co/Qwen/Qwen3-4B-Base).
|
| 28 |
+
|
| 29 |
+
## Training
|
| 30 |
+
|
| 31 |
+
GRPO starts from the SQL-R1-SFT adapter and optimizes generated SQL with a
|
| 32 |
+
layered execution reward:
|
| 33 |
+
|
| 34 |
+
| Outcome | Reward |
|
| 35 |
+
|---|---:|
|
| 36 |
+
| Empty output | -1.00 |
|
| 37 |
+
| Invalid or non-read-only SQL | -0.75 |
|
| 38 |
+
| SQL execution error | -0.25 |
|
| 39 |
+
| Truncated execution result | -0.10 |
|
| 40 |
+
| Executable but incorrect result | +0.25 |
|
| 41 |
+
| Execution-equivalent to the gold query | +1.00 |
|
| 42 |
+
|
| 43 |
+
A low-weight format reward additionally encourages concise SQL-only output.
|
| 44 |
+
Gold SQL and gold execution results are used only by the reward function and
|
| 45 |
+
are never included in the model prompt.
|
| 46 |
+
|
| 47 |
+
- RL training records: 12,885
|
| 48 |
+
- Optimization steps: 300
|
| 49 |
+
- Candidates per prompt: 4
|
| 50 |
+
- Approximate generated rollouts: 1,200
|
| 51 |
+
- Learning rate: 5e-6
|
| 52 |
+
- GRPO beta: 0.001
|
| 53 |
+
- Clipping epsilon: 0.2
|
| 54 |
+
- Precision: BF16
|
| 55 |
+
- Execution backend: parallel read-only SQLite workers
|
| 56 |
+
|
| 57 |
+
## Evaluation
|
| 58 |
+
|
| 59 |
+
Execution accuracy (EX) and execution-valid rate were measured on the complete
|
| 60 |
+
BIRD Dev and Spider Dev splits with the same greedy decoding and execution
|
| 61 |
+
pipeline at every stage.
|
| 62 |
+
|
| 63 |
+
| Checkpoint | BIRD Dev EX | BIRD execution-valid | Spider Dev EX | Spider execution-valid |
|
| 64 |
+
|---|---:|---:|---:|---:|
|
| 65 |
+
| SQL-R1-SFT | 42.37% | 87.29% | 77.27% | 96.62% |
|
| 66 |
+
| **SQL-R1-GRPO** | **42.37%** | **87.35%** | **79.59%** | **97.00%** |
|
| 67 |
+
|
| 68 |
+
GRPO improves Spider Dev EX by 2.32 percentage points over SFT while preserving
|
| 69 |
+
BIRD Dev EX. This is the recommended SQL-R1 checkpoint.
|
| 70 |
+
|
| 71 |
+
These numbers are project-side development-set measurements, not hidden-test
|
| 72 |
+
leaderboard submissions. Results from systems using prompting, database
|
| 73 |
+
contents, self-consistency, reranking, or larger proprietary models are not
|
| 74 |
+
directly comparable.
|
| 75 |
+
|
| 76 |
+
## Usage
|
| 77 |
+
|
| 78 |
+
```python
|
| 79 |
+
import torch
|
| 80 |
+
from peft import PeftModel
|
| 81 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 82 |
+
|
| 83 |
+
base_model_id = "Qwen/Qwen3-4B-Base"
|
| 84 |
+
repo_id = "j2521402/SQL-R1"
|
| 85 |
+
adapter_subfolder = "grpo"
|
| 86 |
+
|
| 87 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 88 |
+
repo_id,
|
| 89 |
+
subfolder=adapter_subfolder,
|
| 90 |
+
)
|
| 91 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 92 |
+
base_model_id,
|
| 93 |
+
torch_dtype=torch.bfloat16,
|
| 94 |
+
device_map="auto",
|
| 95 |
+
)
|
| 96 |
+
model = PeftModel.from_pretrained(
|
| 97 |
+
model,
|
| 98 |
+
repo_id,
|
| 99 |
+
subfolder=adapter_subfolder,
|
| 100 |
+
)
|
| 101 |
+
model.eval()
|
| 102 |
+
|
| 103 |
+
messages = [
|
| 104 |
+
{
|
| 105 |
+
"role": "system",
|
| 106 |
+
"content": (
|
| 107 |
+
"You are a Text-to-SQL assistant. Given a SQLite database schema, "
|
| 108 |
+
"optional evidence, and a question, return exactly one read-only "
|
| 109 |
+
"SQLite query. Do not include explanations or Markdown fences."
|
| 110 |
+
),
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"role": "user",
|
| 114 |
+
"content": (
|
| 115 |
+
'Database schema:\nTABLE "singer" ("Singer_ID" INT, "Name" TEXT);\n\n'
|
| 116 |
+
"Question:\nHow many singers do we have?"
|
| 117 |
+
),
|
| 118 |
+
},
|
| 119 |
+
]
|
| 120 |
+
|
| 121 |
+
inputs = tokenizer.apply_chat_template(
|
| 122 |
+
messages,
|
| 123 |
+
add_generation_prompt=True,
|
| 124 |
+
return_tensors="pt",
|
| 125 |
+
return_dict=True,
|
| 126 |
+
).to(model.device)
|
| 127 |
+
|
| 128 |
+
with torch.inference_mode():
|
| 129 |
+
output = model.generate(
|
| 130 |
+
**inputs,
|
| 131 |
+
max_new_tokens=256,
|
| 132 |
+
do_sample=False,
|
| 133 |
+
eos_token_id=tokenizer.eos_token_id,
|
| 134 |
+
pad_token_id=tokenizer.pad_token_id,
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
completion = output[0, inputs["input_ids"].shape[1]:]
|
| 138 |
+
print(tokenizer.decode(completion, skip_special_tokens=True).strip())
|
| 139 |
+
```
|
| 140 |
+
|
| 141 |
+
## Limitations
|
| 142 |
+
|
| 143 |
+
- Training and evaluation focus on English Text-to-SQL and SQLite.
|
| 144 |
+
- Prompts contain database schemas and optional evidence, but do not perform
|
| 145 |
+
automatic database-content retrieval.
|
| 146 |
+
- Execution equivalence is a strong but imperfect semantic correctness signal.
|
| 147 |
+
- The model may still generate incorrect or expensive queries; execute outputs
|
| 148 |
+
in a read-only sandbox with time and row limits.
|
| 149 |
+
- This is a direct Text-to-SQL model, not a general tool-calling agent.
|
| 150 |
+
|
| 151 |
+
## Project
|
| 152 |
+
|
| 153 |
+
Training, data processing, reward, and evaluation code:
|
| 154 |
+
[j2521402/SQL-R1](https://github.com/j2521402/SQL-R1).
|
| 155 |
+
|
| 156 |
+
Core libraries: PyTorch 2.8.0, Transformers 5.14.1, PEFT 0.19.1,
|
| 157 |
+
TRL 1.8.0, Datasets 5.0.0, and Accelerate 1.14.0.
|
grpo/adapter_config.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"alora_invocation_tokens": null,
|
| 3 |
+
"alpha_pattern": {},
|
| 4 |
+
"arrow_config": null,
|
| 5 |
+
"auto_mapping": null,
|
| 6 |
+
"base_model_name_or_path": "Qwen/Qwen3-4B-Base",
|
| 7 |
+
"bias": "none",
|
| 8 |
+
"corda_config": null,
|
| 9 |
+
"ensure_weight_tying": false,
|
| 10 |
+
"eva_config": null,
|
| 11 |
+
"exclude_modules": null,
|
| 12 |
+
"fan_in_fan_out": false,
|
| 13 |
+
"inference_mode": true,
|
| 14 |
+
"init_lora_weights": true,
|
| 15 |
+
"layer_replication": null,
|
| 16 |
+
"layers_pattern": null,
|
| 17 |
+
"layers_to_transform": null,
|
| 18 |
+
"loftq_config": {},
|
| 19 |
+
"lora_alpha": 64,
|
| 20 |
+
"lora_bias": false,
|
| 21 |
+
"lora_dropout": 0.05,
|
| 22 |
+
"lora_ga_config": null,
|
| 23 |
+
"megatron_config": null,
|
| 24 |
+
"megatron_core": "megatron.core",
|
| 25 |
+
"modules_to_save": null,
|
| 26 |
+
"peft_type": "LORA",
|
| 27 |
+
"peft_version": "0.19.1",
|
| 28 |
+
"qalora_group_size": 16,
|
| 29 |
+
"r": 32,
|
| 30 |
+
"rank_pattern": {},
|
| 31 |
+
"revision": null,
|
| 32 |
+
"target_modules": [
|
| 33 |
+
"q_proj",
|
| 34 |
+
"down_proj",
|
| 35 |
+
"gate_proj",
|
| 36 |
+
"k_proj",
|
| 37 |
+
"o_proj",
|
| 38 |
+
"up_proj",
|
| 39 |
+
"v_proj"
|
| 40 |
+
],
|
| 41 |
+
"target_parameters": null,
|
| 42 |
+
"task_type": "CAUSAL_LM",
|
| 43 |
+
"trainable_token_indices": null,
|
| 44 |
+
"use_bdlora": null,
|
| 45 |
+
"use_dora": false,
|
| 46 |
+
"use_qalora": false,
|
| 47 |
+
"use_rslora": false
|
| 48 |
+
}
|
grpo/adapter_model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b41bba278ef202b1431372a22a953cc79cba80a0d8aa348733b62bd8f6bbaa1f
|
| 3 |
+
size 264308896
|
grpo/chat_template.jinja
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- if tools %}
|
| 2 |
+
{{- '<|im_start|>system\n' }}
|
| 3 |
+
{%- if messages[0].role == 'system' %}
|
| 4 |
+
{{- messages[0].content + '\n\n' }}
|
| 5 |
+
{%- endif %}
|
| 6 |
+
{{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
|
| 7 |
+
{%- for tool in tools %}
|
| 8 |
+
{{- "\n" }}
|
| 9 |
+
{{- tool | tojson }}
|
| 10 |
+
{%- endfor %}
|
| 11 |
+
{{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
|
| 12 |
+
{%- else %}
|
| 13 |
+
{%- if messages[0].role == 'system' %}
|
| 14 |
+
{{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
|
| 15 |
+
{%- endif %}
|
| 16 |
+
{%- endif %}
|
| 17 |
+
{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
|
| 18 |
+
{%- for message in messages[::-1] %}
|
| 19 |
+
{%- set index = (messages|length - 1) - loop.index0 %}
|
| 20 |
+
{%- if ns.multi_step_tool and message.role == "user" and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
|
| 21 |
+
{%- set ns.multi_step_tool = false %}
|
| 22 |
+
{%- set ns.last_query_index = index %}
|
| 23 |
+
{%- endif %}
|
| 24 |
+
{%- endfor %}
|
| 25 |
+
{%- for message in messages %}
|
| 26 |
+
{%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
|
| 27 |
+
{{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
|
| 28 |
+
{%- elif message.role == "assistant" %}
|
| 29 |
+
{%- set content = message.content %}
|
| 30 |
+
{%- set reasoning_content = '' %}
|
| 31 |
+
{%- if message.reasoning_content is defined and message.reasoning_content is not none %}
|
| 32 |
+
{%- set reasoning_content = message.reasoning_content %}
|
| 33 |
+
{%- else %}
|
| 34 |
+
{%- if '</think>' in message.content %}
|
| 35 |
+
{%- set content = message.content.split('</think>')[-1].lstrip('\n') %}
|
| 36 |
+
{%- set reasoning_content = message.content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
|
| 37 |
+
{%- endif %}
|
| 38 |
+
{%- endif %}
|
| 39 |
+
{%- if loop.index0 > ns.last_query_index %}
|
| 40 |
+
{%- if loop.last or (not loop.last and reasoning_content) %}
|
| 41 |
+
{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
|
| 42 |
+
{%- else %}
|
| 43 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 44 |
+
{%- endif %}
|
| 45 |
+
{%- else %}
|
| 46 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 47 |
+
{%- endif %}
|
| 48 |
+
{%- if message.tool_calls %}
|
| 49 |
+
{%- for tool_call in message.tool_calls %}
|
| 50 |
+
{%- if (loop.first and content) or (not loop.first) %}
|
| 51 |
+
{{- '\n' }}
|
| 52 |
+
{%- endif %}
|
| 53 |
+
{%- if tool_call.function %}
|
| 54 |
+
{%- set tool_call = tool_call.function %}
|
| 55 |
+
{%- endif %}
|
| 56 |
+
{{- '<tool_call>\n{"name": "' }}
|
| 57 |
+
{{- tool_call.name }}
|
| 58 |
+
{{- '", "arguments": ' }}
|
| 59 |
+
{%- if tool_call.arguments is string %}
|
| 60 |
+
{{- tool_call.arguments }}
|
| 61 |
+
{%- else %}
|
| 62 |
+
{{- tool_call.arguments | tojson }}
|
| 63 |
+
{%- endif %}
|
| 64 |
+
{{- '}\n</tool_call>' }}
|
| 65 |
+
{%- endfor %}
|
| 66 |
+
{%- endif %}
|
| 67 |
+
{{- '<|im_end|>\n' }}
|
| 68 |
+
{%- elif message.role == "tool" %}
|
| 69 |
+
{%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
|
| 70 |
+
{{- '<|im_start|>user' }}
|
| 71 |
+
{%- endif %}
|
| 72 |
+
{{- '\n<tool_response>\n' }}
|
| 73 |
+
{{- message.content }}
|
| 74 |
+
{{- '\n</tool_response>' }}
|
| 75 |
+
{%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
|
| 76 |
+
{{- '<|im_end|>\n' }}
|
| 77 |
+
{%- endif %}
|
| 78 |
+
{%- endif %}
|
| 79 |
+
{%- endfor %}
|
| 80 |
+
{%- if add_generation_prompt %}
|
| 81 |
+
{{- '<|im_start|>assistant\n' }}
|
| 82 |
+
{%- if enable_thinking is defined and enable_thinking is false %}
|
| 83 |
+
{{- '<think>\n\n</think>\n\n' }}
|
| 84 |
+
{%- endif %}
|
| 85 |
+
{%- endif %}
|
grpo/tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:be75606093db2094d7cd20f3c2f385c212750648bd6ea4fb2bf507a6a4c55506
|
| 3 |
+
size 11422650
|
grpo/tokenizer_config.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": false,
|
| 3 |
+
"backend": "tokenizers",
|
| 4 |
+
"bos_token": null,
|
| 5 |
+
"clean_up_tokenization_spaces": false,
|
| 6 |
+
"eos_token": "<|endoftext|>",
|
| 7 |
+
"errors": "replace",
|
| 8 |
+
"extra_special_tokens": [
|
| 9 |
+
"<|im_start|>",
|
| 10 |
+
"<|im_end|>",
|
| 11 |
+
"<|object_ref_start|>",
|
| 12 |
+
"<|object_ref_end|>",
|
| 13 |
+
"<|box_start|>",
|
| 14 |
+
"<|box_end|>",
|
| 15 |
+
"<|quad_start|>",
|
| 16 |
+
"<|quad_end|>",
|
| 17 |
+
"<|vision_start|>",
|
| 18 |
+
"<|vision_end|>",
|
| 19 |
+
"<|vision_pad|>",
|
| 20 |
+
"<|image_pad|>",
|
| 21 |
+
"<|video_pad|>"
|
| 22 |
+
],
|
| 23 |
+
"is_local": true,
|
| 24 |
+
"local_files_only": false,
|
| 25 |
+
"model_max_length": 131072,
|
| 26 |
+
"pad_token": "<|endoftext|>",
|
| 27 |
+
"split_special_tokens": false,
|
| 28 |
+
"tokenizer_class": "Qwen2Tokenizer",
|
| 29 |
+
"unk_token": null
|
| 30 |
+
}
|
sft/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
base_model: Qwen/Qwen3-4B-Base
|
| 3 |
+
library_name: peft
|
| 4 |
+
pipeline_tag: text-generation
|
| 5 |
+
language:
|
| 6 |
+
- en
|
| 7 |
+
tags:
|
| 8 |
+
- base_model:adapter:Qwen/Qwen3-4B-Base
|
| 9 |
+
- peft
|
| 10 |
+
- lora
|
| 11 |
+
- text-to-sql
|
| 12 |
+
- sql
|
| 13 |
+
- supervised-fine-tuning
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# SQL-R1-SFT
|
| 17 |
+
|
| 18 |
+
SQL-R1-SFT is a LoRA adapter for
|
| 19 |
+
[Qwen3-4B-Base](https://huggingface.co/Qwen/Qwen3-4B-Base), trained to
|
| 20 |
+
translate a SQLite schema, optional evidence, and a natural-language question
|
| 21 |
+
into exactly one read-only SQL query.
|
| 22 |
+
|
| 23 |
+
This is an adapter-only repository. The Qwen3-4B-Base weights are required for
|
| 24 |
+
inference.
|
| 25 |
+
|
| 26 |
+
## Training
|
| 27 |
+
|
| 28 |
+
- **Method:** completion-only supervised fine-tuning
|
| 29 |
+
- **Training data:** filtered BIRD and Spider training examples
|
| 30 |
+
- **Records:** 12,976 train / 608 database-disjoint validation
|
| 31 |
+
- **LoRA:** rank 32, alpha 64, dropout 0.05
|
| 32 |
+
- **Target modules:** all attention and MLP projections
|
| 33 |
+
- **Trainable parameters:** 66.1M (1.62%)
|
| 34 |
+
- **Precision:** BF16
|
| 35 |
+
- **Epochs:** 1
|
| 36 |
+
- **Learning rate:** 1e-4
|
| 37 |
+
- **Effective batch size:** 16
|
| 38 |
+
|
| 39 |
+
Only target SQL tokens contribute to the loss. Schema, evidence, and question
|
| 40 |
+
tokens are masked. The final assistant completion uses Qwen3-4B-Base's native
|
| 41 |
+
`<|endoftext|>` EOS rather than the ChatML turn separator.
|
| 42 |
+
|
| 43 |
+
## Evaluation
|
| 44 |
+
|
| 45 |
+
Execution accuracy (EX) and execution-valid rate were measured with a common
|
| 46 |
+
read-only SQLite evaluator on the public development sets.
|
| 47 |
+
|
| 48 |
+
| Model | BIRD Dev EX | BIRD valid | Spider Dev EX | Spider valid |
|
| 49 |
+
|---|---:|---:|---:|---:|
|
| 50 |
+
| Qwen3-4B-Base | 23.21% | 55.61% | 55.51% | 77.66% |
|
| 51 |
+
| SQL-R1-SFT | **42.37%** | **87.29%** | **77.27%** | **96.62%** |
|
| 52 |
+
|
| 53 |
+
These are public Dev results produced by the SQL-R1 evaluator, not official
|
| 54 |
+
hidden-test leaderboard submissions.
|
| 55 |
+
|
| 56 |
+
## Usage
|
| 57 |
+
|
| 58 |
+
```python
|
| 59 |
+
import torch
|
| 60 |
+
from peft import PeftModel
|
| 61 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 62 |
+
|
| 63 |
+
base_id = "Qwen/Qwen3-4B-Base"
|
| 64 |
+
repo_id = "j2521402/SQL-R1"
|
| 65 |
+
adapter_subfolder = "sft"
|
| 66 |
+
|
| 67 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 68 |
+
repo_id,
|
| 69 |
+
subfolder=adapter_subfolder,
|
| 70 |
+
)
|
| 71 |
+
base_model = AutoModelForCausalLM.from_pretrained(
|
| 72 |
+
base_id,
|
| 73 |
+
dtype=torch.bfloat16,
|
| 74 |
+
device_map="auto",
|
| 75 |
+
)
|
| 76 |
+
model = PeftModel.from_pretrained(
|
| 77 |
+
base_model,
|
| 78 |
+
repo_id,
|
| 79 |
+
subfolder=adapter_subfolder,
|
| 80 |
+
).eval()
|
| 81 |
+
|
| 82 |
+
messages = [
|
| 83 |
+
{
|
| 84 |
+
"role": "system",
|
| 85 |
+
"content": (
|
| 86 |
+
"You are a Text-to-SQL assistant. Given a SQLite database schema, "
|
| 87 |
+
"optional evidence, and a question, return exactly one read-only "
|
| 88 |
+
"SQLite query. Do not include explanations or Markdown fences."
|
| 89 |
+
),
|
| 90 |
+
},
|
| 91 |
+
{
|
| 92 |
+
"role": "user",
|
| 93 |
+
"content": (
|
| 94 |
+
'Database schema:\nTABLE "singer" ("id" INT, "name" TEXT);\n\n'
|
| 95 |
+
"Question:\nHow many singers are there?"
|
| 96 |
+
),
|
| 97 |
+
},
|
| 98 |
+
]
|
| 99 |
+
|
| 100 |
+
inputs = tokenizer.apply_chat_template(
|
| 101 |
+
messages,
|
| 102 |
+
tokenize=True,
|
| 103 |
+
add_generation_prompt=True,
|
| 104 |
+
enable_thinking=False,
|
| 105 |
+
return_dict=True,
|
| 106 |
+
return_tensors="pt",
|
| 107 |
+
).to(model.device)
|
| 108 |
+
|
| 109 |
+
with torch.inference_mode():
|
| 110 |
+
outputs = model.generate(
|
| 111 |
+
**inputs,
|
| 112 |
+
max_new_tokens=512,
|
| 113 |
+
do_sample=False,
|
| 114 |
+
eos_token_id=[
|
| 115 |
+
tokenizer.eos_token_id,
|
| 116 |
+
tokenizer.convert_tokens_to_ids("<|im_end|>"),
|
| 117 |
+
],
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
sql = tokenizer.decode(
|
| 121 |
+
outputs[0, inputs["input_ids"].shape[1]:],
|
| 122 |
+
skip_special_tokens=True,
|
| 123 |
+
).strip()
|
| 124 |
+
print(sql)
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
## Limitations
|
| 128 |
+
|
| 129 |
+
- Training and evaluation target SQLite and English Text-to-SQL benchmarks.
|
| 130 |
+
- Prompts contain schema metadata but not database row contents.
|
| 131 |
+
- The adapter does not implement tool calling or an autonomous SQL agent.
|
| 132 |
+
- Generated SQL should be validated and executed through a read-only,
|
| 133 |
+
resource-limited database connection.
|
| 134 |
+
|
| 135 |
+
## Project
|
| 136 |
+
|
| 137 |
+
Training code, preprocessing, evaluator, and reproducibility details:
|
| 138 |
+
[j2521402/SQL-R1](https://github.com/j2521402/SQL-R1).
|
| 139 |
+
|
| 140 |
+
### Framework versions
|
| 141 |
+
|
| 142 |
+
- PyTorch 2.8.0+cu128
|
| 143 |
+
- Transformers 5.14.1
|
| 144 |
+
- PEFT 0.19.1
|
sft/adapter_config.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"alora_invocation_tokens": null,
|
| 3 |
+
"alpha_pattern": {},
|
| 4 |
+
"arrow_config": null,
|
| 5 |
+
"auto_mapping": null,
|
| 6 |
+
"base_model_name_or_path": "Qwen/Qwen3-4B-Base",
|
| 7 |
+
"bias": "none",
|
| 8 |
+
"corda_config": null,
|
| 9 |
+
"ensure_weight_tying": false,
|
| 10 |
+
"eva_config": null,
|
| 11 |
+
"exclude_modules": null,
|
| 12 |
+
"fan_in_fan_out": false,
|
| 13 |
+
"inference_mode": true,
|
| 14 |
+
"init_lora_weights": true,
|
| 15 |
+
"layer_replication": null,
|
| 16 |
+
"layers_pattern": null,
|
| 17 |
+
"layers_to_transform": null,
|
| 18 |
+
"loftq_config": {},
|
| 19 |
+
"lora_alpha": 64,
|
| 20 |
+
"lora_bias": false,
|
| 21 |
+
"lora_dropout": 0.05,
|
| 22 |
+
"lora_ga_config": null,
|
| 23 |
+
"megatron_config": null,
|
| 24 |
+
"megatron_core": "megatron.core",
|
| 25 |
+
"modules_to_save": null,
|
| 26 |
+
"peft_type": "LORA",
|
| 27 |
+
"peft_version": "0.19.1",
|
| 28 |
+
"qalora_group_size": 16,
|
| 29 |
+
"r": 32,
|
| 30 |
+
"rank_pattern": {},
|
| 31 |
+
"revision": null,
|
| 32 |
+
"target_modules": [
|
| 33 |
+
"k_proj",
|
| 34 |
+
"q_proj",
|
| 35 |
+
"up_proj",
|
| 36 |
+
"gate_proj",
|
| 37 |
+
"v_proj",
|
| 38 |
+
"down_proj",
|
| 39 |
+
"o_proj"
|
| 40 |
+
],
|
| 41 |
+
"target_parameters": null,
|
| 42 |
+
"task_type": "CAUSAL_LM",
|
| 43 |
+
"trainable_token_indices": null,
|
| 44 |
+
"use_bdlora": null,
|
| 45 |
+
"use_dora": false,
|
| 46 |
+
"use_qalora": false,
|
| 47 |
+
"use_rslora": false
|
| 48 |
+
}
|
sft/adapter_model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8a9fa60097d34eb3844ad134e2edb29fa6db7ba901a39505936cc15d971fd9af
|
| 3 |
+
size 264308896
|
sft/chat_template.jinja
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- if tools %}
|
| 2 |
+
{{- '<|im_start|>system\n' }}
|
| 3 |
+
{%- if messages[0].role == 'system' %}
|
| 4 |
+
{{- messages[0].content + '\n\n' }}
|
| 5 |
+
{%- endif %}
|
| 6 |
+
{{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
|
| 7 |
+
{%- for tool in tools %}
|
| 8 |
+
{{- "\n" }}
|
| 9 |
+
{{- tool | tojson }}
|
| 10 |
+
{%- endfor %}
|
| 11 |
+
{{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
|
| 12 |
+
{%- else %}
|
| 13 |
+
{%- if messages[0].role == 'system' %}
|
| 14 |
+
{{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
|
| 15 |
+
{%- endif %}
|
| 16 |
+
{%- endif %}
|
| 17 |
+
{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
|
| 18 |
+
{%- for message in messages[::-1] %}
|
| 19 |
+
{%- set index = (messages|length - 1) - loop.index0 %}
|
| 20 |
+
{%- if ns.multi_step_tool and message.role == "user" and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
|
| 21 |
+
{%- set ns.multi_step_tool = false %}
|
| 22 |
+
{%- set ns.last_query_index = index %}
|
| 23 |
+
{%- endif %}
|
| 24 |
+
{%- endfor %}
|
| 25 |
+
{%- for message in messages %}
|
| 26 |
+
{%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
|
| 27 |
+
{{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
|
| 28 |
+
{%- elif message.role == "assistant" %}
|
| 29 |
+
{%- set content = message.content %}
|
| 30 |
+
{%- set reasoning_content = '' %}
|
| 31 |
+
{%- if message.reasoning_content is defined and message.reasoning_content is not none %}
|
| 32 |
+
{%- set reasoning_content = message.reasoning_content %}
|
| 33 |
+
{%- else %}
|
| 34 |
+
{%- if '</think>' in message.content %}
|
| 35 |
+
{%- set content = message.content.split('</think>')[-1].lstrip('\n') %}
|
| 36 |
+
{%- set reasoning_content = message.content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
|
| 37 |
+
{%- endif %}
|
| 38 |
+
{%- endif %}
|
| 39 |
+
{%- if loop.index0 > ns.last_query_index %}
|
| 40 |
+
{%- if loop.last or (not loop.last and reasoning_content) %}
|
| 41 |
+
{{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
|
| 42 |
+
{%- else %}
|
| 43 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 44 |
+
{%- endif %}
|
| 45 |
+
{%- else %}
|
| 46 |
+
{{- '<|im_start|>' + message.role + '\n' + content }}
|
| 47 |
+
{%- endif %}
|
| 48 |
+
{%- if message.tool_calls %}
|
| 49 |
+
{%- for tool_call in message.tool_calls %}
|
| 50 |
+
{%- if (loop.first and content) or (not loop.first) %}
|
| 51 |
+
{{- '\n' }}
|
| 52 |
+
{%- endif %}
|
| 53 |
+
{%- if tool_call.function %}
|
| 54 |
+
{%- set tool_call = tool_call.function %}
|
| 55 |
+
{%- endif %}
|
| 56 |
+
{{- '<tool_call>\n{"name": "' }}
|
| 57 |
+
{{- tool_call.name }}
|
| 58 |
+
{{- '", "arguments": ' }}
|
| 59 |
+
{%- if tool_call.arguments is string %}
|
| 60 |
+
{{- tool_call.arguments }}
|
| 61 |
+
{%- else %}
|
| 62 |
+
{{- tool_call.arguments | tojson }}
|
| 63 |
+
{%- endif %}
|
| 64 |
+
{{- '}\n</tool_call>' }}
|
| 65 |
+
{%- endfor %}
|
| 66 |
+
{%- endif %}
|
| 67 |
+
{{- '<|im_end|>\n' }}
|
| 68 |
+
{%- elif message.role == "tool" %}
|
| 69 |
+
{%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
|
| 70 |
+
{{- '<|im_start|>user' }}
|
| 71 |
+
{%- endif %}
|
| 72 |
+
{{- '\n<tool_response>\n' }}
|
| 73 |
+
{{- message.content }}
|
| 74 |
+
{{- '\n</tool_response>' }}
|
| 75 |
+
{%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
|
| 76 |
+
{{- '<|im_end|>\n' }}
|
| 77 |
+
{%- endif %}
|
| 78 |
+
{%- endif %}
|
| 79 |
+
{%- endfor %}
|
| 80 |
+
{%- if add_generation_prompt %}
|
| 81 |
+
{{- '<|im_start|>assistant\n' }}
|
| 82 |
+
{%- if enable_thinking is defined and enable_thinking is false %}
|
| 83 |
+
{{- '<think>\n\n</think>\n\n' }}
|
| 84 |
+
{%- endif %}
|
| 85 |
+
{%- endif %}
|
sft/tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:be75606093db2094d7cd20f3c2f385c212750648bd6ea4fb2bf507a6a4c55506
|
| 3 |
+
size 11422650
|
sft/tokenizer_config.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": false,
|
| 3 |
+
"backend": "tokenizers",
|
| 4 |
+
"bos_token": null,
|
| 5 |
+
"clean_up_tokenization_spaces": false,
|
| 6 |
+
"eos_token": "<|endoftext|>",
|
| 7 |
+
"errors": "replace",
|
| 8 |
+
"extra_special_tokens": [
|
| 9 |
+
"<|im_start|>",
|
| 10 |
+
"<|im_end|>",
|
| 11 |
+
"<|object_ref_start|>",
|
| 12 |
+
"<|object_ref_end|>",
|
| 13 |
+
"<|box_start|>",
|
| 14 |
+
"<|box_end|>",
|
| 15 |
+
"<|quad_start|>",
|
| 16 |
+
"<|quad_end|>",
|
| 17 |
+
"<|vision_start|>",
|
| 18 |
+
"<|vision_end|>",
|
| 19 |
+
"<|vision_pad|>",
|
| 20 |
+
"<|image_pad|>",
|
| 21 |
+
"<|video_pad|>"
|
| 22 |
+
],
|
| 23 |
+
"is_local": true,
|
| 24 |
+
"local_files_only": false,
|
| 25 |
+
"model_max_length": 131072,
|
| 26 |
+
"pad_token": "<|endoftext|>",
|
| 27 |
+
"split_special_tokens": false,
|
| 28 |
+
"tokenizer_class": "Qwen2Tokenizer",
|
| 29 |
+
"unk_token": null
|
| 30 |
+
}
|