朝日ネット 技術者ブログ

朝日ネットのエンジニアによるリレーブログ。今、自分が一番気になるテーマで書きます。

オリジナルの音声アシスタントを作ろう (4) - Dialogflow 前編

はじめに

こんにちは。朝日ネットでWebアプリケーションの開発を行っている tommy です。

前回 は Google の Cloud Speech API を使って音声認識をしてテキストデータを得るプログラムを作成しました。 今回は実際に会話をする部分の作成に入っていこうと思います。

※本記事のスクリーンショットは記事執筆時のものです。今後画面や仕様が変更になる可能性があります。また結果は機械学習によるものなので、同じように入力しても同じ結果を得られない可能性があります。

会話API

近年、会話AI や Chatbot の分野は盛り上がりを見せており、実際にいろいろなアプローチから会話エージェントの作成が試みられています。 同時に、まだ発展途上な分野であり確立された手法があるわけではないですが、さまざまな会話用の API が公開されてきています。そのうちの1つが、Google の Dialogflow です。

Dialogflow

Dialogflow はもともと API.AI という名前でしたが、Google に買収され現在の名前に変わりました。 会話用のAPIですが、自動で自然な会話を行ってくれるAPIというより、会話をするために必要な自然言語解析を支援してくれるツールといった感じです。

料金体系はプランを選択した上での従量課金制で、プランにより機能が制限されます。

IBM の Watson Assistant (旧Conversation) も試してみましたが、どちらも大枠が同じなので、Dialogflow を理解すれば Watson Assistant もすんなりと使えると思います。 今回は、前回利用した GCP のサービスの1つなので敷居が低かったこと、全体のコンセプトがシンプルで自分好みだったことから Dialogflow を使ってみました。

用語

Dialogflow を使う上で特徴的な単語がいくつかあります。実際に使ってみる前に以下の単語の意味は抑えていたほうが全体像をつかみやすいと思うので説明します。

Agent

作成する1つの会話AIを Agent と呼びます。

現時点では、GCP の1プロジェクトに対して1つの Agent を作成できます。複数の Agent を作りたい場合は別々にプロジェクトを作成する必要があります。

Intent

日本語にすると「意図」でしょうか。ユーザの発言の意図を解釈するための要素で Dialogflow では一番根幹となるものです。

Intent は主に、ユーザの発言の学習するためのいくつかの文章(Training phrases)とその発言に対する応答(Responses)から構成されます。 ユーザからの発言があると、定義したどれか1つの Intent に分類されその Intent に定義された応答を返します。

Entity

こちらはコンピュータ用語でいう、「データの集合」 でしょうか。ユーザの発言の中の目的語を抽出するための単語の集合です。

例えば、「何かクラシックの音楽をお勧めして。」という発言と 「何かジャズの音楽をお勧めして。」という発言の二つを拾いたいとします。 この場合、もちろん、「クラシックのおすすめを聞かれている」という Intent と「ジャズのおすすめを聞かれている」という Intent をそれぞれ作ることでも対応可能ですが手間です。 なので、実際には、ジャズとクラシックを含む{音楽のジャンル}というEntityを作成し「何か{音楽のジャンル}の音楽をお勧めして。」という発言を拾う Intent を作ることで対応します。

Context

コンテキスト。文脈とか話の流れとかですね。

一つ前の相手の発言だけでは正しい返答は返せません。現在何について話しているのかを記憶しておく機能が Context になります。

Dialog

Dialogflowには無い用語ですが、会話の流れの定義のことです。

Watson AI Assistant のほうにある機能で、概念として抑えておいたほうがいいと思ったので説明します。
会話の流れとは例えば、 「なにか音楽をお勧めして。」→「どういったジャンルがお好きですか?」→「クラシックです。」→「運命がお勧めです。」 といったようなものであり、「どういったジャンルがお好きですか?」に対する相手の返答が、「{音楽のジャンル}です。」ならば、「{曲名}がお勧めです。」 を返すといった流れを定義します。

これは、Dialogflowにはないのですが、似たような概念として、 follow-up intent があります。 ある特定の Intent にマッチした後ならばマッチする Intent で、 例えば、 音楽のお勧めを聞かれている。 という Intent にマッチした後にのみマッチする Intent というものを定義することができ、それを follow-up intent と呼びます。

実際に使ってみる

では、実際に Dialogflow を使ってみます。今回はよくある例ですが、天気予報をする会話BOTを作ろうと思います。 ただし、長くなるので、実際の天気を取得する部分は次回に回します。 ですので、本記事で作成するのは、天気について聞かれたらランダムに天気を返す、お天気"占い"BOTとなります。

Agent 作成

Dialogflow へ行きコンソールに行きます(右上のGO TO CONSOLEから行けます)。 コンソールを開いたら、CREATE AGENT を押してAgent を作成します。

f:id:a-tommy:20181011171248p:plain

Agent名、言語、Time Zoneを設定して Agent を作成します。 すでに、Agent が結び付いていないGCPのプロジェクトがあるなら既存のプロジェクトに作成することもできます。 既存のプロジェクトを指定しなかった場合、新しいプロジェクトが自動的に作成されます。

Intent の作成

続いて Intent を作成していきます。

f:id:a-tommy:20181011172048p:plain

すでに2つのIntentが存在していますね。 Default Fallback Intent はどの Intent にもマッチしなかった場合に呼ばれる Intent です。 Default Welcome Intent は会話を開始したときに呼ばれる Intent です1。また やあ といった簡単な呼びかけにもマッチするようになっています。

それでは、CREATE INTENT を押して、天気について聞かれていることを認識するための Intent を作成しようと思います。

f:id:a-tommy:20181011172954p:plain

Intent名と Training Phrases (明日の東京の天気を教えて) を一つだけ入力したら、保存します2

f:id:a-tommy:20181011173043p:plain

SAVE を押すと、Intent が保存され、自動的に機械学習が始まります(学習中は左上の歯車がぐるぐると回ります)。 右下に緑色の枠で Agent training completed と出たら学習完了です(歯車が止まります)。

右上のTry it nowに先ほど入力した Training Phrases と同じものを入力しEnterを押してみます。

f:id:a-tommy:20181011174225p:plain

そうすると、"USER SAYS" に入力した文字列、"INTENT" にマッチした Intent が 表示されます。 (当たり前ですが)Weatherにマッチしていますね。 では入力する文字列をちょっと変えてみます。

f:id:a-tommy:20181011174525p:plain

Weather にマッチしました。(場合によってはマッチしないかもしれません。) さらに、文字列を変えてみます。

f:id:a-tommy:20181011180352p:plain

どの Intent にもマッチせず Default Fallback Intent が呼ばれました3

Entity を結びつける

先ほど作った Intent では天気について聞かれているということはわかっても、せっかく、明日、東京と入力してもらっているのに、いつ、どこの天気を知りたいのかを取得できません。 ですので、続いてこの いつ、どこ といった情報を抜き出すための設定をしていきます。そのために前述した Entity を使います。

先ほど作った Weather の Intent を選択し、先ほど入力した Training phrases のうち、明日 の部分だけ選択してみます。

f:id:a-tommy:20181012123214p:plain

すると、Entity を選択するためのメニューが表示されます。Entity は自分で左側の Entities メニューから作ることもできますが、あらかじめ基本的な Entity が用意されており(System Entities)、今回はこちらを使おうと思います。

今回は "明日" を日付として認識したいので、 @sys.date を選択します。 続いて、"東京" を場所として認識したいので @sys.location と結び付けます。

f:id:a-tommy:20181012124800p:plain

SAVE して学習が完了したら、Try it now で試してみます。

f:id:a-tommy:20181012125258p:plain

PARAMETAER VALUE の部分で、明日 と 東京 が抜き出せていることが見て取れます。VALUE の部分では元の文字列ではなく日付と解釈した結果の日付文字列が入っています4

Response

以上でユーザの発言の 意図 と 目的語 を得る部分を作ることができました。 続いて、ユーザの発言に対しての応答を作成します。

Intent "Weather" の Response に応答を定義していきます。

f:id:a-tommy:20181012130459p:plain

先ほど結びつけた Entity は Response の中で Parameter として抜き出せます。 PARAMETER NAME の頭に $ をつけた物を Response の中に書くとそこに抜き出した結果が埋め込まれます。

保存して、試してみるとこうなりました。

f:id:a-tommy:20181012142228p:plain

"東京"は東京のまま、"明日"は日付文字列に変わりました。

$date.original と指定すると、ユーザの入力の該当部分を"そのまま"出力することができます。 また、複数のResponse を入力すると、ランダムにResponseを選んで返してくれます。 ただし、こちらでは定型文を返すことしかできず、ちょっとした条件分岐などもすることができません。 Parameter などによって応答を振り分けるには次回紹介する Fulfillment を利用することになります。

最終的に以下の様にして見ました。

f:id:a-tommy:20181012143007p:plain

Action and parameters

Action and parameters を使うと先ほどの Parameter の抜き出しについてもう少し詳しく設定することができます。

f:id:a-tommy:20181012143846p:plain

特に便利なのが、REQUIRED のフラグです。こちらにチェックを入れると、そのパラメータがユーザの発言から得られなかった場合にユーザに要求する様に設定することができます。 チェックを入れた後、Define prompts.. を押すことでユーザに提示する文言を設定することができます。

場所がないバージョンの Training Phrase を追加して、location を REQUIRED に指定してみます。

f:id:a-tommy:20181012145943p:plain f:id:a-tommy:20181012150046p:plain

保存して試してみます。

f:id:a-tommy:20181012150313p:plain f:id:a-tommy:20181012150319p:plain

LINEとの連携

Try it nowを使えばちゃんと Intent にマッチするか、ちゃんと応答が返ってくるかの確認ができますが、これではあまり会話しているようには見えないですね。 AI Assistant にも Try it now は存在して、そちらは実際に会話をしているように動作確認できるのですが、Dialogflow にはありません(あくまで見え方の問題ですが。)。

ですので、実際に会話をできるようにしてみたいと思います。会話UIを自前で用意するのは時間がかかるので、こちらも次回に回して、今回は外部サービスとの連携を試してみたいと思います。 Dialogflow は現時点で Facebook や Slack などのいくつかのツールとの連携が可能になっています。Google Assistant と連携して最終的に Google Home から自分の AI を呼び出すといった事も可能です。 今回はLINEとの連携を使ってみようと思います。

LINE Developer にてチャネルを作成

まずは LINE Developers にログインをします。

ログインができたなら、プロバイダーを作成します。現時点ではプロバイダー作成に必要なのは名前だけです。 プロバイダー名はサービス提供者(企業・個人)の名前です。

f:id:a-tommy:20181011152112p:plain

プロバイダーが作成できたならば次にチャネルを作成します。 チャネルとは実際にLINEでユーザと会話するアカウントとなります。

f:id:a-tommy:20181011154303p:plain

今回は、Dialogflow と連携するための Messaging API のチャネルを作成します。

f:id:a-tommy:20181011154539p:plain

全て入力必須。 アプリ名は友達として表示されるときの名前。 プランは今回 Push Message を送らないのでどちらでも大丈夫です。もし、そのまま本番で使う予定ならばフリーを選ぶ必要があるでしょう。

Dialogflow との連携

LINE のチャネルが作成できたならば次に Dialogflow との連携を設定します。 まずは、Dialogflow の Integrations のページへ行きます。

f:id:a-tommy:20181011155452p:plain

そこで LINE を選択して、ダイアログを表示させます。

f:id:a-tommy:20181011160406p:plain

右上のトグルボタンをonにして、連携を有効にします。Webhook URL は LINE のチャネルに設定するものです。

続いて、別画面で LINE Developer の先ほど作成したチャネルを開き、チャネルの基本設定を表示します。

f:id:a-tommy:20181011160837p:plain

このページで、Channel ID、Channel Secret、アクセストークンを取得して、先ほどのDialogflowのLINE連携ダイアログに設定します。 アクセストークンは最初発行されていないので「再発行」で作成します。

続いて、逆に、先ほどの Webhook URL をこちらのチャネルの基本設定画面に設定し、Webhook 送信 を「利用する」に変更します。 ついでに自動応答メッセージ を利用しないに 変更しておいたほうがいいと思います。(利用する だとDialogflowの応答文とは別に毎度定型文が返信されてしまいます。)

LINE で会話をする

連携が完了したら、実際に自分のLINEアカウントで、作成した BOT を友達に追加して会話してみましょう。 チャネルの基本設定に友達として追加するためのQRコードや user ID が記載されているのでこちらを使って友達として追加できます。

f:id:a-tommy:20181011162649j:plain

Trainingで精度を上げる

ここまでやってきて、実際に会話できるようになったわけですが(まともに応答できるのは1種類だけですが)、実際に会話をしてみると、ちょっとしたニュアンスの違いで認識してくれなかったり、逆に全く違うのにIntentにマッチしてしまったりということが多々発生すると思います。

機械学習で自動的に表記ゆれを吸収してくれるのですが、Training Phrasesが少ない状況だとどうしても認識の精度は落ちてしまいます。また、どうしても、学習の部分はブラックボックスとなるので意外なフレーズを認識失敗したりして思い通りにいかなかったりします。 最初に最適な学習データ全てを用意するのは不可能ですので、実際に会話を行ってみて、うまく認識できなかったものを正しい Initent のTraining Phrases に追加していくという作業が AI 作成のメインとなってきます。

それを効率的に行うことができる機能が Training です。

f:id:a-tommy:20181012152831p:plain

こちらでは、過去数件の会話のログをもっていて、どのような発言が どの Intent に分類されて どのように応答したかが記録されています。 意図通りの Intent にマッチしなかったものを選び、特定の Intent の Training Phrase に追加することが可能です。

例えば、本記事で作成したIntentの場合、「明後日の天気を教えて?」は Weather にマッチしたのに、「今日の天気を教えて?」はマッチしませんでした。(ただし、"明後日" は@sys.dateとして認識されていないです。) また、「天気」とだけ入力しても Weatherにマッチしてしまいますが、こちらはマッチしないで欲しいです。

ですので、それぞれが正しくマッチするように修正します。

f:id:a-tommy:20181012153434p:plain

この状態で APPROVE を選択するとそれぞれが自動的に選択した Intent の Training Phrases に追加され学習されます。(この場合「天気」は Default Fallback Intent へと追加されます。)

おわりに

今回は実際に会話を行う部分を作成するために Dialogflow を使ってみました。 ただし、本記事の段階ではあてずっぽうに天気を言う実用性のない BOT となってしまっています。 今回はプログラミングの知識がない人でも使える範囲のみを扱いました。逆に次回はほとんどの内容がプログラミングになります。 しかし、今回の範囲でも、Q&A システムのような特定の応答を返すだけのBOTは作成可能だと思います。

次回は、実際に天気を取得する部分の作成、および、LINE ではなく自分のアプリケーションと連携する部分を作っていこうと思います。

採用情報

朝日ネットでは新卒採用・キャリア採用を行っております。


  1. Eventという機能で会話の開始時に呼ぶと定義されていますが、本記事では Event については説明しません。連携する物によっては明確に会話の開始が無かったりするので使われない可能性があります。

  2. Training Phrases を入力した後に Enter を押した場合後述した Entity が自動で選択された状況になりスクリーンショットとは違った状況になります。

  3. 実は現時点では、「天気」や「東京」と入力しても Weather にマッチしてしまいます。おそらく、なるべくいずれかの Intent にマッチさせようと働くので、Intent が少ない現段階では一致する単語を持つだけでマッチしてしまうんだと思います。

  4. 残念ながら、先ほど試していた “神奈川” は 執筆時点では @sys.location に含まれていないらしく、 今日の神奈川の天気を教えて は認識してもらえませんでした。 今日の神奈川県の天気を教えて としたところ正しく認識してもらえました。