Watson Conversation の使い方を学ぶ
はじめに
この記事ではチャットボットを開発するために必要な Watson Conversation の技術的な解説をします。最低限必要な Watson Conversation の知識を付け、この記事をベースにユニークなサービスを作りましょう。なお、今回の解説範囲にチャット画面 (LINE や Slack、独自開発の UI) との連携部分については含まれません。予めご了承ください。
必要なスキル
Watson Conversation を理解するのに関して、特にスキルは必要ありませんが、実際にチャットボットをアプリケーションとして稼働させるにはプログラミングスキルが必要です。
Watson Conversation について
3.1. Watson Conversation とは
Watson Conversation とは、チャットボットのような対話アプリケーションを開発するためのプラットフォームです。機械学習の技術や自然言語認識の技術を使用しており、会話フローをグラフィカルに開発できるツールも提供しています。
作成した会話フローを標準提供の API を使用して画面に表示することでチャットボットが実現できます。この API の I/O は、インプットが「ユーザーの発言」、アウトプットが「ユーザーの発言に対する返事」です。チャット画面でユーザーが発言すると、その文字列が API で POST され、返された「返事」をチャット画面に表示するという構成を取ることで、チャットボットが実現できます。
3.2. Watson Conversation に必要な 4 つの概念
Watson Conversation で会話フローを開発するには、以下の 4 つの概念を理解する必要があります。
- Intent (発言の意図)
ユーザーが発言した入力テキストに含まれる「意図」です。Watson Conversation は入力テキストを分類器で分類し、その発言でユーザーが求めている意図を理解します。
- Entity (意味付けされた単語)
ユーザーが発言した入力テキストから抽出された意味付けされたキーワードが Entity です。入力テキストから抽出された Entity は、ユーザーの「目的」の対象物を示したりします。
- Dialog (対話の流れ)
ユーザーの発言に対応する対話の流れを制御するロジックを Dialog の組み合わせ (ダイアログ・ノード) で実装します。ユーザー要求 (Intent と Entity) に応じてひとつの返事を返すだけの簡単なノードから、ユーザーが求めるものを掘り下げるための木構造となったダイアログ・ノードもあります。
- Context (会話の背景)
Context とは、ユーザーと Watson Conversation が対話を行うにあたって情報を保持しておくことができる領域のことで、対話の回数の保持や、必要な情報がすべて入力されたかのチェックなどに利用できます。また、チャットボットが画像を返したり、DB の参照を行ったりなどのサーバー側の処理が必要な場合は、この Context 領域に任意の値をセットしておき、その値を変化させることで対応できます。
Watson Conversation でチャットボットの裏側を開発する
4.1. チャットボットのイメージ
今回題材とするチャットボットのイメージは以下とします。
- テーマ:おすすめの車を教えてくれるチャットボット
- 機能:
- 挨拶をすると挨拶を返してくる
- 「車が欲しい」などという言うと、どんな車が良いか聞いてくる
- 車の色を言うと、色を復唱して他に何かあるか聞いてくる
- 他に何もない言うと、伝えた色の車の画像を送ってくる
- お礼や同意をすると、締めの言葉が返ってくる
- 会話フロー概要:
4.2. 開発の流れ
前述のような会話フローは、「ユーザーからの入力とそれに対する返答」という会話のセットを繋げていくことで実現します。そのため、開発の流れとしては、会話のセットを一つずつ作っていくというのが基本的であり、シンプルです。本記事では、以下のように会話のフローを 5 つのフェーズに分け、順番に作っていくこととします。
- 挨拶フェーズ
- 用件フェーズ
- 色指定フェーズ
- 最終確認フェーズ
- 会話終了フェーズ
4.3. 開発をする
4.3.1. 挨拶フェーズ
このフェーズでは、ユーザーが挨拶をしたら Watson Conversation が挨拶を返して用件を聞くというフローを作ります。
まず行うことは、「おはよう」や「こんにちは」を挨拶と認識するように設定することです。
Intents タブにて「#挨拶」という Intent を作成し、ユーザーとして想定される世代や性別、地域を考慮して挨拶のワードを登録していきます。下図では代表的な挨拶を登録しました。
※Watson Conversation では Intent を ”#” で始まる名前で表記します
Intent の設定が終わったら、Watson Conversation が挨拶を認識するかどうかをテストします。Watson Conversation の画面右上にある吹き出しのマークをクリックすると、標準提供のテストツールが利用できるので、そちらを利用します。
このテストツールでは、入力された文章がどう認識されたのか。また、それに対する Watson Conversation の回答が確認できます。
上図では、「こんにちは」という入力が「#挨拶」と認識されていることが確認できます。しかし、「#挨拶」と認識された場合の Watson Conversation の返答をまだ設定していないため、返答として「解釈できませんでした。申し訳ありませんが違う表現を試していただけますか。」が返されています。つまり、「#挨拶」と認識された場合の返答を設定することで挨拶フェーズが完成します。それではその返答を設定しましょう。返答の設定 (会話フローの設定) は Dialog タブで行います。
Dialog タブではノードと呼ばれる箱を作成し、繋げていくことで返答を制御します。新しいノードを作成すると下図のような画面が表示されます。ここで設定できることは主に、「If bot recognizes(もし~と認識したら)」「Then respond with (~と返答し)」「And finally (~する)」の 3 つです。
ここでは単純に、「Watson Conversation が「#挨拶」を認識したら挨拶を返し、ユーザーの発言を待つ」といったものを設定します。この場合、設定は下図のようになります。
画面を閉じ、テストツールでもう一度挨拶をしてみましょう。
「#挨拶」と認識されているにも関わらず、挨拶を返すノードへ遷移しませんでした。これは、ノードが上から下、左から右という順で評価されてしまうため、挨拶ノードの評価がされる前に anything_else のノードで条件が合ってしまったことによる現象です。このような場合は、下図のように enything_else のノードを最下部へ移動させておくことで解決できます。
Watson Conversation が「こんにちは」を「#挨拶」と認識し、設定していた挨拶が返されました。以上から分かるように、ノードの評価における優先順位を考慮して Dialog を組み立てていくことはとても重要です。
4.3.2. 用件フェーズ
このフェーズでは、「車が欲しい」という旨の文章がユーザーから入力された際に、「どのような車をご希望ですか?」と返すようなフローを作ります。このフェーズで考慮する点は、ユーザーの要望が必ずしも「車が欲しい」ではないことです。もし今回のように、「車が欲しい」という要望にのみ対応するチャットボットを作る際は、「車が欲しい」とは違う要望の場合に、その要望には対応していないことをユーザーへ返すことが望ましいです。
まずは 4.3.2 同様、Intent で「車が欲しい」の表現で考えうる文章を登録していきます。
ユーザーが入力した文章が「#車が欲しい」を認識すると「どのような車をご希望ですか?」と返すようにダイアログ・ノードを作成します。
テストツールで確認してみましょう。
「#車が欲しい」が認識され、設定した文章が返されました。一見問題なく見えますが、「パーツが欲しいんだけど」という入力にはどうでしょうか。
「パーツが欲しいんだけど」という文章を「#車が欲しい」と認識してしまいました。内部的に「欲しい」という単語が「#車が欲しい」として認識されやすくなっていることが原因で起こっている現象と考えられます。これを解決するには、Entity を使うと便利です。
Entity に「車」と、その類義語を登録します。
登録後、テストツールで再度「車が欲しいんだけど」と入力してみましょう。
「#車が欲しい」に加え、「@車」を認識しました。これは、Watson Conversation がユーザーの発言から目的の「対象物」を認識したことを意味します。
※Watson Conversation では Entity を ”@” で始まる名前で表記します
そして、Dialog の用件ノードの条件に、AND 条件で「@車」を追加することで「パーツが欲しいんだけど」で「#車が欲しい」が認識されても「@車」が認識されないので、「どのような車をご希望ですか?」が返らないようになります。
試しに先程は期待通りに動作しなかった「パーツが欲しいんだけど」を入力してみましょう。
この通り、「@車」が認識されなかったので、用件ノードへの遷移しないようになりました。
最後に、「パーツが欲しい」というような対応できない入力に対して、その要望には対応していないことをユーザーへ返すノードを作成します。
上図のように、車の購入希望でない要望には対応していない旨を返すようになりました。
4.3.3. 色指定フェーズ
このフェーズでは、「○○色の車が良い」という旨の文章がユーザーから入力された際に、「○○色の車ですね。他には何かありますか?」と返すようなフローを作ります。ここで考慮するのは、4.3.2 の用件フェーズの直後にこのフェーズに入るという点と、ユーザーが指定した色の情報を保持しておく必要があるという点です。とあるフェーズの直後に入れたいフェーズを作るというのは、ダイアログ・ノードを入れ子にすることで実現します。また、情報の保持は Context という記憶領域を利用して実現します。
まずは、Entity で使用する色の登録をします。
これで各色を「@色」と認識するようになります。
続いて、ダイアログ・ノードを作成します。前述にもある通り、用件フェーズの直後に入るフェーズのため、用件ノードのメニューから「Add child node」を選択し、用件ノードの子として色指定ノードを作成します。また、色に応じて返す文章を変えたいため、「Customize」から「Multiple responses」を有効にします。
次に、色の指定以外の発言や、対応していない色を指定された際に返す文章を anything_else ノードで作成します。「Jump to…」に同じレイヤーの最上部ノード(今回は「色指定ノード」)を設定しておくことで、anything_else と判定された後、再度色の指定以外の発言や対応していない色を指定された際に、同じくこの anything_else ノードへ導くことができます。仮に「Jump to…」を指定しなかった場合、次にユーザーが入力した文章の評価は 1 つ上のレイヤーの最上部から始まるため、意図した動作をしません。
ここまでで一度動作の確認をしてみましょう。
正しく動作しています。次に、anything_else に入るような発言がされた際の動作を確認してみましょう。
上図のように、特定の色を指定しない限り「色の指定をしてください。」という anything_else ノードへ入ることが確認できました。一度 anything_else ノードへ入っても、「Jump to…」の設定により、特定の色が指定されれば「○○色の車ですね。」が返されていることが分かります。
会話のフローはこれで完成ですが、ユーザーが指定した色の情報を保持しておくために Context の設定をする必要があります。Context 領域に ”car_color” という変数を作り、ユーザーの入力に応じてその値を ”red” や ”blue” に変更することで、その Context を読み込んだアプリケーション・サーバーで ”car_color” の値に応じた画像を返すという動作を実現することができます。
下図のように、各レスポンスの設定で「JSON editor」を開き、”context” の値を入力します。(緑枠部参照)
全てのレスポンスで context の設定が完了したら、テストツールで確認してみましょう。
色の指定をして認識された段階で、テストツール画面の右上にある「Manage Context」をクリックすると、現在 Context 領域に保存されている変数と値が確認できます。
上図は、青色を指定して「青色の車ですね。」が返ってきた際の「Manage Context」画面です。”car_color” 変数に ”blue” という値が入っていることが確認できます。Context は Watson Conversation の API で常にレスポンスの中に含まれる領域です。アプリケーション・サーバーで Context の中身を取得し、IF 文などで「”car_color” が ”blue” だった場合は・・・」という制御をします。Context を上手に利用することができれば、あたかも人間と話しているかのようなチャットボットの実現に限りなく近づくことでしょう。
4.3.4. 最終確認フェーズ
このフェーズでは、4.3.3 で返された「他には何かありますか?」に対して特に無いという旨を返すと、Context の ”car_color” の値に応じた画像返すようなフローを作ります。ここで考慮すべきなのは、Watson Conversation には画像を返す機能が無いということです。チャットボットの UI での画像表示は、Context の利用が必要です。画像を送るべきタイミングで Context の ”send_image” を ”on” にし、それをアプリケーション・サーバー側で検知することで実現できます。
まずは Intent で「特に無い」といった意味合いの文章を登録しましょう。Entity で否定系の単語を登録するのも有効ですが、この場合、日本語では「大丈夫」や「OK」なども「特に無い」の意味のため、Intent でフォローした方が正常な動作に期待ができます。
次に、色指定フェーズの直後に入るフェーズのため、「最終確認ノード」を「色指定ノード」の子として作成します。
また、「#条件確定」が認識された場合、「あなたのご要望に合う車はこちらです。」のメッセージと共に画像を返すため、4.3.3 と同様に ”send_image” を ”on” にする Context を設定します。(下図参照)
次に、「もう一度色を指定したい」などの要望に対応できるノードを用意します。色の再指定の表現は様々あります。例えば、「別の色にしたい」などです。これは「@色」を認識したときに色指定ノードへ Jump する設定で実現できます。しかし、「やっぱり赤色じゃなくて青色が良い」などの表現も「@色」と認識されてしまう可能性があり、正確性に欠けてしまいます。正確性を重視するのであれば、「○○色の車ですね。他には何かありますか?」の文章に「再度色を指定する場合は『やり直し』と入力してください」といったコメントを加え、「@やり直し」を認識できるようにユーザーを誘導するという方法があります。今回はこの方法で対処しましょう。
「@やり直し」を Entity に登録し、「@やり直し」を認識した場合は「色指定ノード」へ Jump するようなノードを作成します。
「@やり直し」のノードを上部へ配置したのには理由があります。「やりなおし」と入力すると「@やり直し」が認識されますが、同時に「#条件確定」も認識されてしまいました。条件に適合しやすいノードを上部へ配置すると多くの入力がそのノードに拾われてしまうため、条件に適合しにくいノードをより上部へ配置する必要があります。
4.3.5. 会話終了フェーズ
このフェーズでは、4.3.4 で返された車の画像に対して「良いね。」や「ありがとう。」などを返すと締めくくりの言葉を返すフローを作ります。4.3.4 同様、色を再選択したい場合は「やり直し」と入力するよう誘導します。会話終了ノードは最終確認ノードの子として作成しましょう。また、このフェーズで 4.3.4 にて ”on” にした Context の ”image_send” 変数の値を ”off” にすることを忘れてはいけません。”on” の状態を変更しない限り車の画像を返し続けるようになる可能性があるためです。
まずは、「良いね。」や「ありがとう。」を認識するように設定しますが、今回はユーザーがどのような入力をするかの予想は非常に困難です。このような場合は、Intent である程度のフレーズを登録し、Entity で「良い」や「ありがとう」、「OK」などを「@ポジティブ」で認識できるようにしておくことで「#会話終了」OR「@ポジティブ」といった条件で広い表現に対応するのがひとつの手段です。また、「良いね、でもあまり好みじゃないな。」などの複雑かつネガティブなフレーズに対応するのは簡単ではありませんので、4.3.4 同様、「再度色を指定する場合は『やり直し』と入力してください。」と誘導するのが良いかもしれません。
「#会話終了」の Intent はこちら
「@ポジティブ」の Entity はこちら
Dialog はこちら
「@やり直し」のノード・会話終了のノード・その他の 3 つのノードで下図のように Context の ”image_send” を ”off” にします。
まとめ
今回の記事では簡単なチャットボットを作る際の考慮点を中心に、手順を追ってご説明しました。今回ご紹介できなかった部分もたくさんあります。文中にもある通り、トライ・アンド・エラーで品質を高めていくということを第一に、ご自身でユニークかつ人間に近い会話ができるチャットボットを開発しましょう。
今回ご紹介したチャットボットはこちらの記事で作成しているチャットボットをベースとしています。LINE のチャットボットとして稼働する部分まで記載されていますので、合わせてご覧ください。
この記事にはコメントがありません