Amazon Web Services ブログ

【寄稿】Amazon Lex 上で「はい・いいえ」形式の質問を繰り返しユーザーの意図を把握する方法

この投稿はアクセンチュア株式会社 Technology グループ所属のエンジニア 金 敬源 氏に、Amazon Lex を活用したプロトタイピングについて寄稿いただいたものです。

はじめに

Amazon Lex はチャットボット向けの会話型 AIを提供するサービスで、Alexaと同じテクノロジーを利⽤した会話インターフェースの構築が可能です。⾳声をテキストに変換するためのディープラーニングを利⽤した⾃動⾳声認識(Automatic Speech Recognition; ASR)と、テキストの意図を認識する⾃然⾔語理解(Natural Language Understanding; NLU)の機能が提供されているため、⽂字チャットだけではなく、音声チャット機能も備えたアプリケーションを簡単に構築できます

本稿では Amazon Lex V2を用いて、「はい・いいえ」のような簡単な選択肢を繰り返し提示しながら会話を進行させ、ユーザーの意図を理解するチャットボットを実現します。そのために、Chatbot UI、Lex chatbot、AWS Lambdaを使う方法をご紹介します。

エンドユーザーは⾳声だけで会話が進められるよう、Lex のレスポンスの再⽣、ユーザーの⾳声取り込み、音声入力の終了とともにボットに音声を送信するなどの機能を持つUIが必要になります。今回は以下の AWS ブログでも紹介されているChatbot UIを使用します。

Deploy a Web UI for Your Chatbot
https://aws.amazon.com/jp/blogs/machine-learning/deploy-a-web-ui-for-your-chatbot/

チャットボットの例として、Amazon Lex V2 に備わっているテンプレートの一つである OrderFlowers をベースとし、「はい・いいえ」で推移する会話フローを持つチャットボットを作成します。Lex では、ユーザーの入力した内容 (Intent) について「はい・いいえ」でユーザに確認する ConfirmIntent という機能を提供しています。ただし、Lex では Intent あたり1つしかConfirmIntent を宣⾔できないため、ConfirmIntent を複数組み合わせて、「はい・いいえ」で推移する会話フローを作成することは、直接的にはできません。そこで複数の ConfirmIntent を使うため、複数の Intent を利⽤し、Intent の連続性を保つため Context を設定してフローを完成させます。

Context を使って Intent の連続性を確保しようとすると、フローの途中で ConfirmIntetnt のフローに入って Intent が Close することになり、⾳声⼊⼒が途切れてしまいます。また、音声入力の場合、レスポンスカードの表示が抜けてしまいます。そのため、今回は Lambda を活用して、Intent 遷移時に起こる切断とレスポンスカード表示の欠落がないようにします。

Amazon Lex V2の準備

Amazon Lex V2のテンプレートの中で OrderFlowers をベースとしてチャットボットを作成します。

  1. 「ボットを作成」を押して開始する。
  2. 「例から開始」を選択し、 サンプルボットで OrderFlowers を選択する。
  3. 「ボットに言語を追加」で日本語を選択する。
  4. 「はい・いいえ」のスロットタイプを作成する。

テンプレートの OrderFlowers は単⼀ Intent ですが、このブログの目的とするチャットボットは単一 Intent では実現できません。そこで、Intent を追加して ConfirmIntent の入力により、Intent を遷移させます。以下の図に示すように、作成するチャットボットのフローは Intent 1とIntent 2 で構成されます。それぞれの Intent の設定について説明します。

 

Intent 1 (OrderFlowersConfirm)

  1. OrderFlowersConfirm のインテント名で Intent を作成します。
  2. サンプル発話に「こんにちは」を追加します。
  3. 確認プロンプトに「はい・いいえ」を促すような質問を設定します。
  4. 「コードフック」において「フルフィルメントにLambda関数を使用」を選択します。ここで利用する Lambda 関数は Confirmation メッセージを表示し、ユーザーの⼊⼒を Intent 2 に渡します。

Intent 2 (OrderFlowers)

  1. 「Amazon Lex V2の準備」で追加した OrderFlowers の Intent に対してスロットを追加します。名前を FirstIntentFlagとして、作成したスロットタイプ YesOrNo を指定します。
  2. 「コードフック」を設定します。
    「初期化と検証に Lambda 関数を使用」にチェックします。Lambda で Intent 1 から渡された Confirmation ⼊⼒を検証し、レスポンスカードを表示します。

Lambda 関数の作成

チャットボットから呼び出す Lambda 関数について順番に説明します。

  1. Intent 1 から Intent 2 を呼び出します。現在の Intent が OrderFlowersConfirm であるとき、次の Intent に遷移するための Yes or No の質問として「3000円以上のご注⽂から承っていますが、宜しいでしょうか」を表示し、次のIntent である OrderFlowers を呼び出すようにします。
    // ---------------ConfirmIntentFunction-----------------------
    function confirmIntent(intentName ,slots, message) {
        return {
            'sessionState':{
                'dialogAction': {
                    'type': 'ConfirmIntent'
                    
                },
                'intent':{
                    'name':intentName,
                    'slots':slots,
                    'state':'Fulfilled'
                }   
            },
            'messages':[message]
        };
    }
    
    // ---------------Main handler-----------------------
    const slots = intentRequest.sessionState.intent.slots;
    const intentName = intentRequest.sessionState.intent.name;
    
    if(intentRequest.invocationSource == 'FulfillmentCodeHook'){
       if(intentName == 'OrderFlowersConfirm'){
          callback(confirmIntent('OrderFlowers', slots, 
                        {contentType: 'PlainText',
                         content: '3000円以上のご注文から承っていますが、宜しいでしょうか(はい/いいえ)'}));
       }
    }
  2. Intent 2 の ConfirmIntent を実行して、Yes か No かを判定します。Yes の場合はチャットを続行し、Noの場合は「それでは注文を行いません。」と表示してチャットを終えます。intentRequest.sessionState.intent.confirmationStateを チェックすることで Yes か No かを判定することができます。
    // ---------------CloseFunction-----------------------
    function close(sessionState, fulfillmentState, intentName, slots, message) {
        return {
            'sessionState': {
                'activeContexts': [],
                'dialogAction': {
                    'type': 'Close'
                },
                'intent': {
                    'name': intentName,
                    'slots': slots,
                    'state': fulfillmentState
                }
            },
            'messages': [message]
        };
    }
    // ---------------Main handler-----------------------
    if (intentRequest.invocationSource == 'DialogCodeHook') {
       if (intentName == 'OrderFlowers') {
       //Intent1で「はい」の場合
       if (intentRequest.sessionState.intent.confirmationState == 'Confirmed') {
       //Intent1で「いいえ」の場合
       } else if (intentRequest.sessionState.intent.confirmationState == 'Denied') {
              //会話終了
             callback(close({}, 'Failed', intentName, slots, { contentType: 'PlainText', content: 'それでは、注文は行いません。' }))
            }
        }
    }
    
  3. レスポンスカードを表示します。Chatbot UI で⾳声を⼊⼒する場合、PostContent() ではレスポンスカードを返すことができません。⾳声とテキスト⼊⼒に対応するためにSessionAttributes にレスポンスカードの内容を返します。SessionAttributes.appContext にレスポンスカードの JSON を入れます。
    // ---------------DelegateFunction-----------------------
    function delegate(sessionAttributes, intentName ,slots){
        return {
            'sessionState':{
                'dialogAction': {
                    'type': 'Delegate'
                    
                },
                'sessionAttributes':sessionAttributes,
                'intent':{
                    'name':intentName,
                    'slots':slots
                }   
            }
        };
    }
    
    // ---------------Main handler-----------------------
    var responseCard = getResponseCard(); 
    outputSessionState.sessionAttributes.appContext = JSON.stringify(responseCard);
    callback(delegate(intentRequest.sessionState.sessionAttributes, intentName, slots));
    

    レスポンスカードの JSON は以下のとおりです。

    function getResponseCard(){
        return{           
            "responseCard": {
                    "contentType": "application/vnd.amazonaws.card.generic",
                    "genericAttachments": [
                        {
                            "buttons": [
                              {
                                "text": "バラ",
                                "value": "バラ"
                              },
                              {
                                "text": "チューリップ",
                                "value": "チューリップ"
                              },
                              {
                                "text": "ユリ",
                                "value": "ユリ"
                              }
                            ],
                            "title": "受け取る花の種類"
                        }
                    ],
                    "version": "1"
                }
            }
    }
    

上記の Lambda 関数を AWS Lambda のコンソールで作成し、Amazon Lex の画面からLambda 関数とチャットボットをひも付けます。Amazon Lex の左のメニューから、デプロイ、エイリアスと選択し、言語で Japanese (japan) をクリックすると以下のような設定画面が現れます。作成した Lambda 関数をここで指定します。

実行結果の確認

  1. CloudFormation から Chatbot UI をインストールして、今回作成したチャットボットの動きを確認します。事前に作成した Lex Chatbot のリージョンに合わせて Launch Stack ボタンをクリックします。
Northern Virginia
Oregon
Ireland
Sydney
Singapore
London
Tokyo
Frankfurt
Canada (Central)
  1. CloudFormation でパラメーターを入力する箇所がありますので、以下の通り入力します。
    • LexV2BotId: ボットの ID を入力します。
    • LexV2BotAliasId: エイリアスのIDを入力します。このブログでは「TestBotAlias」を使用します。
    • LexV2BotLocaleId: jp_JP と入力します。

実行した結果は以下のようになります。「はい・いいえ」で回答ができており、また、レスポンスカードについても正しく表示されています。

  • 「はい・いいえ」での回答
  • レスポンスカード表示

著者について

金 敬源(Kim Koungwon)

アクセンチュア株式会社 Technology グループ所属のエンジニア。AWS のサービスを活用し、過去事例のない新しいテクノロジーやアイデアを実証する事が好きです。プライベートでは、フットサル、ゴルフを楽しんでいます。