Всё началось с простого вопроса: почему малый бизнес теряет клиентов ночью?

Клиент заходит на сайт в 23:00, пишет в чат — и уходит. Потому что менеджер спит. Утром менеджер видит сообщение, перезванивает — а клиент уже купил у конкурента.

Стандартное решение — чат-бот. Но обычный чат-бот либо ограничен заранее заданными сценариями, либо требует интеграции с крупными облачными LLM. (отвечает по скриптам), либо слишком дорогой (GPT-4 за десятки тысяч в месяц), либо хранит данные за рубежом, что не всегда удобно для российского бизнеса.

Я решил сделать иначе.

Проблема переключения между ИИ и оператором

Главная сложность оказалась не в интеграции с моделью, а в сохранении непрерывности диалога. После передачи клиента оператору необходимо было сохранить единый контекст разговора, не меняя интерфейс для пользователя. Для этого relay-сервер хранит состояние сессии и динамически маршрутизирует сообщения либо в vLLM, либо в MAX, в зависимости от текущего режима обработки.

Что в итоге получилось

ИИ-консультант на базе Qwen3 30B отвечает клиентам на сайте. Когда клиент хочет поговорить с живым человеком — оператор получает уведомление в MAX с кратким резюме всего диалога. Отвечает прямо из мессенджера. Клиент видит один непрерывный разговор и не знает что канал переключился.

Вся установка — один тег перед </body>:

<script src="https://llmcod.ru/widget/ВАШ_ID.js"></script>

Как это работает технически

Архитектура состоит из трёх частей:

1. Виджет на сайте — обычный JS чат, подключается через WebSocket к relay-серверу. Никаких iframe, никаких внешних зависимостей.

2. Relay-сервер (FastAPI + WebSocket) — центральный компонент. Держит сессию пользователя, проксирует сообщения в vLLM или в MAX в зависимости от режима. Хранит историю диалога и маппинг session_id ↔ MAX chat_id.

Ещё одна проблема возникла при переключении между режимами. Если оператор подключается слишком рано, ИИ не успевает собрать достаточный контекст. Если слишком поздно — клиент может уйти. Поэтому порог эскалации сделан настраиваемым и определяется количеством сообщений в диалоге.

3. MAX бот — получает уведомления об эскалации. Оператор видит резюме диалога и отвечает прямо в мессенджере.

Схема передачи сообщений:

Клиент → WebSocket → Relay → vLLM (AI режим)
                           ↓ (при эскалации)
                     MAX webhook ← MAX бот ← Оператор

При эскалации relay вызывает vLLM для суммаризации истории диалога и отправляет оператору готовое резюме. Оператор не читает весь чат — видит только суть.

Почему MAX, а не Telegram

Несколько причин:

  • MAX — российский мессенджер, данные хранятся в РФ

  • API MAX позволяет получать webhook и отвечать от имени бота

  • MAX предоставляет API для ботов и webhook-механизм, достаточный для реализации сценария передачи диалога оператору.

Ключевой момент — резюме диалога

Это главное отличие от обычного "перевода на оператора". Когда клиент нажимает кнопку — оператор получает не просто уведомление, а готовый контекст:

? Клиент просит оператора
Сайт: ООО Ромашка

? Резюме:
Клиент интересуется доставкой в регионы. 
Уточнял сроки и стоимость. Хочет заказать 
на следующей неделе.

? Последнее сообщение:
А скидки на первый заказ есть?

✏️ Ваш ответ → придёт клиенту как сообщение оператора.

Оператор сразу в контексте. Не нужно читать историю, не нужно переспрашивать клиента "а что вы хотели?".

Мультитенантность

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

  • Свой MAX бот с отдельным токеном

  • Свой webhook endpoint: /relay/{client_id}/webhook

  • Свой виджет: /widget/{client_id}.js

  • Свой системный промпт с описанием бизнеса

Добавить нового клиента — один API вызов:

curl -X POST "https://llmcod.ru/admin/clients" \
  -H "X-Admin-Token: ..." \
  -d '{
    "name": "ООО Ромашка",
    "bot_token": "...",
    "operator_user_id": 12345678,
    "system_prompt": "Ты ассистент магазина цветов..."
  }'

В ответ приходит готовый <script> тег для вставки на сайт.

Как формируется контекст модели

При подключении клиент описывает свой бизнес в свободной форме — прайс, режим работы, частые вопросы, тон общения. Это становится системным промптом модели.

Дополнительно модель знает текущее время (московское) — может сообщить клиенту рабочее ли сейчас время, когда будет доступен оператор.

Контекст диалога — последние 6 сообщений. Этого достаточно для большинства сценариев поддержки.

Инфраструктура

  • Модель: Qwen3 30B A3B Instruct (Q4_K_M GGUF)

  • Инференс: vLLM с GGUF квантизацией

  • GPU: NVIDIA Tesla V100 32 ГБ

  • CPU: 2 х Intel Xeon Gold 6244

  • RAM: 128 ГБ

  • сервер Dell T440

  • В зависимости от длины контекста скорость генерации составляет до ~98 токенов/с.

  • Контекст: 32K токенов

  • Инференс модели и хранение диалогов выполняются на сервере, расположенном в России.

nvidia-smi
nvidia-smi

Модель запущена через OpenAI-совместимый API — тот же chat/completions endpoint. Это важно для интеграции с любым кодом который уже работает с OpenAI SDK.

Что можно настроить

Через личный кабинет клиент управляет:

  • Цветом виджета

  • Системным промптом (до 10 000 символов)

  • Порогом эскалации (после скольких сообщений предлагать оператора)

  • Подпиской и продлением

Демонстрационный стенд

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


Если интересно как устроен relay-сервер или вопросы по интеграции MAX API — отвечу в комментариях.

Комментарии (7)


  1. netricks
    09.06.2026 10:20

    Уууу... ИИ и MAX в одной статье... А вы смелый.


  1. pewpew
    09.06.2026 10:20

    Почему MAX, а не Telegram

    • MAX — российский мессенджер, данные хранятся в РФ

    А если я например живу и работаю в Казахстане или Республике Беларусь. Почему мне важно, чтобы данные хранились именно в РФ? Хочу понять вашу логику.


  1. llmcod Автор
    09.06.2026 10:20

    Здравствуйте. Сервис пока расчинан на Россию и телеграм не работает в РФ по крайней мере у меня совсем. Из за этого выбран МАХ.


  1. kalapanga
    09.06.2026 10:20

    Клиент заходит на сайт в 23:00, пишет в чат — и уходит. Потому что менеджер спит.

    А вот если менеджеру придёт сообщение в МАХ, то он, забыв про сон, вскочит и, не одевая штанов, бросится отвечать клиенту!


  1. llmcod Автор
    09.06.2026 10:20

    Это зависит от ваших предпочтений и настройки описани в промте


  1. diomas
    09.06.2026 10:20

    API MAX позволяет получать webhook и отвечать от имени бота

    Вот этот момент непонятен: макс как-то сам хостит вебхуки ботов или что это имеется в виду? В чем отличие от вебхуков для ботов в телеграме?


    1. llmcod Автор
      09.06.2026 10:20

      MAX работает так же как Telegram — вы регистрируете свой URL, и MAX присылает туда POST-запросы при каждом новом сообщении боту. Хостить нужно самостоятельно.

      # Регистрация webhook в MAX
      curl -X POST "https://botapi.max.ru/subscriptions" \
        -H "Authorization: ВАШ_ТОКЕН" \
        -d '{"url": "https://ваш-сервер.ru/webhook"}'
      

      Отличие от Telegram практически одно — авторизация без Bearer (токен передаётся напрямую в заголовке), и user_id/chat_id при отправке сообщений идут как query-параметры, а не в теле запроса. В остальном — та же схема webhook → обработчик → ответ через API.