Модульные диалоговые системы

Сейчас машинное обучение меняет способы взаимодействия бизнеса с клиентами, особенно в клиентских сервисах коммуникации. AI-ассистенты не только автоматизируют рутинные задачи для сотрудников кол-центров и порталов технической поддержки, но и создают новые возможности для персонализированного общения с клиентами по различным сценариям.
При проектировании и разработке таких сервисов важно учитывать этические аспекты потенциального пользователя. Например, AI-ассистенты, взаимодействуя с пользователями, работают с большими объёмами запросов, которые могут включать личную информацию, культурные, национальные и религиозные аспекты.
Такие решения должны использовать данные в рамках этических стандартов и исключать неверную интерпретацию ответов в процессе взаимодействия с пользователем. Здесь важно понимать, кто взаимодействует с пользователем и что из себя представляет интеллектуальный помощник.
Интеллектуальным помощником обычно называют решения, разработанные с помощью диалоговых систем на основе моделей машинного обучения. Эти модульные диалоговые системы взаимодействуют с пользователем на естественном языке в тексте или речи через различные интерфейсы.
Поговорим о них подробнее.
Диалоговая система состоит из компонентов, которые позволяют взаимодействовать с пользователями на естественном языке: модули Natural Language Understanding, Dialog management и Natural Language Generation.

NLU (Natural Language Understanding)

Модуль NLU отвечает за анализ и интерпретацию входящего текста в диалоговых системах. Он принимает запрос через API от приложения (мессенджер, веб-приложение, чат-бот), который послал пользователь. На этом этапе главная задача — извлечь из текста намерения пользователя и основные элементы (имена, даты, места).

Сценарий работы NLU

Представьте, что пользователь написал запрос: «Пожалуйста, забронируй столик в ресторане "Итальяно" на завтра на 19:00 для четырёх человек».
Информация проходит этапы предварительной обработки — токенизацию и нормализацию:
  • Токенизация: ["Пожалуйста", "забронируй", "столик", "в", "ресторане", "Итальяно", "на", "завтра", "на", "19:00", "для", "четырёх", "человек"]
  • Нормализация: ["пожалуйста", "забронировать", "столик", "в", "ресторан", "итальяно", "на", "завтра", "на", "19:00", "для", "4", "человек"]
Затем определяется намерение — бронирование ресторана. И извлекаются сущности:
  • название_ресторана: "Итальяно"
  • дата: "завтра"
  • время: "19:00"
  • количество_персон: "4"
Теперь возможно формирование структуры данных (например, в JSON) и определение следующего действия в диалоге.

Dialog Management (DM)

Ядром всей диалоговой системы является модуль управления диалогом, Dialog Management (DM): у некоторых вендоров он так и называется Core. DM отслеживает текущее состояние диалога, включая информацию о предыдущих намерениях и выполненных действиях. Это позволяет системе сохранять контекст и делать правильные предсказания о следующем шаге на основе накопленной информации.
За выбор следующего шага в зависимости от контекста, намерений пользователя, сущностей и состояния диалога отвечает именно DM. Это может быть либо ответ пользователю, либо вызов какого-нибудь действия (например, вызов API).

Использование политик

DM может использовать различные политики для принятия решений о том, как должна реагировать система, — основанные на правилах или на моделях машинного обучения. Это делает систему гибкой и способной адаптироваться к новым сценариям.
Например, для простых и предсказуемых сценариев DM может следовать заранее определённым правилам, что обеспечивает точное выполнение предсказуемых действий. Если используется политика машинного обучения, то DM использует обученные модели машинного обучения на диалогах, чтобы предсказывать следующие шаги. Это позволяет улучшать точность и адаптировать генерацию ответа к новым ситуациям, не прописанным в правилах.
Rule-based — это тип диалоговых систем, которые реализуются на правилах. Например, телеграм-бот отвечает, используя предопределённый текст, в простых сценариях, где требования к диалогу ограничены и предсказуемы. Такая политика хорошо сработает в обработке часто задаваемых вопросов (FAQ), где ответы формируются на основе правил без необходимости сложной обработки естественного языка.
Data-driven — реализация таких решений основана на управлении данными и имеет два механизма:
  • Retrieval-based — когда бот использует заранее созданный набор данных для извлечения наиболее подходящего ответа. При запросе система сопоставляет введённый текст с существующими ответами и выбирает наилучший вариант на основе схожести. Такой механизм используется в базах знаний, где нужен точный ответ из большого объёма данных.
  • Generating — механизм с использованием нейронных сетей, которые позволяют генерировать уникальные ответы на данных, на которых была обучена модель. Такие диалоговые системы генерируют ответы даже для сильно нетипичных запросов, что делает это подходящим в сложных сценариях и требует объёма данных для обучения и мощных вычислительных ресурсов, а также могут выдавать слишком общие или непредсказуемые ответы, если не оптимизированы должным образом.

Работа с контекстом через слоты (Slot Filling)

Текст, предоставленный пользователем, DM сохраняет в слоты. Эти слоты могут хранить важные данные, такие как местоположение, имена или даты, которые могут использоваться на следующих шагах диалога для предоставления более контекстно ориентированных ответов.

Управление действиями

DM определяет, когда и какие кастомные действия должны быть выполнены. Эти действия могут включать вызов внешних API, доступ к базам данных или выполнение других бизнес-операций.

Сценарий работы DM

DM преобразует структуры данных в формат, нужный на вход для модели. Предобработка данных включает кодирование намерений, действий и других признаков с использованием методов, таких как one-hot encoding или преобразование текстовых данных в числовые представления с помощью эмбеддингов. Все необходимые признаки объединяются в единый входной тензор, который будет использоваться моделью для предсказания следующего действия.
Для того чтобы предсказать следующее действие в диалоге на основе текущего состояния, нужно собрать все необходимые признаки и преобразовать их в формат, пригодный для использования моделью машинного обучения.
Продолжим рассматривать ситуацию, где пользователь сформулировал сообщение: «Пожалуйста, забронируй столик в ресторане "Итальяно" на завтра на 19:00 для четырёх человек».
От NLU получен следующий семантический фрейм:

JSON

# Семантический фрейм от NLU
nlu_output = {
    'intent': 'бронирование_ресторана',
    'entities': {
        'название_ресторана': 'Итальяно',
        'дата': 'завтра',
        'время': '19:00',
        'количество_персон': '4'
    }
} 
Компонент DM получает данные от NLU, принимая намерение и сущности для дальнейшей обработки:

PYTHON

# Компонент DM получает данные от NLU
current_intent = nlu_output['intent']
extracted_entities = nlu_output['entities'] 
DM сохраняет данные в слоты, которые могут быть использованы на следующих шагах диалога для предоставления более контекстно-ориентированных ответов.

PYTHON

slots = {
    'restaurant_name': extracted_entities.get('название_ресторана'),
    'date': extracted_entities.get('дата'),
    'time': extracted_entities.get('время'),
    'number_of_people': extracted_entities.get('количество_персон')
} 
Полученные намерения DM преобразует в пригодный для модели вид. Для кодирования намерения пользователя используется one-hot encoding:

PYTHON

# Список возможных намерений
intents = ['приветствие', 'бронирование_ресторана', 'заказ_еды', 'прощание']

# Кодирование намерения с помощью one-hot encoding
intent_vector = [1 if intent == current_intent else 0 for intent in intents]
# Вектор намерений: [0, 1, 0, 0] 
Дальше кодируются уже сформированные слоты:

PYTHON

# Статус слотов (1, если слот заполнен, иначе 0)
slot_vector = [
    1 if slots['restaurant_name'] else 0,
    1 if slots['date'] else 0,
    1 if slots['time'] else 0,
    1 if slots['number_of_people'] else 0
]
# Вектор слотов: [1, 1, 1, 1] 
Следующим шагом происходит кодирование истории диалога. Предположим, что в нашей ситуации это начало диалога и предыдущих действий нет:

PYTHON

# Список возможных действий
actions = ['action_greet', 'action_ask_restaurant', 'action_ask_date', 'action_ask_time', 'action_ask_people', 'action_make_reservation', 'action_goodbye']

# История предыдущих действий (пуста)
previous_actions = ['action_listen', '']  # 'action_listen' — ожидание ввода пользователя

# Кодирование предыдущих действий
action_vectors = []
for action in previous_actions:
    action_vector = [1 if act == action else 0 for act in actions]
    action_vectors.append(action_vector)
# Вектор действий[0]: [0, 0, 0, 0, 0, 0, 0]
# Вектор_действий[1]: [0, 0, 0, 0, 0, 0, 0] 
Объединяем все признаки в единый входной тензор:

PYTHON

# Объединение всех признаков в один входной тензор
input_tensor = intent_vector + slot_vector
for action_vector in action_vectors:
    input_tensor += action_vector
# Получаем входной тензор, который отправляется в модель:
# [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 
DM передаёт входной тензор в модель для предсказания следующего действия. Предполагаем, что модель загружена и доступна как ml_model:

PYTHON

# Вызов модели для предсказания следующего действия
action_probabilities = ml_model.predict([input_tensor])  # Модель возвращает вероятности действий 
Вот так будут выглядеть выходные данные модели (словарь действий и их вероятностей):

PYTHON

action_probabilities = {
    'action_make_reservation': 0.9,
    'action_ask_missing_info': 0.05,
    'action_default_fallback': 0.05
} 
DM выбирает действие с наивысшей вероятностью (определение, когда и какие кастомные действия должны быть выполнены. Эти действия могут включать вызов внешних API, доступ к базам данных или выполнение других бизнес-операций. В нашем случае это действие 'action_make_reservation': 0.9.
DM выполняет бронирование:

PYTHON

def action_make_reservation(slots):
    # Извлечение значений слотов
    restaurant_name = slots.get('restaurant_name')
    date = slots.get('date')
    time = slots.get('time')
    number_of_people = slots.get('number_of_people')

    # Логика бронирования (например, обращение к внешнему API)
    reservation_success = make_reservation(
        restaurant_name=restaurant_name,
        date=date,
        time=time,
        number_of_people=number_of_people
    )

    return reservation_success

# Выполнение действия
reservation_success = action_make_reservation(slots) 
Если бронирование прошло успешно, DM обновляет состояние диалога, отмечая успешное завершение задачи.
Далее DM передаёт результат действия и необходимые данные в NLG.

NLG (Natural Language Generation)

Этот модуль отвечает за генерацию и формирование исходящего текста в диалоговых системах. NLG создаёт ответ, который передаётся через API приложению (мессенджер, веб-приложение, чат-бот) для отображения пользователю.
Задача NLG — последовательно сформировать текстовый ответ на основе внутренних данных системы и выявленных намерений пользователя, обеспечивая естественность и понятную коммуникацию.

Сценарий работы DM

NLG получает от DM информацию о результате действия (например, успешное бронирование) и данные из слотов — название ресторана, дата, время и количество персон.
На основе полученных данных NLG формирует ответ, используя заранее подготовленные шаблоны или правила. Например, подставляет значения из слотов в текст ответа, чтобы сообщить пользователю об успешном бронировании или запросить недостающую информацию.
Далее генерируется ответ: сформированный текст передаётся пользователю через соответствующий канал коммуникации (мессенджер, веб-приложение и т. д.).
Модуль NLG использует данные, предоставленные DM, для формирования понятного и релевантного ответа пользователю. Он учитывает результаты выполненных действий и текущие слоты, чтобы обеспечить персонализированное взаимодействие. Это завершает цикл обработки запроса пользователя, объединяя работу NLU, DM и NLG для естественного взаимодействия с пользователем.

Rasa

Предлагаем разобрать работу конкретной диалоговой платформы Rasa и рассмотреть последовательность обработки запроса пользователя и то, как каждый компонент взаимодействует друг с другом в процессе диалога.
✏️ Rasa — это среда машинного обучения с открытым исходным кодом, которую используют для создания диалоговых чат-ботов.
Общий процесс вам уже знаком: пользователь отправляет запрос через интерфейс (например, через веб-приложение), который обрабатывается NLU для распознавания намерений. Далее происходит управление диалогом с помощью Core (он же управляет диалогом DM), где нейронная сеть и логика управления диалогом определяют, какое действие выполнить. Если необходимо, система выполняет API-запрос во внешние сервисы для получения информации. После этого компонент NLG генерирует финальный ответ, который отправляется обратно пользователю.
В деталях это выглядит следующим образом:
NLU
  • Intent Classification (классификация намерений) отвечает за понимание того, что пользователь хочет сделать. Например, в запросе «Какая погода в Москве?» система классифицирует намерение как «получить информацию о погоде».
  • Entity Extraction (извлечение сущностей) — параллельно с классификацией намерений система извлекает ключевые сущности из текста, такие как «завтра» в данном запросе, что позволяет использовать эту информацию для дальнейших действий.
Core (выполняет функции DM)
  • Entity Input и API Call — после того как намерение и сущности распознаны, система определяет, какие функции ещё нужно выполнить. На этом этапе происходит запрос к API (например, для получения прогноза погоды), где система использует извлечённые сущности — дату и местоположение.
  • Recurrent Neural Network (RNN) — это ключевая часть обработки диалога. Система использует нейронную сеть для анализа контекста диалога и предсказания следующего действия. Она учитывает предыдущие шаги, чтобы выдать наиболее релевантный результат.
  • Action Mask помогает сузить возможные действия на основе текущего состояния диалога и классифицированного намерения. Он предотвращает выполнение неподходящих действий.
  • Renormalization и sample action: на основе предыдущих шагов система нормализует и выбирает следующее действие для выполнения (например, вызов API или выдачу готового ответа).
  • Entity Output: если в результате действий нужно передать пользователю сущности (например, прогноз погоды с температурой), они подготавливаются к отправке через этот блок.
  • Action Type — выбирается тип действия.
NLG
После того как все действия были выполнены, система NLG генерирует ответ, который отправляется пользователю. В данном случае это сообщение «Будет солнечно, 20 градусов».
NLG использует информацию из предыдущих этапов (например, данные от API) для генерации естественного текста, который отправляется обратно пользователю через интерфейс.
Чтобы настроить Rasa, сначала нужно настроить окружение.

Установка и настройка окружения

Предварительно установите:
  • Python (3.7-3.10): Rasa работает с версиями Python 3.7 и выше, но ниже 3.11.
  • pip — менеджер пакетов Python, который будет использоваться для установки Rasa.
  • Virtualenv (рекомендуется): использование виртуальной среды для изоляции окружения и зависимостей проекта.
  1. Убедитесь, что pip установлен. Выполните команду:
    python -m ensurepip --upgrade
  2. Установите virtualenv, если он ещё не установлен:
    pip install virtualenv
  3. Создайте виртуальное окружение:
    python -m venv rasa_env
  4. Активируйте виртуальное окружение:
    source rasa_env/bin/activate

Установка и настройка Rasa

⚙️ В проектной работе вы будете работать со средой Rasa, поэтому сейчас предлагаем пошаговую инструкцию по её установке.
  1. Установите Rasa через pip: pip install rasa.
  2. Установите библиотеку transformers для работы с предобученными LLM-моделями, такими как BERT, GPT: pip install transformers.
  3. Проверьте, что Rasa и окружение установлено, выполните команду rasa --version
    Если установка прошла успешно, то вы увидите похожее:
    Rasa Version      :         3.6.20
    Minimum Compatible Version: 3.5.0
    Rasa SDK Version  :         3.6.2
    Python Version    :         3.10.15
  4. После установки Rasa, инициализируйте новый проект Rasa, который создаст структуру проекта: rasa init.
  5. Rasa создаст базовый проект с файлами, такими как:
  • nlu.yml — этот файл содержит примеры сообщений пользователей и соответствующие им интенты. Он используется для обучения модели распознавания намерений (интентов) и сущностей в сообщениях.
  • domain.yml описывает основные компоненты бота: интенты, сущности, ответы, слоты и действия. Этот файл задаёт структуру взаимодействия с ботом.
  • config.yml задаёт конфигурацию пайплайна для обработки сообщений, включая токенизаторы, классификаторы и другие компоненты. Здесь также можно указать политики для управления диалогами.
  • stories.yml содержит сценарии диалогов (истории), которые представляют последовательности интентов и действий. Эти сценарии используются для обучения модели предсказывать следующий шаг в диалоге.
  • rules.ym используется для описания правил — определённых сценариев, которым бот должен строго следовать. Например, всегда отвечать определённым образом на конкретные интенты или всегда завершать диалог в определённых случаях.
  • endpoints.yml — этот файл нужен для настройки внешних сервисов и интеграций, таких как подключение к базе данных, вебхуки или кастомные действия. Например, если ваш бот должен взаимодействовать с внешним API.
  • credentials.yml нужен для настройки учётных данных и токенов для интеграции с внешними веб-сервисами.
Среда для создания чат-бота готова.

Что почитать про Rasa?

Introduction to Rasa Open Source & Rasa Pro

Задание 1

Какой модуль в Rasa отвечает за интерпретацию входящих запросов пользователя?
DM не занимается интерпретацией запросов пользователя. Его задача — управлять диалогом, выбирая следующее действие на основе намерений, которые уже определил NLU, и текущего состояния диалога. Например, если пользователь попросил забронировать столик, DM решит, что делать дальше: подтвердить бронирование или запросить дополнительную информацию, такую как количество гостей.
NLG отвечает за генерацию ответов на основе результатов работы NLU и DM. Например, если NLU определил намерение «бронирование ресторана», а DM выбрал действие «подтверждение бронирования», то NLG сгенерирует текст, который будет отправлен пользователю: «Ваш столик забронирован на завтра в 19:00».
NLU — это модуль, который интерпретирует входящие запросы пользователя, определяя намерение (что пользователь хочет сделать) и извлекая ключевые сущности (например, даты, места, имена). Например, если пользователь напишет: «Забронируй столик на завтра в 19:00», NLU поймёт, что намерение пользователя — бронирование и извлечёт сущности: время ("19:00") и дату ("завтра").

Задание 2

Какая из следующих характеристик описывает rule-based (основанные на правилах) диалоговые системы?
Rule-based системы не используют машинное обучение, они работают на основе чётко прописанных правил и сценариев. Системы, которые генерируют ответы с помощью машинного обучения, относятся к data-driven (generating) системам. Например, для обработки запроса «Сколько стоит билет на поезд?» rule-based система может заранее иметь набор ответов в зависимости от направления и даты поездки, а система с машинным обучением сгенерирует уникальный ответ на основе обученных данных.
Rule-based системы лучше всего работают с предсказуемыми запросами, где возможные сценарии взаимодействия известны заранее. Для сложных и непредсказуемых запросов, таких как запросы с нетипичными формулировками или неструктурированной информацией, используются data-driven системы, которые могут адаптироваться и генерировать ответы на основе данных. Например, запрос «Расскажи мне о путешествии в космос» слишком сложен для rule-based системы, но система, основанная на машинном обучении, может справиться с такой задачей.
Rule-based системы работают по жёстко заданным правилам, что делает их эффективными для простых сценариев, например для обработки часто задаваемых вопросов (FAQ). Такие системы могут быть полезны в тех ситуациях, когда сценарий общения можно предугадать. То есть если бот должен ответить на вопрос «Какова ваша политика возврата?», система использует заранее прописанный ответ.
Rule-based системы не нуждаются в обучении и данных, так как все возможные ответы и действия заранее прописаны. Для data-driven систем, особенно generating-систем, требуется большое количество данных для обучения, чтобы они могли генерировать ответы на различные запросы. Например, для обученной системы нужно множество диалогов, чтобы она могла правильно интерпретировать и отвечать на запросы, такие как «Посоветуй мне хороший ресторан в этом районе».

Что посмотреть про модульные диалоговые системы?

What is AI ethics?
Как устроена Алиса. Лекция Яндекса
Этика и безопасность искусственного интеллекта
Создание QA-ассистента для чат-бота с Yandex DataSphere

Итоги

  • Диалоговая система состоит из компонентов, которые позволяют взаимодействовать с пользователями на естественном языке: модули Natural Language Understanding, Dialog management и Natural Language Generation.
  • Модуль NLU отвечает за анализ и интерпретацию входящего текста в диалоговых системах. Он принимает запрос, который послал пользователь, через API. На этом этапе главная задача — извлечь из текста намерения пользователя и основные элементы в процессе токенизации и нормализации.
  • Ядром всей диалоговой системы является модуль управления диалогом, Dialog Management. DM отслеживает текущее состояние диалога и выбирает следующий шаг в зависимости от контекста, намерений пользователя, сущностей: ответ пользователю или вызов какого-либо действия.
  • Для простых и предсказуемых сценариев (например, в чат-ботах) DM может следовать заранее определённым правилам, что обеспечивает точное выполнение предсказуемых действий. В ситуациях, не прописанных в правилах, используется политика машинного обучения: DM использует обученные модели машинного обучения на диалогах, чтобы предсказывать следующие шаги.
  • Модуль NLG получает данные от DM и формирует понятный и релевантный ответ пользователю. Он учитывает результаты выполненных действий и текущие слоты, чтобы обеспечить персонализированное взаимодействие. Это завершает цикл обработки запроса пользователя, объединяя работу NLU, DM и NLG для естественного взаимодействия с пользователем.
  • Одной из популярных диалоговых платформ с открытым исходным кодом является RASA. С её помощью можно создавать чат-боты для разных предметных задач.