Локальный бот-аналитик для SQL: пошаговый гайд на примере ecom.tech 2026 | AiManual
AiManual Logo Ai / Manual.
03 Фев 2026 Гайд

Бот-аналитик на локальной LLM: как мы в ecom.tech разгрузили команду и не отправили данные конкурентам

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

Проблема: аналитики тонут в рутине, а данные слишком чувствительны для ChatGPT

В ecom.tech - российском маркетплейсе с оборотом в сотни миллионов - каждый день рождалось 50-70 одинаковых вопросов от отделов маркетинга, продаж и логистики. "Какая категория товаров показала самый высокий рост в Москве за последний месяц?" "Сколько клиентов из Санкт-Петербурга совершили повторные покупки?" "Какой средний чек у пользователей, которые пришли через TikTok?"

Аналитики тратили 60% рабочего времени на рутинные SQL-запросы. Пробовали ChatGPT - получили предупреждение от юридического отдела: данные о клиентах, закупочных ценах и логистических маршрутах не должны покидать периметр компании. Даже с анонимизацией оставался риск утечки структуры данных и бизнес-логики.

Ключевая ошибка, которую совершают 90% компаний: пытаются использовать публичные LLM для внутренних данных без понимания рисков. Даже если вы "забыли" передать реальные значения, сама структура запросов (JOIN между таблицами users и orders, фильтры по регионам, агрегации по категориям) раскрывает архитектуру вашего бизнеса.

Решение: локальная модель, изолированная база, строгие guardrails

Мы построили систему, которая работает по принципу "ничего не выходит за пределы серверной стойки". Три кита архитектуры:

  1. Локальная LLM - модель работает на наших GPU, без доступа в интернет
  2. Изолированная БД-реплика - только для чтения, с ограниченным набором таблиц
  3. SQL-валидатор - проверяет каждый запрос перед исполнением

Зачем такая паранойя? Представьте, что бот по ошибке сгенерирует "DELETE FROM users WHERE id > 0". Или начнет делать тяжелые JOIN на производственных таблицах в час пик. Или - что хуже всего - через подсказку в промпте передаст структуру вашей базы в ответ пользователю.

💡
Мы выбрали подход PoC (Proof of Concept) вместо полноценного внедрения. Цель - доказать работоспособность на ограниченном наборе данных и запросов, а потом масштабировать. Слишком многие команды пытаются сразу построить "идеальную систему" и тонут в сложности.

Выбор модели: почему не Llama 3.2 и не DeepSeek-V3

На февраль 2026 года в топе локальных моделей для SQL несколько кандидатов:

Модель Размер Точность на Spider Плюсы Минусы для нашего кейса
SQLCoder-2 7B 7B параметров 86% Специализирована на SQL, понимает диалекты Требует 16GB VRAM
Llama 3.2 3B 3B параметров 72% Быстрая, работает на CPU Часто ошибается в сложных JOIN
DeepSeek-Coder-V3 1.3B 1.3B параметров 68% Очень легкая, хороша для простых запросов Плохо справляется с бизнес-логикой

Мы выбрали SQLCoder-2 7B с квантованием до 4-бит. Почему? Потому что специализированные модели всегда бьют универсальные в своей нише. SQLCoder тренировали именно на генерации SQL, она понимает разницу между PostgreSQL, MySQL и даже умеет работать с оконными функциями.

А вот Llama 3.2, несмотря на всю ее популярность, слишком часто генерировала синтаксически правильный, но логически неверный SQL. Типичная ошибка: "SELECT COUNT(*) FROM orders WHERE user_id IN (SELECT id FROM users WHERE city = 'Москва')" вместо более оптимального JOIN.

Не верьте benchmark'ам на идеальных датасетах вроде Spider. В реальности ваша база содержит кастомные поля, нестандартные названия таблиц и бизнес-специфичную логику. Специализированная модель справится лучше.

1 Подготовка изолированной базы данных

Первое правило безопасности: бот не должен касаться production-базы. Создаем реплику только для чтения с ограниченным доступом:

-- Создаем пользователя только для чтения
CREATE USER bot_reader WITH PASSWORD 'complex_password_here';
GRANT CONNECT ON DATABASE ecom_db TO bot_reader;

-- Даем доступ только к определенным таблицам
GRANT SELECT ON users, orders, products, categories TO bot_reader;

-- Запрещаем доступ к служебным таблицам
REVOKE ALL ON payment_logs, admin_logs, internal_audit FROM bot_reader;

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

CREATE SCHEMA bot_schema;

CREATE VIEW bot_schema.safe_users AS
SELECT 
    id,
    -- Хэшируем email вместо оригинала
    MD5(email) as email_hash,
    city,
    registration_date,
    -- Группируем возраст в диапазоны
    CASE 
        WHEN age < 20 THEN 'under_20'
        WHEN age BETWEEN 20 AND 30 THEN '20_30'
        ELSE 'over_30'
    END as age_group
FROM public.users;

Это не просто "безопасность", это защита от глупых ошибок. Если бот случайно сгенерирует запрос с email в WHERE-условии, он просто не найдет совпадений - потому что работает с хэшами.

2 Создание RAG-системы со схемой базы

Самая частая ошибка новичков: скормить модели "сырую" схему базы. 200 таблиц, 3000 колонок - модель запутается. Вместо этого создаем структурированное описание:

{
  "tables": [
    {
      "name": "orders",
      "description": "Таблица заказов. Содержит информацию о покупках клиентов.",
      "columns": [
        {"name": "id", "type": "integer", "description": "Уникальный идентификатор заказа"},
        {"name": "user_id", "type": "integer", "description": "Ссылка на клиента в таблице users"},
        {"name": "product_id", "type": "integer", "description": "Ссылка на товар в таблице products"},
        {"name": "amount", "type": "decimal", "description": "Сумма заказа в рублях"},
        {"name": "created_at", "type": "timestamp", "description": "Дата и время создания заказа"}
      ],
      "relationships": [
        {"foreign_table": "users", "foreign_key": "id", "local_key": "user_id"},
        {"foreign_table": "products", "foreign_key": "id", "local_key": "product_id"}
      ],
      "example_queries": [
        "SELECT COUNT(*) FROM orders WHERE created_at >= '2025-01-01';",
        "SELECT user_id, SUM(amount) FROM orders GROUP BY user_id ORDER BY SUM(amount) DESC LIMIT 10;"
      ]
    }
  ]
}

Этот JSON становится контекстом для модели. Мы не просто даем имена таблиц - мы объясняем бизнес-смысл, приводим примеры запросов, показываем связи. Без такого структурирования точность падает на 30-40%.

Если вам интересно глубже погрузиться в архитектуру RAG для баз данных, посмотрите нашу статью "Когда SQL и векторный поиск дерутся за ваши данные", где мы разбираем гибридные подходы.

3 Настройка локальной LLM с Ollama

Ollama - не единственный вариант, но самый удобный для быстрого старта. Устанавливаем и загружаем модель:

# Устанавливаем Ollama
curl -fsSL https://ollama.ai/install.sh | sh

# Загружаем SQLCoder-2 с 4-битным квантованием
ollama pull sqlcoder2:7b-q4_K_M

# Запускаем модель с увеличенным контекстом
ollama run sqlcoder2:7b-q4_K_M \
  --num_ctx 8192 \
  --temperature 0.1 \
  --seed 42

Температуру ставим 0.1 - нам нужна детерминированность, а не креативность. Контекст увеличиваем до 8192 токенов, чтобы поместилась схема базы и история диалога.

💡
Настройка seed (зерна) критически важна для воспроизводимости. Без этого один и тот же запрос от пользователя может генерировать разный SQL в разное время - кошмар для отладки и тестирования.

4 Промпт-инжиниринг: как заставить модель генерировать безопасный SQL

Вот промпт, который мы используем в ecom.tech. Обратите внимание на строгие инструкции:

Ты - SQL-ассистент для базы данных маркетплейса ecom.tech.

СХЕМА БАЗЫ ДАННЫХ:
{вставляем JSON со схемой}

ПРАВИЛА:
1. Генерируй только SQL-запросы на диалекте PostgreSQL 15
2. НИКОГДА не используй DROP, DELETE, UPDATE, INSERT, TRUNCATE
3. Используй только таблицы из приведенной схемы
4. Всегда добавляй LIMIT к запросам, если пользователь не указал иное
5. Если запрос требует JOIN нескольких таблиц - объясни логику в комментарии
6. Для дат используй формат 'YYYY-MM-DD'
7. Если не уверен в правильности запроса - верни NULL и объясни почему

ВОПРОС ПОЛЬЗОВАТЕЛЯ: {вопрос пользователя}

SQL-ЗАПРОС:

Ключевой момент: правило "верни NULL, если не уверен". Лучше не дать ответ, чем дать неправильный. В ранних версиях бот иногда генерировал SQL для несуществующих таблиц - потому что пользователь упомянул "отчеты", а модель решила, что есть таблица reports.

5 SQL-валидатор: последний рубеж защиты

Даже с лучшим промптом модель может ошибиться. Наш валидатор проверяет:

import sqlparse
from sqlparse.sql import Token
from sqlparse.tokens import Keyword, DML

def validate_sql(sql: str) -> tuple[bool, str]:
    """Проверяет SQL-запрос на безопасность"""
    
    # 1. Парсим запрос
    parsed = sqlparse.parse(sql)[0]
    
    # 2. Проверяем, что это SELECT
    first_token = parsed.token_first(skip_cm=True)
    if not first_token or first_token.value.upper() != 'SELECT':
        return False, "Только SELECT-запросы разрешены"
    
    # 3. Ищем запрещенные операции
    forbidden = ['DROP', 'DELETE', 'UPDATE', 'INSERT', 'TRUNCATE', 
                 'GRANT', 'REVOKE', 'ALTER', 'CREATE']
    
    for token in parsed.flatten():
        if token.ttype is Keyword and token.value.upper() in forbidden:
            return False, f"Запрещенная операция: {token.value}"
    
    # 4. Проверяем наличие LIMIT (если не агрегация)
    has_limit = any(
        token.ttype is Keyword and token.value.upper() == 'LIMIT'
        for token in parsed.flatten()
    )
    
    # 5. Проверяем сложность запроса
    estimated_cost = estimate_query_complexity(parsed)
    if estimated_cost > 1000:  # Условная метрика
        return False, "Запрос слишком сложный для автоматического выполнения"
    
    return True, "OK"

Валидатор не просто ищет ключевые слова - он оценивает сложность запроса. Слишком много JOIN? Слишком большие таблицы? Отклоняем и просим пользователя уточнить.

Интеграция с бизнес-процессами: как мы внедряли бота

Техническая часть - только половина успеха. Вторая половина - заставить людей использовать систему. Наша стратегия:

  1. Фаза альфа-тестирования - 5 аналитиков, только простые запросы
  2. Сбор обратной связи - фиксируем каждый случай, когда бот ошибся
  3. Доработка промпта - добавляем исключения для частых ошибок
  4. Постепенное расширение - добавляем новые таблицы и типы запросов

Через месяц бот обрабатывал 40% всех рутинных запросов. Аналитики экономили 2-3 часа в день. Но главное - мы создали "живую" систему, которая училась на ошибках.

Самый частый вопрос от руководства: "А если бот даст неправильные данные, и мы примем ошибочное решение?" Ответ: бот НЕ принимает решения. Он только генерирует SQL. Аналитик всегда проверяет результат, прежде чем использовать его в отчетах.

Типичные ошибки и как их избежать

За 3 месяца работы мы набили все возможные шишки:

Ошибка Последствия Решение
Без LIMIT в агрегатных запросах PostgreSQL пытался посчитать SUM по всей таблике из 50 млн строк Добавили правило: всегда LIMIT, если нет GROUP BY
Неправильные алиасы таблиц Запрос "SELECT u.name, o.amount FROM users o JOIN orders u" - полная путаница Добавили в промпт требование использовать понятные алиасы
Игнорирование индексов Модель генерировала запросы без учета индексов, что замедляло выполнение Добавили информацию об индексах в схему базы

Самая коварная ошибка: модель иногда "выдумывала" поля, которых нет в базе. Пользователь спрашивал "сколько клиентов из офлайн-магазинов", а модель искала поле offline_store в таблице users. Решение: добавили в валидатор проверку существования колонок через INFORMATION_SCHEMA.

Что дальше? Планы на 2026 год

Наш PoC доказал жизнеспособность подхода. Следующие шаги:

  • Добавление большего контекста - не только схема, но и примеры реальных бизнес-запросов
  • Интеграция с BI-системами - бот будет не только генерировать SQL, но и строить графики в Metabase
  • Мультимодальность - пользователь загружает скриншот таблицы Excel, а бот предлагает SQL для аналогичных данных в базе
  • Обучение на собственных данных - fine-tuning модели на исторических запросах аналитиков ecom.tech

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

Локальные LLM для бизнеса - это не будущее, это настоящее. Вопрос не в том, стоит ли внедрять такие системы, а в том, как сделать это безопасно и эффективно. Наш опыт в ecom.tech показывает: начинайте с малого, тестируйте на изолированных данных, и не ожидайте 100% точности с первого дня.

Главный урок: лучший бот-аналитик не тот, который никогда не ошибается (такого не существует), а тот, чьи ошибки безопасны и понятны. И который освобождает людей от рутины, а не создает новые проблемы.