Перейти к содержимому
Последнее обновление

SQL-функции для LLM

Кратко Apache Doris предоставляет семейство SQL-функций AI_*, которые передают значение столбца строки внешней LLM и возвращают результат прямо в запросе. Вы один раз настраиваете провайдера в виде AI-ресурса RESOURCE, а затем используете AI_CLASSIFY(...), AI_EXTRACT(...) или AI_GENERATE(...) везде, где допустимо значение. Cortex AISQL от Snowflake и AI Functions от Databricks решают те же задачи; семейство AI_* в Apache Doris служит их аналогом с открытым исходным кодом.

SQL-функции для LLM в Apache Doris: SQL-функции AI_* в Doris передают значения столбцов в LLM и возвращают результат прямо в запросе, поэтому классификация, извлечение данных и создание сводок выполняются средствами SQL.

Зачем использовать SQL-функции AI_* в Apache Doris?​

SQL-функции AI_* в Apache Doris избавляют от необходимости создавать внешний сервис на Python для классификации текстовых столбцов, извлечения данных, создания сводок или маскирования PII. Значительная часть аналитической работы с текстовыми столбцами на деле вовсе не аналитика. Кому-то приходится классифицировать обращения в поддержку по темам, определять тональность отзывов, извлекать названия товаров из жалоб в свободной форме, составлять сводки длинных заметок о звонках или скрывать PII перед экспортом. Работа повторяется, столбцы уже находятся в хранилище, и не хватает только модели. Apache Doris уже предоставляет эмбеддинги через EMBED() и сервер MCP для AI-клиентов, поэтому эта карточка дополняет набор возможностей, доступных через SQL.

Обычно для этого создают сервис на Python. Он забирает строки из Doris, вызывает OpenAI или Anthropic, разбирает ответ и записывает результат обратно. Такой сервис постепенно теряет синхронизацию с исходной таблицей, самостоятельно обрабатывает повторные попытки и находится вне механизмов управления доступом и наблюдаемости хранилища.

Функции AI_* переносят этот цикл в SQL. Модель становится зарегистрированным ресурсом. Вызов выполняется через функцию. Результат представляет собой столбец, который можно сохранить с помощью INSERT, использовать для фильтрации в WHERE или вычислять на лету. Один язык, одна граница транзакции, одно место для чтения журнала аудита.

Что представляют собой SQL-функции AI_* в Apache Doris?​

Семейство AI_* в Apache Doris представляет собой набор функций, доступных из SQL и выполняющих HTTP-вызов к провайдеру LLM. Каждая функция подставляет входные столбцы в фиксированный шаблон промпта и возвращает типизированный результат, поэтому планировщик обрабатывает их как любые другие скалярные функции. Apache Doris обращается к провайдеру через AI-ресурс, который вы один раз создаёте с помощью CREATE RESOURCE ... TYPE='ai'. Десять скалярных функций покрывают наиболее распространённые задачи, а одна агрегатная функция, AI_AGG, объединяет несколько строк в единый ответ, созданный LLM.

Основные термины

  • AI-ресурс: именованное подключение к провайдеру LLM. Хранит provider_type, конечную точку, имя модели, ключ API и параметры настройки (temperature, max_token, max_retries, retry_delay_second). Поддерживаются двенадцать провайдеров: OpenAI, Anthropic, Gemini, DeepSeek, MoonShot, QWen, MiniMax, Zhipu, Baichuan, VoyageAI, Jina и local для конечных точек, развёрнутых на собственной инфраструктуре.
  • Скалярные функции AI_*: AI_GENERATE, AI_TRANSLATE, AI_SUMMARIZE, AI_SENTIMENT, AI_CLASSIFY, AI_EXTRACT, AI_FIXGRAMMAR, AI_MASK, AI_FILTER, AI_SIMILARITY. Каждая принимает имя ресурса первым аргументом, столбец вторым, а также небольшой набор аргументов для конкретной задачи, например набор меток или целевой язык.
  • AI_AGG: агрегатная функция, которая объединяет все строки группы, отправляет их в LLM с пользовательским промптом и возвращает одну сводку для каждой группы. Аналог AI_SUMMARIZE для групп строк.
  • default_ai_resource: переменная сеанса, которая выбирает ресурс на оставшуюся часть сеанса, позволяя опустить явный первый аргумент.

Как работают SQL-функции AI_* в Apache Doris?​

SQL-функции AI_* в Apache Doris выполняются как скалярные UDF на BE: планировщик направляет каждый вызов на выполнение, BE объединяет строки в пакеты, и для каждого пакета провайдеру отправляется один HTTP-запрос, после чего типизированное значение возвращается в SQL.

  1. Регистрация модели. CREATE RESOURCE проверяет конечную точку пробным вызовом (проверка пропускается при provider_type = 'local' или ai.validity_check = 'false'), маскирует ключ API в выводе SHOW RESOURCES и сохраняет конфигурацию в метаданных FE.
  2. Планирование вызова. Когда планировщик встречает функцию AI_*, он направляет работу на BE так же, как для любой скалярной UDF. Первый аргумент функции должен быть литералом с именем ресурса; выражение на этом месте планировщик отклоняет на этапе анализа.
  3. Формирование пакетов на BE. BE накапливает входные строки в пакет, размер которого ограничен embed_max_batch_size (по умолчанию 5) и ai_context_window_size (по умолчанию 128 KB суммарного текста), затем отправляет один HTTP-запрос для каждого пакета. Слишком большая строка получает отдельный пакет, поэтому один длинный документ не задерживает выполнение остальной части запроса.
  4. Повторные попытки и тайм-ауты. HTTP-вызов учитывает параметры ресурса ai.max_retries и ai.retry_delay_second. Для каждого запроса действует оставшееся время из query_timeout сеанса, поэтому медленный провайдер не продлевает выполнение запроса сверх отведённого времени.
  5. Возврат типизированного значения. Скалярные функции возвращают STRING (или BOOLEAN для AI_FILTER, DOUBLE для AI_SIMILARITY). Значение можно сохранить, использовать для фильтрации или передать следующему оператору, не выходя за рамки SQL.

Быстрый старт​

CREATE RESOURCE "deepseek_chat" PROPERTIES (
"type" = "ai", "ai.provider_type" = "deepseek",
"ai.endpoint" = "https://api.deepseek.com/chat/completions",
"ai.model_name" = "deepseek-chat", "ai.api_key" = "sk-xxx"
);
SET default_ai_resource = "deepseek_chat";

CREATE TABLE reviews (id INT, body STRING)
DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1;
INSERT INTO reviews VALUES
(1, 'Battery dies in 4 hours. Returning it.'),
(2, 'Fits perfectly, color is exactly as pictured. Love it.');

SELECT id, body, AI_SENTIMENT(body) AS sentiment,
AI_CLASSIFY(body, ['battery', 'fit', 'price', 'shipping']) AS topic
FROM reviews;

Ожидаемый результат

+----+--------------------------------+-----------+---------+
| id | body | sentiment | topic |
+----+--------------------------------+-----------+---------+
| 1 | Battery dies in 4 hours... | negative | battery |
| 2 | Fits perfectly, color is... | positive | fit |
+----+--------------------------------+-----------+---------+

Запрос выполняет два обращения к LLM, по одному на функцию, причём при каждом обращении обе строки входят в один пакет. Выходные столбцы имеют строковый тип, поэтому последующие GROUP BY topic или соединение работают без разбора данных.

Когда следует использовать SQL-функции AI_* в Apache Doris?​

Функции AI_* в Apache Doris подходят для пакетного обогащения данных, дозаполнения данных в ETL и агрегирования нескольких строк, но не для интерактивных запросов с временем ответа менее секунды или нагрузок, требующих строгой воспроизводимости.

Подходящие сценарии

  • Пакетное обогащение текстовых столбцов: классификация обращений в поддержку каждую ночь, определение тональности новых отзывов или однократное извлечение структурированных полей из счетов при поступлении данных.
  • Дозаполнение внутри базы данных: UPDATE t SET topic = AI_CLASSIFY(body, [...]) WHERE topic IS NULL позволяет выполнять всю работу в одном месте и использовать преимущества транзакций Doris.
  • Агрегирование нескольких строк через AI_AGG: еженедельные сводки жалоб по каждому товару, краткие обзоры заметок встреч для руководства, тематические подборки новостных статей.
  • Семантическая фильтрация в WHERE: AI_FILTER('Is this a security incident?', body) для разовой первичной сортировки, когда дообучать классификатор избыточно.

Неподходящие сценарии

  • Вызов AI_* для каждой строки при каждом обновлении дашборда. Каждая строка означает один вызов провайдера, а стоимость растёт с числом строк и частотой обновления. Сохраните результат в столбце, создайте для него индекс и выполняйте запросы к этому столбцу. О предварительном вычислении см. Инкрементальное материализованное представление.
  • Интерактивные запросы с временем ответа менее секунды. Даже в лучшем случае вывод LLM занимает сотни миллисекунд, а ограничения частоты запросов увеличивают задержки самых медленных запросов. Используйте AI_* для пакетной обработки и ETL, а не для запросов, завершения которых пользователь ждёт после нажатия кнопки.
  • Задачи поиска похожих объектов. Столбец с эмбеддингами в сочетании с векторным индексом и cosine_distance обеспечивает более быстрый, дешёвый и воспроизводимый поиск. О реализации средствами SQL см. Эмбеддинги.
  • Любые задачи, требующие строгой воспроизводимости. Ответы провайдера недетерминированы, если не зафиксировать temperature = 0, но даже тогда небольшие обновления на стороне модели меняют результаты. Сохраняйте снимок результата вместо повторного вычисления при каждом запросе.
  • Нагрузки, которым нужен провайдер вне поддерживаемого списка. Любой провайдер за пределами двенадцати значений provider_type должен предоставлять API, совместимый с OpenAI, Anthropic или Gemini, либо работать как конечная точка local.

Дополнительные материалы​

  • AI в Doris: все возможности AI, в том числе то, как функции AI_*, эмбеддинги, векторный поиск и сервер MCP работают вместе.
  • Обзор AI-функций: все поддерживаемые провайдеры, полный список свойств CREATE RESOURCE и отдельные примеры для каждой функции.
  • Эмбеддинги: EMBED() использует тот же механизм AI-ресурсов и подходит для случаев, когда следующим шагом будет векторный поиск.
  • Гибридный поиск: как сочетать столбцы, сгенерированные LLM, с предикатами полнотекстового поиска и ANN в одном запросе.
  • Справочник Snowflake Cortex AISQL: ближайший аналог для сравнения возможностей разных хранилищ.
  • Сервер MCP: другая сторона возможностей AI, позволяющая AI-клиентам выполнять запросы к Doris через инструменты Model Context Protocol.
  • Тип данных VARIANT: естественный выбор для хранения JSON, который возвращают AI_EXTRACT и аналогичные функции.
  • Databricks AI Functions: подход другого поставщика к той же идее.