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

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

Вы можете найти окончательный код на моем GitHub: https://github.com/MartinGentleman/weather-bot

Для этого вам понадобятся только базовые навыки Python и никакие навыки машинного обучения.

Бот будет очень просто продемонстрировать все важные функции Rasa Stack. Это простой пример возможного обсуждения с вашим будущим ботом:

привет
Привет, мой друг.
Меня зовут Мартин.
Приятно познакомиться, Мартин.
Как поживаете ты
Я в порядке.
Какая погода в Новой Зеландии
В Окленде, Новая Зеландия, в основном ясно, 11 ° C.
Пока
Пока.

Архитектура чат-бота

Раса НЛУ: понимание естественного языка

Понимание естественного языка как область искусственного интеллекта, связанная с машинами, распознающими письменный язык.

В случае с чат-ботом NLU - это первый компонент, который принимает вводимые пользователем данные в виде строки, а затем с помощью обученной машинной модели он определяет намерение пользователя, лежащее в основе его / ее слов. вместе со структурированными данными (имя пользователя, запрошенное местоположение и т. д.). Затем намерение передается механизму диалога.

Rasa Core: движок диалога

Механизм диалога принимает намерение на входе и предоставляет действие на выходе. Машинное обучение историй используется, чтобы научить движок реагировать на различные намерения в контексте. Rase Core может обработать действие и вернуть полный текстовый вывод или просто вернуть рекомендованное действие в зависимости от желания вашей клиентской архитектуры.

Клиент

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

Установить зависимости

Для этого проекта вам необходимо установить три пакета Python:

pip install rasa[spacy]
python -m spacy download en_core_web_md
python -m spacy link en_core_web_md en
pip install weather-api

Структура проекта

Скрипты Python: trainer.py и bot.py

Мы создадим два основных скрипта:

  • trainer.py будет использоваться для машинного обучения нашего чат-бота через командную строку.
  • bot.py будет использоваться для запуска нашего бота в командной строке.

Конфигурация NLU и определение домена

Для проекта требуются всего две конфигурации:

  • nlu-config.yml - это конфигурация, используемая Rasa NLU для настройки конвейера.
  • domain.yml - это конфигурация, используемая Rasa Core, чтобы собрать все вместе для нашего механизма диалога.

Признание намерений и рассказы

Мы создадим каталог data, в котором разместим nlu-data.md и stories.md.

  • nlu-data.md используется Rasa NLU машинным обучением для обучения распознаванию намерений на основе ввода текста пользователем.
  • stories.md используется Rasa Core машинным обучением для объединения намерений и действий в контексте для механизма диалога.

Оба файла используют очень простой формат MD.

Действия

Действия используются для получения программных ответов, выходящих за рамки простого сочетания ввода и вывода текста. В нашем случае мы воспользуемся действием для получения информации о погоде с помощью weather-api из «Yahoo! Погода".

Настроить NLU

Нашим первым шагом будет настройка конвейера понимания естественного языка для машинного обучения Rasa NLU с помощью файла nlu-config.yml. Информацию можно найти в документации: http://rasa.com/docs/nlu/master/pipeline/

Наша конфигурация будет иметь следующий вид:

language: "en"

pipeline:
- name: "nlp_spacy"
- name: "tokenizer_spacy"
- name: "intent_entity_featurizer_regex"
- name: "intent_featurizer_spacy"
- name: "ner_crf"
- name: "ner_spacy"
- name: "ner_synonyms"
- name: "intent_classifier_sklearn"

Не думайте, что мы используем одновременно ner_crf и ner_spacy. Они используются для распознавания именованных объектов и позволяют NLU извлекать имена, места, даты и т. Д. Из введенных пользователем данных. NER CRF требует, чтобы вы научили его распознавать определенные слова. NER Spacy поставляется с предварительно обученной базой данных, которую вы можете использовать напрямую. Мы будем использовать Spacy, чтобы получить объекты с названиями городов / стран для нашего действия с погодой. Попробуйте https://explosion.ai/demos/displacy-ent, чтобы увидеть, какие данные он может извлечь из ваших предложений и какие имена он использует для своих сущностей. В нашем коде мы будем использовать только PERSON и GPE.

Построить домен

Файл домена domain.yml используется диалоговым механизмом Rasa Core машинного обучения. Более подробная информация находится в документации здесь: http://rasa.com/docs/core/domains/

Наша стартовая конфигурация будет выглядеть так:

slots:
  PERSON:
    type: text

intents:
  - greeting
  - how_are_you
  - bye
  - my_name_is

actions:
  - utter_greeting
  - utter_how_i_am
  - utter_bye
  - utter_its_nice_to_meet_you

templates:
  utter_greeting:
    - Hi!
    - Hello, my friend.
  utter_how_i_am:
    - I am doing ok.
    - I am good.
  utter_bye:
    - Bye.
    - Good bye.
  utter_its_nice_to_meet_you:
    - It's nice to meet you, {PERSON}.
    - Nice to meet you, {PERSON}.

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

Части конфигурации:

  • слоты, которые используются для передачи данных вашим действиям. Мы используем имя PERSON, потому что именно так Spacy называет объект.
  • намерения, идентифицированные NLU на основе вашего nlu-data.md
  • действия определяют реакцию вашего бота. Имена простых текстовых ответов начинаются с utter_.
  • шаблоны определяют фактические текстовые ответы, используемые механизмом диалога. Движок выберет один случайный ответ из всех вариантов. Обратите внимание, что utter_its_nice_to_meet_you использует слот PERSON в ответе, чтобы персонализировать его.

Подготовьте данные NLU для намеренного распознавания

Это будут наши данные в nlu-data.md для машинного обучения Rasa NLU:

## intent:greeting
- hey
- hello
- hi
- heya

## intent:how_are_you
- how are you
- how is it going
- how is life

## intent:bye
- bye
- good bye

## intent:my_name_is
- I am [Martin](PERSON)
- I am [Jack](PERSON)
- I'm [Steven](PERSON)
- im [Jack](PERSON)
- My name is [Martin Novak](PERSON)

Отформатировать файл MD довольно просто, если вы посмотрите на него, и вы можете найти дополнительную информацию в официальной документации на http://rasa.com/docs/nlu/master/dataformat/ .

Вы также можете использовать JSON вместо формата уценки, но я считаю MD более лаконичным и с ним проще работать вручную.

Обратите внимание на использование объекта PERSON на основе именования Spacy. Для ner_crf вы можете использовать свои собственные имена, и они будут переданы как объекты в механизм диалога. Spacy фактически работает совершенно независимо, поэтому он распознает все объекты независимо от их присутствия в данных NLU и передает их в Rasa Core.

Подготовьте истории для движка диалога

Теперь заполните файл stories.md приведенным ниже содержимым:

## greeting
* greeting
- utter_greeting

## how are you
* how_are_you
- utter_how_i_am

## good bye
* bye
- utter_bye

## my name is
* my_name_is
- utter_its_nice_to_meet_you

Обратите внимание, что базовый пример действительно очень прост - вы просто обучаете своего бота связывать намерения с конкретными ответами. Это стало бы более сложным, если бы вы хотели, чтобы на одно и то же намерение реагировали по-разному в другом контексте. Типичным примером может быть намерение tell_me_more, которое можно обработать как:

## dialogue about myself
* who_are_you
- utter_introduction
* tell_me_more
- utter_more_personal_information

## dialogue about turtles
* do_you_like_turtles
- utter_i_love_turtles
* tell_me_more
- utter_list_of_favorite_turtles

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

Дополнительную информацию об историях можно найти здесь, в документации Rasa Core: http://rasa.com/docs/core/stories/

Обучите своего бота

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

Первый сценарий - это trainer.py, который вы используете как для NLU, так и для механизма диалога.

Он прост в использовании, поэтому вы должны использовать его прямо сейчас. Просто позвони:

$ python trainer.py train-all

Скрипт будет работать некоторое время в зависимости от скорости вашего компьютера. По завершении вы должны найти новый каталог / models, в котором размещаются результаты машинного обучения.

Играйте со своим ботом

Пришло время насладиться плодами своей тяжелой работы, создав bot.py как:

Чтобы начать, просто запустите это в своей командной строке:

$ python bot.py run

Боту снова требуется некоторое время, чтобы загрузить модели в память. Как только он ответит: «Бот загружен. Введите сообщение и нажмите Enter: », и вы сможете начать общение со своим творением.

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

Создать действие для погоды

Пришло время научить вашего бота определять погоду. Для этого нам нужно будет изменить несколько файлов.

Сначала добавьте их в свой nlu-data.md:

## intent:get_weather
- what's the weather
- what's the weather in [Czech Republic](GPE)
- what is the weather
- what is the weather in [New Zealand](GPE)
- whats the weather

## synonym:Prague
- Czech Republic
- Czechia
- CR
- CZ

## synonym:Auckland
- New Zealand
- NZ
- Zealand

Здесь мы обучаем Rasa NLU распознавать намерение погоды get_weather и получаем данные с меткой GPE из Spacy. Мы также определили синонимы для Прага и Окленд. Это заменит название страны Чешская Республика на название ее столицы Прага перед передачей на обработку. Мы делаем это, потому что Weather API может работать только с городами, но я хочу, чтобы мой бот также знал несколько стран.

Затем мы обновляем stories.md:

## get weather
* get_weather
- action_get_weather

Затем мы обновляем файл domain.yml следующим образом:

slots:
  GPE:
    type: text
intents:
  - get_weather
actions:
  - actions.weather.ActionGetWeather

И, наконец, мы также создаем само действие в actions / weather.py:

Код очень короткий и должен быть достаточно простым для понимания. Обратите внимание, что мы используем только rasa_core.actions.action.Action в качестве аргумента для нашего класса и что мы читаем слот GPE из трекера, используя: трекер .get_slot ('GPE').

Более подробную информацию о действиях вы можете найти в официальной документации: http://rasa.com/docs/core/customactions/

Вот и все. Чтобы научить его работать с погодой, потребовалось совсем немного усилий. Теперь вам нужно только потренировать его и снова поиграть с ним:

$ python trainer.py train-all
$ python bot.py run

Создать полный HTTP-сервер

У вас есть много вариантов взаимодействия с ботом. Чаще всего вам может потребоваться HTTP-сервер, который будет использовать REST и JSON для взаимодействия с вашим клиентским приложением.

Rasa Core поможет вам, и все, что вам нужно сделать, это позвонить:

$ python -m rasa_core.server -d models/dialogue -u models/nlu/default/current -o models/out.log

И ваш сервер запущен. Поздравляю.

Теперь вы можете вызывать свой сервер через его API на порт 5005:

$ curl -XPOST localhost:5005/conversations/default/respond -d '{"query":"hi"}'

Ответ должен выглядеть так:

[{"recipient_id":"default","text":"Hi!"}]

Дополнительную информацию можно найти в документации: http://rasa.com/docs/core/http/

Создать HTTP-сервер без действий

Вы также можете реализовать все действия и ответы только в своем клиенте и использовать Rasa только для предоставления структурированных данных и предлагаемых действий. Это достаточно просто, но ваш domain.yml потребует некоторых изменений. Удалите все шаблоны, добавьте строку с action_factory: remote и замените actions.weather.ActionGetWeather на action_get_weather. В результате файл должен выглядеть так:

action_factory: remote
slots:
  PERSON:
    type: text
  GPE:
    type: text

intents:
  - greeting
  - how_are_you
  - bye
  - my_name_is
  - get_weather

actions:
  - utter_greeting
  - utter_how_i_am
  - utter_bye
  - utter_its_nice_to_meet_you
  - action_get_weather

Теперь вам нужно снова обучить своего бота:

$ python trainer.py train-all

И создайте сервер той же командой, что и раньше:

$ python -m rasa_core.server -d models/dialogue -u models/nlu/default/current -o models/out.log

Теперь ваше приложение вызовет синтаксический анализ конечной точки:

$ curl -XPOST localhost:5005/conversations/default/parse -d '{"query":"whats the weather in Czechia"}' | python -mjson.tool

В результате:

{
    "next_action": "action_get_weather",
    "tracker": {
        "events": null,
        "latest_event_time": 1533754493.632554,
        "latest_message": {
            "entities": [
                {
                    "confidence": null,
                    "end": 28,
                    "entity": "GPE",
                    "extractor": "ner_spacy",
                    "processors": [
                        "ner_synonyms"
                    ],
                    "start": 21,
                    "value": "Prague"
                }
            ],
            "intent": {
                "confidence": 0.5698297728652463,
                "name": "get_weather"
            },
            "intent_ranking": [
                {
                    "confidence": 0.5698297728652463,
                    "name": "get_weather"
                },
                {
                    "confidence": 0.17811828280443054,
                    "name": "greeting"
                },
                {
                    "confidence": 0.14514645701950404,
                    "name": "bye"
                },
                {
                    "confidence": 0.061169221207596984,
                    "name": "how_are_you"
                },
                {
                    "confidence": 0.045736266103222144,
                    "name": "my_name_is"
                }
            ],
            "text": "whats the weather in Czechia"
        },
        "paused": false,
        "sender_id": "default",
        "slots": {
            "GPE": "Prague",
            "PERSON": null
        }
    }
}

Под следующим действием вы можете увидеть, что ожидается action_get_weather, и ваш собственный клиент должен его выполнить.

Вы можете снова найти дополнительную информацию здесь: http://rasa.com/docs/core/http/.

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

об авторе

Мартин Новак
www.meet-martin.com

Мартин - опытный менеджер с богатым опытом работы в ведущих международных командах и основатель библиотеки функционального программирования @ 7urtle / lambda.