Генератор SQL на базе LLM — понятный продукт с понятной ценностью. Он может быть отдельной платформой или инструментом для агента, решающего более общую задачу. Генерировать код модели с попеременным успехом, к счастью, умеют.
И что же? Берем API с моделью помощнее, даем ей доступ к БД, задаем вопрос, смотрим на результат, и всё — полноценная замена аналитику? Конечно, нет, ведь аналитик делает гораздо больше, чем просто пишет и исполняет SQL.
Однако давайте остановимся на SQL и посмотрим, почему это тоже не так просто:
-
Во внутренний контур никто API от OpenAI или Anthropic не встроит и уж тем более не будет туда отправлять чувствительные данные.
-
Если нет возможности обратиться к внешним API, то надо разворачивать модель локально и желательно без GPU, а это дорого и инфраструктура пока не готова.
-
Открытые LLM нередко ошибаются, особенно когда контекста много и он плохо сформулирован или когда речь заходит об определенном диалекте SQL, например PostgreSQL 17.
-
Процесс сбора данных и обучения LLM под конкретный диалект дорогостоящий во всех смыслах.
-
На локальных моделях можно использовать грамматики для guided decoding, однако их разработка и отладка — задачи непростые.
По итогу проблемы есть. Посмотрим, как их можно решить.
Что позволяет модели хорошо генерировать SQL?
В нашей области практика — критерий истины, поэтому рассмотрим несколько существующих подходов, которые дают отличные результаты в бенчмарках.
CHASE-SQL
Авторы CHASE-SQL предположили, что использование различных техник генерации SQL по-отдельности нецелесообразно: каждая из них имеет уникальные особенности, преимущества и недостатки.
Если нам важна именно точность на бенчмарке, а не доступность или скорость модели, почему бы не воспользоваться всем имеющимся арсеналом?
То есть решаем задачу по отдельности в нескольких обособленных пайплайнах, а затем результат каждого подхода отправляем в модель-селектор, выбирающую финальный ответ.
В сущности, каждый пайплайн из себя представляет хитрый промптинг крупной модели, типа Gemini или Claude, и этап саморефлексии в случае синтаксической ошибки.
SQLFuse
Веха в развитии систем для решения задачи Text-To-SQL, совмещающая в себе лучшие практики промпт-инжиниринга, эффективные многомодульные пайплайны, красивые архитектурные решения, технологии fine-tuning'а LLM и многое другое.
Модель состоит из 4 частей:
-
Schema Mining — все про промптинг и создание контекста для модели. Здесь достаются таблицы, столбцы и констреинты типа primary key и foreign key.
-
Schema Linking — модуль, позволяющий выделить значимое подмножество столбцов и таблиц для генерации SQL. Выполняется тоже при помощи языковой модели, обученной конкретно этой задаче при помощи SFT (Supervised Fine-Tuning).
-
SQL Generation — основная модель, в которую направляется весь накопленный ранее контекст вместе с вопросом пользователя. Тоже обучается отдельно при помощи SFT на TRAIN-датасете из Spider-бенчмарка.
-
SQL Critic — стандартный прием, когда результат генератора валидируется еще одним этапом. Только на этот раз у модели есть примеры хороших и плохих практик, пары схожих вопросов и ответов и другая априорная информация.
SkyRL-SQL
Основан на RL-дообучении базовой модели так, чтобы она могла в несколько шагов решать поставленную задачу (Multi-Turn RL). По сути, этот подход наиболее близок тому, что будет описано в этой статье.
Соответственно, совокупность дообучения моделей, формирования контекста и выстраивание пайплайнов позволяют сделать генерацию SQL стабильным и перспективным мероприятием.
Бенчмаркинг
Как оценивать SQL-генераторы? Можно на глаз на известной задаче, но это несерьезно. Обычно прибегают к помощи хорошо сконструированных, проверенных комьюнити и временем бенчмарков. Для задачи text-to-SQL есть 2 общепринятых бенчмарка — Spider и BIRD. Посмотрим, как выглядит каждый из них.
Spider
Классический кросс-доменный text-to-SQL-бенчмарк проверяет способность модели обобщаться на новые схемы БД и генерировать сложные SQL (joins, nested, group by/having и так далее).
Главные метрики:
-
Exact Match (EM) — точное совпадение с эталонным SQL.
-
Execution Accuracy (EX) — совпадение результатов выполнения предсказанного и эталонного SQL.
Примеры из бенчмарка:
|
Вопрос |
Ответ |
|
How many heads of the departments are older than 56 ? |
SELECT count(*) FROM head WHERE age > 56 |
|
List the name, born state and age of the heads of departments ordered by age. |
SELECT name , born_state , age FROM head ORDER BY age |
|
List the creation year, name and budget of each department. |
SELECT creation , name , budget_in_billions FROM department |
|
What is the maximum and minimum budget of the departments? |
SELECT max(budget_in_billions) , min(budget_in_billions) FROM department |
|
What is the average number of employees of the departments whose rank is between 10 and 15? |
SELECT avg(num_employees) FROM department WHERE ranking BETWEEN 10 AND 15 |
BIRD
Большой бенчмарк для text-to-SQL, который ближе к реальному миру. Основной акцент сделан на корректном вычленении значений из таблиц.
Метрики:
-
EX/EM.
-
Soft F1 по результатам выполнения (снижает чувствительность к порядку столбцов и пропускам).
Пример из бенчмарка:
|
Вопрос |
Ответ |
|
What is the ratio of customers who pay in EUR against customers who pay in CZK? |
SELECT CAST(SUM(CASE WHEN |
|
In 2012, who had the least consumption in LAM? |
SELECT |
|
What was the average monthly consumption of customers in SME for the year 2013? |
SELECT AVG( |
|
What was the difference in gas consumption between CZK-paying customers and EUR-paying customers in 2012? |
SELECT SUM(CASE WHEN |
|
Which year recorded the most consumption of gas paid in CZK? |
SELECT SUBSTR( |
Как дообучать думающие модели?
Почему не работает классический SFT?
Под SFT (Supervised Fine-Tuning) обычно понимают обучение модели на размеченных парах (вход → желаемый выход) с минимизацией какого-либо функционала, например кросс-энтропии. То есть модель просто учится имитировать ответы.
Для задач, где требуется длинное рассуждение (SQL, код, математика), такой подход быстро упирается в два фундаментальных ограничения.
Во-первых, нет готовых reasoning-датасетов. Открытые наборы либо вообще не содержат CoT (chain-of-thought), либо включают короткие, шумные и несогласованные пояснения.
Во-вторых, нет соответствия конечной цели. SFT оптимизирует правдоподобие целевых токенов, тогда как практические метрики — это правильность исполнения (EX для SQL), предпочтения пользователей и все такое.
Получается, что модель лучше пишет, но не обязательно лучше решает.
Как доработать датасет под SFT? Генерация reasoning-части
На практике эту дыру пытаются закрыть reverse-майнингом CoT: берут сильную модель, дают ей исходную задачу с правильным ответом или возможностью проверить себя и просят восстановить правдоподобную цепочку рассуждений.
Дальше — многократная генерация вариантов, автоматическая проверка, выбор лучших траекторий, нормализация стиля и упаковка в формат (вход → reasoning + ответ). Получается датасет, на котором уже можно делать SFT так, чтобы ученик учился формату и логике рассуждения, а не только финальному выводу.
Этот путь работает, но у него есть три неприятные особенности:
-
Дорого и долго. Сильная модель стоит денег и времени; верификация тоже не бесплатна (поднятие окружений, исполнение запросов, перегенерации при неудаче).
-
Не всегда эффективно. Учитель иногда реконструирует красивую, но несвязную цепочку мыслей. В результате после фильтрации остается меньше качественных примеров, чем хотелось бы.
-
Трудно исключить утечку априорной информации из промпта. Чтобы reverse-майнинг вообще сработал, в промпт обычно добавляют подсказки: ответ или структуру решения. Все это априорные знания, которые затем оказываются в данных для SFT, что в целом делает SFT бессмысленной затеей.
Что такое Reinforcement Learning?
Обучение с подкреплением (RL) — это идеология, в которой модель рассматривается как политика, выбирающая действия так, чтобы максимизировать ожидаемое вознаграждение.
Есть три основные сущности: состояние (контекст для модели), действие (следующий токен или целая последовательность) и награда. В классическом виде агент взаимодействует со средой, пробует варианты, получает обратную связь и обновляет политику, чтобы повысить суммарную награду.
В контексте LLM наградой могут быть результаты исполнения (прошел ли тест, правильно ли выполняется SQL), предпочтения (какой ответ пользователи считают лучшим). Ключевое идеологическое отличие от SFT в том, что RL оптимизирует именно целевую метрику, а не правдоподобие ответов.
Если нам важна EX, мы обучаемся так, чтобы ее повысить; если важны пользовательские предпочтения, награда формулируется из суррогатной модели предпочтений и направляет обновления политики.
GRPO
GRPO (Group Relative Policy Optimization) — это вариант PPO для RL-дообучения, где обучение ведется по группам из нескольких сэмплов на один и тот же запрос.
Здесь важно то, что оптимизируется политика не по абсолютным наградам, а по относительным преимуществам внутри группы ответов. Это снижает дисперсию градиента и убирает необходимость в Value Model (подробнее про PPO).

Для каждого запроса сэмплируем
ответов
из старой политики
, считаем sequence-level награды
и превращаем их в относительные преимущества:
Отношение вероятностей берется на уровне токена:
Оптимизационный функционал в стиле PPO:
GSPO
GSPO (Group Sequence Policy Optimization) — относительно новый подход к RL-дообучению языковых моделей, который очень схож с GRPO. Отличается он тем, что градиент функционала зависит не от вероятностного распределения конкретных токенов, а от всей последовательности сразу.
Достигается это следующим изменением в формуле:
Как оказалось, такое изменение приводит к более стабильному обучению и быстрой сходимости, особенно для длинных цепочек рассуждений и MoE-моделей.
Больше интересных подробностей про GRPO vs GSPO можно узнать здесь.
GGPO?
К параметрам сэмплирования в vLLM можно добавить и грамматику в формате GBNF, как я описывал в предыдущей статье. Она позволит избежать синтаксически неверных выражений в ходе генерации эквивалентных SQL, однако для этого необходимо иметь на руках соответствующую грамматику.
Таким образом, мы можем в целом озаглавить этот фреймворком, как GGPO (Guided Grammar Policy Optimization).
Датасет
Для обучения было специально подготовлено 2 датасета:
-
https://huggingface.co/datasets/Safreliy/BIRD-train-postgresql
-
https://huggingface.co/datasets/Safreliy/synthetic_text_to_sql
Каждый из них отфильтрован так, чтобы сэмплы отрабатывали на СУБД PostgreSQL.
Во-первых, необходимо, чтобы БД создавались и заполнялись без ошибок, как в случае BIRD, так и в случае synthetic.
Во-вторых, необходимо, чтобы SQL-запросы корректно выполнялись и возвращали непустой результат.
Еще есть демодатасет с reasoning-контентом для предварительного SFT-дообучения, но его качество еще нужно верифицировать:
https://huggingface.co/datasets/Safreliy/BIRD-reasoning-postgresql
Результаты
Техническая информация:
-
Обучение производили на A100 80GB на протяжении трёх суток.
-
Фреймворк дообучения — TRL (GRPO + sequence-level sampling = GSPO).
-
Количество генераций в группе на один сэмпл равняется 10.
-
LoRA:
,
.
-
Генерация rollouts при помощи vLLM.
-
Параметры сэмплирования: temperature=0.7, top_p=0.9, top_k=20.
-
Batchsize = 20.

На валидационном датасете мы получили прирост целевой метрики на ~11% относительно базовой модели, что достаточно неплохо для такой крохи, как Qwen3-0.6B. При этом эпоха завершилась лишь на 28%, очевидно, что потенциал дальнейшего улучшения метрики присутствует.
Попробовать модель самому можно здесь.
Прогон на BIRD-бенчмарке
А как ведет себя модель на mini-dev-версии BIRD-бенчмарка?
Проведем эксперимент — 30 раз прогоним 500 примеров из бенчмарка на базовой модели Qwen3-0.6B (назовем ее BASE) и на нашей LLM, дообученной при помощи GSPO (назовем ее FT). И там, и там поставим temperature=0.3 и top_p=0.9.
Примеры из бенчмарка разбиты на 3 категории: simple, moderate и challenging. По каждой из них будем считать метрику EX. Также посчитаем суммарный total по всем категориям. Таким образом, будем мерить улучшение или ухудшение метрики по 4 разным показателям.
Также стоит помнить, что по примерам распределение неравномерное. Так, в simple входит 148 примеров, в moderate входит 250, а в challenging — 102, в сумме total=500.
Посмотрим на сводную табличку с подсчитанной статистикой:
|
|
|
|
|
|
|
|
|
|
|
|
simple (N=148) |
24.055 ± 1.964 |
23.807 ± 2.021 |
−0.248 |
−1.03 |
[−1.239; 0.744] |
0.63647 |
0.88056 |
−0.123 |
✖ |
|
moderate (N=250) |
6.627 ± 1.006 |
6.053 ± 0.865 |
−0.573 |
−8.65 |
[−1.040; −0.120] |
0.02310 |
0.06930 |
−0.603 |
✖ |
|
challenging (N=102) |
2.744 ± 1.322 |
3.659 ± 1.285 |
+0.915 |
+33.33 |
[0.261; 1.568] |
0.01120 |
0.04480 |
+0.692 |
✅ |
|
total (N=500) |
10.993 ± 0.797 |
10.820 ± 0.846 |
−0.173 |
−1.58 |
[−0.587; 0.234] |
0.44028 |
0.88056 |
−0.208 |
✖ |
Получилась интересная картина: BASE-модель уже неплохо генерирует SQL, и по total обогнать ее пока не удалось. Но если посмотреть по категориям, картинка становится яснее. Больше всего мы преуспели в challenging — самой малочисленной группе: относительный прирост EX составил +33%.
Из-за малого вклада этой категории в общий счет это почти не сдвинуло total. При этом есть некоторая просадка в moderate (−8.65%) — самой многочисленной категории. Однако после учета множественных проверок (Holm-adj p) она не считается статистически значимой.
Мы используем пермутационный тест со статистикой Уэлча как основной.
Идея такая: считаем t-статистику Уэлча (устойчивую к разным дисперсиям) для наблюдаемых данных, затем многократно перемешиваем метки групп (BASE/FT), каждый раз пересчитываем ту же статистику и смотрим долю значений статистики, не менее экстремальных, чем наблюдаемое.
Такой подход не требует предположений о распределении и хорошо работает при умеренных объемах выборки.
Для оценки величины эффекта мы приводим Hedges’ g — это стандартизированная разница средних. Это значение удобно интерпретировать: ~0.2 (малый эффект), ~0.5 (средний эффект), ~0.8 (сильный эффект).
Итог: дообучение надежно усилило модель на самых сложных задачах, но немного ослабило на средних, что, тем не менее, незначимо с точки зрения статистики.
Дальше для улучшения метрик можно:
-
Сделать предварительное обучение при помощи SFT на reasoning-датасете с постобучением при помощи GSPO.
-
Сделать калибровку датасета так, чтобы получить равномерное распределение по всем категориям сложности задач.
-
Увеличить ранг LoRA.
-
Увеличить время обучения так, чтобы покрыть больше примеров из TRAIN.
-
Добавить грамматику для guided decoding, покрывающую обучающий и валидационный датасеты.
Автор: Safreliy
