LLM'ы в преобразовании запроса на естественном языке в SQL (text2sql)

Изображение создано с помощью Kandinsky 2.2.

Изображение создано с помощью Kandinsky 2.2.

Привет, Хабр! На связи участница профессионального сообщества NTA Марина Коробова.

Данные занимают центральное место в информационном обществе. Именно информация является основой для принятия решений, развития бизнеса и научных исследований. Многие организации инвестируют огромные средства в системы, способные хранить, обрабатывать и анализировать данные.

Одной из главных проблем, с которыми сталкиваются компании, это непосредственная работа с базами данных с помощью языка SQL (Structured Query Language). Не все знают этот язык, и не у всех есть время изучать его. Поэтому на рынке появляются инструменты, позволяющие писать запрос на естественном языке и получать ответ на языке запросов.

В посте познакомлю вас с двумя AI-инструментами для генерации SQL-запросов: SQLCoder Defog и SQLthroughAI.

Введение

Проблема преобразования запросов на естественном языке в SQL-запросы является одной из ключевых задач в области обработки естественного языка (Natural Language Processing, NLP). Одним из наиболее эффективных подходов к решению задачи text2sql является использование больших языковых моделей (Large Language Models, LLM). В научных публикациях используются различные наименования этой задачи: NL2SQL, seq2sql, NLQ-SQL, NLQ2Query, natural language to SQL и прочее. В данном посте все эти термины являются синонимами.

Модели типа LLM for SQL-queries обучаются и тестируются на больших наборах пар запросов на естественном языке (natural language querying, NLQ) и языке SQL, которые способны извлекать информацию из одной или нескольких баз данных. Часто используются такие наборы данных, как Spider, WikiSQL, SParC и другие.

Запрос text-to-SQL обычно состоит минимум из двух компонентов: вопроса на естественном языке и описания (схемы) базы данных. Необязательными элементами являются демонстрационный пример и инструкции по выполнению задачи.

Основными проблемами применения LLM for SQL-queries являются генерирование ошибочных ответов (галлюцинации модели) и риск похищения пользовательских данных. Пользователи должны самостоятельно проверять выдаваемый моделью SQL-запрос, поскольку нет никаких гарантий, что скрипт будет рабочий. Вторая же проблема решается созданием собственной LLM или размещением автономной (self-hosted) модели на собственном сервере.

Сейчас на рынке доступно множество решений так или иначе связанных с генерацией SQL-запросов: Dataherald, DB-GBT, NL2SQL и другие.

В продолжение предыдущего поста я сосредоточилась на модели SQLCoder Defog, а для сравнения с ней выбрала SQLthroughAI, использующую технологии от Open AI.

Немного о моделях

SQLCoder — это большая языковая модель с 15 миллиардами параметров, дообученная на модели StarCoder компанией Defog. Модель прошла обучение на 10 537 вопросах, заданных людьми на основе 10 различных схем баз данных. Обучение проходило в два этапа в зависимости от уровня сложности вопросов:

  • первый этап: «легкие» и «средние» вопросы (easy+medium);

  • второй этап: «сложные» и «сверхсложные» вопросы (hard+extra-hard).

Эта классификация была выполнена путем адаптации рубрикации, используемой набором данных Spider. Результаты обучения на данных, взятых с первого этапа, были сохранены в модели под названием defog-easy. Для оценивания корректности предлагаемых запросов компания разработала свой собственный фреймворк — sql-eval.

SQLCoder превосходит gpt-3.5-turbo и text-davinci-003, которые являются моделями, более чем в 10 раз превышающими его размер, а при тонкой настройке для отдельных схем баз данных SQLCoder будет обладать такой же или лучшей производительностью, чем GPT-4 OpenAI, с меньшей задержкой (на A100 GPU).

Способы использования SQLCoder:

  • непосредственно скачать из Hugging Face;

  • воспользоваться демо-версией через веб-сайт;

  • запустить блокнот в Colab.

SQLthroughAI — это инструмент искусственного интеллекта, созданный на базе технологий от Open AI. На сайте представлено крайне мало информации, поэтому неизвестно, как именно была доработана модель, но за этой информацией можно обратиться к разработчикам: SQLtroughAI@gmail.com.

Почему я выбрала этот AI-помощник? Он бесплатный, не требует API key и имеет веб-интерфейс.

Практическая часть

Поскольку я хотела, чтобы любой пользователь смог самостоятельно поэкспериментировать с запросами, то реализую все практические примеры на сайтах моделей.

Я буду писать запросы на русском языке, заставляя модель подстраиваться под запросы рядового пользователя. Поэтому, как вы понимаете, качество представленных результатов будет ниже ожидаемого. В случае, если модель допустит ошибку, попробую помочь ей, добавив немного контекста.

Хочу отметить, что несмотря на информацию, представленную на сайте о том, что в настоящее время SQLthroughAI поддерживает только английский язык, AI-помощник принимал запросы на русском языке и выдавал корректные SQL-ответы.

Все задания взяты c сайта sql-academy. Выберу базу данных «Авиаперелеты» и продемонстрирую работу большой языковой модели.

Схема базы данных во всех запросах одинаковая. Создам её с помощью DDL (языка описания данных). Также перед промтом для модели SQLCoder буду писать MySQL, поскольку сайт sql-academy принимает ответы только на этом диалекте.

Для SQLthroughAI создам схему базы данных вручную и настрою связи с помощью веб-интерфейса. При отправке промта необходимо выбирать все таблицы из базы данных, и отмечать необходимый диалект, в моём случае — MySQL.

Сразу отмечу, что на сайте был представлен единственный сложный запрос для данной таблицы. Поэтому я попросила AI-инструменты сгенерировать сложные запросы и для другой базы данных Airbnb.

Авиаперелеты

SQLCoder

CREATE TABLE trip(
id INT PRIMARY KEY,
company INT, -- идентификатор компании-перевозчика
plane VARCHAR, -- модель самолета
town_from VARCHAR, -- город вылета
town_to VARCHAR, -- город прилёта
time_out DATETIME, -- время вылета
time_in DATETIME -- время прилёта
); 

CREATE TABLE company(
id INT PRIMARY KEY,
name VARCHAR -- название компании-перевозчика
);

CREATE TABLE pass_in_trip(
id INT PRIMARY KEY,
trip INT, -- идентификатор билета
passenger INT, -- идентификатор пассажира
place VARCHAR -- место пассажира в самолёте
);

CREATE TABLE passenger(
id INT PRIMARY KEY,
name VARCHAR -- имя и фамилия пассажира
);

SQLthroughAI

Интерфейс для создания полей в таблице. Предлагается всего 4 типа поля (string, date, number, id).

Интерфейс для создания полей в таблице. Предлагается всего 4 типа поля (string, date, number, id).

3519b516c937167441e07810efc66503.png2f813214847063635a7eb3869636085a.pngad3f0d3886cb5aa3d079815cd9d525ac.png

Airbnb

SQLCoder

-- отзывы на арендуемое жилье
CREATE TABLE Reviews( 
id INT PRIMARY KEY,
reservation_id INT, -- идентификатор брони
rating INT, -- рейтинг от 1 до 5
); 

-- пользователи сервиса бронирования
CREATE TABLE users(
id INT PRIMARY KEY,
name VARCHAR, -- имя и фамилия пользователя
email VARCHAR, -- электронная почта пользователя
email_verified_at DATETIME, -- дата подтверждения почты
password VARCHAR, -- пароль от аккаунта
phone_number VARCHAR -- номер телефона пользователя
);

-- история бронирования жилья
CREATE TABLE Reservations(
id INT PRIMARY KEY,
user_id INT, -- идентификатор  пользователя
room_id INT, -- идентификатор  жилья
start_date DATETIME, -- дата начала бронирования
end_date DATETIME, -- дата окончания бронирования
price INT, -- цена за сутки
total INT -- общая стоимость бронирования
);

-- доступные вариант жилья
CREATE TABLE Rooms(
id INT PRIMARY KEY,
home_type VARCHAR, -- тип жилья
address VARCHAR, -- адрес жилья
has_tv BOOLEAN, -- наличие телевизора
has_internet BOOLEAN, -- наличие интернета
has_kitchen BOOLEAN, -- наличие кухни
has_air_con BOOLEAN, -- наличие кондиционера
price INT, -- цена за сутки
owner_id INT, -- идентификатор владельца
latitude FLOAT, -- географическая широта
longitude FLOAT -- географическая долгота
);

SQLthroughAI

5005e5f260bfa0582717e9589140a784.pngВыбираю все таблицы из базы данных для формирования запроса.

Выбираю все таблицы из базы данных для формирования запроса.

Примеры запросов

№ 55:

NL-query (запрос на естественном языке)

Удалить компании, совершившие наименьшее количество рейсов.

SQL query (полученный SQL-запрос)

SQLCoder (неверно)

SQLthroughAI (верно)

WITH min_trip_count AS (

SELECT company, count(*) AS trip_count

FROM trip

GROUP BY company

ORDER BY trip_count ASC

LIMIT 1)

DELETE FROM company

WHERE id IN (SELECT company

FROM min_trip_count)

DELETE FROM company

WHERE id IN

(SELECT t.company

FROM trip t

GROUP BY t.company

HAVING COUNT(*) =

(SELECT MIN(count_flights)

FROM (SELECT COUNT(*) AS count_flights

FROM trip

GROUP BY company ) AS subquery ) );

Комментарий

В чём же проблема решения от SQLCoder? Модель считает, что только одна компания совершает наименьшее количество рейсов. К сожалению, даже корректировка запроса не помогла решить данную задачу.

№ 58:

NL-query

Добавить отзыв с рейтингом 5 на жилье, находящиеся по адресу »11218, Friel Place, New York», от имени «George Clooney».

В качестве первичного ключа (id) укажите количество записей в таблице + 1.

Резервация комнаты, на которую вам нужно оставить отзыв, уже была сделана, нужно лишь её найти.

SQL query

SQLCoder (верно)

SQLthroughAI (неверно)

INSERT INTO reviews (id, rating, reservation_id)

VALUES (

(SELECT COUNT(*) + 1 FROM reviews as a),

5,

(SELECT r.id

FROM reservations r

JOIN rooms r1 on r.room_id = r1.id

WHERE r1.address = '11218, Friel Place, New York'

and r.user_id = (SELECT u.id FROM users u WHERE u.name = 'George Clooney')));

INSERT INTO Reviews (id, reservation_id, rating)

VALUES (

(SELECT COUNT(*)+1 FROM Reviews),

(SELECT id

FROM Reservations

WHERE room_id = (SELECT id FROM Rooms WHERE address = "11218, Friel Place, New York")),

5);

Комментарий

SQLthroughAI не учитывает условие, связанное с пользователем (name = 'George Clooney'), и поэтому даже не связывает необходимые таблицы.

№ 68:

NL-query

Для каждой комнаты, которую снимали как минимум 1 раз, найдите имя человека, снимавшего ее последний раз, и дату, когда он выехал.

Поля в результирующей таблице:

room_id

name

end_date

Используйте конструкцию »as room_id» для вывода идентификатора комнаты.

SQL query

SQLCoder (верно)

SQLthroughAI (верно)

WITH last_seen AS (

SELECT r.room_id, u.name, r.end_date FROM reservations r join users u on r.user_id = u.id

WHERE r.start_date = (SELECT max(start_date)

FROM reservations

WHERE room_id = r.room_id))

SELECT l.room_id, l.name, l.end_date

FROM last_seen l

GROUP BY l.room_id, l.name, l.end_date

HAVING count(*) >= 1;

SELECT r.room_id AS room_id,

u.name AS name,

r.end_date AS end_date

FROM Reservations r

JOIN users u ON r.user_id = u.id

WHERE r.room_id IN

(SELECT room_id

FROM Reservations

GROUP BY room_id

HAVING COUNT(DISTINCT user_id) > 0 ) AND r.id = ( SELECT id FROM Reservations r2 WHERE r2.room_id = r.room_id ORDER BY end_date DESC LIMIT 1 )

Комментарий

Как можно увидеть, подход моделей к решению отличается, но это не влияет на успешность выполнения задания.

№ 69:

Мне кажется, что данное задание составлено некорректно. В итоговом решении требуется замена NULL на нулевые значения, поэтому было принято решение скорректировать запрос на естественном языке.

Модели плохо справлялась с данным заданием, поэтому явно указала необходимую конструкцию.

NL-query

Вывести идентификаторы всех владельцев комнат и сумму, которую они заработали. Суммирование происходит по полю total.

Замени все NULL в поле суммы на ноль с помощью COALESCE.

Используйте конструкцию »as owner_id» и »as total_earn» для вывода идентификаторов владельцев и заработанной суммы соответственно.

SQL query

SQLCoder (верно)

SQLthroughAI (верно)

SELECT rooms.owner_id as owner_id,

COALESCE(sum(reservations.total),0) as total_earn

FROM rooms LEFT JOIN reservations

ON rooms.id = reservations.room_id

GROUP BY rooms.owner_id;

SELECT owner_id as owner_id, COALESCE(SUM(total), 0) as total_earn

FROM Rooms

LEFT JOIN Reservations ON Rooms.id = Reservations.room_id

GROUP BY owner_id

Комментарий

Обе модели успешно справились с заданием.

№ 71:

NL-query

Найдите какой процент пользователей, зарегистрированных на сервисе бронирования, хоть раз арендовали или сдавали в аренду жилье. Результат округлите до сотых.

Поля в результирующей таблице:

percent

Используйте конструкцию »as percent» для вывода процента активных пользователей. Пример формата ответа — 65.23.

SQL query

SQLCoder (неверно)

SQLthroughAI (неверно)

WITH active_users AS (

SELECT count(*) AS active_users_count

FROM users

WHERE id IN (SELECT DISTINCT user_id

FROM reservations))

SELECT ROUND(100.0 * active_users.active_users_count / (SELECT count(*)

FROM users), 2) AS percent

FROM active_users;

SELECT (COUNT(DISTINCT u.id) / COUNT(DISTINCT r.user_id) * 100) AS percent

FROM users u

LEFT JOIN Reservations r ON u.id = r.user_id

WHERE u.email_verified_at IS NOT NULL

AND r.user_id IS NOT NULL

AND (r.start_date IS NOT NULL OR r.end_date IS NOT NULL)

Комментарий

Как видно, обе модели не учитывают владельцев жилья, также SQLthroughAI не использует команду округления.

Оценка моделей

Модель

База данных

Уровень сложности

Верно (номера заданий)

Неверно (номера заданий)

Процент верных

SQLCoder

Перелёты

Лёгкие

2, 3, 4, 5, 6, 7, 9, 28, 56

1, 12, 14, 15

17/26≈65%

Средние

8, 13, 16, 29, 30

10, 11, 67

Сложные

55

Airbnb

Сложные

58, 68, 69

71

SQLthroughAI

Перелёты

Лёгкие

2, 3, 4, 5, 7, 9, 14, 15, 28, 56

1, 6, 12

18/26≈69%

Средние

10, 11, 16, 29, 30

8, 13, 67

Сложные

55

Airbnb

Сложные

68, 69

58, 71

Как видно, каждая из моделей выполнила примерно две трети запросов успешно.

SQLCoder

SQLthroughAI

Лёгкие

≈ 69,2%

≈ 76,9%

Средние

≈ 62,5%

≈ 62,5%

Тяжелые

≈ 60%

≈ 60%

Сравнение моделей

В таблице я сравнила модели и результаты их работы:

SQLCoder

SQLthroughAI

Способы использования

Hugging Face; Colab; веб-сайт.

Веб-сайт.

Возможность доработки модели

Да

Нет

Поддерживаемые базы данных

MySQL, PostgreSQL, Amazon Redshift, Showflake, BigQuery, Azure SQL

MySQL, PostgreSQL, MS SQL, Mongo DB, Oracle PL/SQL, BigQuery, MariaDB

Способы создания базы данных

DDL

CSV/Excel; DDL; вручную на сайте

Настройка типов данных

Все известные типы

String, Date, Number, ID

Регистрация

Нет

Да

Процент полученных верных ответов

65%

69%

Вывод

SQLCoder и SQLthroughAI частично справились с задачей преобразования запроса на естественном языке в запрос на языке SQL. Не рекомендую пользователям без опыта в данной области применять эти AI-помощники, поскольку почти в трети случаев всё ещё совершаются ошибки, и это может быть критично для ваших данных. Тем не менее, как помощник или генератор идей эти инструменты могут быть полезными: инструменты могут предложить пользователю различные варианты запросов и помочь синтаксически правильно составить их.

© Habrahabr.ru