Олег ФроловРазработчик аналитических систем

Кейсы · 2026

Cyber AI — автоответы на маркетплейсах

SaaS для продавцов: бот разбирает вопросы и отзывы покупателей на Wildberries, Ozon и Яндекс Маркете, ведёт чат на сайте и в мессенджерах — из одной базы знаний и с одним счётом.

Год2026
РольАрхитектура, бэкенд, фронтенд, инфраструктура
СтатусРаботает в проде
СтекPython, FastAPI, PostgreSQL, pgvector, Docker, nginx
7каналов общения с покупателем
28 300строк Python в 47 модулях
63миграции схемы базы
843коммита за 31 рабочий день

Задача

Покупатель на маркетплейсе задаёт вопрос под карточкой или пишет отзыв. Ответить надо быстро и по делу: молчание роняет карточку в выдаче, а отписка «спасибо за обращение» роняет доверие. У продавца с тысячей позиций это отдельная работа на весь день, и на неё нанимают человека.

При этом отвечать наугад нельзя. Выдуманная характеристика товара дороже молчания: за неё продавец отвечает и перед покупателем, и перед площадкой.

Решение

Продавец подключает кабинет площадки ключом, заливает свои правила, прайсы и описания товаров. Дальше сервис разбирает поток сам:

  • на хорошие оценки отвечает без спроса;
  • на плохие готовит черновик и оставляет решение человеку;
  • на вопрос отвечает, только если в базе знаний есть чем;
  • не знает — зовёт живого человека и передаёт ему диалог.

Тот же бот с той же базой знаний работает пузырём чата на сайте продавца, отдельной страницей-чатом по ссылке, ботом в Telegram и в MAX.

Экран «Каналы»: семь способов, которыми бот попадает к покупателю
Одна база знаний семь каналов — Виджет на сайте, страница-чат, Telegram, MAX, Wildberries, Ozon и Яндекс Маркет. Канал включается переключателем, тексты заливаются один раз.
Лента вопросов и отзывов с площадок с готовыми ответами бота
Экран, ради которого продукт покупают Оценка, товар, готовый ответ и решение человека: опубликовать, переписать, не отвечать. Под ответом видно, сколько он стоил.

Как собирается ответ

Вопрос из любого канала идёт по одному пути:

  1. база знаний клиента разрезана на фрагменты;
  2. поиск двойной — по смыслу (векторы, pgvector HNSW, эмбеддинги bge-m3) и по словам (полнотекстовый индекс с русской морфологией);
  3. два списка сводятся в один рангами, а не весами;
  4. ответ строится только по найденному;
  5. на выходе развилка: опубликовать в канал самому или отдать черновиком человеку.

Третий пункт — то место, где обычно застревают. Подбирать веса под каждого клиента невозможно: у одного база собрана из PDF, у другого из карточек товара, и коэффициенты, настроенные под первого, ломают выдачу у второго. Слияние рангами (RRF) к этому устойчиво: оно смотрит на порядок, а не на абсолютные оценки, которые у двух разных поисков просто несопоставимы.

Список источников базы знаний с числом фрагментов у каждого
База знаний У каждого источника видно, на сколько фрагментов он разрезан. Ниже — дообучение: исправленный человеком ответ возвращается в базу и работает дальше.

Чем отличается от аналогов

Одна база знаний — все каналы сразу

Обычно чат на сайте, бот в мессенджере и ответы на маркетплейсе — три разные подписки и три набора текстов, которые расходятся через месяц. Здесь материал заливается один раз, любой из семи каналов включается переключателем, а товары из кабинета продавца попадают в ту же базу автоматически.

Изоляция клиентов в самой базе, а не в коде

Данные разных продавцов разделены построчной защитой Postgres (RLS): чужая строка не отдаётся, даже если в запросе забыли условие. Ошибка в фильтре превращается в пустой ответ, а не в утечку прайса конкуренту.

Это принципиальный выбор места для защиты. Проверка в коде живёт ровно до первого запроса, который её обошёл; проверка в базе не обходится никак.

Плата за ответ, а не за тариф

Нет пакетов с лимитами и пропадающими остатками: деньги лежат на счёте аккаунта и тратятся на любой проект клиента. Четыре ступени качества модели переключаются на ходу, и кабинет сразу показывает, на сколько ответов хватит остатка.

Выбор ступени качества модели карточками
Ступени качества У каждой написано, во сколько обходится ответ. Переключается на ходу, остаток пересчитывается сразу.

Молчание вместо выдумки

Бот отвечает только тем, что нашлось в базе. Для отзывов это разведено ещё жёстче: хорошие оценки бот закрывает сам, плохие готовит черновиком. Порог задаёт продавец.

Настройка подключения к Ozon: порог звёзд и отдельные галочки
Подключение площадки Ключ из кабинета продавца, порог оценки и две отдельные галочки: на отзывы и на вопросы.
Отзыв со снимками покупателя и ответом бота под ними
Отзывы с фотографиями Снимки покупателя разбираются вместе с текстом отзыва.

Настраивается продавцом, а не подрядчиком

Виджет ставится одной строкой в шаблон сайта, площадка подключается ключом из кабинета продавца, характер бота задаётся обычным текстом. Кабинет двуязычный, с тёмной темой и встроенной справкой со скриншотами, которые пересобираются вместе с интерфейсом.

Код вставки виджета и список разрешённых доменов
Установка виджета Одна строка в шаблон сайта и список доменов, на которых ключ работает.

Дообучение из работы

Продавец правит ответ бота в диалогах — исправленная пара возвращается в базу знаний и работает дальше. Отдельного обучения не запускается: правка сразу становится источником.

Лента диалогов и переписка с кнопками вмешательства человека
Передача человеку Когда бот не знает, он зовёт живого человека и отдаёт ему диалог целиком.

Работает из России и разговаривает с миром

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

Инженерные задачи

Telegram заблокирован в обе стороны. С российского сервера не уходят запросы к Telegram и — что заметили не сразу — не приходят вебхуки обратно. Канал выглядел живым: бот подключался, настройки сохранялись, а сообщения покупателей не доходили. Решено собственным мостом: исходящее идёт прокси, входящее принимает наш домен на европейской стороне и передаёт внутрь.

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

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

Тихие поломки дороже громких. Самые дорогие ошибки здесь не падали с ошибкой: обновление настройки молча не срабатывало, если промежуточного ключа ещё не было в структуре, — клиент видел «не подключено» на работающем виджете. Такие места закрыты общим помощником и проверками, а разбор каждой записан в журнал решений, который в проекте ведётся наравне с кодом.

Статика без сборщика тоже кэшируется. Забытая версия в адресе оставляет ошибку жить неделю. Выкатка сайта сведена в одну команду: отправить, сбросить кэш, сверить хеши с живым сайтом и сказать, что именно доехало.

Аналитика: сколько бот ответил сам, откуда пришли вопросы, во сколько обходится ответ
Аналитика Сколько бот закрыл сам, откуда пришли вопросы и во сколько обходится ответ.

Чем сделано

СлойТехнологии
БэкендPython, FastAPI, asyncpg, SSE, httpx
ДанныеPostgreSQL, pgvector HNSW, tsvector, Row Level Security, Redis, MinIO
Моделиединый шлюз к нескольким поставщикам, эмбеддинги bge-m3, слияние RRF, vision
ФронтендVanilla JS без сборки, RU/EN, тёмная тема, виджет в iframe
ИнфраструктураDocker Compose, nginx, Cloudflare, squid, Let's Encrypt
ИнтеграцииWildberries, Ozon Seller + OAuth, Яндекс Маркет, Telegram Bot API, MAX, приём платежей, SMTP

Векторный и полнотекстовый поиск живут в одной базе — отдельное хранилище векторов не заводилось, чтобы изоляция клиентов оставалась в одном месте. Кабинет, витрина, виджет и суперадминка — статика на общем хостинге, без узла сборки.

Объём

  • 28 300 строк Python в 47 модулях бэкенда;
  • 63 миграции схемы;
  • 7 каналов общения с покупателем;
  • 44 набора проверок интерфейса, гоняются в контейнере на сервере;
  • 843 коммита за 31 рабочий день.

Числа про клиентов и обороты сюда намеренно не вынесены: это данные владельца бизнеса, а не разработчика.