Меня зовут Владислав Маковеев, я руковожу группой разработки в компании Ozon Банк. Однажды меня пригласили на хакатон, где можно было поработать с новыми стеками технологий и посоревноваться в решении задач. Я подумал: почему бы и нет? Одной из задач стало создание бизнес-кейса для общения с клиентами через разные мессенджеры – Telegram, WhatsApp, ВКонтакте. Ведь клиенты могут быть в разных платформах, и менеджерам приходится переключаться между ними.
Из этого и родилась идея: объединить все каналы общения в единое пространство, чтобы сотрудники могли общаться с клиентами прямо в 1С, не переключаясь между окнами и не авторизуясь в каждом мессенджере отдельно. Это значительно упрощает работу: больше не нужно альт-табиться между приложениями.
Прежде чем перейти к технической реализации, расскажу, какие возможности я реализовал в этом мессенджере. Начнем с управления аккаунтами.
Управление аккаунтами в мессенджере
Аккаунты поддерживаются для разных мессенджеров: WhatsApp, Telegram, VK – в принципе, любого, у которого есть публичное API. Управление аккаунтами включает в себя возможность добавления, настройки и удаления учетных записей.
Я приведу пример на базе WhatsApp, так как именно с ним у меня больше всего интеграций – бизнес-клиенты охотно общаются через этот мессенджер, хотя причины этой предпочтительности мне не до конца понятны.
Что можно делать с аккаунтами?
-
Архивировать и восстанавливать;
-
Обновлять данные (WhatsApp часто блокирует аккаунты за рассылки);
-
Выходить и входить в аккаунт;
-
Полностью удалять учетную запись.
Также реализована история бизнес-аккаунтов: можно создавать новые инстанции или удалять старые, тем самым гибко управляя количеством активных подключений.
Авторизация через QR-код
Следующий этап – авторизация через QR-код. Это современный и удобный способ, особенно когда нужно авторизоваться как с личного, так и с бизнес-аккаунта. Мы реализовали небольшой модуль, который при открытии страницы мессенджера или при создании нового аккаунта предлагает пользователю отсканировать QR-код для входа.
Как это работает? При заходе в мессенджер у каждого пользователя 1С есть привязанный аккаунт. Я подробнее расскажу об этом ниже, на схеме, где покажу все зависимости. На данном этапе проверяется: есть ли у пользователя активный аккаунт и авторизован ли он. Если нет – появляется уведомление с предложением авторизоваться.
Далее мы запрашиваем QR-код для конкретного инстанса и токена, обращаясь к Green API – именно через него реализована интеграция с WhatsApp. В ответ получаем QR-код в формате Base64.
Теперь главный вопрос: как отобразить этот QR-код в 1С? Здесь я использовал веб-макет – функционал, позволяющий вставить изображение в элемент Image напрямую из строки Base64. Главное – не использовать слишком тяжелые изображения, иначе страница будет долго загружаться.
После отображения кода запускается обработчик ожиданий, который периодически обращается к Green API (или нашему промежуточному сервису), проверяя, прошел ли пользователь авторизацию по этому QR-коду.
QR-код уникальный и одноразовый. Как только пользователь сканирует его и подтверждает вход, система фиксирует авторизацию и предоставляет доступ к переписке.
Интерфейс мессенджера и работа с диалогами
Теперь о самом интерфейсе. У нас реализован привычный «чат-интерфейс» – слева отображаются диалоги, справа – содержимое выбранного диалога с историей сообщений. Это позволяет вести переписку с клиентами в одном окне, независимо от того, через какой мессенджер происходит общение.
Менеджер может открыть мессенджер прямо из карточки контрагента или отдельно – в любом случае он увидит всю историю переписки. Это особенно полезно: можно быстро ознакомиться с предыдущими обсуждениями и продолжить диалог без потери контекста.
Завершенные диалоги помечаются значком замка – так легко понять, что обращение уже закрыто. Это помогает эффективно управлять текущими и архивными переговорами. Например, если диалог велся по конкретной заявке, можно настроить именование, чтобы в названии отражался номер обращения или тема. Это позволяет сразу понимать, по какому вопросу велась переписка, и видеть, что обращение уже обработано и закрыто.
При новом обращении от клиента можно открыть новый диалог – так история не смешивается. Все хранится в одном месте, без необходимости переключаться между разными приложениями. Это делает работу удобнее, прозрачнее и эффективнее.
Оповещение операторов о новых сообщениях
Когда клиент отправляет сообщение, возникает естественный вопрос: как оператор узнает о новом обращении? Чтобы решить эту задачу, я использовал систему взаимодействия в 1С – механизм, который позволяет оперативно уведомлять пользователей о событиях.
Когда на сервер приходит новое сообщение, система автоматически формирует уведомление через механизм обсуждений. Ниже я подробнее расскажу, как это реализовано технически и как выглядит в коде.
В результате пользователь получает оповещение вида: «Посмотрите – вам пришло сообщение от клиента с таким-то текстом». В этом уведомлении есть гиперссылка. Достаточно кликнуть по ней – и система перенаправит прямо на карточку контрагента, где уже будет доступна вся переписка. Это позволяет быстро отреагировать, не теряя контекст.
Архитектура решения: библиотечный подход и метаданные
Теперь перейдем к тому, что находится «под капотом». При разработке я стремился к универсальности – чтобы решение можно было легко адаптировать и масштабировать в будущем.
На хакатоне, где у нас было ограниченное время, я реализовал библиотечный подход. Были выделены общие сущности и типовые модули, которые можно переопределять по классической схеме 1С.
Так, для каждого мессенджера предусмотрен отдельный общий модуль – его может создать и доработать разработчик. Это позволяет гибко расширять функционал. Также реализованы общие метаданные, в которых хранятся данные об аккаунтах, сообщениях и самих мессенджерах.
Давайте разберем, как все это связано. Ранее я упоминал, что при входе в мессенджер система проверяет, есть ли у пользователя привязанный аккаунт и авторизован ли он. Структурно пользователь связан с аккаунтом, а аккаунт, в свою очередь, связан с типом мессенджера – то есть с тем, через какое приложение ведется общение.
Конечно, можно было бы все хранить в одном справочнике, но я сознательно выбрал более гибкую архитектуру – чтобы в будущем легко добавлять новые мессенджеры без глобальных переделок.
Контрагент связан с контактной информацией – стандартная практика в БСП. Из карточки можно получить номер телефона, email и другие данные. Все это участвует в формировании диалога: он привязан к пользователю (менеджеру) и к контрагенту. А к самому диалогу уже подключаются сообщения.
Таким образом, в разрезе одного диалога мы можем получить всю переписку, прочитать ее и продолжить общение. Также становится понятно, через какой мессенджер идет общение – эта информация хранится отдельно, но доступна по связи «диалог ? мессенджер».
Теоретически, связь с мессенджером можно было бы хранить прямо в диалоге, но на этапе прототипирования мы выбрали текущую структуру. Она оказалась удобной и масштабируемой, поэтому оставили ее как есть.
Внутреннее взаимодействие и регламентные задания
Теперь расскажу, как все это работает изнутри. Библиотека выделена отдельно – она автономна и содержит регламентные задания, которые отвечают за отправку и получение сообщений. Кроме базовых задач, могут быть и дополнительные регламентные задания. Например, для WhatsApp реализована проверка состояния аккаунтов: нужно понимать, не заблокирован ли аккаунт, чтобы вовремя его обновить или создать новую инстанцию.
Сам встроенный мессенджер реализован внутри 1С и построен на веб-формах. Они отображают список диалогов и содержимое переписки – используются стандартные элементы управления: текстовые поля, кнопки и прочие компоненты платформы 1С.
Механизм отправки сообщений через мессенджеры
Как устроена отправка сообщений? Библиотека сначала определяет, к какому мессенджеру относится сообщение, обращается к соответствующему модулю и вызывает нужные методы для отправки.
Для большинства мессенджеров используются унифицированные API-методы, но в случае с Telegram я реализовал отдельный шлюз. Чуть ниже объясню, почему.
Ключевой элемент – переопределяемый общий модуль. У нас есть общий модуль с экспортным методом, который по предопределенному элементу справочника определяет, какой модуль использовать для конкретного мессенджера.
В принципе, можно было реализовать это через соответствие – было бы, наверное, удобнее, чем через иначе если. Это сократило бы ветвления в коде. Тогда можно было бы сразу получить нужный модуль и работать с ним.
Но в любом случае в каждом модуле – под WhatsApp, Telegram и другие – реализованы унифицированные методы. То есть методы называются одинаково, независимо от реализации: «ОтправитьСообщение», «ПолучитьСообщение». Это позволяет использовать единый интерфейс в регламентных заданиях, просто разделяя их на фоновые процессы. Такой подход упрощает вызов методов в каждом модуле.
Однако остаются и уникальные функции – ведь API у разных мессенджеров отличаются. Для них приходится использовать специфические методы. Например, в WhatsApp есть операции, связанные с управлением бизнес-аккаунтами: создание новых инстанций, удаление старых и т.п. Такие функции реализуются отдельно и не подлежат унификации.
Процесс отправки сообщений: очередь и многопоточность
Перейдем к отправке сообщений. Все начинается с выборки. Важно отметить, что этот процесс выполняется в фоновом режиме – в рамках регламентного задания, которое работает автономно и обслуживает все мессенджеры одновременно.
При этом нет отдельного регламентного задания для каждого мессенджера – используется одно общее. Оно выбирает все сообщения из очереди и группирует их по типу мессенджера. Затем для каждого мессенджера запускается отдельный фоновый поток.
Таким образом, одно регламентное задание управляет несколькими фоновыми процессами. Это позволяет распределить нагрузку и избежать ситуации, когда один мессенджер «задерживает» другой. В противном случае могли бы возникать значительные простои, особенно при высокой нагрузке.
Хотя, конечно, все зависит от настройки регламентного задания. Например, если оно выполняется каждые 5 секунд, очередь вряд ли будет накапливаться. Но если у вас очень высокий пиковый трафик – скажем, от 100 до 500 сообщений в секунду – задержки все же могут появляться.
Чтобы ускорить отправку, мы разбиваем сообщения на пакеты. Допустим, в одном мессенджере накопилось 500 сообщений – их тоже нужно обрабатывать порционно, чтобы ответы отправлялись как можно быстрее.
Сначала распределяем по мессенджерам, затем внутри каждого – дополнительно дробим на потоки. Но здесь важно поставить ограничение: иначе может запуститься слишком много фоновых заданий (например, 500), и это серьезно нагрузит РП-хост, который просто не выдержит такой нагрузки.
После всех этих этапов – группировки, распределения и ограничения – мы формируем финальные пакеты и приступаем к отправке сообщений.
Структура очереди и проверка контактов
Все это работает через очередь, устроенную следующим образом. У нас есть регистр сведений, в котором хранятся сообщения с разрезом по диалогам и по типу мессенджера – чтобы система знала, через какой канал отправлять.
В каждом сообщении, естественно, содержится контактная информация получателя. Кстати, при выборе получателя мы проводим проверку: существует ли у контрагента аккаунт в выбранном мессенджере. Это помогает избежать ошибок на этапе отправки. Например, если клиент не зарегистрирован в WhatsApp, система заранее сообщит: «Нет активной регистрации». Это позволяет оператору вовремя скорректировать канал связи.
Код отправки сообщений и получение сообщений
Теперь немного о реализации. Приведу пример кода. Как я уже говорил, ключевые блоки выделены красным. Сначала мы определяем модуль мессенджера по его типу – именно тот, что мы настраивали через предопределенные элементы.
Далее, зная имя модуля, мы вызываем его метод в рамках длительной операции – например, «ОтправитьСообщение».
Что касается получения сообщений – логика похожа, но с небольшим отличием: выборка идет не по диалогам, а по аккаунтам. Сначала получаем список активных аккаунтов, затем для каждого формируем выборку входящих сообщений и забираем их через API мессенджера.
Таким образом, мы собираем все необходимые данные и готовы к дальнейшей обработке – например, к отображению в интерфейсе или к отправке уведомлений.
Отправка уведомлений через систему взаимодействия
После получения сообщений мы формируем уведомления. Именно для этого используется система взаимодействия в 1С – механизм, позволяющий оповещать пользователей о новых событиях.
Как и ранее, ключевые блоки кода выделены красным. Сначала мы проверяем, зарегистрирована ли база в системе взаимодействия – это важно, потому что без регистрации отправка уведомлений невозможна. Если база не зарегистрирована, уведомления, естественно, не отправляются – просто нет канала для передачи.
Далее определяем тип мессенджера и проверяем, существует ли у пользователя уже открытое обсуждение с нужным идентификатором. Я сохраняю идентификатор обсуждения в разрезе мессенджера – это позволяет быстро понять, нужно ли создавать новое обсуждение или можно использовать существующее. Информация хранится в отдельном регистре сведений.
Затем получаем пользователя в 1С и соответствующего пользователя в системе взаимодействия – и уже через него отправляем сообщение.
Сначала запрашиваем обсуждение по идентификатору. Если оно существует – просто добавляем в него новое сообщение. Если нет – создаем обсуждение. При этом можно использовать любые шаблоны оформления – все гибко настраивается. После создания обсуждения в него можно отправлять уведомления.
В итоге реализуется простое и надежное взаимодействие: мы формируем текст уведомления и отправляем его пользователю через стандартный механизм системы взаимодействия.
Генерация интерфейса: HTML-шаблоны и CSS
Теперь поговорим о том, как формируется интерфейс. Как я уже упоминал, используется веб-интерфейс на основе шаблонов, который отображает сообщения.
Дело в том, что стандартные формы 1С не очень подходят для красивого и интерактивного отображения чата. А нам важно видеть не только текст, но и статусы сообщений, цитаты, ответы – все, что делает переписку удобной и наглядной.
Поэтому я реализовал интерфейс через HTML-шаблон. Все шаблоны хранятся в макетах.
Подход простой: использую список (<ul>, <li>), а с помощью CSS придаю ему современный и аккуратный вид.
Кстати, в создании шаблона мне помог ИИ. Я не стал делать его вручную – зашел в ChatGPT и попросил: «Давай нарисуем красивые чат-формочки». Он предложил несколько вариантов, мы с ним «пообщались», подкорректировали стили – и в итоге получили простой, но вполне приличный и функциональный шаблон для отображения сообщений.
Работа с изображениями и Base64
Еще один важный момент – отображение иконок и изображений. Например, статусы доставки, прочтения или типы сообщений. Через CSS их делать неудобно, особенно если нужны кастомные графические элементы. Проще использовать картинки.
Но возникает вопрос: как вставить изображения в app-форму, если они еще не загружены? Вставлять Base64 напрямую в код макета – не самое лучшее решение: строка получается очень длинной, увеличивает размер конфигурации и замедляет загрузку. Поэтому я поступил проще: добавил нужные иконки в библиотеку картинок самой конфигурации. При отрисовке шаблона они динамически конвертируются в Base64 и подставляются в HTML напрямую.
Альтернативный способ – разместить изображения на FTP-сервере или в публичном веб-доступе и подключать их через src с URL. Оба подхода рабочие и имеют право на существование. Однако если использовать Base64, стоит быть осторожным с большими изображениями – из-за кодировки размер увеличивается примерно на 30–35%, а при высоком разрешении это может серьезно замедлить отрисовку интерфейса.
Формирование диалогов и ограничения решения
Далее формируется сам диалог. По сути, он реализован как таблица значений. В этой таблице хранится имя диалога, а в отдельном поле – готовый HTML-макет с историей сообщений. То есть при открытии диалога макет извлекается и подставляется в веб-форму для отображения.
У такого подхода есть как плюсы, так и минусы. Главный недостаток – если в диалоге много сообщений, макет может достигать огромных размеров, что сильно нагружает систему, особенно при работе с веб-макетами. Это может замедлять отрисовку и потреблять много памяти.
Однако для прототипа или в сценариях с короткими диалогами такое решение вполне работоспособно. Оно простое и быстро реализуется.
Кроме того, я добавил поле с датой диалога, чтобы можно было сортировать их по времени – самые свежие отображаются сверху, более старые – ниже. Это улучшает восприятие и помогает операторам быстрее находить актуальные переписки.
Интеграция с Telegram через отдельный шлюз
Теперь об интеграции с Telegram. Как я уже упоминал, она реализована через отдельный шлюз, написанный на 1С. Этот шлюз взаимодействует с основной базой по REST API. То есть я не обращаюсь напрямую из основной базы к Telegram. Вместо этого шлюз сам опрашивает Telegram API и передает данные в основную систему.
При этом используется не Webhook, а polling – регулярные запросы к API Telegram. Я выбрал такой подход в целях безопасности: любые входящие данные сначала проходят через шлюз, где обрабатываются и валидируются, прежде чем попасть в основную базу.
Представьте, если кто-то отправит вредоносное сообщение, например, с командой DropDatabase, оно сначала попадет в шлюз, и если что-то пойдет не так – пострадает он, а не основная база с критичными данными о клиентах. Это, конечно, не панацея, но дополнительный уровень защиты. Кроме того, такой подход избавляет от необходимости публиковать основную базу в интернете.
Я не использую Webhook, потому что мои базы не опубликованы и недоступны извне. Если бы пришлось работать через Webhook, пришлось бы открывать внешний доступ – и тогда любой мог бы попытаться атаковать систему, например, DDoS-ом.
А при текущей схеме мы сами инициируем запросы к Telegram, ничего не открывая снаружи. Это безопаснее и проще в поддержке.
Недостатки и преимущества шлюза для Telegram
У этой архитектуры есть и недостатки. Первый – прослойка между основной базой и Telegram. Из-за этого возникают задержки: при каждом запросе нужно поднимать сеанс в 1С на стороне шлюза, что требует времени. Конечно, это можно оптимизировать: кэшировать сеансы, поддерживать их активными, переиспользовать соединения. Но все равно небольшая задержка остается.
Еще один минус – необходимость поддерживать логику в двух конфигурациях одновременно: и в основной базе, и в шлюзе. При изменениях приходится вносить правки в обе части, чтобы методы и форматы данных оставались согласованными.
Тем не менее, у схемы есть и преимущества: безопасность, контроль над данными, гибкость в обработке. Я уже дважды использовал это решение на хакатонах, переносил логику в разные проекты. Сейчас она работает и в моей основной базе, и параллельно – в шлюзе.
То есть, по сути, есть два подхода – прямая интеграция и шлюз. Выбор зависит от требований к безопасности, доступности и архитектуре. Каждый может выбрать то, что больше подходит именно ему.
Использование ИИ через API
Теперь перейдем к AI. На данный момент он работает через API. Я рассматривал возможность использовать, например, ChatGPT – ведь можно было бы задействовать собственную модель, – но времени на ее обучение не хватило.
Вот как это устроено. У нас есть операторы, которые работают в определенных часовых поясах. Мы это учитываем: у каждого пользователя – оператора – прописано его рабочее время. Также у контрагентов указан их часовой пояс.
Когда приходит сообщение от клиента, система сначала проверяет: идет ли сейчас рабочее время у автоответчика? Есть ли свободные операторы? Если время нерабочее – сообщение ожидает реакции оператора. Если же рабочее, но в этот момент нет доступных сотрудников, система переходит к следующему шагу – запускает обработку сообщения с помощью ИИ.
Таким образом, автоматический ответ формируется только тогда, когда живые операторы недоступны.
Шаблоны и работа ИИ с категориями обращений
Как происходит обработка? Я реализовал систему шаблонов, вдохновленную подходом БСП. Шаблоны создаются отдельно для каждого мессенджера – это несложно настроить, и подсистему можно легко доработать. Кроме того, я добавил категории шаблонов – чтобы понимать, к какому типу обращений тот или иной шаблон относится: например, «возврат», «доставка», «техническая поддержка» и т.п.
После настройки – это, конечно, ручная работа – в дело вступает ИИ. Он анализирует диалог: учитывает как новые, так и предыдущие сообщения. Пока что это реализовано через внешний сервис (пока это не полноценная «аишка», а скорее вспомогательный инструмент).
Система передает диалог ИИ с запросом: «Определи категорию этого обращения». После получения категории мы ищем подходящий шаблон в соответствующей группе. Если шаблон найден, ИИ берет всю историю переписки и шаблон, и на их основе формирует ответ. У него есть промпт, который задает стиль и структуру ответа, а также контекст – данные из диалога и справочников.
Но возможна ситуация, когда подходящая категория не определена. Это вполне реалистичный сценарий – ведь запросы бывают нестандартные. В таком случае система отвечает клиенту: «Подождите немного, с вами свяжется оператор. Сейчас я не могу помочь». При этом ИИ автоматически создает задачу для сотрудника, указывая: «Вот вопрос, для которого не нашлось шаблона. Предлагаю отнести его к такой-то категории». Это помогает постепенно расширять базу знаний.
Проблемы и ограничения ИИ-обработки
У такого подхода есть существенный недостаток: ИИ не всегда однозначно определяет категорию, а ответ по промпту может быть неточным. Ошибки случаются примерно в 60% случаев – то есть соотношение успеха и сбоя примерно 40 на 60.
Поэтому такой механизм нельзя использовать без контроля. Автоматический ответ требует проверки, особенно в критичных сценариях. Важно понимать: ИИ – это помощник, а не замена человеку.
Планы по развитию решения
В первую очередь хотелось бы доработать и развить саму модель ИИ. Было бы здорово, чтобы вместе с нашим продуктом мы поставляли предварительно обученную модель, которую уже можно использовать «из коробки». Идея в том, чтобы обучить модель на базовых кейсах – чтобы она уже изначально понимала контекст, умела распознавать типовые запросы и давать корректные ответы. Это повысит удобство для пользователей и ускорит внедрение.
Однако реализация потребует времени, ресурсов и, что важно, вычислительной мощности. Даже если решение будет облачное, нам потребуется отдельный ресурс для обучения и дообучения модели. Без этого модель останется «голой» и малополезной.
Еще одно направление – автоматическая проверка корректности ответов модели. На данный момент я пока не вижу простого способа реализации, но идея в том, чтобы каким-то образом автоматизировать процесс валидации. Возможно, одна ИИ-модель может оценивать ответы другой. Например, по принципу «лесенки доверия»: сложные кейсы проверяются более сильной моделью, а типовые – базовой. В идеале – создать автовалидатор, который определял бы, насколько ответ соответствует ожиданиям.
Сейчас валидация возможна только вручную: оператор или тестировщик оценивает ответ, нажимая «да» или «нет». Такой подход масштабировать сложно, поэтому автоматизация здесь – ключевая задача на будущее.
Безопасность и шифрование сообщений
Сейчас сообщения хранятся в базе данных в открытом виде. В мессенджере они отображаются расшифрованными – иначе операторам было бы неудобно работать. Но если злоумышленник получит доступ к СУБД, он увидит всю переписку напрямую, включая персональные данные пользователей. Это серьезный риск.
Хочется реализовать отдельное защищенное хранилище, где сообщения будут зашифрованы. При этом доступ к расшифровке должен быть строго контролируемым – например, только в момент отображения в интерфейсе. Такой подход снизит риски утечки данных и повысит уровень доверия со стороны клиентов.
Оптимизация загрузки сообщений в интерфейсе
Еще один важный аспект – оптимизация загрузки сообщений в веб-интерфейсе. Сейчас при большом объеме переписки мы загружаем все сразу, что сильно нагружает систему. Лучше реализовать подгрузку по курсору через API. Это позволит загружать сообщения порционно – по мере необходимости.
Особенно это актуально, когда открыто несколько диалогов. Сейчас все сообщения из всех диалогов попадают в таблицу значений, что создает нагрузку на память клиента (например, в браузерных кэшах). Реализация пагинации или бесконечного скролла через API снизит потребление ресурсов и улучшит пользовательский опыт.
*************
Статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART TECH EVENT.
Вступайте в нашу телеграмм-группу Инфостарт