LUISとQnaMaker、それを活用するBotServiceの概要とアクティブラーニングまで

# はじめに
この記事は[Microsoft Azure Advent Calendar 2017](https://qiita.com/advent-calendar/2017/azure) の6日目の記事です。

# 注意点（17/12/25追記）
記事を書いた直後にいろいろとGAになり、すでに遺物になっている可能性があります。。
下記などに詳しく載っています！
[MS Cogbot Advent Calendar 2017](https://qiita.com/advent-calendar/2017/cogbot)

# この記事は
Azureの自然言語解釈系サービスの2つと、それを利用可能とするPaaS機能について簡単な説明と使ってみた所感を記します。

17/12/6時点の情報で記載します。

- 自然言語解釈系
    - [LUIS](https://www.luis.ai/)
    - [QnaMaker](https://qnamaker.ai/) 
- PaaS
    - [Bot Service](https://docs.microsoft.com/ja-jp/bot-framework/azure-bot-service-overview)

正直日本語対応を謳ってますが、Preview的で、Unicode対応＋分かち書きちょっとできるくらいの感触なので、今後に期待というところです。

[昨日のAdvent Calendarの記事](https://qiita.com/bigplants/items/676d3612d0346dc1ced6)もQnaMakerとBotServiceから一歩進んだ記事ですので、ぜひ参考に。

## LUIS

Language Understanding Intelligent Serviceの略ということで、イメージは[公式](https://www.luis.ai/)を見るとわかります。

![スクリーンショット 2017-12-07 22.34.08.png](https://qiita-image-store.s3.amazonaws.com/0/106874/0e0fd066-e539-11ba-d004-2c692c350349.png)

utterance(文章)を入力とし、intent(文意)とentity(要素)をパースしてJSON形式で返すAPIとなっています。
教師あり学習なので数十の例文が必要です。下記作業はちょっと手がかかりますので、チャットボットに必須のユーザの問いかけ実データを使って再訓練なども手間がかかりそうです。

必要な作業は下記。チュートリアルレベルはドキュメントに書いてあります。

- intent(文意)、entity(要素)を定義する
    - intentは３０個まで定義できますが、多いと精度が下がります。ボットの目的を絞って、必要最小限にしましょう。
    - 事前定義済み要素(prebuilt entity)もありますが（時間など）日本語はあまり対応していないと思った方が良いでしょう
- intentごとに例文を入力し、その正解のentityを指定する
    - 例文を入れると分かち書きされるので、entityをクリックする形です
    - 例文入力後
![スクリーンショット 2017-12-07 22.59.19.png](https://qiita-image-store.s3.amazonaws.com/0/106874/6717e050-b87e-5464-289d-724ccfc798eb.png)
    - entity指定後
![スクリーンショット 2017-12-07 23.01.57.png](https://qiita-image-store.s3.amazonaws.com/0/106874/f9b83705-0a61-6685-847c-343e68b1be49.png)
- 学習させ、テスト用インターフェースで試す
    - LINEのようなインターフェースがあります
- APIを公開する
    - キー取得など。指示に従っていけば特に迷わない認識です。

intentがある程度違うものであり、例文バリエーションを整えれば。。。
使用するデータをエンジンの改善に使うという規約と記憶してるので、日本語の精度を上げるためにどんどん使って欲しい、という印象を受けました。
しかし登録したentityのリストを取得する手法、entityを直接登録する手法がよくわからなくて辛い印象があリました（ご存知でしたらフォローください）

## QnA Maker

[公式](https://qnamaker.ai/) 

問いかけの文章を投げると、それに近い答えをスコアとともに返却してくれるAPIです。
こちらも教師あり学習で、QとAのペアを学習させる必要があります。
TSVで投入するのがベタですが、QAサイトのURLやWORD形式でも読めるそうです。
ただしフォーマット制約が厳しいのであまり期待しない方が良いです。
QAボットはかける手間の割に使えるものができるので、手始めにはベストです

トレーニングするインターフェースは対話的で、間違ったQAがあったら左の3択から修正しよう、なければあとで正しいAnswerをて入力する、というところが使いやすいです。
同じAnswerを期待するQuestionを右側にどんどん追加していけるのもグッドかと。

![スクリーンショット 2017-12-07 23.27.17.png](https://qiita-image-store.s3.amazonaws.com/0/106874/1f389909-fddb-c42b-ac78-1c5d93ec832d.png)

## Bot Service（ボットサービス）

[Bot Service](https://docs.microsoft.com/ja-jp/bot-framework/azure-bot-service-overview)

App Serviceで「ボットサービス」と検索すると出てきます（Bot serviceだと当たらない？前は当たった気がするんだが）。

![スクリーンショット 2017-12-07 23.49.05.png](https://qiita-image-store.s3.amazonaws.com/0/106874/441d0592-e967-211d-ccdb-523b45defae0.png)
![スクリーンショット 2017-12-07 23.50.25.png](https://qiita-image-store.s3.amazonaws.com/0/106874/bea9abb3-47ee-9fc7-0723-79fd66addffc.png)

上記2つのサービスはテンプレートがあるので速攻です。
途中でQnAMakerのナレッジベース名をプルダウンで選択すれば連携終了。
デプロイされると、ブラウザ上で編集できる形でサンプルコードが出来上がります。
VisualStudioと連携してやるべきでしょうが、ちょっとの修正ならブラウザ上でも。

![スクリーンショット 2017-12-07 23.54.56.png](https://qiita-image-store.s3.amazonaws.com/0/106874/d6a35fc1-2546-f302-f276-ecd2587d274b.png)

Slack、SkypeやFacebookMessengerなども連携先のAPI情報を貼り付ければ連携OK！という仕組みです。

![スクリーンショット 2017-12-07 23.42.47.png](https://qiita-image-store.s3.amazonaws.com/0/106874/1d7817f3-2aed-a028-5c43-58beb471f134.png)
![スクリーンショット 2017-12-07 23.43.18.png](https://qiita-image-store.s3.amazonaws.com/0/106874/32455e72-f300-96fb-d079-de79b475c521.png)

### 少し修正

[アクティブラーニング](https://qnamaker.ai/Documentation/ActiveLearning)、すなわちスコアがあまり高くないAnswerがいくつか出てきたとき、候補を提示してユーザに選んでもらう、というのをやってみました。

しかし何度ドキュメントを読んでもうまくいかず。。。
結果BotServiceが指定するライブラリのバージョンをあげたら解決しました。

修正前

```json:project.json
{
  "frameworks": {
    "net46": {
      "dependencies": {
        "Microsoft.Bot.Builder.Azure": "3.2.1",
        "Microsoft.Bot.Builder.CognitiveServices": "1.0.3"
      }
    }
  }
}
```

修正後

```json:project.json
{
  "frameworks": {
    "net46": {
      "dependencies": {
        "Microsoft.Bot.Builder.Azure": "3.2.1",
        "Microsoft.Bot.Builder.CognitiveServices": "1.1.0"
      }
    }
  }
}
```

これでQnaMakerDialogのクラスを一つ作り、run.csxから呼べばOKです。
TODO込みのコードで残念なのは許してください。

```csharp:BasicQnAMakerDialog.csx
using System;
using System.Threading.Tasks;

using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.CognitiveServices.QnAMaker;

// For more information about this template visit http://aka.ms/azurebots-csharp-qnamaker
[Serializable]
public class BasicQnAMakerDialog : QnAMakerDialog
{
    // Go to https://qnamaker.ai and feed data, train & publish your QnA Knowledgebase.
 	public BasicQnAMakerDialog() : base(new QnAMakerService(new QnAMakerAttribute(Utils.GetAppSetting("QnASubscriptionKey"), Utils.GetAppSetting("QnAKnowledgebaseId"), "良い回答が見つかりませんでした。別の質問に変えてもらえますか？",0.5)))
//   public BasicQnAMakerDialog() : base(new QnAMakerService(new QnAMakerAttribute(Utils.GetAppSetting("QnASubscriptionKey"), Utils.GetAppSetting("QnAKnowledgebaseId"))))
    {
    }
}

// ここから追加。TODO：APIキーとナレッジキーがべた書きになってしまったので良いやり方が知りたい。
[Serializable]
[QnAMaker("<QnAMakerのAPIキー>", "<ナレッジキー>", "わかりませんので別の質問にかえて", 0.10, 4)]
public class QnADialogWithActiveLearning : QnAMakerDialog
{
// TODO：こんな感じでかけそうなのにうまく動かなかった
//    	public QnADialogWithActiveLearning() : base(new QnAMakerService(new QnAMakerAttribute(Utils.GetAppSetting("QnASubscriptionKey"), Utils.GetAppSetting("QnAKnowledgebaseId"), "良い回答が見つかりませんでした。別の質問に変えてもらえますか？",0.3,3)))
    protected override async Task QnAFeedbackStepAsync(IDialogContext context, QnAMakerResults qnaMakerResults)
    {
        // responding with the top answer when score is above some threshold
        if (qnaMakerResults.Answers.Count > 0 && qnaMakerResults.Answers.FirstOrDefault().Score > 0.75)
        {
            await context.PostAsync(qnaMakerResults.Answers.FirstOrDefault().Answer);
        }
        else
        {
            await base.QnAFeedbackStepAsync(context, qnaMakerResults);
        }
    }

}
```

これで自信がある回答はシングルアンサー、自信がないとマルチアンサーを返すようになります。

![スクリーンショット 2017-12-08 0.09.35.png](https://qiita-image-store.s3.amazonaws.com/0/106874/4c1b19fd-1dbc-7e27-8ecd-d827fb0f6622.png)

まだ実際ユーザーが何を選択したかどうかがQnAMakerに返る訳ではなさそうなので、実際のアクティブラーニングにはもう一手間必要そうです。
どこかに吐いといて、バッチ学習でも良いと思います。

## 終わりに

簡単に紹介しました。今後に期待な部分も多いですし、英語のドキュメントもやや不親切ですが、
これくらいのアプリが1日あれば十分できてしまい、かつ料金もほぼ無料ということで
うまく付き合っていきたいところです。
wikiなどで情報共有しているサイトもあるかもしれませんが、意外とボット作っちゃった方がはやいかも？

以上です。