テンプレコピペで非エンジニアでもOK!Microsoft Bot Framework × LUISでAI搭載botを作成してみた

このエントリーをはてなブックマークに追加

こんにちは、岡田です!

Bot作成に興味はあるけど、なんだか難しそう……という人のためにMicrosoft Bot Frameworkを使いつつ、手とり足とり作成方法を教えるこのシリーズ。本日は、いよいよAI搭載Botを作成します!

具体的には、LUISというサービスとMicrosoft Bot Frameworkを連携することでAI搭載Botを作っていこうと思います。LUISについては前回の記事でも紹介しているので割愛します。

詳細な作成方法に入る前に、ざっくりと自然言語を理解するときにLUIS側がどんな動きをしているのか復習も兼ねて説明します!

自然言語理解AIとプログラムをつなぐ仕組み

LUISとBotを連携させるときには、前回の記事でご紹介した「インテント(意図)」「エンティティ(意味のある単語)」が非常に重要な役割をはたします。

おさらい
インテント(Intents): その発言が、どういった意図を持っているのかをカテゴリー分けしていく概念
エンティティ(Entities): その発言のなかにある、意味のある単語をカテゴリー分けしていく概念

自然言語理解AIと連携したプログラムでは、判別した「インテント」によって、実行するアクションを分岐させます。そして、そのアクションに必要となる情報を「エンティティ」から呼び出します。
この説明だけだと、何が何やらサッパリですね…。

「Siri」「OK, Google」「Cortana」のようなアシスタントアプリを例にしてみましょう!

これらのアプリに「明日の朝7時に起こして」と話しかけたときの、アシスタントアプリのAIの中の動きを例にしてみます。

ん? 人間の言葉だ!人間の言葉は難しいな……。

そうだ、学習データをもとに、インテントとエンティティに分解してみよう。

この文章は、きっと……『アラームをセットしたい』という インテント(意図) の文章だな!

でも何時にアラームをセットすればいいんだ……?

うーん、エンティティ(意味のある単語) を探してみよう…。 お! きっと「明日」と「7時」という単語だ!

よし、人間が何をしたいかわかったぞ! 「明日」の「7時」に『アラームをセットする』ように、スマホに命令をだそう!

……と、このようにAIくんは自然言語(人間がふつうに使う言葉)を、インテントとエンティティに分解することで初めてスマホにアラームをセットする事ができます。

人間には簡単な事でも、機械には難しかったんですね…。

ちなみに、このインテントとエンティティに分解していく手法は、LUISだけではなく、wit.aiやapi.aiといったAIでも基本的に同じのようです。この機会に覚えておいて損はないと思います。

Botで実際にやってみよう!

さて、さきほど紹介したAIくんの思考回路を、Microsoft Bot Frameworkでも試してみましょう。

※入門・環境構築については記事ボリュームの関係上、割愛させていただきます。入門記事は、下記などを参考にしてみてください。
>> Bot Builder for Node.js (Bot Framework Version 3.0)で’Hello World’ Part-1

今回つかう環境は、下記の通りです。

  • Node.js
  • botbuilder V3 ( Microsoft Bot Framework )

botbuilderとは、Node.jsでMicrosoft Bot Framework用のBotを作成するライブラリです。

botbuilderには、LUISと連携するためにIntentDialogという便利なものが用意されています。

今回は、LUISと連携するBotのテンプレートをご用意しました。

こちらをコピペして改造するだけで、簡単にAI搭載Botを作成できるかのではないかと思います!

少し長いですが、コードと合わせて順に解説していきますね!

Botの準備

この部分では、Botの準備をしています。

var restify = require('restify');
var builder = require('botbuilder');

//=========================================================
// ボットの準備
//=========================================================

// Restifyサーバの設定
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
  console.log('%s listening to %s', server.name, server.url);
});

// ボットの接続先設定
var connector = new builder.ChatConnector({
  // MicrosoftBotFramework公式サイトで取得した、IDとパスワードを入力します
  appId: '******************************',
  appPassword: '******************************'
});

// ボットの仕組みを提供してくれるUniversalBotオブジェクトを作成
var bot = new builder.UniversalBot(connector);

// ***/api/messagesをエンドポイントとして、ボットをサーバで提供する
server.post('/api/messages', connector.listen());

ただ、この部分は特に、理解したり覚えたりする必要はありません。

Botを作成するときには毎回絶対使う部分ですので、おまじないのような物だと思っていただいて大丈夫です!

17〜18行目には、Microsoft Bot Framework公式サイトで取得したIDとパスワードを入力しましょう。

インテントと処理を結びつける「IntentDialog」

さて、ここが重要な部分です!

IntentDialogは、LUISによって判定した「インテント」と「プログラムの処理」を結びつける役割をします。

この部分を作り込むことでSiriやCortanaのような機能が実装できちゃう、ってことですね。

では、早速ソースを見てみましょう!

//=========================================================
// IntentDialogオブジェクトの用意
//=========================================================

// 認識に指定するLUIS APIのURLを指定
var recognizer = new builder.LuisRecognizer('**********************************');

// IntentDialogオブジェクトを作成
var intents = new builder.IntentDialog({
  recognizers: [recognizer]
});


//=========================================================
// 会話の処理
//=========================================================

// 初期ダイアログを、intentDialogとして使用する
bot.dialog('/', intents);

// インテントと処理の結びつけ
intents
    .matches('intentA', function (session, args) {

        // インテントが 'intentA' だったときの処理をここに記述します。

    })
    .matches('intentB', function (session, args) {

        // インテントが 'intentB' だったときの処理をここに記述します。

    })

34行目には、作成したLUIS APIのURLを入れましょう。

さて、実際にインテントと処理の結びつけを行っているのは 49-60行目 です。

‘intentA’にマッチしたときは、その中に処理を書いて……
‘intentB’にマッチしたときは、その中に処理を書いて……

という型に当てはめていくだけです。非常にわかりやすく、シンプルですね!

「エンティティ」を抽出しよう!

IntentDialogでインテントと処理を結びつける事ができました!

これである程度の事ができそうですが、これではまだぜんぜん高度な事はできません。実用には程遠い状態です…。

どういう事でしょうか?

ここで少し、前半のAIくんの思考回路を思い出してください。

この文章は、きっと……『アラームをセットしたい』という インテント(意図) の文章だな!

でも何時にアラームをセットすればいいんだ……?

そう、今はまさにこの状態です……。

インテントによって「どんなアクションすればいいかはわかった」のですが、「アクションをするための具体的な情報」がわからないのです……。

AIくんはどのように、それを理解したんでしたっけ? 続きを見てみましょう!

うーん、エンティティ(意味のある単語) を探してみよう…。 お! きっと「明日」と「7時」という単語だ!

よし、人間が何をしたいかわかったぞ! 「明日」の「7時」に『アラームをセットする』ように、スマホに命令をだそう!

そうでした! 「エンティティ(意味のある単語)」によって理解していましたね!

botbuilderにも、エンティティを抽出するEntityRecognizerというものが用意されています。サンプルコードでは、下記の部分で使われています。

    .matches('intentC', function (session, args) {

        // インテントが 'intentC' だったときの処理をここに記述します。


        // ▼ 応用 ▼

        // argsの中には、LUISの認識結果が入っています。
        console.log(args);

            //  例えば、天気予報Botを想定したLUISの場合 :  「明日の東京の天気は?」を解析すると..

            //  { score: 1,
            //  intent: 'AskWeather',
            //  intents:
            //   [ { intent: 'AskWeather', score: 1, actions: [Object] },
            //     { intent: 'None', score: 0.0144235147 } ],
            //  entities:
            //   [ { entity: '東京',
            //       type: '場所',
            //       startIndex: 3,
            //       endIndex: 4,
            //       score: 0.9854452 },
            //     { entity: '明日',
            //       type: '日にち',
            //       startIndex: 0,
            //       endIndex: 1,
            //       score: 0.963219762 } ] }

            // 上記のような結果が得られます。


        // EntityRecognizerを使うと、指定したエンティティの内容を抽出できます。
        var area = builder.EntityRecognizer.findEntity(args.entities, '場所');

        // 「場所」エンティティが認識できた場合の処理
        if (area) {
            session.send("あなたが天気を知りたい場所は、" + area + "ですね!"); // この場合、「東京」が出力されます。
        }

    })

こちらも、思いのほか簡単ですね!

var 変数名 = builder.EntityRecognizer.findEntity(args.entities, '抽出したいエンティティ名');

で抽出するだけです。

断片的に解説しましたが、LUIS搭載Botの基本はざっと以上になります! これだけです。

じっくりご覧になりたい方は、ぜひGitHubでご覧ください!

実践編: 天気を教えてくれるAI搭載Botの作成

さてここまで、LUIS搭載Botの作り方をご紹介しました。

ただ、テンプレートだけだとすこし具体的なイメージが湧きづらいですよね……。というわけで、今回は実際にサンプルBotも作成しました!
>> okajax’s LUIS Bot Demo

02-webchat%e3%82%b9%e3%82%af%e3%82%b7%e3%83%a7

「今日の東京の天気は?」
「明日の名古屋」
「大阪は明日どう?」

など、天気を尋ねると答えてくれるBotです。

日にちは、「今日」か「明日」の範囲で答えられます。もちろんAIなので、どんどん学習していきますよ。

GitHubにソースコードもご用意していますので、興味ある方はご覧ください!
>> okajax / luis-bot-demo

お天気botの中身の解説

用意している「インテント」と「エンティティ」は、以下のようになっています。

03-luis%e7%ae%a1%e7%90%86%e7%94%bb%e9%9d%a2%e3%82%b9%e3%82%af%e3%82%b7%e3%83%a7

インテント
  • None
  • AskWeather
エンティティ
  • 日にち
  • 場所
  • 天気

天気予報の機能

今回、天気予報の機能の部分は、weather-yahoo-jpというモジュールを使用しました。

「場所」エンティティを抽出し、その情報をもとにYahoo!天気からスクレイピングしています。


Botの処理

Bot内のおおまかな処理の流れは、以下の通りです。

  • AskWeatherインテントと判定されたら、予報の処理開始
  • 場所エンティティがあれば、それをもとにYahoo!天気から情報をスクレイピング
  • 日にちエンティティがあれば、中身が「今日」か「明日」か調べる
  • 「{日にち}の{場所}の天気は、{予報の結果}です!」というテキストを発言させる

割愛している部分もありますが、上記のような形です。

全貌が気になる方は、ぜひソースコードをご覧ください!

おわりに

いかがでしたでしょうか。

Microsoft Bot Frameworkに用意されているIntentDialogとEntityRecognizerを使えば、AI搭載Botがけっこうシンプルに作れそうですね!

この記事で、AI搭載Bot作成の敷居が下がればいいなと思っています!

皆さんも面白いBotを作ったら、ぜひ教えてくださいね。

それではー!