Skip to content
Русскоязычный чатбот
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
CSharpCode все последние изменения в проекте, включая интерпретатор фраз и новый… Sep 20, 2018
data
ruchatbot Большой рефакторинг кода; пробная интеграция с RASA Jul 23, 2019
scripts Большой рефакторинг кода; пробная интеграция с RASA Jul 23, 2019
tmp Delete old model files (use those in docker container instead) Jul 23, 2019
README.md
README.relevance.md В описание добавлены ссылки на статьи по теме Jul 20, 2018
chatbot-console.PNG оформление описания Jan 19, 2018
chatbot-telegram.png добавлен скриншот для Telegram фронтэнда бота Jan 20, 2018
dockerfile Большой рефакторинг кода; пробная интеграция с RASA Jul 23, 2019
setup.py

README.md

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

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

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

B:> Привет, буду рад поговорить
H:> Как тебя зовут?
B:> кеша
B:> А как тебя зовут?
H:> Меня зовут Илья.
B:> Приятно познакомиться.
H:> Сколько будет 2 плюс 2?
B:> 4
H:> Меня как зовут?
B:> илья
H:> Сколько сейчас времени?
B:> 17 часов 47 минут

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

Данный чатбот архитектурно сочетает два разных подхода. Во-первых, ответ на заданный вопрос ищется в базе знаний с помощью NLP моделей (retrieval-based архитектура). Во-вторых, чатбот может генерировать реплики без использования базы знаний (см. генеративные smalltalk-правила). База знаний состоит из двух больших частей - база фактов и FAQ. В базе фактов ищется факт, на основе которого можно сформулировать ответ, даже если текст ответа в явном виде не содержится в факте. В FAQ ищутся готовые ответы на типовые вопросы, при этом текст ответа выдается собеседнику без изменений.

Запуск

Есть два способа запуска чатбота под 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). Формат этого файла описан в шапке файла. Среди разных фактов там можно увидеть запись об имени бота:

Меня зовут Вика

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

При добавлении новых фраз в вышеуказанные файлы следует по возможности воздерживаться от использования лексики, неизвестной языковым моделям чатбота. С определенными оговорками, список слов в файле 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).

База знаний

Знания функционально разделены на 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 алгоритмы.

  5. Архитектура движка чатбота полностью отделена от каналов доставки сообщений. Например, есть варианты чатботов для консоли и в виде веб-сервиса.

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

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 указывают именно этот подкаталог в качестве местоположения моделей. Таким образом, после скачивания репозитория чатбот должен быть доступен для использования без предварительного обучения.

You can’t perform that action at this time.