Перейти к содержанию
Новое AiManual теперь в MAX Подписаться
Публикация AiManual

Локальные LLM для Text-to-SQL в WMS: тест gemma4, qwen и deepseek на задаче автоматизации счетов

Практический тест локальных LLM для Text-to-SQL в корпоративной WMS: gemma4:26b, qwen и deepseek на сервере с 30 GB RAM без GPU. Только одна модель сгенерировал

Коротко

Что будет в материале

  1. 01

    Введение: зачем мы вообще тестировали локальные LLM для SQL

  2. 02

    Методология тестирования: железо, модели и задача

  3. 03

    Результаты теста: кто справился, а кто - нет

  4. 04

    Практические метрики: скорость инференса на CPU

Введение: зачем мы вообще тестировали локальные LLM для SQL

Ручное написание SQL для биллинга в WMS отнимает часы. Разработчики логистической компании столкнулись с задачей: счета за услуги склада формируются через сложные запросы с десятком JOIN и агрегаций. Каждый новый тип услуги требовал нового запроса. Решение - Text-to-SQL: оператор пишет на естественном языке, что нужно посчитать, модель генерирует SQL.

Облачные API сразу отпали. Данные счетов содержат персональную информацию клиентов и финансовые показатели - выносить это за периметр компании нельзя. Добавьте сюда задержки сети и предсказуемость затрат: при тысячах запросов в день счёт от провайдера становится непрогнозируемым. Оставался один путь: локальный инференс на собственном железе.

Цель этого теста - проверить, способны ли современные открытые модели генерировать корректный SQL на реальной бизнес-задаче без GPU, на сервере с 30 GB RAM. Спойлер: справилась только одна.

Методология тестирования: железо, модели и задача

Конфигурация сервера и ограничения

Сервер, на котором проводился тест, не был спроектирован под инференс. Это стандартная машина для внутренних задач: Intel Xeon E5-2660 v3 (10 ядер, 20 потоков, частота 2.6 ГГц), 30 GB DDR4 RAM, без дискретного GPU. Операционная система - Ubuntu 22.04 LTS.

Запуск моделей - через llama.cpp с квантованием Q4_K_M. Контекстное окно - 4096 токенов, температура - 0.1 (минимальная вариативность для детерминированной генерации кода). Все модели загружались в оперативную память целиком, без оффлоада на диск - это критично для скорости инференса на CPU.

Тестируемые модели и их особенности

В тест попали три семейства моделей, каждое в двух вариантах: универсальная версия и coder-специализация. Размеры - от 9B до 30B параметров. Выбор обусловлен доступностью: все модели свободно распространяются и имеют поддержку в llama.cpp.

  • gemma4:26b - флагманская модель Google с архитектурой смеси экспертов (MoE). 26B общих параметров, но активны только 4B на токен. Это позволяет запускать её на CPU с умеренным потреблением памяти и приемлемой скоростью.
  • qwen2.5:14b и qwen2.5-coder:14b - универсальная и кодовая версии от Alibaba. Coder-вариант дообучался на репозиториях кода и SQL, что должно давать преимущество в генерации запросов.
  • deepseek-coder-v2:16b и deepseek-llm:16b - модель от DeepSeek, известная сильными результатами на бенчмарках кода. Coder-версия позиционируется как инструмент для программистов.

Ожидание было очевидным: coder-версии должны показывать лучшие результаты на Text-to-SQL. Реальность оказалась сложнее.

Тестовая SQL-задача: выставление счета в WMS

Задача взята из продуктивной базы данных склада. Нужно сформировать счёт за услуги хранения и обработки грузов за апрель 2026 года для конкретного клиента. База содержит семь таблиц: clients, contracts, storage_log (ежедневные записи о занятых палето-местах), operations (погрузка, разгрузка, переупаковка), tariffs, invoices, invoice_items.

Промпт, который подавался каждой модели:

Схема базы данных:
- clients (id, name, inn, contract_id)
- contracts (id, client_id, start_date, end_date, tariff_group)
- storage_log (id, contract_id, date, pallets_count, zone)
- operations (id, contract_id, date, op_type, quantity, unit)
- tariffs (id, tariff_group, op_type, zone, price_per_unit)
- invoices (id, client_id, period_start, period_end, total)
- invoice_items (id, invoice_id, description, quantity, unit_price, amount)

Сформируй SQL-запрос для создания счёта клиенту ООО "Логист-Трейд" за апрель 2026.
Нужно посчитать:
1. Стоимость хранения по каждой зоне склада (сумма палето-мест за месяц * тариф зоны)
2. Стоимость операций по каждому типу (количество * тариф операции)
3. Итоговую сумму

Запрос должен быть одним SQL-выражением, без временных таблиц.

Ожидаемый результат - запрос с корректными JOIN по цепочке clients → contracts → storage_log/operations → tariffs, группировкой по зонам и типам операций, фильтрацией по дате и названию клиента, и итоговой суммой через подзапрос или CTE.

Результаты теста: кто справился, а кто - нет

Gemma4:26b - единственный верный результат

Gemma4:26b сгенерировала корректный SQL с первого раза. Запрос использовал CTE для хранения и операций, корректно соединил все семь таблиц, правильно применил фильтр по названию клиента и диапазону дат, сгруппировал результаты по зонам и типам операций, и вывел итоговую сумму.

Сгенерированный запрос (упрощённо):

WITH storage_cost AS (
  SELECT 
    sl.zone,
    SUM(sl.pallets_count * t.price_per_unit) as cost
  FROM clients c
  JOIN contracts ct ON c.contract_id = ct.id
  JOIN storage_log sl ON ct.id = sl.contract_id
  JOIN tariffs t ON ct.tariff_group = t.tariff_group 
    AND t.zone = sl.zone
  WHERE c.name = 'ООО "Логист-Трейд"'
    AND sl.date BETWEEN '2026-04-01' AND '2026-04-30'
  GROUP BY sl.zone
),
operations_cost AS (
  SELECT
    o.op_type,
    SUM(o.quantity * t.price_per_unit) as cost
  FROM clients c
  JOIN contracts ct ON c.contract_id = ct.id
  JOIN operations o ON ct.id = o.contract_id
  JOIN tariffs t ON ct.tariff_group = t.tariff_group
    AND t.op_type = o.op_type
  WHERE c.name = 'ООО "Логист-Трейд"'
    AND o.date BETWEEN '2026-04-01' AND '2026-04-30'
  GROUP BY o.op_type
)
SELECT 'storage' as item_type, zone as detail, cost
FROM storage_cost
UNION ALL
SELECT 'operation', op_type, cost
FROM operations_cost
UNION ALL
SELECT 'total', 'Итого', (SELECT SUM(cost) FROM storage_cost) + 
                         (SELECT SUM(cost) FROM operations_cost);

Запрос оптимален: один проход по таблицам, никаких лишних подзапросов, читаемая структура. Скорость инференса - 4.2 токена в секунду. Вся генерация заняла 47 секунд. Потребление RAM на пике - 18.4 GB из доступных 30 GB.

Qwen и Deepseek: где они ошиблись

Остальные модели справились хуже. Coder-специализация не дала ожидаемого преимущества.

qwen2.5-coder:14b сгенерировала синтаксически верный запрос, но перепутала связи таблиц: соединила storage_log напрямую с clients, минуя contracts. Результат - подсчёт палето-мест по всем клиентам, а не по одному. Модель поняла структуру задачи, но не справилась с нормализацией схемы.

qwen2.5:14b (базовая) выдала запрос с халлюцинированным столбцом clients.legal_name вместо name. Запрос упал бы с ошибкой на проде.

deepseek-coder-v2:16b - самая неожиданная неудача. Модель проигнорировала условие «одним SQL-выражением» и сгенерировала три отдельных запроса с комментариями «выполните первый, затем второй, затем третий». Для автоматизированной системы это неприемлемо.

deepseek-llm:16b (базовая) создала корректный JOIN, но потеряла фильтр по дате. Запрос посчитал бы стоимость за весь период действия контракта.

Сводная таблица результатов:

Модель Корректность SQL Время инференса RAM (пик)
gemma4:26b Полная, оптимальный запрос 47 сек 18.4 GB
qwen2.5-coder:14b Ошибка в JOIN (пропущена таблица contracts) 22 сек 12.1 GB
qwen2.5:14b Халлюцинация столбца 19 сек 11.8 GB
deepseek-coder-v2:16b Нарушено требование «один запрос» 31 сек 13.5 GB
deepseek-llm:16b Потерян фильтр по дате 28 сек 13.2 GB

Практические метрики: скорость инференса на CPU

Цифры говорят сами за себя. На CPU без GPU generation speed составил от 3.1 до 5.8 токенов в секунду в зависимости от модели. Gemma4:26b показала 4.2 t/s - средний результат по скорости, но единственный приемлемый по качеству.

47 секунд на генерацию - это много или мало? Для оператора WMS, который формирует счёт вручную 15-20 минут, это мгновенно. Система не обязана отвечать за миллисекунды: оператор отправляет запрос, через минуту получает готовый SQL, проверяет и выполняет. Ручное написание такого запроса заняло бы от 10 до 30 минут в зависимости от сложности тарифной сетки.

Сравнение с облачными API: GPT-4o сгенерировал бы аналогичный запрос за 3-5 секунд, но ценой отправки конфиденциальных данных во внешний контур. Локальный инференс на gemma4:26b даёт полный контроль над данными при десятикратном увеличении времени ответа - для сценария биллинга это приемлемый компромисс.

Если скорость критична, можно рассмотреть qwen2.5-coder:14b с её 22 секундами на ответ и ценой периодических ошибок в JOIN. Такой подход потребует слоя валидации SQL перед выполнением - тема для отдельного теста.

Выводы: какую модель выбрать для Text-to-SQL в условиях ограниченного железа

Прямой ответ: gemma4:26b с квантованием Q4_K_M. Это единственная модель из протестированных, которая выдала корректный и оптимальный SQL на реальной задаче. 18.4 GB RAM на пике оставляют запас на 30 GB сервере для операционной системы и других процессов.

Критерии выбора модели для Text-to-SQL

Чек-лист для тех, кто выбирает модель под свою задачу:

  • Размер модели vs доступная RAM. Модель должна помещаться в память целиком. Gemma4:26b с MoE-архитектурой требует 18-20 GB в Q4_KM - вдвое меньше, чем можно было ожидать от 26B модели.
  • Архитектура. MoE (смесь экспертов) даёт преимущество на CPU: активны только 4B из 26B параметров на каждом токене. Это снижает требования к пропускной способности памяти.
  • Наличие coder-специализации. Тест показал, что coder-версии не гарантируют лучшего качества. Deepseek-coder нарушила требования к формату вывода, qwen-coder ошиблась в связях таблиц. Универсальная gemma4 обошла специализированные модели.
  • Поддержка квантования. Без квантования gemma4:26b заняла бы все 30 GB и не оставила бы места для системы. Q4_K_M - минимально необходимый уровень для запуска.
  • Сообщество и совместимость. Все протестированные модели поддерживаются llama.cpp, что упрощает развёртывание. Gemma4 имеет активное сообщество и регулярные обновления.

Промпт-инжиниринг решает многое. В тесте использовалась полная схема БД в промпте - без неё даже gemma4 не справилась бы. Для сложных схем с десятками таблиц стоит рассмотреть RAG: динамическую подгрузку релевантных описаний таблиц в промпт. Это тема для следующего теста.

Если 47 секунд ожидания неприемлемы, а бюджет позволяет добавить GPU, обратите внимание на тесты производительности серверов - например, 24-часовые краш-тесты YADRO VEGMAN показывают, какие конфигурации выдерживают непрерывный инференс без сбоев.

Ограничения теста и дальнейшие шаги

Тест проведён на одном запросе. Это не гарантирует, что gemma4:26b справится с любой задачей Text-to-SQL в WMS. Один запрос покрывает базовый сценарий с JOIN и агрегациями, но не проверяет оконные функции, рекурсивные CTE или сложную фильтрацию с подзапросами.

Направления для дальнейших исследований:

  • Тестирование на наборе из 50+ запросов разной сложности. Это даст статистически значимую оценку точности и позволит выявить систематические ошибки моделей. Методология такого теста разобрана в кейсе миграции с Claude Sonnet на Qwen - там использовался эвал на 50 примерах со слепым судьёй.
  • Файнтюнинг на доменных данных. Дообучение gemma4 на схеме конкретной WMS и исторических запросах может поднять точность и снизить время инференса за счёт более коротких промптов.
  • RAG для схемы БД. Когда таблиц больше 20-30, полная схема не влезает в контекст. RAG-подход с векторизацией описаний таблиц и динамической подгрузкой релевантных фрагментов - логичный следующий шаг.
  • Слой валидации SQL. Даже gemma4 может ошибиться на следующем запросе. Автоматическая проверка синтаксиса и запуск EXPLAIN перед выполнением защитят продовую базу от некорректных запросов.

Выбор провайдера модели тоже влияет на результат. В тесте использовались квантованные версии из официальных репозиториев llama.cpp, но разные провайдеры (bartowski, unsloth, lm-studio) могут давать разное качество на одних и тех же моделях. Детальное сравнение провайдеров для Qwen и Gemma с конкретными цифрами pass@1 и связности ответов - в прямом тесте провайдеров для кодинга и общения.

Результат теста однозначен: локальный Text-to-SQL на CPU возможен уже сейчас. Gemma4:26b справляется с реальной задачей биллинга в WMS на сервере за 47 секунд. Остальные модели пока не дотягивают до уровня надёжности, необходимого для автоматизации без постоянного контроля человека.

Подписаться на канал