フルフィルメントを作成する(Dialogflow)

フルフィルメントは、アクションでユーザー入力を取得するための会話型インターフェースと、その入力を処理して最終的にアクションを遂行するためのロジックを定義します。

会話を定義する

アクションの定義が完了したら、アクションの定義に対応する会話を作成できます。それには、Dialogflow インテントと対応するフルフィルメントを作成します。インテントは、文法を定義します。つまり、そのインテントをトリガーするために必要なユーザーの呼びかけを定義します。インテントがトリガーされると、対応するフルフィルメントがそれを処理します。

会話全体の文法を定義するために必要な数だけのインテントを作成できます。

インテントを作成する

Dialogflow の左側のナビゲーションの [Intents] (インテント)のメニュー項目で [+] 記号をクリックします。インテント エディタが表示されます。インテント エディタには、次の情報を入力できます。

  • [Intent name](インテントの名前)は IDE に表示されるインテントの名前です。
  • コンテキストを使用すると、インテントをトリガーするスコープを特定のケースに限定できます。詳細については、コンテキストに関する Dialogflow ドキュメントをご覧ください。
  • [Events](イベント)はユーザーの呼びかけを必要とせずに、インテントをトリガーできます。イベントの一例として、GOOGLE_ASSISTANT_WELCOME イベントがあります。これにより、Google アシスタントはアクションを呼び出すことができます。このイベントは、アクションのデフォルトのアクションに使用されます。組み込みヘルパー インテントについて詳しくは、ドキュメントをご覧ください。
  • [Training phrases](トレーニング フレーズ)はインテントをトリガーするために必要なユーザーの呼びかけ(文法)を定義します。インテントをトリガーするユーザーの呼びかけとして、ここにいくつか(5~10 個)のフレーズを入力します。サンプル フレーズを入力すると、Dialogflow はそのフレーズの不自然でないバリエーションを自動的に処理します。
  • [アクションとパラメータ] では、フルフィルメントに渡すデータを定義します(このインテントでフルフィルメントが有効になっている場合)。これには、ユーザー入力から解析されたデータや、トリガーされたインテントを検出するためにフルフィルメントで使用する名前が含まれます。この名前は、後でインテントを対応するフルフィルメント ロジックにマッピングする際に使用します。アクションの定義について詳しくは、Dialogflow ドキュメントのアクションとパラメータをご覧ください。

  • [レスポンス] は Dialogflow レスポンス ビルダーであり、フルフィルメントを呼び出すことなく、このインテントに対するレスポンスを Dialogflow 内で直接定義できます。この機能は、フルフィルメントを必要としない静的レスポンスに役立ちます。これを使用すると、簡単なウェルカム メッセージや別れのメッセージを提供できます。ただし、ほとんどのインテントで、フルフィルメントを使用してユーザーに応答することがよくあります。

  • [Fulfillment] では、このインテントがトリガーされたときにフルフィルメントを呼び出すかどうかを指定します。Dialogflow エージェントのほとんどのインテントで、これを有効にする可能性が高いです。インテントにこのアイテムを表示するには、[Fulfillment] メニューでエージェントのフルフィルメントを有効にする必要があります。

Dialogflow でレスポンスを作成する

インテントによっては、フルフィルメントからレスポンスを返す必要がない場合があります。そのような場合は、Dialogflow のレスポンス ビルダーを使用してレスポンスを作成できます。

[Responses] 領域で、ユーザーに返すテキスト レスポンスを指定します。デフォルトのテキスト レスポンスは、複数の Dialogflow 統合で機能するシンプルな TTS テキスト レスポンスです。Google アシスタントのレスポンスについては、レスポンスをご覧ください。

フルフィルメントでレスポンスを作成する

フルフィルメント コードは、アクションの Webhook フルフィルメント ロジックでホストされます。たとえば、Silly Name Maker サンプルの場合、このロジックは Cloud Functions for Firebase の index.js にあります。

フルフィルメントを使用するインテントがトリガーされると、Dialogflow からインテントに関する情報を含むリクエストを受け取ります。次に、インテントを処理してレスポンスを返すことにより、リクエストに応答します。このリクエストとレスポンスは、Dialogflow Webhook で定義されます。

Node.js クライアント ライブラリを使用してリクエストを処理し、レスポンスを返すことを強くおすすめします。このクライアント ライブラリを使用する際の一般的なプロセスは次のとおりです。

  1. Dialogflow オブジェクトを初期化します。 このオブジェクトは、リクエストのリッスンと解析を自動的に処理し、フルフィルメントで処理できるようにします。
  2. リクエストを処理する関数を作成します。これらの関数は、ユーザー入力とインテントの他のコンポーネントを処理し、Dialogflow に返すレスポンスを構築します。

Dialogflow オブジェクトを初期化する

次のコードは、Dialogflow をインスタンス化し、Google Cloud Functions 用のボイラープレート Node.js の設定を行います。

Node.js
'use strict';

const {dialogflow} = require('actions-on-google');
const functions = require('firebase-functions');

const app = dialogflow({debug: true});

app.intent('Default Welcome Intent', (conv) => {
  // Do things
});
exports.yourAction = functions.https.onRequest(app);
Java
public class DfFulfillment extends DialogflowApp {
  private static final Logger LOGGER = LoggerFactory.getLogger(DfFulfillment.class);

  @ForIntent("Default Welcome Intent")
  public ActionResponse welcome(ActionRequest request) {
    // Do things
    // ...
  }

リクエストを処理する関数を作成する

ユーザーがインテントをトリガーするフレーズを話すと、Dialogflow からリクエストを受け取ります。これは、フルフィルメントの関数で処理します。この関数では通常、次のことを行います。

  1. ユーザー入力を処理するために必要なロジックを適用します。
  2. トリガーされたインテントに応答するためのレスポンスを作成します。適切なレスポンスを作成するには、ユーザーが使用しているサーフェスを考慮してください。さまざまなサーフェスに合わせてレスポンスをカスタマイズする方法について詳しくは、サーフェス機能をご覧ください。
  3. レスポンスを使用して ask() 関数を呼び出します。

次のコードは、呼び出しインテント(input.welcome)とダイアログ インテント(input.number)を処理する 2 つの TTS レスポンスを作成する方法を示しています。これらはユーザーをアクションに誘導し、Dialogflow インテントに対してユーザーが発した番号をエコーするものです。

Node.js
const app = dialogflow();
app.intent('Default Welcome Intent', (conv) => {
conv.ask('Welcome to number echo! Say a number.');
});
app.intent('Input Number', (conv, {num}) => {
// extract the num parameter as a local string variable
conv.close(`You said ${num}`);
});
Java
@ForIntent("Default Welcome Intent")
public ActionResponse defaultWelcome(ActionRequest request) {
  ResponseBuilder rb = getResponseBuilder(request);
  rb.add("Welcome to number echo! Say a number.");
  return rb.build();
}

@ForIntent("Input Number")
public ActionResponse inputNumber(ActionRequest request) {
  ResponseBuilder rb = getResponseBuilder(request);
  Integer number = (Integer) request.getParameter("num");
  rb.add("You said " + number.toString());
  return rb.endConversation().build();
}

上記のコードに付属するカスタム インテントの入力番号は、@sys.number エンティティを使用してユーザーの発話から数値を抽出します。次に、ユーザーからの番号を含む num パラメータをフルフィルメントの関数に送信します。

インテントごとに個別のハンドラを用意する代わりに、フォールバック関数を追加することもできます。フォールバック関数内で、そのフォールバック関数をトリガーしたインテントを確認し、それに応じて適切な処理を行います。

Node.js
const WELCOME_INTENT = 'Default Welcome Intent';
const NUMBER_INTENT = 'Input Number';
const NUMBER_PARAMETER = 'num';
// you can add a fallback function instead of a function for individual intents
app.fallback((conv) => {
 // intent contains the name of the intent
 // you defined in the Intents area of Dialogflow
 const intent = conv.intent;
 switch (intent) {
   case WELCOME_INTENT:
     conv.ask('Welcome! Say a number.');
     break;
   case NUMBER_INTENT:
     const num = conv.parameters[NUMBER_PARAMETER];
     conv.close(`You said ${num}`);
     break;
 }
});
Java
// you can add a fallback function instead of a function for individual intents
@ForIntent("Default Fallback Intent")
public ActionResponse fallback(ActionRequest request) {
  final String WELCOME_INTENT = "Default Welcome Intent";
  final String NUMBER_INTENT = "Input Number";
  final String NUMBER_ARGUMENT = "num";
  // intent contains the name of the intent
  // you defined in the Intents area of Dialogflow
  ResponseBuilder rb = getResponseBuilder(request);
  String intent = request.getIntent();
  switch (intent) {
    case WELCOME_INTENT:
      rb.add("Welcome! Say a number.");
      break;
    case NUMBER_INTENT:
      Integer num = (Integer) request.getParameter(NUMBER_ARGUMENT);
      rb.add("You said " + num).endConversation();
      break;
  }
  return rb.build();
}

一致しない場合の再プロンプト

Dialogflow は、インテントのトレーニング フレーズで定義された入力文法のいずれにも一致しない場合、フォールバック インテントをトリガーします。通常、フォールバック インテントは、アクションに必要な入力を提供するようユーザーに再度求めます。フォールバック インテントの [Response] 領域で、再プロンプト フレーズを指定できます。また、Webhook を使用してレスポンスを指定することもできます。

ユーザーのレスポンスがアクションのトレーニング フレーズと一致しない場合、Google アシスタントは入力の処理を試みます。この動作により、ユーザーは会話の途中でアクションを変更しやすくなります。たとえば、ユーザーが「今週はどんな映画を上映する?」と質問し、会話中にコンテキストを変更して「明日の天気は?」としましょう。この例では、「明日の天気は?」は最初のプロンプトによってトリガーされた会話に対する有効なレスポンスではないため、アシスタントは自動的にこの一致を処理し、ユーザーを適切な会話に移します。

アシスタントがユーザーの入力に一致する適切なアクションを見つけられなかった場合、ユーザーはそのアクションのコンテキストに戻ります。

有効な不一致のシナリオに応じて、アシスタントがアクションを中断させる可能性があるため、ユーザークエリを処理する手段としてフォールバック インテントを使用しないでください。フォールバック インテントは、有効な入力を求めるユーザーに再度プロンプトを表示する場合にのみ使用してください。

フォールバック インテントを作成するには:

  1. Dialogflow のナビゲーション メニューで [Intents] をクリックします。
  2. [インテントを作成] の横にある ⋮ をクリックして、[フォールバック インテントを作成] を選択します。([Default Fallback Intent] をクリックして編集することもできます)。
  3. ユーザーに聞き返す再プロンプト フレーズを指定します。これらのフレーズは会話調にして、できるだけユーザーの現在のコンテキストに即したものにしてください。

    フルフィルメントを使用せずに行う場合: インテントの [Response] 領域で、フレーズを指定します。Dialogflow は、より具体的なインテントがトリガーされるまで、このリストからランダムにフレーズを選択してユーザーに話しかけます。

    フルフィルメントを使用して作成する場合:

    1. インテントの [Fulfillment] セクションで [Enable webhook call for this intent] をオンにします。
    2. リクエストを処理する関数を作成するセクションで説明されているように、フルフィルメント ロジックで他のインテントと同じようにフォールバック インテントを処理します。

    たとえば、次の関数は、Node.js クライアント ライブラリconv.data オブジェクト(状態を維持するために使用できる任意のデータ ペイロード)を使用して、フォールバック インテントがトリガーされた回数を追跡するカウンタを保存します。これが複数回トリガーされると、アクションが終了します。コードには表示されませんが、フォールバック以外のインテントがトリガーされた場合は、他のインテントでこのカウンタを 0 にリセットする必要があります。(実装方法について詳しくは、Number Genie サンプルをご覧ください)。

    Node.js
    app.intent('Default Fallback Intent', (conv) => {
     conv.data.fallbackCount++;
     // Provide two prompts before ending game
     if (conv.data.fallbackCount === 1) {
       conv.contexts.set(DONE_YES_NO_CONTEXT, 5);
       conv.ask('Are you done playing Number Genie?');
     } else {
       conv.close(`Since I'm still having trouble, so I'll stop here. ` +
         `Let's play again soon.`);
     }
    });
    Java
    @ForIntent("Default Fallback Intent")
    public ActionResponse defaultFallback(ActionRequest request) {
      final String DONE_YES_NO_CONTEXT = "done_yes_no_context";
      ResponseBuilder rb = getResponseBuilder(request);
    
      int fallbackCount =
          request.getConversationData().get("fallbackCount") == null
              ? 0
              : (Integer) request.getConversationData().get("fallbackCount");
      fallbackCount++;
      request.getConversationData().put("fallbackCount", fallbackCount);
    
      if (fallbackCount == 1) {
        rb.add(new ActionContext(DONE_YES_NO_CONTEXT, 5));
        rb.add("Are you done playing Number Genie?");
      } else {
        rb.add("Since I'm still having trouble, so I'll stop here. Let's play again soon")
            .endConversation();
      }
      return rb.build();
    }

コンテキストの使用

Dialogflow が特定の状況でのみフォールバック インテントをトリガーする場合は、コンテキストを使用します。これは、さまざまな一致しないシナリオに対して異なるフォールバック インテントを使用する場合に便利です。

  • フォールバック インテントにコンテキストを設定しなかった場合、そのインテントは、他のインテントが一致しないときに Dialogflow がトリガーするグローバル フォールバック インテントとみなされます。コンテキストを使用する場合、定義されているフォールバック インテントのうちの 1 つだけ必要です。
  • フォールバック インテントに入力コンテキストを設定すると、Dialogflow は次の条件が当てはまる場合にこのフォールバック インテントをトリガーします。

    • ユーザーの現在のコンテキストは、インテントで定義されたコンテキストのスーパーセットです。
    • 他に一致するインテントがない。

    これにより、それぞれ異なる入力コンテキストが設定された複数のフォールバック インテントを使用して、一致するインテントがない場合の再プロンプトを特定のシナリオに合わせてカスタマイズできます。

  • フォールバック インテントに出力コンテキストを設定すると、フォールバック インテントがトリガーされて処理された後も、ユーザーを同じコンテキストに維持できます。

詳細については、Dialogflow コンテキストをご覧ください。

入力がない場合の再プロンプト

引き続き操作を必要とする Google Home などの音声デバイスでユーザーがそれ以上入力しない場合の処理方法について詳しくは、再プロンプトのページをご覧ください。