Генератор 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, покрывающую обучающий и валидационный датасеты. 


