Привет, Хабр! На связи участница профессионального сообщества 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.     № 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? Модель считает, что только одна компания совершает наименьшее количество рейсов. К сожалению, даже корректировка запроса не помогла решить данную задачу. 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'), и поэтому даже не связывает необходимые таблицы. 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 ) Как можно увидеть, подход моделей к решению отличается, но это не влияет на успешность выполнения задания. Мне кажется, что данное задание составлено некорректно. В итоговом решении требуется замена 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 Обе модели успешно справились с заданием. 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-помощники, поскольку почти в трети случаев всё ещё совершаются ошибки, и это может быть критично для ваших данных. Тем не менее, как помощник или генератор идей эти инструменты могут быть полезными: инструменты могут предложить пользователю различные варианты запросов и помочь синтаксически правильно составить их.  Профессиональное сообщество