Git Product home page Git Product logo

chatbot's Introduction

Вопросно-ответная диалоговая система (чатбот)

Краткое описание

Чатбот - это набор инструментов, позволяющих организовывать диалоговые сессии примерно такого вида:

B:> Здравствуй
H:> привет
B:> Привет, давай познакомимся?
H:> давай
B:> Хорошо
B:> Как тебя зовут?
H:> илья
B:> меня зовут Вика
B:> Где ты живешь?
H:> в москве
B:> Тебе нравится в Москве?
H:> да
B:> Чем ты занимаешься?
H:> работаю на стройке
B:> Это опасная работа.
B:> Чем ты увлекаешься?
H:> компьютерными играми
B:> Теперь мы знакомы
B:> Я люблю компьютерные игры.

В этом примере реплики чатбота отмечены символами B:>, а реплики человека - символами H:>.

Данный чатбот архитектурно сочетает два подхода.

Во-первых, retrieval-based архитектура: ответ на заданный вопрос ищется в базе знаний с помощью набора NLP моделей.

Во-вторых, rule-based подход: чатбот может генерировать реплики и управлять диалогом помощью описанный вручную правил, сценариев и веб-форм - см. далее описание файла rules.yaml.

База знаний чатбота состоит из двух больших частей - базы фактов и FAQ. В базе фактов ищется факт, на основе которого можно сформулировать ответ, даже если текст ответа в явном виде не содержится в факте. В FAQ ищутся готовые ответы на типовые вопросы, при этом текст ответа выдается собеседнику без изменений. Поиск информации в базе фактов осуществляется моделью релевантности предпосылки и вопроса. Подбор подходящей записи в FAQ выполняется помощью детектора синонимичности. Обе эти модели обучаются на больших датасетах.

Правила и вербальные формы описываются вручную, но также опираются на несколько NLP моделей. Модель синонимичности и классификатор интента позволяют выбирать подходящее правило. Named Entity Recognition модуль извлекает из реплики человека необходимую ключеую информацию.

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

H:> Как тебя зовут?
B:> вика

То есть чатбот нашел в своей базе фактов релевантную информацию и сгенерировал ответ. А с использованием сценария диалог выглядит примерно так:

B:> Здравствуй
H:> как тебя зовут
B:> меня зовут Вика
B:> А тебя как зовут?
H:> Артур
B:> Редкое имя.

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

H:> а скажи, как меня зовут?
B:> Артур 

То есть чатбот запомнил, что ему сказало собеседник - свое имя, и включил этот новый факт в стандартный процесс генерации ответа.

Запуск

Есть два способа запуска чатбота под Linux.

Простой способ - выкачать и запустить docker-образ текущего релиза. Допустим, chatbot.tar.gz это скачанный файл, тогда для запуска нужно выполнить команды:

docker image load -i chatbot.tar.gz
docker run -ti -e PYTHONIOENCODING=utf-8 chatbot

Текущая пре-альфа версия чатбота не оптимизирована и достаточно долго загружает файлы словарей и моделей. После появления приглашения можно ввести тестовые вопросы:

Привет, как тебя зовут?
Наверное, ты робот, да?
Что ты любишь делать?
Ты в шахматы умеешь играть?
А в шашки?
Ты знаешь, что такое белый карлик?

Более сложный способ - выкачать содержимое репозитория, установить ряд необходимых питоновских библиотек, включая:

pip install git+https://github.com/Koziev/rutokenizer
pip install git+https://github.com/Koziev/rupostagger
pip install git+https://github.com/Koziev/ruword2tags
pip install git+https://github.com/Koziev/rusyllab

Затем запустить ./script/console_bot.sh

Кастомизация чатбота, константы профиля

Используемые базы знаний и FAQ, а также наборы правил ведения диалога указываются в профиле, который загружается при старте экземпляра бота. В скрипте console_bot.sh можно увидеть указание на тестовый профиль [profile_1.json](data/rules.yaml](https://github.com/Koziev/chatbot/blob/master/data/profile_1.json), позволяющий боту отвечать на несколько простых вопросов. В этом профиле в качестве базы знаний указан файл [profile_facts_1.dat]((data/rules.yaml](https://github.com/Koziev/chatbot/blob/master/data/profile_facts_1.dat). Формат этого файла описан в шапке файла.

Среди разных фактов там можно увидеть запись:

меня зовут $name_nomn

Конструкция $name_nomn означает, что в строку при загрузке чатбота будет подставлена константа с именем name_nomn, определенная в файле profile_1.json в разделе constants:

	"constants": {
		"gender": "ЖЕН",
		"name_nomn": "Вика"
	}

Так как бота может встречаться в нескольких местах (база фактов, FAQ, правила), то удобнее задать имя в одном месте, в файле профиля.

Когда чатбот обрабатывает вопрос "Как тебя зовут?", он определяет, что этот факт наиболее релевантен для ответа на заданный вопрос, и далее запускает процедуру построения ответа. Само имя "Вика" нигде не "зашито" в языковых моделях. Поэтому для его смены не нужно переобучать нейросетки, а достаточно отредактировать данную запись.

Вторая константа с именем "gender" определяет грамматический род для бота, в данном случае женский. В том же файле фактов можно найти такую запись:

Я $chooseAdjByGender(нужен, нужна), чтобы отвечать на вопросы посетителей чата

Конструкция $chooseAdjByGender(нужен, нужна) позволяет выбрать одно из перечисленных слов, фильтруя их по константе грамматического рода. Таким образом, реплики бота становятся более релевантными "биологической" природе бота.

Все вышесказанное справедливо и для записей в FAQ, и для правил скриптования бота.

При добавлении новых фраз в вышеуказанные файлы следует по возможности воздерживаться от использования лексики, неизвестной языковым моделям чатбота. С определенными оговорками, список слов в файле tmp/dataset_words.txt известен чатботу и модет использоваться.

Остальные правила для движка чатбота собраны в файле data/rules.yaml.

Правила для чатбота

Правила собраны в файле data/rules.yaml с форматом YAML. Смотрите комментарии в файле, поясняющие структуру правил, а также пояснения в разделе "Порядок применения правил" далее. Привязка набора правил к экземпляру бота выполняется в профиле - текстовом файле типа [profile_1.json](data/rules.yaml](https://github.com/Koziev/chatbot/blob/master/data/profile_1.json).

Вербальные формы задают перечень слотов, которые пользователь должен заполнить своими ответами. Каждый слот задается вопросом, который бот задаст, если соответствующая информация отсутствует в стартовой реплике собеседника. Например, для формы заказа еды нужно, чтобы пользователь указал, что он хочет заказать, сколько порций и когда нужно привезти заказ. Вербальная форма активируется правилом, которое реагирует на *намерение (aka intent)
или текст реплики. К примеру, правило-триггер может реагировать на наличие ключевого слова заказать. Если пользователь скажет "хочу заказать пиццу", то запустившаяся вербальная форма найдет в этой фразе заполнение для слота "какую еду", а для слотов "сколько порций" и "когда доставить" информация будет запрашиваться заданными уточняющими вопросами. После того, как все слоты вербальной формы будут заполнены, будет активирован обработчик, например заданный пользовательский код. Соответствующая диалоговая сессия выглядит примерно так:

B:> Добрый день
H:> хотелось бы заказать что-нибудь покушать
B:> Что заказать?
H:> пиццу с ананасами
B:> Сколько порций?
H:> две
B:> Заказываю: что="пиццу с ананасами", сколько="две"

Технически извлечением информации для слотов заведует Named Entity Recognition модуль со своей нейросетевой классификационной моделью, тренируемой на расширенной версии датасета.

Пример вербальной формы можно найти в файле rules.yaml поиском по подстроке "form".

Сценарии описывают примерный перечень вопросов, который бот будет задавать после какой-либо реплики собеседника с заданным интентом или текстом. Пример работы простого сценария:

B:> Добрый день
H:> как тебя зовут
B:> меня зовут Вика
B:> А тебя как зовут?
H:> Артур
B:> Редкое имя.

Особенность сценариев в том, что перед тем, как задать прописанный в сценарии вопрос, чатбот сначала проверит: не знает ли он уже ответ на этот вопрос. Если у бота уже есть нужная информация, вопрос он задавать не будет. Например, если собеседник ранее уже сообщил свое имя и оно было запомнено в базе фактов, то прописанный в сценарии вопрос "как тебя зовут" задавать не надо. Такая "рефлексия" делает диалог с чатботом менее механическим и более живым. Пример сценариев можно найти в файле файле rules.yaml поиском по подстроке "scenario".

База знаний

Знания функционально разделены на 2 части.

FAQ-правила - состоят из пар "вопрос - ответ". Для удобства обработки перефразировок вопросов для одного ответа может быть несколько. Когда движок бота обрабатывает вопрос собеседника, он ищет среди FAQ-правил наиболее близкий опорный вопрос. Если поиск удался, то в качестве ответной реплики бота будет выдан текст из этого FAQ-правила. Сопоставление опорных вопросов и запроса собеседника выполняется с помощью модели синонимичности. В демо-версии чатбота FAQ-правила собраны в файле data/faq2.txt. Для примера, введите вопрос "Что такое белые карлики" и бот выдаст соответствующую инфомацию:

H:> что такое белые карлики
B:> Белые карлики — проэволюционировавшие звёзды с массой, не превышающей
предел Чандрасекара

F-правила, или просто факты, представляют из себя одиночные предложения, описывающие элементарные факты о самом чатботе, собеседнике или окружении. Получив вопрос собеседника, чатбот ищет в этой базе факт, максимально релевантный заданному вопросу (сравни с FAQ-правилами). Если такой факт найден, то он далее поступает в движок генерации ответа. Сопоставление вопроса собеседника и предпосылок производится с помощью модели релевантности. В демо-версии чатбота факты собраны в файле [profile_facts_1.dat]((data/rules.yaml](https://github.com/Koziev/chatbot/blob/master/data/profile_facts_1.dat). К примеру, ответ на вопрос "Как тебя зовут?" подразумевает поиск соответствующего факта - см. абзац про кастомизацию бота.

Порядок применения правил

  1. Если есть история диалога (>1 реплики), то реплика собеседника прогоняется через модель интерпретации для восстановления полной фразы, раскрытия анафоры, гэппинга и т.д.

  2. Среди comprehension правил ищется достаточно близкий вариант фразы в if блоке. Если нашлось, то вместо исходной фразы дальше будет обрабатываться then-фраза из найденного правила. Таким образом выполняется некоторая нормализация фраз собеседника.

  3. Определяется intent с помощью обученного на датасете data/intents.txt классификатора (см. далее).

  4. Определяется грамматическая модальность - является ли реплика вопросом, утверждением или приказом.

  5. Для приказов: пытаемся найти правило для обработки (секция rules в rules.yaml) и выполняем его. При поиске используется либо определенный intent (if-часть содержит ключевое слово intent), либо проверяется синонимичность с помощью модели синонимичности. Если правило не найдено, то вызывается дефолтный обработчик - пользовательская функция, зарегистрированная в on_process_order. Если и он не обработал приказ, то будет сказана фраза "unknown_order" в rules.yaml

  6. Для утверждений: пытаемся найти правило обработки (секция rules в rules.yaml) и выполнить его. Далее, факт сохраняется в базе знаний. Наконец, пытаемся найти smalltalk-правило: это правило в группе rules (rules.yaml), в котором опорная часть (if) и результативная часть (then) заданы с ключевым словом text. Ищется правило, в котором опорная часть максимально синонимична входной фразе, если найдено - чатбот скажет фразу, которая указана в then-ветке.

  7. Для вопросов: сначала проверяется, нет ли похожего (модель синонимичности) вопроса среди FAQ-правил (файл faq2.txt). Если есть - выдается содержимое найденного FAQ-правила. Иначе начинается процедура генерации ответа. С помощью модели релевантности (см. отдельный раздел про ее дообучение и валидацию) ищутся максимальной релевантные предпосылки в файлах premises*.txt. Если не найдена достаточно релевантная предпосылка, то выдается фраза "no_relevant_information" из rules.yaml.

В ходе генерации ответа может потребоваться ответить "да" или "нет". Эти фразы находятся в rules.yaml в разделе "answers".

Переобучение модели релевантности

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

  • это текстовый tab-separated файл premise_question_relevancy.csv. В колонке premise находятся предпосылки (факты), question - вопросы. Колонка relevance содержит 1 для нелевантных пар, 0 для нерелевантных. Таким образом, чтобы модель считала предпосылку и вопрос релевантными, надо добавить к этому датасету запись с relevance=1. Следует избегать добавления повторов, так как это будет приводить к искажению оценок точности при обучении.

После изменения файла premise_question_relevancy.csv нужно запустить обучение скриптом train_lgb_relevancy.sh. Обучение идет примерно полчаса. В результате в каталоге .../tmp будут созданы новые файлы lgb_relevancy.*, содержащие правила модели релевантности.

Контроль качества модели релевантности

Любые ошибки при работе модели релевантности негативно сказываются на общем качестве диалогов, поскольку многие другие части чатбота используют результаты выбора предпосылок из базы знаний в качестве входной информации. Чтобы контролировать качество этой модели, желательно верифицировать ее работу на тестовых вопросах и наборе тестовых предпосылок. Для выполнения этой верификации мы используем простой консольный скрипт query2_lgb_relevancy.sh. Он загружает текущую обученную модель релевантности и список предпосылок из базы знаний (файлы ../data/premises*.txt) и тренировочного датасета premise_question_relevancy.csv. Затем с консоли вводится проверочный вопрос, модель вычисляет его релевантность по всем предпосылкам и выводит список из нескольких самых релевантных. Если в этом списке есть явно нерелевантные предпосылки с высокой оценкой (допустим, выше 0.5), то есть смысл добавить такие предпосылки с вопросом в качестве негативных примеров в датасет premise_question_relevancy.csv и переобучить модель релевантности, запустив скрипт train_lgb_relevancy.sh.

Верификация модели синонимичности

С помощью скрипта scripts/query2_lgb_synonymy.sh можно искать примеры неверной работы модели синонимичности. В консоли вводится фраза, для которой модель вычисляет похожесть к набору фраз из датасетов. Результаты, ранжированные по убыванию похожести, выводятся в консоль. Если среди фраз с похожестью > 0.5 есть явно ошибочные, их можно внести как негативные примеры (в файл paraphrases.txt или в собранный датасет synonymy_dataset.csv), затем переобучить модель скриптом scripts/train_lgb_synonymy.sh

Модель определения intent'а

С помощью модели intent'а можно присвоить фразе собеседника одну метку из набора возможных и далее обрабатывать фразу с учетом этой метки правилами (раздел rules в rules.yaml).

Данные для обучения находятся в текстовом файле data/intents.txt Его формат прост и описан в комментарии в начале файла.

После модификации этого файла необходимо собрать датасет с помощью PyModels/preparation/prepare_intents_dataset.py, затем запустить обучение классификатора с помощью scripts/train_intent_classifier.sh

Отличительные особенности чатбота

  1. Новая информация (факты), сообщаемые пользователем, могут немедленно добавляться в базу знаний и использоваться в последующих ответах наряду с остальными фактами. Именно так в базу знаний бота попадает имя собеседника, которое он сообщает. Переобучение моделей при этом не требуется.

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

  3. Ориентированность на клиент-серверный механизм; способ доставки сообщений отвязан от ядра системы и может быть реализован в виде текстовой консоли, бота для мессенджера, браузерного клиента для веб-сервиса и т.д.

  4. Ответы чатбота по умолчанию не программируются скриптами или аналогичными средствами, а генерируются обучаемыми моделями. В необходимых случаях используются нейросетевые deep learning модели, а также классические NLP алгоритмы.

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

B:> Привет, буду рад пообщаться
H:> сколько букв в слове мама?
B:> 4

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

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

B:> Здравствуй
H:> как тебя зовут?
B:> кеша
B:> А как тебя зовут?
H:> илья
B:> Приятно познакомиться.
H:> как меня зовут?
B:> илья

В данном примере чатбот задает вопрос "А как тебя зовут", рассчитывая заполнить пробел в своей базе знаний. Собеседник сообщает свое имя, и его ответ интерпретируется как "Меня зовут Илья". Эта реплика рассматривается как полноценный факт и запоминается в базе знаний, что видно на последних двух репликах диалога, где собеседник спрашивает у бота свое имя и получает его.

Способ генерации ответа выбирается в зависимости от контекста. В частности, чатбот может выполнять простые арифметические операции:

B:> Привет, буду рад поговорить
H:> Чему равно 2 плюс 3?
B:> 5

Консольный фронтенд для бота

Реализован в файле console_chatbot.py. Запуск под Linux выполняется скриптом scripts/console_bot.sh

Console frontend for chatbot

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

Технические подробности реализации

Список моделей:

Посимвольное встраивание слово в вектор фиксированной длины wordchar2vector_model.py
Определение способа генерации ответа nn_model_selector.py
Определение слов, копируемых из предпосылки в ответ nn_wordcopy3.py
Определение достаточности набора предпосылок для генерации ответа nn_enough_premises_model.py
Генерация ответов yes/no nn_yes_no_model.py
Посимвольная генерация ответа xgb_answer_generator_model.py
Определение релевантности предпосылки и вопроса lgb_relevancy_detector.py
Интерпретация реплики собеседника (раскрытие анафоры, дополнение ответа etc) nn_interpreter.py
Определение синонимии фраз nn_synonymy_detector.py

Набор моделей и конкретная реализация могут сильно меняться по мере развития проекта, поэтому список является не окончательным.

Описание тренировки и использования модели посимвольного встраивания слов смотрите на отдельной странице.

Также доступно описание модели для определения релевантности факта и вопроса.

Pretrained models

Модель встраивания слов в векторное пространство тренируется с помощью скрипта https://gist.github.com/Koziev/e39689adec30ae5bf6afaa1ca47c08e5 (Python, gensim) и текстового корпуса размером около 10 Гб, в котором текст предварительно разбит на слова и приведен к нижнему регистру.

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

Скрипты запуска бота, например console_bot.sh указывают именно этот подкаталог в качестве местоположения моделей. Таким образом, после скачивания репозитория чатбот должен быть доступен для использования без предварительного обучения.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.