VoiceUI/ConversationalUI 対話モデル設計

## Background
対話モデルの設計方法や例、注意点を、*Dialogflow*を例に紹介します。

### *Dialogflow*とは
会話形式の入力クエリの自然言語処理を行うツール。
ユーザーの発話したクエリを分析し、諸々の評価点をもとに、どのような意図の命令として解釈するのがいいか、学習をもとにスコア付けをおこない、応答を決定します。
*Actions On Google*や*Cortana*などのVUIサービスや、*Facebook Messenger*、*Slack*、*Line*などのConversationalUIサービスと連携できます。

## 対話モデルとは
対話モデルはVoiceUIやConversationalUIなどのユーザーからの自由入力に応える対話システムで利用される、応答モデルのことです。
ユーザーの応答サンプルに対し、どのようなデータを取得し、どの応答をかえすか定義します。

## 対話モデルの構成要素及び設定例
*Dialogflow*では下記の要素から成り立っています。
その他のVUIシステムについては以下の表を参考ください

| Dialogflow | Alexa | Clova |　|
|-----|-----|------|--------|
| Intent| Intent| Intent ||
| Entity| Slot| Slot ||
| Training Phrase | Sample Utterances(サンプル発話) | サンプル発話 ||
| Context | Attribute | Attribute| Alexa,ClovaではFulfillmentで参照/書き込み可。Intentの判定には利用されない |
| Event | || Alexa,ClovaではBuild-in Intentとして定義されているものがある |
| Parameter | インテントスロット| （スロットリスト） ||

### Agent
各種設定、連携設定、及び対話モデルで構成される一つのプロジェクト的なもの。

### Entity
クエリの中で同一モデルの単語とその同義語は、パラメータセットとして、`Entity`で作成します。
多くの場合、`Entity`はパラメータとして`Action`で処理します。
`Entity`も学習により拡張することが可能です。

```
例）商品カテゴリEntity
* book: 本、書籍
* food: 食品、食べ物、食い物
* clothing: 衣類、服、洋服、衣料品
```

*Dialogflow*ではシステム規定の`Entity`も用意していて、日付、場所、数値などがあります。

### Intent
`Intent`とは、同じアクションを行うものをまとめ、必要な情報をシステムに渡すための機能です。
「ゲームに回答する」「商品を検索する」「一覧の次のページに行く」など、クエリから求められている同一の意図のものをまとめます。
`Intent`は適切なサイズで作る必要があり、なんでも同じ`Intent`にしたり、逆に大量の`Intent`を作成してバラバラの`Action`を取るようにするのは、どちらも意図しない動作となる場合があります。
`Intent`はクエリの目的ごとに作成します。

#### Training Phrase
`Intent`を実現するにあたり、ユーザーがどの様に発話するのか、あらかじめ考えられる言い方を学習しておく必要があります。
`Paramater`として`Action`に渡す必要がある場合は、クエリの該当部分を指定します。
学習の量を増やすと、より多くの言い回しをカバーできます。

#### Event
システムによる規定アクション（様々なアプリの起動イベント、*Actions On Google*のListUIからの選択など）は、`Event`を介して、`Agent`にはシステム値のみ送られます。この場合はイベント値でクエリが分析されるので`Training Phrase`は必要ありません。
（※ただし、規定アクション外の自由入力でも`Action`を行いたい場合は両方設定します）

#### Context
文字通り文脈を表し、`Context`というパラメータで、文脈ごとのデータを保持、伝搬することができます。`Context`には`Lifespan`が設定されていて、ユーザーは生存期間内の`Context`すべて持つことになります。明示的に破棄することもできます。

*Dialogflow*では、Intentごとに`InputContext`と`OutputContext`を設定します。 この機能は段階的に選ぶ必要があるときなどに利用され、`InputContext`で必須Contextを持っているクエリに`Intent`が割り当てられるようにし、`OutputContext`では次以降の`Intent`への必須Context受け渡しに使われます。

ただし、`InputContext`を持っていない場合でも、そのIntentが割り当てられる場合もあります。これについては[後述](#%E6%B3%A8%E6%84%8F%E7%82%B9)します。

#### Parameter
クエリから必要な値を取得し、`Action`に渡す機能です。多くの場合は`Training Phrase`に含まれている`Entity`を渡します。
ユーザーのクエリから必須パラメータを取得出来ていない場合、リカバリーする`prompt`を返し、ユーザーに必要分を補ってもらうことも可能です。

#### Response / Action
*Dialogflow*の`Response`を利用すれば、`Fulfillment`を介さずに静的な応答を返すことが可能です。
`Fulfillment`を利用する場合に、どのActionを実行するか、`Action`で定義し、マッピングします。
※ *Actions On Google*ではクライアントライブラリv2で`Action`が廃止され、Intent名でマッピングするようになりました

## 機械学習と候補となるIntentの決定
*Dialogflow*では機械学習の結果に基づき、候補となるIntentのスコア付けを行います。
スコアには下記の要素が影響します。

* Event
* Training Phrase
* Context
* 総出現回数

*Actions On Google*などの連携アプリでは、この結果から最もスコアの高い処理を採用します。

### 注意点
**機械学習の結果次第で、期待IntentではないIntentが選出されることがあります。**
例えば、contextAの「Yes」の総出現回数が多く高く評価されたことにより、期待IntentがcontextBの「Yes」ではなく、contextAの「Yes」が返されることが起こりえます。
その場合は`Priority`を変更し、スコアを上下させることにより、期待Intentが返るよう、調整を行います。
それ以外に、`Context`を増やすことにより、会話の詳細度をあげることでもスコアの変更が期待できます。
※という事例を見た気がしたのですが、Dialogflowの[ブログ](https://blog.dialogflow.com/post/how-contexts-and-followup-intents-work/)には下記のようにあったので、幻かも知れない
> An intent will only be matched if all of the input contexts it specifies are currently active


## 構成例:クイズゲーム
### Intents
```
AnimalQuizAgent
├─Default Welcome Intent
│  ├─Yes-start game
│  └─No-bye
├─Start quiz
├─Category selected
│  ├─Collect answer
│  │  ├─Yes-continue game
│  │  └─No-quit game
│  ├─Give up
│  └─Fallback for quiz
├─Change category
├─Category fallback
├─How to play
├─Default Fallback Intent
└─Bye
```

### Entities

```
QuizCategories
├─cat: cat 猫 ネコ ねこ にゃんこ 猫ちゃん にゃんこちゃん 猫さん にゃんこさん にゃんにゃん
├─dog: dog 犬 イヌ いぬ わんこ わんわん わんちゃん ワンちゃん ワンワン
├─rabbit: rabbit 兎 ウサギ うさぎ うさたん うささん ぴょんぴょん うさちゃん
└─random: random なんでも おまかせ ランダム どれでも 適当
```

### 詳細

| インテント名<br />必須コンテキスト | Training Phrase / Event | Response |
|-----------------|------------------|------------------|
| **Default Welcome Intent**<br />output: DefaultWelcomeIntent-followup | Event: WELCOME | こんにちは。動物クイズです。さまざまな動物のクイズに挑戦できます。ゲームをはじめますか？ |
| **Yes-start game**<br />input: DefaultWelcomeIntent-followup | はい、もちろん、やってみる | どの動物のクイズに挑戦しますか？<br />List UI: 犬、猫、兎、おまかせ |
| **No-bye**<br />input: DefaultWelcomeIntent-followup | いいえ、やらない、いらない | 残念です。今度ぜひ挑戦してください。<EOC> |
| **Start quiz** | 動物クイズする、動物のクイズ初めて、クイズやってみる、クイズ挑戦してみる、はじめる、スタート<br />`※事前の文脈がなくはじめれるものは独立させます` | どの動物のクイズに挑戦しますか？<br />List UI: 犬、猫、兎、おまかせ |
| **Category selected**<br />input: game<br />output: game, category |  | Event: `actions_intent_OPTION`<br />`※ListUI タップイベントの結果を取得`<br /><br /><犬>、<犬> にする、<犬> をやってみる、<犬> のクイズをやってみたい、<犬> のクイズをやりたい、<犬> のクイズだして、<犬> のクイズに挑戦したい | では<<犬>>の問題をはじめます。<br />「次のうち、犬が食べてはいけないものはなんでしょう。<br />1 番、みかん。2 番、りんご。3 番、ぶどう」 |
| **Collect answer**<br />input: game, category<br />output: game, category,   continue | <1番>、<1> | 「3 番、ぶどうが正解です。」次のクイズに進みますか？ |
| **Yes-continue game**<br />input: game, category, continue | はい、もちろん、やってみる |  |
| **No-quit game**<br />input: game, category, continue | いいえ、やらない、いらない、もうおしまい、もういい | また遊びましょうね。 <EOC> |
| **Give up**<br />input: game, category<br />output: game,  category, continue | わからない、ギブアップ、難しすぎる、難しい | 「3 番、ぶどうが正解です。」次のクイズに進みますか？ |
| **Fallback for quiz**<br />input: game, category | みかん、りんご、ぶどう<br />`※ 的確にエラー判定させるよう、頻出エラーをFallbackに学習させることも可能です` | 何番でしょう？ |
| **Change category**<br />input: game, category<br />output: output, ~~category~~<br />`※ category を選び直すので廃棄` | 別の動物もやりたい、他の動物のクイズ頂戴、違う動物のクイズして | どの動物のクイズに挑戦しますか？<br />List UI: 犬、猫、兎、おまかせ |
| **Category fallback**<br />input: game |  | カテゴリから選択してください。 |
| **How to play** | ヘルプ、使い方、やり方、ルール教えて、どうやって遊ぶの | カテゴリを選択してクイズに答えてください。「スタート」でクイズをはじめ、「終了」でアプリを退出します。クイズの途中では「ギブアップ」することも可能です。 |
| **Default Fallback Intent** |  | わかりませんでした。もう一度言ってください。「ヘルプ」で使い方を確認できます。 |
| **Bye** | さようなら、おしまい、バイバイ、終了 | さようなら <EOC> |