Dialogflowで日本語版ELIZA風チャットボットをノーコードで作る

#初めに
この記事は**Dialogflowでチャットボット**を作成する練習として**ELIZAもどき**が作れないか試してみた記録です。
チャットボットが好きなだけの非プログラマがいい加減な知識で書いていることを予めご了承ください。
#ELIZAとは
**ELIZA**（イライザ）は人口無能の起源と言われるチャットボットプログラムです。
中でも**セラピスト**としてのキャラクター付けをされたDOCTORスクリプトが有名です。
単純な**パターンマッチ技法**（特定のキーワードが入力文にあればそれに対応した応答文を返す）で作られてはいますが、相手の使った言葉を応答文に取り入れたり、話が途切れないよう質問を返すような応答をしたり、ELIZA自体への質問は躱すような反応をするなどの会話らしい会話を続けるための工夫が凝らされており、当時はプログラムではなく人間が応答していると信じた人も多かったそうです。
#ELIZAの仕組み
ELIZAの応答を作る中核的な仕組みは次の三つで出来ています。

* key　キー。マッチする**キーワードと優先度**（ランク）を設定
* decomp　分解。入力文中の**キーワード前後の要素を抜き出す**。
* reasmb　再構成。キーに対応する応答文に、必要に応じて抜き出した**要素をはめ込み応答文を完成**させる。

他にも、応答文をストックしておいて会話が続かないときに思い出したようにその話をするという素晴らしい仕組みもあるのですが（reasm_for_memory）、ノーコードでは厳しそうだったので割愛。
#Dialogflowについて
DialogflowはGoogleが提供している、チャットボットやAIアシスタントを作るためのサービスです。面倒な言語処理部分を良い感じにやってくれます。
["**Dialogflow ES**"](https://dialogflow.cloud.google.com/?hl=ja "Dialogflow ES")というスタンダード版なら基本無料で利用できます。

Dialogflowの始め方～使い方の説明はこちらの記事がわかりやすいかと思います。
[『**Googleの無料サービス「Dialogflow」を使ってノーコードでチャットボットを作ってみた**』]
(https://ledge.ai/dialogflow-try/ "Googleの無料サービス「Dialogflow」を使ってノーコードでチャットボットを作ってみた")

一つ注意点を書いておきますと、左上のロゴの横の地域選択をTokyo,Japanではなく**US**にしておかないと、LINEや他サービスに接続するためのメニュー"Integrations"が表示されなくて困ることになります。というか私はなりました。
![スクリーンショット 2021-02-28 180055.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/7eb82952-8025-eb5e-9026-9e22dd4b447e.png)
#Dialogflowの基本
Dialogflowでは基本的に

* **Intents**（インテント・意図）
* **Entities**（エンティティ・実体）
* **Contexts**（コンテキスト・文脈）

の三つを使って会話を作っていきます。
ELIZAにはコンテキストに類する機能は無いので、前二つの機能である程度再現できそうです。
##インテント
こう話しかけられたらこう返事をする、という会話の根幹部分を設定する部分です。
初期状態では

* **Default Fallback Intent**（デフォルトフォールバックインテント）
* **Default Welcome Intent**（デフォルトウェルカムインテント）

の二つのインテントが存在します。
「**デフォルトフォールバックインテント**」は他に該当するインテントが無かった時に呼び出されるインテントなので、**無いとまずい**です。
「**デフォルトウェルカムインテント**」は音声アシスタントなどで使う時に初めに呼び出されるインテントらしいので、今回のようなチャットボットの場合は無くても多分大丈夫。
ですがせっかくあるので「こんにちは」等**会話の初めになりそうな挨拶**が入力された時用のインテントとして使っていこうと思います。

"**Training phrases**"に入力例を設定し、"**Responses**"に応答文を設定します。
例えば"**Training phrases**"に

>「こんにちは」「こんにちわ」「今日は」「やあ！」「ごきげんよう」

など、想定される入力例を複数設定することで、言い回しの違いや表記ゆれにも対応できます。

応答文は**Shift+Enterキーで改行**できます。

"**Responses**"は"**Text Responses**"というグループに各30個まで応答文を登録でき、その中からランダムで選んで応答します。
"**Text Responses**"グループ自体を複数作ることが出来ますが、応答フレーズが30個以上になるわけではなく、各グループから一つずつランダムで応答文を選んで、その全てを一度の応答文として出力します。
![イラスト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/f9147012-bab8-5293-37fb-f009d136b5e1.png)
##エンティティ
反応したい語句や取得したい語句を登録する部分です。
本来、予約や購入といったシーンで予約日時や商品名などの**必要な情報を入力文から取得**するといった用途が想定されている機能のようですが、**言葉の揺らぎを吸収**したり、**入力語句を言い換える**のにも使えます。

先ほどのインテントでの例のように、各インテントのトレーニングフレーズでマッチさせたい語句を登録しても良いのですが、エンティティで設定したほうが認識されやすくなりますし、複数のインテントから使いまわせて便利です。
何より、エンティティに設定した語句が入力文中にあった場合、それを**取得して応答文の中で使うことが出来る**ので、ELIZA風チャットボットを作るには重要な機能です。
![イラスト1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/9496f39e-d550-e971-540d-bcd02925dc08.png)
##コンテキスト
インテント同士の前後関係を設定する機能です。**会話のルート・フラグ管理**。
**アウトプットコンテキスト**で「これ以降この話題に入る」（最大5ターン ・インテント毎に更新可能）というのをフラグ立てし、**インプットコンテキスト**で「このインテントはどのフラグを受け継いでいるか」を設定します。
インテントに排他的な親子関係（一本道ルート）を設定する**フォローアップインテント**という機能もあります。
今回は使わないのでこれ以上の説明は割愛。
#インテントとエンティティを使ってELIZAっぽい応答を作ってみる
ELIZAの応答の一例として、入力文中に「母・父・娘・息子」等の家族を表す単語があった場合、

1. 「あなたのご家族についてもう少しお聞かせください」
1. 「あなたの（取得した入力語句）について考えるとき、他に何が思い浮かびますか？」

と返すものがあります。
これをDialogflowで再現していきます。
##エンティティで設定した語句をインテントのキーワードマッチに使う
まず、**エンティティー**でマッチさせたい語句を登録します。
![イラスト3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/41f73f22-ef40-3b3b-4d2b-657cc5f9f63b.png)
次に、家族についての会話をする**インテント**を作成します。
![イラスト4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/998aad5c-0857-1e5e-0332-689aa2ab72f3.png)
画像のようにトレーニングフレーズを入力していくと、語句が自動でハイライトされる場合があります。
既存のエンティティとして認識されたということです。
画像の例の場合、「父・母」は先ほど設定した"familymember"として認識されているので問題ありませんが、特に認識して欲しいわけではない「仲」も登録した覚えのないエンティテイとして認識されています。
これはDialogflowが初めから持っている**システム・エンティティ**で、日時・場所・数字などのエンティティがあります。
今回はそこは特に認識して欲しくないので、**ハイライト部分をドラッグ**したり、認識エンティティ一覧の右端の**バツ印をクリック**することで、**ハイライトを消去**します。
ハイライトしてほしい範囲がずれている場合も同様に**ドラッグで範囲を変更**できます。
ハイライト範囲は問題ないけれどエンティティが意図したものでない場合は、**ハイライト上をクリックし、別のエンティティに変更**することが出来ます。
トレーニングフレーズ中にエンティティ名を入れたい場合は「**@エンティティ名**（例の場合"@familymember"）」と書きます。

これで、入力文中に家族を表す語句があった場合このインテントが呼び出されるようになりました。
あとはレスポンス欄に
> 「あなたのご家族について、もう少し聞かせてください。」
> 「ご家族の中で他には誰がそういったことを？」

といった応答文を書いて、インテント名右横のセーブボタンでセーブしたら完了です。
（応答文はオリジナルのELIZAのものを私が意訳したものなので、ELIZAの応答と完全に同じというわけではないことをご了承ください）

ELIZAでは複数ある応答文をランダムで選ぶのではなく、上から順番に使っていくのですが、Dialogflowではノーコードでは無理そうだったのでランダムで妥協しました。
##さらに応答文にエンティティーで取得した語句をはめ込んで使う
先ほどの応答文でも十分会話っぽくはなっていますが、さらに相手の使った単語を応答文に取り入れることで、より相手の話を聞いている感を演出できます。ELIZAの得意技です。
応答文に

> あなたの**$familymember**が？

と、「**$エンティティ名**」をはめ込むだけで、**入力文から取得された語句を使用**できます。
この時、エンティティを作るときに見出しに設定した語句が使われるので、

> ユーザー「**親父**が頑固で話を聞かないんだ」
> ボット「あなたの**親父**が？」

といった微妙に失礼な感じにはならずに、

> ボット「あなたの**お父さん**が？」

と言い換えてくれます。
逆に、入力された語句をそのまま使いたいときは「**$エンティティ名.original**」（例の場合は$familymember.original）で使用できます。
Responsの上にある**Action and parameters**のVALUE欄で、デフォルトでどちらを使うかを設定することもできます。
![イラスト5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/8a03f8df-ad47-ee29-eee2-b9a09fe0a5d1.png)
余談ですが、Action and parametersのREQUIREDにチェックを入れると、その要素が全て埋まるまで質問を返してくれるインテントが作れます。（リストの右に質問する文章を登録する欄が表示される）
グーグルホームさんとかにカレンダーへの予定の登録を頼むと「何日に登録しますか」とか必要事項を追加質問してくれる感じのやつです。
##エンティティに登録してない語句も取得してみる

> ユーザー「よく**怖い**夢を見るんです」
> bot「**怖い**夢ですか？」

という会話ができるようにしたいと思います。
「怖い」の部分が「面白い」でも「水の」でもなんでも取得できることを目指します。
![イラスト6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/235cf642-2052-e08f-acf7-160c8ab78548.png)
「夢を見た」や「夢見た」といった共通する部分はエンティティに登録しておきます。
トレーニングフレーズを色んなパターンで登録し、**取得したい夢の内容部分**をドラッグでハイライトし、クリックしてシステムエンティティの一つである**@sys.any**を選択しておきます。
これで、応答文に

> **$any**夢ですか？

と書くことで

> **怖い**夢ですか？

と話せるようになりました。**運が良ければ。**
トレーニングフレーズに無い未知の入力文からDialogflowさんがどこを@sys.anyとして切り出してくるかは謎なので、「よく怖い夢ですか？」「こないだ悲しい夢ですか？」など不自然な感じになることも多いです。
ひたすら地道に後述のトレーニングで調整します。
構文解析APIなどを使えばもっと正確に切り出せるのかもしれませんが、面倒なので今回はこれで良しとします。

#トレーニングで調整
こうしてエンティティとインテントをどんどん作っていけばチャットボットはできるのですが、テスト（コンソール画面右上の**"Try it now"からテスト**できます）してみると、登録した語句を入力しているのに該当無しの時用のフォールバックインテントに飛ばされたり、意図したのとは全然違うインテントが呼び出されることが多々あります。

DialogflowさんはAIでいい感じに学習して柔軟にやってくれるので、気を利かせてか勝手に違うことをやってくれるっぽいのです。
なので、こまめに"**Training**"メニューから「この場合はこっちのインテントやで」「このエンティティは使わんでええで」と教えてあげなくてはいけません。
「がんばれ森川君2号」でpitの教育をする感じです。伝わらない例えですみません。

Trainingの他に**History**というメニューもあり、実際の会話履歴を確認することもできます。
そちらでは使われたインテントへのリンクもあるのでインテントを確認したいときにも便利です。
#優先度設定
インテント編集画面でインテント名左横の色付きドットをクリックすることで、そのインテントの呼び出し優先度を変更できます。
オリジナルELIZAさんは「コンピューター」とか「プログラム」とか「ボット」と言われた場合最優先で反応するように設定されていたので、このELIZAもどきボットでもそうしてみました。
#ELIZAもどきのサンプルボットELIZAA
こうしてできたボットがこちらです。

https://bot.dialogflow.com/ece8a560-64bc-4a1d-b390-3681a7d2885d

日本語の性質上本家ELIZAさんのように自然に語句が切り出せなかったり、あちこち妥協した部分があったりで、出来の良いチャットボットになったとは言い難いですが、Dialogflowの使い方に慣れるという目的は果たせたので良しとします。
#作ったボットをLINEボットにする
本題でないため書くのが後回しになりましたが、この工程はボットが完成してからじゃなくても良いというか、むしろ始めのほうにやったほうがLINE上での挙動も随時確認出来て良い気がします。

大まかな手順としては、

1. 「**LINE for Business**」のアカウントを作る
1.  ボット用の**LINE公式アカウント**を作成
1. Dialogflowの**Integrations**メニューからLINEと連携する

といった感じです。
LINE以外にもツイッターやSlackなど色んなサービスと連携できます。

細かい手順はこちらの記事が詳しいです。
 [**Googleの無料サービス「Dialogflow」ノーコードでLINEチャットボットを作ってみた**](https://ledge.ai/dialogflow-try-3/ "Googleの無料サービス「Dialogflow」ノーコードでLINEチャットボットを作ってみた")
#最後に
今回のELIZAもどきはLINEボットにしていないのですが、「WANDERLUST」という別のLINEボットもDialogflowで作っているので良かったら遊んでみてください。
会話とルーン占いができます。
（ELIZAもどきより会話部分を頑張って作り込んでます！）
![LINEwl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/9a84dab2-0d1e-8ed5-c5ec-cd4eb39ece6c.png)
![LINEwl2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161869/e4953461-1576-2e80-a573-16611cd04249.png)
Dialogflowを使っていませんが、占いと挨拶機能だけのツイッターボット版もあります。
https://twitter.com/WLbot

最後までお読みいただきありがとうございました。