会話構築のヒント

一般的なタスクの処理方法に関するヒントが示されます。

ノードの追加

  • ノードの目的を示すノード名を追加します。

    今はノードで実行される内容がわかっていても、数カ月後には忘れてしまう場合があります。 また、ノード名はログに表示されるため、今後の会話のデバッグに役立ちます。

  • タスクを完了するために必要な情報を収集するには、ユーザーから情報を引き出すために、一連の別個のノードではなく、スロットを含むノードを使用します。 スロットを使用した情報の収集を参照してください。

  • 複雑なプロセス・フローの場合は、プロセスの開始時に提供する必要がある情報についてユーザーに通知します。

  • アシスタントによるダイアログ・ツリーの処理順序と、経路上でのフォルダー、ブランチ、ジャンプ先、および脱線の影響について理解します。 ダイアログのフローを参照してください。

  • ジャンプ先はむやみに追加しないでください。 ジャンプ先を追加すると、ダイアログ・フローが複雑化し、後でダイアログをデバッグすることが困難になります。

  • 現在のノードと同じブランチのノードにジャンプするには、「ジャンプ先 (Jump-to)」 ではなく*「ユーザー入力をスキップ (Skip user input)」* を使用します。

    これを選択すると、ジャンプ先の子ノードを削除または再配列するときに、現在のノードの設定を編集する必要がなくなります。 次の処理の定義を参照してください。

  • ノードからの脱線を有効にする前に、最も一般的なユーザー・シナリオをテストします。 また、戻るために、考えられる脱線先ノードを必ず構成してください。 脱線を参照してください。

応答の追加

  • 回答は、簡潔かつ有用になるようにします。

  • 応答にユーザーのインテントを反映します。

    こうすることで、ユーザーに対し、ボットがユーザーを理解していることが示され、理解していない場合は、すぐに誤解を修正する機会がユーザーに与えられます。

  • 回答が頻繁に変更されるデータに依存している場合は、回答に外部サイトへのリンクを含めます。

  • ボタンを過度に使用しないでください。 ユーザーが一連のボタンから事前定義されたオプションを選択するようにすると、実際の会話との違いが大きくなり、ユーザーが真に求めることを学習する能力が低下します。 実ユーザーが自分自身の言葉を使用して要求を伝達できるようにすると、この入力を使用してシステムをトレーニングし、より良いインテントを得ることができます。

  • 1 つのノードで十分である場合は、一連のノードを使用しないでください。 例えば、ユーザーが指定した詳細に応じてさまざまな応答を返す場合は、単一のノードに複数の条件付き応答を追加します。 条件付き応答を参照してください。

  • 応答での言葉遣いには注意してください。 システムに対するユーザーの反応は、単に応答をどのようなフレーズにするかに基づいて変化させることができます。 1 行のテキストを変更することで、複雑なプログラムのソリューションを実装するために、複数行のコードを書き込む必要がなくなります。

ユーザー入力から情報を取り込むためのヒント

求める情報をユーザー入力から正確に取り込むためにダイアログ・ノードで使用する構文を知ることは、困難になる場合があります。 一般的な目標に対処するために使用できるいくつかのアプローチを以下に示します。

  • ユーザーの入力を返す: ユーザーが発したテキストをそのまま取り込み、それを応答で返すことができます。 応答で次の SpEL 式を使用して、ユーザーが指定したテキストを応答で繰り返すことができます。

    You said: <? input.text ?>.

    自動修正がオンになっていて、修正される前のユーザーの元の入力を返す場合は、<? input.original_text ?> を使用できます。 ただし、最初に original_text フィールドが存在することを確認する応答条件を必ず使用してください。

  • ユーザー入力の単語数の判別: input.text オブジェクトでサポートされる任意のストリング・メソッドを実行できます。 例えば、次の SpEL 式を使用して、ユーザー発話にある単語数を把握できます。

    input.text.split(' ').size()

  • 複数のインテントの処理: 2 つの別個のタスクを表す入力をユーザーが入力します。 I want to open a savings account and apply for a credit card. ダイアログでは、どのようにこの両方を認識して対処するのでしょうか。 複合質問 のブログ・エントリーを参照してください。

  • あいまいなインテントの処理: ユーザーが入力した入力があいまいであるため、アシスタントは、潜在的に対処する可能性があるインテントを持つ複数のノードを検出できます。 ダイアログは、後に続くダイアログのブランチをどのように認識するのでしょうか。 明確化を有効にすると、オプションをユーザーに表示して、ユーザーに適切なものを選択するよう求めることができます。 詳しくは、明確化を参照してください。

  • 入力に含まれている複数のエンティティーの処理: あるエンティティー・タイプの最初に検出されたインスタンスの値のみを評価するには、@entity == 'specific-value' ではなく、@entity:(specific-value) という形式の構文を使用します。

    例えば、@appliance == 'air conditioner' を使用すると、最初に検出された @appliance エンティティーの値のみが評価されます。 しかし、@appliance:(air conditioner) を使用すると、entity['appliance'].contains('air conditioner') に展開されます。これは、ユーザー入力に「エアコン」という値の @appliance エンティティーが 1 つ以上検出されたときに必ず一致します。

  • ログからのデータの隠蔽: コンテキスト変数に情報を保管し、メッセージ・コンテキストの $private セクション内にコンテキスト変数をネストすることにより、情報がログに保管されないようにすることができます。 例えば、$private.my_infoなどです。 プライベート・オブジェクトにデータを格納することで、ログからのみデータを隠すことができます。 情報は依然として、基礎となる JSON オブジェクトに保管されています。 この情報がクライアント・アプリケーションにさらされないようにしてください。

  • 個人情報を確認する: 個人情報 (PII) がないか確認し、ユーザーが PII を後のプロセスに送信しないようにするには、パターン・エンティティーを条件とするダイアログ・ノードを追加します。 そのノードをダイアログ・ツリーの先頭に配置して、最初に入力を確認するようにします。 例えば、エンティティーは、米国社会保障番号パターンまたは E メール・アドレス・パターンをチェックする場合があります。 その後、Please do not submit personally identifiable information. Can you reenter your request? のような応答をすることができます。オプションで、PII を使用してユーザーがサブミットした情報が保持されないようにするために、コンテキストをリセットすることができます。

条件の使用上のヒント

  • 特殊文字を含む値があるかどうかを検査する: エンティティーまたはコンテキスト変数に、アポストロフィ (') などの特殊文字を含む値が入っているかどうかを検査する場合は、検査する値を括弧で囲む必要があります。 例えば、エンティティーまたはコンテキスト変数に名前 O'Reilly が含まれているかどうかを検査するには、名前を括弧で囲む必要があります。

    @person:(O'Reilly) および $person:(O'Reilly)

    アシスタントは、これらの省略表現を以下の完全な SpEL 式に変換します。

    entities['person']?.contains('O''Reilly') および context['person'] == 'O''Reilly'

    SpEL では 2 つ目のアポストロフィを使用して、名前の中の単一のアポストロフィをエスケープします。

  • 複数の値のチェック: 複数の値をチェックする場合は、OR 演算子 (||) を使用する条件を作成して、条件に複数の値をリストできます。 例えば、コンテキスト変数 $state にマサチューセッツ、メイン、またはニューハンプシャーの省略形が含まれる場合に true になる条件を定義するには、次の式を使用できます。

    $state:MA || $state:ME || $state:NH

  • 数値の検査: 数値を比較する場合は、まず、検査対象のエンティティーまたは変数に値があることを確認してください。 エンティティーまたは変数に数値が含まれていない場合、数値比較では NULL 値 (0) として扱われます。

    例えば、ユーザー入力に含まれるドル値が 100 未満であるかどうかを確認するとします。 条件 @price < 100を使用し、@price エンティティーが NULL の場合、価格が設定されていなくても 0 は 100 より小さいため、条件は true として評価されます。 このタイプの不正確な結果を防ぐには、@price AND @price < 100 などの条件を使用します。 @price に値がなければ、この条件は正しく false という結果を返します。

  • 特定のインテント名パターンを持つインテントがあるかどうかを検査する: パターンに一致するインテントを探す条件を使用できます。 例えば、「User_」で始まるインテント名のインテントを見つけるには、条件で次のような構文を使用します。

    intents[0].intent.startsWith("User_")

    ただし、この場合は、信頼度が 0.2 未満であっても、検出されたすべてのインテントが対象になります。 また、信頼度スコアに基づいて無関係と見なされるインテントが返されないことも確認してください。 そのためには、条件を次のように変更します。

    !irrelevant && intents[0].intent.startsWith("User_")

  • ファジー・マッチングがエンティティー認識に与える影響: エンティティーを条件として使用し、ファジー・マッチングが有効になっている場合、@entity_name は、一致の信頼性が 30% を超える場合にのみ true と評価します。 つまり、@entity_name.confidence > .3の場合のみです。

入力でのエンティティー・パターン・グループの格納および認識

パターン・エンティティーの値をコンテキスト変数に保管するには、エンティティー名に .literal を付加します。 この構文を使用すると、ユーザー入力のうち、指定したパターンと一致する正確な範囲のテキストが変数に格納されます。

.literal の追加
変数
E メール <? @email.literal ?>

パターン・エンティティーに複数のグループを定義した場合に、単一グループのテキストを保管するには、保管するグループの配列番号を指定します。 例えば、@phone_number エンティティーのエンティティー・パターンが以下のように定義されているとします (括弧がパターン・グループを表すことに注意してください)。

\b((958)|(555))-(\d{3})-(\d{4})\b

ユーザー入力で指定された電話番号の市外局番だけを保管するには、以下の構文を使用します。

市外局番のみ
変数
area_code <? @phone_number.groups[1] ?>

グループ・パターンの定義に使用した正規表現ごとにグループに区切られます。 例えば、エンティティー @phone_number で定義されているパターンに一致するユーザー入力が 958-234-3456 である場合、以下のグループが作成されます。

グループの詳細
グループ番号 正規表現エンジンの値 ダイアログの値 説明
グループ[0] 958-234-3456 958-234-3456 最初のグループは、必ず、一致した文字列全体です。
グループ[1] ((958)l(555)) 958 最初に定義されたグループの正規表現に一致する文字列。この場合は ((958)l(555))
グループ[2] (958) 958 OR 式の 1 つ目のオペランドとして指定されたグループと一致する ((958)l(555))
グループ[3] (555) null OR 式の 2 つ目のオペランドとして指定されたグループと一致しない ((958)l(555))
グループ[4] (\d{3}) 234 グループに定義された正規表現に一致する文字列。
グループ[5] (\d{4}) 3456 グループに定義された正規表現に一致する文字列。

対象の入力部分を取得できるグループ番号を簡単に調べるには、一度にすべてのグループの情報を抽出します。 以下の構文を使用して、グループ分けされたすべてのパターン・エンティティーの一致部分を含む配列を返すコンテキスト変数を作成できます。

一致グループの配列
変数
array_of_matched_groups <? @phone_number.groups ?>

「Try it out」ペインを使用してテスト用の電話番号の値を入力します。 入力が 958-123-2345 の場合、この式によって $array_of_matched_groups["958-123-2345","958","958",null,"123","2345"] が設定されます。

そのため、配列内の各値を 0 から始めてカウントすると、必要なグループのグループ番号がわかります。

配列エレメント
配列要素の値 配列要素の番号
「958-123-2345」 0
「958」 1
「958」 2
null 3
「123」 4
「2345」 5

結果から、電話番号の最後の 4 桁をキャプチャーするには、例えばグループ #5が必要であると判断できます。

グループ分けされたパターン・エンティティーを表すために作成された JSONArray 構造を返すには、以下の構文を使用します。

一致したグループの JSON
変数
json_matched_groups <? @phone_number.groups_json ?>

この式は、$json_matched_groups に以下の JSON 配列を設定します。

[
  {"group": "group_0","location": [0, 12]},
  {"group": "group_1","location": [0, 3]},
  {"group": "group_2","location": [0, 3]},
  {"group": "group_3"},
  {"group": "group_4","location": [4, 7]},
  {"group": "group_5","location": [8, 12]}
]

location は、ゼロから始まる文字オフセットを使用して、入力テキストにおける検出されたエンティティー値の開始位置と終了位置を示す、エンティティーのプロパティーです。

2 つの電話番号が入力として提供されることが想定される場合は、2 つの電話番号をチェックできます。 例えば、次の構文を使用して、2 つ目の番号の市外局番を取得できます。

一致したグループの JSON
変数
second_areacode <? entities['phone_number'][1].groups[1] ?>

入力が I want to change my phone number from 958-234-3456 to 555-456-5678 の場合、$second_areacode555 になります。