Самое первое, для чего был создан Starbot, мало чем отличалось от бота для пинг-понга. Его единственная обязанность заключалась в том, чтобы обнаруживать, когда кто-то упоминает имя моего кузена в чате, и отвечать на это словом «сука». Кто-то говорил «джастин», бот отвечал «сука». Довольно отказоустойчивый алгоритм, и я считал свою работу над этой функцией выполненной.

Название Starbot в то время не было чем-то особенным. Это было мое старое имя пользователя Starlight, но с bot в конце. По сути, его ответственность заключалась в том, чтобы заменять меня всякий раз, когда меня не было рядом, чтобы подшутить над этой группой друзей на этом конкретном сервере. Это был я, но как бот. Но так как я знал, что было бы скучно, если бы он давал ответы один на один для заданных фраз (называть Джастина стервой быстро надоело), ​​я решил дать Старботу целую кучу сообщений, которые он мог бы отправлять, вызывая всякий раз, когда кто-то упомянул его в чате. Это было началом печально известных звонков at-Starbot, которые мы знаем сегодня.

Шло время, несмотря на то, что Старбот мог произнести более сотни рукописных фраз, чтобы дерзить, принижать, высмеивать или клеветать на моих друзей в мое отсутствие, я по-прежнему находил решение ограниченным. Это стало слишком предсказуемо. Несмотря на то, что какие бы конкретные фразы ни отвечал Старбот, они были случайными, в течение нескольких месяцев в конце концов ни один из ответов не был новым, и мы снова застревали, слушая сломанный трек. Мне пришлось бы бесконечно добавлять новые фразы, наполненные отсылками и шутками, которые устаревали бы, как только наступал очередной сезон. Кроме того, это было слишком личное. Все ответы Starbot были полностью написаны мной (за исключением нескольких копипастов, которые я позаимствовал из Reddit), и я знал, что было бы лучше, если бы я каким-то образом использовал сообщества Starbot для создания всегда актуальных, всегда специфичных для сервера, всегда развивающихся способы издеваться над моими друзьями. Логично предположить, что следующим шагом стала генерация естественного языка с помощью машинного обучения.

Я просмотрел Интернет в поисках примеров машинного обучения, используемого в контексте онлайн-чатов. Лучшим примером, который я смог найти, было сообщество Subreddit Simulator на Reddit, которое использовало цепи Маркова для создания сообщений на основе нескольких известных сабреддитов. Немного изучив цепи Маркова, я решил попробовать реализовать их в Starbot и, следуя шаблону Subreddit Simulator, начал разрабатывать систему, которая моделировала бы язык, используемый на разных серверах, к которым Starbot имел доступ.

Я пропущу здесь обсуждение первой реализации Markov Language Engine, чтобы обсудить, как работает текущая реализация. Во-первых, общая архитектура Starbot разделена на три категории: передняя (регистрирует и прослушивает JDA и Discord), средняя (обрабатывает все после прослушивания событий) и задняя (обрабатывает операции, расположенные близко к диску, такие как данные и собственность). загрузка). Markov Engine расположен в средней части вместе с Audio Engine, который обрабатывает воспроизведение музыки, и Chat Engine, который обрабатывает все функции, связанные с чатом, включая обработку команд и логику сообщений. Таким образом, Markov Engine не связан напрямую с внешним интерфейсом, но используется Chat Engine специально для команд и потока сообщений, связанных с функциями, связанными с Markov.

Внутренности марковской функциональности разделены на три части. Сам Markov Engine, который обрабатывает интерфейс с Chat Engine и управляет созданием и удалением определенных языковых моделей с конкретными гильдиями, а также сбором сообщений гильдии для формирования модели. Класс Markov Language Model обрабатывает создание, импорт и экспорт модели. Класс генератора предложений использует данные модели для формирования серии строк, разделенных пробелами, известных людям как «предложения». Эти три объединенных процесса всей системы можно резюмировать следующим образом:

  1. Пользователь (я) инициирует создание марковской модели конкретной гильдии с помощью команды !markov init (которая скрыта от публичного просмотра и может использоваться только мной, чтобы предотвратить перегрузку Starbot, когда он находится на серверах Oracle с бесплатным уровнем)
  2. MarkovLanguageEngine получает запрос на создание модели и собирает каждое сообщение на каждом канале, который Starbot может прочитать на этом сервере.
  3. Затем сообщения используются для создания экземпляра MarkovLanguageModel, специфичного для этого сервера.
  4. Модель сохраняется на сервере Starbot для загрузки во время выполнения в будущем*
  5. В MarkovLanguageEngine на основе этой модели создается SentenceGenerator.
  6. В следующий раз, когда кто-то упомянет Starbot, будет найден генератор предложений, специфичный для этой гильдии, и предложение, основанное на модели их гильдии, будет сгенерировано и отправлено на канал.

*Данные модели представляют собой карту JSON сопоставлений слов со словами, которые следуют за этим словом по частоте. Карта‹String‹String, Long››. Из соображений конфиденциальности пользователей из этих данных нельзя реконструировать исходное сообщение, а также определить автора исходного сообщения, если только пользователь уже не имеет доступа к серверу, на котором была создана модель.

В первый раз, когда эта система была реализована, у меня ушло около недели на исследования и на написание вместе взятых. Во второй раз у меня ушло около шести часов и один из двух свободных столиков в социально удаленном Starbucks. Текущая реализация все еще далека от совершенства. Я могу указать около дюжины мест, где система дает сбой, был реализован хакерский обходной путь или что-то заметно сломано, что, вероятно, никогда не будет исправлено. Но то, что он действительно достиг моей первоначальной цели: создать бота, который мог бы имитировать модели и идеи людей в моих сообществах.

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

Следующими шагами в развитии естественного языка Starbot (или, как я начал называть его, Инициативой Starbot Natural Language Initiative), вероятно, будет изучение более сложных методов анализа естественного языка на стороне моделирования. Система токенизатора, используемая в настоящее время для идентификации слов в предложении, буквально представляет собой регулярное выражение с разделением на основе пробелов, потому что исходная система токенизатора, которую я использовал в OpenNLP, плохо работала с эмодзи. Как только это будет выяснено, Старбот может начать искать дополнительную информацию о словах, которые он видит. Например, если Старбот знает, что предыдущее слово было прилагательным («абсолютный»), тогда он может подумать, что существительное будет хорошим кандидатом для последующего («болван»). Другие вещи, такие как завершение его открытых кавычек, круглых скобок и вариантов форматирования, будут сопровождаться анализом, выходящим за рамки только последнего слова, добавленного в предложение. Если бы мне пришлось смоделировать это прямо сейчас, диаграмма машинного обучения для этого выглядела бы так:

последнее слово предложения -› [Марков] -› следующее слово предложения

И улучшенная версия будет:

все предложение на данный момент -› [Марков] -› следующее слово предложения

Возможно, в будущем вывод изменится с «следующее слово» на «предложение для остальной части предложения до завершения» или что-то в этом роде, но общая идея есть. Некоторый ввод. Какой-то процесс. Какой-то вывод. Возвращайтесь снова, пока у нас не будет предложения, которое заканчивается часовым, заканчивающимся предложением, которое в системе обозначает конец сообщения.

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

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