Привет, Хабр! Меня зовут Игорь Козлов и я — ведущий разработчик в команде «Membrana Голос» от МТС. Наш продукт — это сервис, который принимает звонки, когда вы заняты, и общается со звонящими почти как живой человек. Он основан на полноценном диалоговом фреймворке, десятках моделей машинного обучения и тщательно продуманной логике обработки интентов. Мы взяли за основу open source-фреймворк Rasa, но сильно его доработали, чтобы превратить в гибкую платформу для управления голосовыми диалогами.

В этом материале я покажу, как мы переписали Action Server и обучили DIETClassifier, а также расскажу, как нам удалось обойти ограничения Rasa и сделать умного, настраиваемого и устойчивого к ошибкам телефонного ассистента.

Зачем нам понадобился Rasa

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

Одна из фич — встроенный ИИ-секретарь, который берёт на себя рутину общения. Он умеет определять приоритетность звонков: забирает на себя незнакомые вызовы, а звонки от добавленных контактов напрямую отправляет пользователю. 

Телефонный секретарь Membrana основан на open source-версии фреймворка Rasa. По сути, это связующее ядро, которое объединяет разные инструменты обработки естественного языка в единый пайплайн — от предобработки текста до генерации ответа. Это и есть главное преимущество Rasa: она позволяет собрать в одном месте всё, что нужно для диалога — модели, фичавайзеры, экстракторы и кастомную логику.

Как мы дорабатывали фреймворк Rasa для Membrana

В основе работы фреймворка Rasa лежат две ключевые составляющие:

  • Core — набор ML-компонентов, которые отвечают за обработку пользовательских сообщений. Core анализирует входной текст, извлекает из него entity (сущности) и определяет intent (намерение пользователя). У этой части есть собственный endpoint, через который проходит вся цепочка обработки: от токенизации и фичирования до классификации. Результаты работы Core — распознанные интенты и сущности — передаются дальше в Action Server.

  • Action Server — компонент, который управляет поведением ассистента. Он получает структурированные данные от Core и выбирает, какой ответ или действие нужно выполнить. Логика этой части описана на Python и основана на наборе правил и сценариев.

Главная особенность Rasa — end-to-end-подход: вся цепочка обработки, от текста до ответа, объединена в единую модель. Это и преимущество, и ограничение. Из коробки Rasa следует строгой архитектурной логике, описанной в документации, и не позволяет легко от неё отступать.

Однако в Membrana мы решили эту проблему. Мы перенастроили взаимодействие стандартных компонентов Rasa так, чтобы они работали с нашей собственной логикой принятия решений. Теперь фреймворк использует кастомные сценарии, которые проще дорабатывать, тестировать и масштабировать без переобучения модели.

«Из коробки» Rasa не решает всех задач. Чтобы добиться качественных ответов, мы пересобрали архитектуру и разделили ответственность за выбор реплики на две части:

  • ML-компоненты — сюда входят модели, экстракторы сущностей, фичарайзеры и прочие инструменты машинного обучения.

  • Python-логика — код, который управляет выбором ответов и сценариев на основе заданных правил и эвристик.

Это разделение дало нам два независимых направления для развития секретаря:

  • Улучшить ML-часть. Мы можем точнее определять интенты — за счёт дополнительного обучения, использования предобученных или более сложных моделей и подбора гиперпараметров. Это путь повышения метрик и точности распознавания.

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

В результате, Membrana не просто реагирует на команды, а адаптируется к поведению пользователя, сохраняя контекст и корректируя собственные решения на лету.

Расскажу подробнее о внесённых в Rasa изменениях.

Доработка Core

Основное ядро распознавания в Rasa — это компонент DIETClassifier. Он отвечает за определение интента (намерения пользователя) и entity (сущностей в тексте). Однако его ключевое ограничение заключается в том, что модель не является предобученной: она обучается с нуля во время сборки общей модели секретаря — на внутреннем датасете, который, по очевидным причинам, не может охватить всё разнообразие реальных фраз.

Из-за этого DIETClassifier иногда испытывает трудности с пониманием фраз, которые не представлены в обучающем наборе. Чтобы повысить качество распознавания, мы внедрили в пайплайн custom components — собственные модули, подключающие предобученные модели:

  • SpaCy с моделью ru_core_news_sm;

  • RuBERT Tiny;

  • Natasha.

Эти инструменты извлекают дополнительные векторные признаки (features) для DIETClassifier и помогают корректнее выделять сущности, с которыми базовой модели работать сложно.

Помимо этого, в процессе тестирования мы столкнулись с неожиданной проблемой: модель периодически ошибочно определяла нецензурные выражения там, где их не было. Это происходило из-за схожести некоторых слов с матерными по написанию. Чтобы снизить количество ложных срабатываний, мы добавили компонент Sentiment Analysis, основанный на RuBERT Tiny. Он позволяет оценивать эмоциональную окраску фразы и определять, действительно ли в сообщении есть негатив — или это просто ложная тревога.

Отдельное улучшение коснулось извлечения имён. Мы добавили модель Natasha специально для выделения entity типа “имя”. Предобученные модели существенно повышают качество в этой области: без них закрыть весь спектр имён в русском языке практически невозможно.

Доработка Action сервера

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

Такой подход удобен, когда сценарии стабильны, но плохо работает в системах, где логика должна динамически меняться. Любое обновление — будь то новый ответ или корректировка сценария — требовало переобучения всей модели с подбором гиперпараметров. Чтобы избавиться от этой проблемы, мы кардинально переработали архитектуру Action Server и сделали три ключевых изменения:

  • Вынесли в отдельный компонент тексты, которые возвращала модель. Ранее они были жёстко “зашиты” в её структуру. Теперь они могут редактироваться независимо от обучения. Это позволяет оперативно менять формулировки и сценарии без пересборки модели.

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

  • Создали новую систему определения сценариев. В классической Rasa переход между состояниями зависел от простых условий: распознанного интента и найденного entity. Теперь система может учитывать: несколько интентов и entity одновременно, их историю, текст запроса, комбинированные условия  (AND, OR) и приоритеты срабатывания.

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

В результате мы получили гибкий и масштабируемый Action Server, который сохраняет преимущества Rasa, но при этом позволяет развивать логику ассистента как полноценный программный модуль — независимо от ML-части.

Схема диалога

Мы используем Rasa с полностью измененной логикой как Action-сервера, так и Core. Получился совершенно новый фреймворк, использующий все преимущества Rasa и лишенный его недостатков. Покажу, как это работает в кейсах с диалогами.

Когда пользователь взаимодействует с ИИ-секретарём, весь процесс обработки запроса проходит через несколько этапов:

  1. Получение данных. Запрос переводится в текстовый формат и вместе с метаинформацией передается в компонент Core.

  2. Извлечение признаков (feature extraction). Внутри пайплайна выполняется несколько шагов:

    • SpaCyNLP токенизирует текст и извлекает базовые лингвистические признаки.

    • RuBERT Tiny добавляет контекстные векторные представления (эмбеддинги) слов.

    • CountVectorFeaturizer строит частотные представления слов и фраз.

    • RegexFeaturizer выделяет паттерны на основе регулярных выражений.

    • Полученные фичи объединяются и передаются в DIETClassifier, который определяет интент (в нашем примере — greet, приветствие).

  3. Извлечение сущностей (entity extraction). На этом этапе работают несколько специализированных компонентов:

    • RegexEntityExtractor — ищет сущности по регулярным шаблонам.

    • EntitySynonymMapper — сопоставляет найденные значения с заранее определёнными синонимами.

    • SentimentAnalysis — определяет эмоциональный тон сообщения (например, mood = neutral).

    • Natasha — извлекает именованные сущности, такие как имена людей (в нашем случае — Игорь).

  4. Передача данных в Action Server. Вся собранная информация (интенты, сущности, настроение и контекст) отправляется в Action Server. Сначала базовое правило Rasa перенаправляет данные в наш кастомный диспетчер, который оценивает вероятность каждой ветки сценария.

  5. Выбор сценария и генерация ответа. Диспетчер рассчитывает «очки» для каждой ветки на основе интентов, сущностей и текста. В приведённом выше примере максимальное значение получает сценарий state_name. Далее запрос попадает в соответствующий обработчик, где Python-код анализирует контекст (например, знаком ли абонент, звонил ли он сегодня) и формирует финальный ответ, который возвращается пользователю.

Итоги

За год работы с Rasa я глубоко погрузился в его логику и  могу сказать, что это очень мощный инструмент, незаслуженно обделенный вниманием в России. У него много интеграций с разными площадками (telegram, slack и другие), а также есть подробные гайды почти на все случаи жизни. Если перед вами стоит задача бысто создать чат-бота, рекомендую обратить внимание именно на Rasa.

Для работы с Rasa важно понимать специфику собственных задач. Большинству скриптовых сценариев достаточно базовой логики — она достаточно хорошо реализована в этом фреймворке. В этом материале я описал моменты,  на решения которых может уйти достаточно много времени. Надеюсь, это поможет с вашими проектами.

По итогам работы мы c одной стороны ушли от стандартных сценариев использования фреймворка и полностью переписали свой action-cервер, но с другой — сохранили логику поведения модуля. Это позволит нам в будущем легко обновляться или использовать pro-версию без поддержки собственного форка. Так мы закрыли свои потребности без использования ресурсоемких LLM.

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

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