自然言語入力処理のMicrosoft LUIS(日本語版)を使ってChatBotサンプルを作ってみる

>**※重要** 2019/04/15 追記
>時が過ぎて、[QnA Maker](https://qnamaker.ai/)が成熟した製品に成長したため、ヘルプデスクなどでよく利用される1問1答シナリオ(FAQシナリオ)ではQnA Makerが最適なソリューションであると考えています。そのQnA Makerについて説明する投稿を以下にしています。
>2018年12月の投稿・・・[MicrosoftのFAQチャットボット技術を検証してみた〈QnA Makerでの実装〉](https://qiita.com/tomohiku/items/c0ced418227136535e17)


>**※重要** 2018/04/14 追記
1年半前にこの投稿を書いた時はLUISはリリースされて間もなく、その後ヘルプデスクの質問対応を代替するチャットボットにも最適化されていくと予測していました。そのため、この投稿で扱っている例ではヘルプデスクに質問するようなシナリオで紹介しました。しかし、2018/4時点ではこのシナリオにはLUISは最適化されておらず、かわりに同じMicrosoft Cognitive Serviceに[QnA Maker](https://qnamaker.ai/)という製品が登場しています。
しかし、QnA Makerもまだまだ未成熟であり、現状でもっとも現実的な答えは以下で投稿している[Microsoft Cognitive Toolkit](https://www.microsoft.com/en-us/cognitive-toolkit/)を利用する方法です。この投稿を参考にしてくださった皆様、誤解を生む投稿をしてしまい申し訳ありませんでした。

>2018年4月の投稿・・・[Microsoftの自然言語分類技術を本気で検証してみた](https://qiita.com/tomohiku/items/63dff5751326a9f59dea)

>この投稿では「ヘルプデスクの質問対応を代替するシナリオ」のチャットボットの現況と実装方法をガイドしています。また「LUISが適さない理由」や「QnA Makerが未熟な点」についても記載しています。


#はじめに
Enterprise界隈でChatBotが少しずつブームになりつつあるなと感じるこの頃。
FacebookのザッカバーグやMicrosoftのサティアなどITプラットフォームの巨人が、
かなりの熱量で「会話による対話」を推しまくるので、
「どうも直観的にピンとこないけど、多くの人にとってはすごくイイのかも！」と思っている人が多いのではないかと感じます。

実は僕もこう思ってました
**ChatBotって、まったくといってピンとこない！**
何がピンってこないかって、何が便利なのかわからない。
専用アプリの方がいいんじゃないの？
なんで会話にする必要があるの？
「人が古来よりもっともナチュラルなコミュニケーション手段としてきたのは会話だ。だから会話はより人にとって便利なUIなんだ」
みたいな論理で説明されてますが、
目的を限定して特化させたアプリの方が便利だろ！
ってのが、僕の初めの印象です。

**とはいえ、使ってないくせにその良さの何がわかるんだ**ってやつです
中身を見ないで批判するなんて、いまいちなエンジニアがいうことだと思ってるので、
とりあえずBotを作って、考えて、中身を見てみようと思います。

#この試行の目的
1．ChatBotの一般的な実装パターンを学び、作り、そのアーキテクチャをまとめ、理解する
2．業務のユースケースを設定し、それに合わせた実装にすることでユーザの利用感により近づけ、より深い気づきを得る
　　ユースケースは真っ先にBot化しやすそうな**「社内ヘルプデスク業務」**に設定
3．ChatBotをデモできるくらいのサンプルアプリを作ってみることで、その特性やメリットデメリットを考える時間を自分に作り、より深い考察を得る
~~4．作ることを楽しむ←正直、これが一番大きいかも。。。~~

※作ったサンプルソースは公開できるようにして、GitHubに置いています。
　リンクは、利用するまでの手順を添えて、最後の方にかいています。

#作ってみたChatBotアプリのイメージ
会話は、自由な会話でやりとりするパターンと、選択肢を選んでやりとりするパターンの2パターンの合わせ技で作ってみました。

●自由な会話でやりとりするパターン
①「こんにちは」と話しかける
![image](https://qiita-image-store.s3.amazonaws.com/0/74428/2553c450-d4c8-96df-6fe9-684e56921919.png)

②「VPNが繋がらない」と打ってみる
詳細ページが案内される。
![image](https://qiita-image-store.s3.amazonaws.com/0/74428/e4de96c6-1c78-6608-e05f-3a0b29a798c6.png)

③「Wifiが壊れた」と打ってみる
![image](https://qiita-image-store.s3.amazonaws.com/0/74428/8ffc2d52-1394-4d27-3f80-0d46413a6fe7.png)


●選択肢を選んでやりとりするパターン
①「こんにちは」と話しかける
![image](https://qiita-image-store.s3.amazonaws.com/0/74428/2553c450-d4c8-96df-6fe9-684e56921919.png)

②「【インフラ】PC・ネットワーク関連」を選ぶ
![image](https://qiita-image-store.s3.amazonaws.com/0/74428/4789bbf6-5d89-e0b8-1b62-02817cc00975.png)

③「無線LAN(Wifi)・有線LAN関連」を選ぶ
![image](https://qiita-image-store.s3.amazonaws.com/0/74428/b39659c9-cb1c-8bd2-6d69-04cfeef63008.png)

④「こんにちは」のあとに「その他」を選んだ場合
![image](https://qiita-image-store.s3.amazonaws.com/0/74428/88e9c93a-d3e1-3ce8-a0ed-73ad42158619.png)



#使うテクノロジー
・Microsoft Cognitive Services ,Language Understanding Intelligent Service (LUIS) 日本語版
・Microsoft Bot Framework
・Skype (コンシューマー向けのやつ。）
・Azure App Services（Freeのプラン）
・Visual Studio 2015
  ・CodeはC#

LUISですが、先週見ると密かに日本語版が使えるようになっていました。
~~Blogとかに記載ないのですが・・・。（日本語に対応したくらいでGlovalのBlogには書かねぇぜってことでしょうか）~~　← 使えるようになってから2週間遅れくらいで、Update通知メールで書いてました。日本語対応については小さい字で、中国語対応については大きな字で書いてありました。時代を感じますね。

#Botって何が新しいんだろう？

**①一気にプライベートゾーンに飛び込める**
サイトやモバイルアプリでは、まだアプリとユーザの距離が遠い。
LineやFacebookメッセ、What's Appのような普段使いしているアプリに入りこむことで、プライベートゾーンに飛び込む。
保険の営業がいままではカフェで商談してたのが、客の家のリビングで商談するようになった感じですね。これはエンジニアには理解しにくい違いかもですが、営業やマーケティングの人にとってはかなり嬉しいことだと思います。

**②UIがより簡単になる**
ちょっとした入力作業や編集作業を、手軽なUIで行える。

**③単純なやりとりと大量に処理できる**
Microsoftのりんなは、シャープのツイッターにインターンをした時、11時から18時で32,882ツイート、1秒平均1.3ツイートしたとのこと。シャープに人がやっていたツイートの数年分らしいです。
この速さは、もはや人と比べられる速度じゃないですね。もし、ChatBotが人と同じくらい賢い回答ができるようになったら、この速さで捌いてくれることは大きなメリットですね。
[この件に関する参考ツイート](https://twitter.com/SHARP_JP/status/718002563254095872/photo/1)

#利用シーン
まず検討されやすいと考えられる利用シーン。

①電話での自動応対機能の置換え
②Help Desk機能の一部置換え
 ヘルプデスクが電話対応している問合せの中でも「数が多く」「回答が簡単」な問合せをボットにさせる
③パーソナライズされた頻度が低い通知
　ヤマト運輸のお届け通知のイメージ。実は、僕はこのアプリが大好きだし、素晴らしすぎると思っている。Lineでお届け日時の確認の通知が届き、その場で**簡単**に配達日時を変更できる。再配達も**簡単**にできる。利用者にとっても助かるし、運輸会社にとってコスト増の元凶となる不在配達数を削減できる。あと付け加えると、Botがまだ世に少ないタイミングででてきたパイオニア的なアプリなのにも関わらずこの便利さは、素晴らしすぎると思う。
④簡易的な入力＆編集
宅配便の再配達依頼をLineの画面で数回のボタンでできたり、会社の勤務管理をLineで簡単に入力できるなど、繰り返しの多い定例作業で、かつ小さな入力や変更では、効率の向上が大きい。

#Botの実装アーキテクチャ
- Botの機能分解図
- 
![image](https://qiita-image-store.s3.amazonaws.com/0/74428/03e87901-7bee-e3ed-9839-a7d6dde37e38.png)

- Bot Frameworkの各機能の役割

１. Bot Connector
Chat Botのメイン処理をするWebAPIと、会話アプリ（SkypeやFacebookメッセ、Slack,What's APPなどを紐づけてくれる機能）。同じMicrosoft製品のSkypeは、非常に簡単に連携できる。それ以外は、手順書を整備してくれているので、それどおり進めると連携させることができる。
欠点は、LINEにまだ対応していないこと。LINEは現状、Bot Connectorを使わずにLINEとWebAPIを紐づける必要がある。

BotConnectorは以下のページでMyBotを作成することで、使えるようになる
[Microsoft Bot Frameworkのページ](https://dev.botframework.com/bots)

２. Bot Framework の Visual Studio Template
Bot Frameworkで開発するためのVisual StudioのTemplateを、追加して利用する。
このTemplateは、中身はASP.NET WebAPI テンプレートの改造版のようなイメージ。
Bot ConnectorやBot State、LUISなどが使い始めやすくしてある。

３. Bot State
ASP.NET系のアプリで使うセッションのような機能。ユーザデータをWebサーバ側で保持する機能。
普通のSessionとは別物のBot Stateという機能として提供されている。

```sample.cs
//Stateの初期化
StateClient stateClient = activity.GetStateClient();

//UserDataの値取り出し
BotData userData = await stateClient.BotState.GetUserDataAsync(activity.ChannelId, activity.From.Id);
bool SentGreeting = userData.GetProperty<bool>("Greeting");

//UserDataの値セット
userData.SetProperty<boot>("Greeting", true);
await stateClient.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData);

```
４. LUIS（Language Understanding Intelligent Service)

この機能こそが、会話のプラットフォームの肝になるもので、機会学習の進歩によりできるようになった新技術。「自然言語を機械が理解する」というミラクルを実現する部分になります。
この機能の役割をざっくりいうと、自由な文章を渡すと呼び出すべき関数名と引数を教えてくれる機能です。
例えば、「今日の天気は何ですか？」という自由文を渡すと、「Weather」という関数と紐づく文言と「2016/10/08」(今日)という引数となる文言を返してくれます。
これを受け取ると、Weatherの関数の中で、「2016/10/08」の天気を調べ、「今日の天気は晴れです。」という文章を作って、ユーザ側に返却すればよいということになります。
関数と紐づく文言が「Intent（意図）」、引数になる部分が「Entity」と呼ばれます。なんでこんなわかりにくい言い方するんですかね？IntentとEntityってすごく理解しにくい名前な気がするのは僕だけでしょうか。最初見たとき、なかなか理解できませんでした。

LUISは、単純にIF文の集合体ではなく、機械学習で文章の近さを確率として考慮してくれます。
例えば、「今日の天気は何ですか？」「今日の天気は何でしょう？」「今日の天気は何？」など、同じ意味なのに、違う文言いわゆる言葉のゆらぎを、「95％、天気の話だね」とか「80％、天気の話だね」とか率を添えて、いい感じに教えてくれます。なのでアプリ側としては、80％以上だったら合致していると決めて、処理していきます。
つまり、ちょっとくらい言い回しが変わっても、ちゃんとWeatherというIntentを返してくれます。
賢いですね～。人の脳では当たり前にできることだから、Non ITの人からしたら、その凄さはわかってくれないかもですが。。。。

ただ、人材と一緒で賢い人は簡単には用意できず、それなりの苦労が必要になります。
最初は、LUISは赤ちゃんで何も知りません。なので、スパルタ教育でもなんでもいいのですが、育てあげる必要があります。
具体的な学習させ方を下のLUIS設定画面で説明します。
この画面は「VPNが繋がらない」と文言に、「NotConnect」というIntentが紐づけられており、「vpn」の文言に「デバイス」というEntityが紐づけられていることを示しています。

![image](https://qiita-image-store.s3.amazonaws.com/0/74428/a68f07ba-1930-a0f0-2351-8ef29bbcb819.png)

この検索ボックスっぽい入力フィールドにひたすら例文を打ち込み、IntentとEntityの設定をしていくというのが教育方法になります。
※もちろんCSVのようなフォーマットで一括登録は可能です。
つまり「例文」「それに対応するIntent」「Entityとするワード」「対応づけるEntity」を、登録しまくらないと精度が上がらないということです。
めんどくさいですね～。

日本語は未対応ですが、英語ではコルタナやBingで培われたプリセットがたくさん提供されています。つまり他所で育ててくれたLUISを使えます。しかし、どこまでそれが有用かは微妙ですね、天気の話とか、アラームセットとか、あまり自分が作るChat Botに入れる必要ないように感じるので。
各業界の業務に対応したプリセットができてくるようになるとすごく有難いのですが・・・。まだ少し先な気がします。

５．Bot Builder SDK
１～４で述べた各個別機能をまとめたものの総称。

６．Bot Directory
作ったボットを公開するストアみたいなもの。購入機能はないみたいですが。


**●自由文と既定文を分類しているところの処理**

図の②で分類を行っていますが、ここは非常にシンプルな方法で行います。
ソースを見てみます。

```sample.cs
//activity.Textがユーザから送られてきた文章
if (activity.Text == "Hello" || activity.Text == "こんにちは")
{ 
/////処理
}
  else if (activity.Text == "電話で対応してほしい")
{
/////処理
}else{
  //既定文にヒットしなかったらLUISを呼ぶ
  await LUIS(activity);
}
```

**●LUISから返ってきたIntent＆EntityとC#の関数との紐づけ**

以下のコードのようにIntentをごとに関数を呼び分けています。Entityはresultの中から取り出します。

```sample.cs
[LuisIntent("")]
public async Task None(IDialogContext context, LuisResult result)
{
  string message = $"ごめんなさい。勉強不足でわかりませんでした。");
  await context.PostAsync(message);
  context.Wait(MessageReceived);
}

[LuisIntent("Broken")]
[LuisIntent("NotConnect")]
public async Task Broken(IDialogContext context, LuisResult result)
{
  string message;
  if (result.Entities.Count == 0)
  {
   message = ($"何のトラブルですか？もう一度、言い換えて教えてもらえませんか？");
  } else { 
   message = ($"" + result.Entities[0].Entity + "のトラブルですね。\n\n");
  }
  await context.PostAsync(message);
  context.Wait(MessageReceived);
}
```

# Chat Botの会話設計について
今回、ユーザに自由文で発言させるパターンと、ボタンを選択してもらって発言するパターンを考えましたが、後者の方だけでも多くの利用用途があるように感じています。
また自由文を使うにしても、ある程度ボタンの選択肢で内容を絞ってから自由文を使わせるようにナビゲートした方が発言を限定することができ、LUISで育てる手間が大きく減ります。

こういったことを考慮しながら会話を設計していくかと思いますが、この設計手法がインターネットをいろいろ探しても見つからず、仕方なく自作で考えました。
たぶん、まだよい設計手法とか設計フレームワークとかが世の中に出てきてないんだろうなと思います。
私が設計をするために使ったツールは、マインドマップです。
以下はマインドマップで書いた絵になります

![image](https://qiita-image-store.s3.amazonaws.com/0/74428/9064d410-3ccb-bb49-2c8b-3d15d81f0f76.png)

いろいろ試したのですが、マインドマップが一番しっくりきました。
こういうツリー構造を書いて、会話を設計し、関係者と議論していくのが良いかと考えてます。
そして、このツリーをXMLなどにエクスポートして、アプリで読み込ませてそのまま実装するとかは比較的簡単にできそうなので、近々そういう製品もでてくるだろうな予想されます。


#サンプルソース
作ったアプリはGitHubに置いています。

https://github.com/tomohiku/LUISApp

●動かすために必要な設定
１．ASP.NETアプリを公開するためのAzure App Serviceを用意 
　※インターネット公開されればどんなWebサーバでもOK
　※Azureサブスクリプションがあれば、Visual Studioで自動作成できる
２．LUISでApplicationを作成。IDとKeyを取得する。
　※Azureサブスクリプションが必要。AzureポータルからLUISサービスを使えるようにする。
３．Microsoft Bot FrameworkのサイトでMy Botを作成。AppIDとPasswordを取得する。 
　※Skypeとの連携は勝手にやってくれる
４．GitHubから落としたアプリに次の設定をする
　①Web.configにMy BotのAppIDとPasswordを設定
　②HelpBot.csにLUISのIDとKeyを設定
５．Skypeの連絡先に作ったBotをAdd。Microsoft Bot FrameworkのMy Botのサイトで作ったBotをAddするためのリンクがでてくる。


# さいごに
10月6日に行われたGoogleの新製品発表で、Google Homeが発表されました。
それは、音声で話しかけるとAIが音声で回答してくれる画面のないデバイスです。例えば電気を消してとかも頼めるし、天気を教えてとも聞ける。
これは精度が高まっていくと、いわゆるお手伝いさんや秘書のような人と同じような仕事を機械やってくれるということであると思います。

これを見ていて、Chat Botって音声会話に向かうための中間的な技術なんだなーって感じました。音声でなんでもできるようになったら、みんなスマフォから電話をするかのように、AIにいろいろ指示を出すようになるのかな。

「もしもし、あのさ、今日の19時からの8チャンネルの世にも奇妙な物語を録画しておいてくれる？」

とか家族に頼むように、AIに頼むような時代がもう近くにあるんだなーと。
そんな時代が来るのはすごく楽しみだし、きっと今勉強しているChatBotの知識はその時に、もっと役に立つんだろうなーと、そのGoogleの発表会を見ながら思いました。