[日本語Alexa] インテントチェーン(Intent Chaining) スキル側で自由に別のインテントに遷移できるようになったので、しびれるぐらい自然に会話が進むようになった(新機能)

2019.03.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

AIソリューション部の平内(SIN)です。

昨日、Alexaのブログで、別のインテントから、ダイアログモードに遷移できるようになったとのアナウンスがありました。


Use Intent Chaining to Enter Dialog Management from a Different Intent

2019/03/02現在、まだ日本語のドキュメントは整備されていませんが、英語ドキュメントでは、以下で使用方法が確認できます。
Change the intent or update slot values during the dialog

別インテントへの遷移は、下記のようにDialog.Delegateに、updatedIntentを追加するような形で行われます。

.addDirective({
    type: 'Dialog.Delegate',
    updatedIntent: {
      name: 'OrderIntent',
      confirmationStatus: 'NONE',
      slots: {}
    }
  })

なお、遷移できるのは、ダイアログモードのインテントのみです。

2 カフェの注文を受けるスキル

今回は、カフェで注文をとるスキルを例に、動作を確認してみました。

注文を取るインテントはOrderIntentです。

OrderIntentは、2つスロット(drinknumber)を持ち、共に、必須スロットとなっています。(ダイアログモードとなっている)

以下は、Lambdaのコードの主要部分です。

const LaunchRequestHandler = {
    canHandle(h) {
        return h.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(h) {
        const speechText = 'ようこそクラスメソッドカフェーへ、ご注文をどうぞ';
        return h.responseBuilder
            .speak(speechText)
            .reprompt(speechText)
            .getResponse();
    }
};

const OrderdIntentHandler = {
    canHandle(h) {
        return h.requestEnvelope.request.type === 'IntentRequest'
            && h.requestEnvelope.request.intent.name === 'OrderIntent';
    },
    handle(h) {
        const dialogState = h.requestEnvelope.request.dialogState;
        if (dialogState !== 'COMPLETED') {
            return h.responseBuilder
            .addDelegateDirective()
            .getResponse();
        } else {
            return h.responseBuilder
            .speak('ご注文ありがとうございます')
            .withShouldEndSession(false)
            .getResponse();
        }
    }
};

exports.handler = Alexa.SkillBuilders.custom()
    .addRequestHandlers(
        LaunchRequestHandler,
        OrderdIntentHandler)
    .lambda();

動作は、以下のような感じになります。最初のユーザーの発話では、OrderIntentに突入できないので、LaunchRequestとなっており、「ご注文をどうぞ」の誘導で、OrderIntentへ入るように誘導しています。

一応、スキルの開始と同時に、OrderIntentのサンプル発話含めれば、いきなり入れることは可能ですが・・・これをユーザーに求めるのは、ちょっと難しい部分もあります。

3 addDelegateDirectiveによるインテント遷移

スキル開始時、特定のインテントにヒットする発話がない場合、Lambdaには、LaunchRequestのリクエストが到着します。そして、目的のインテントに入るように、そのサンプル発話を促すようなメッセージを返すことになります。

今回の新機能を使って、LaunchRequestのハンドラを書き換えると次のようになります。

addDelegateDirectiveを返し、nameに遷移先のインテントを指定しています。

const LaunchRequestHandler = {
    canHandle(h) {
        return h.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(h) {
        const speechText = 'ようこそクラスメソッドカフェーへ';
        return h.responseBuilder
            .addDelegateDirective({
                name: 'OrderIntent',
                confirmationStatus: 'NONE',
                slots: {}
            })
            .speak(speechText)
            .reprompt(speechText)
            .getResponse();
    }
};

この時、返されるレスポンスは以下のとおりです。Dialog.DelegateupdatedIntentが追加されていることが確認できます。

"response": {
    "outputSpeech": {
        "type": "SSML",
        "ssml": "<speak>ようこそクラスメソッドカフェーへ</speak>"
    },
    "directives": [
        {
            "type": "Dialog.Delegate",
            "updatedIntent": {
                "name": "OrderIntent",
                "confirmationStatus": "NONE",
                "slots": {}
            }
        }
    ],

使ってみると、次のようになります。

「ようこそクラスメソッドカフェへ」の発話の後、いきなり「コーヒーと紅茶のどちらになさいますか」と続きます。

これは、既にOrderIntentに入っており、必須スロットのdrinkが入っていないので、モデルで定義されたAlexaの音声プロンプトが返されているのです。

4 addElicitSlotDirectiveによるインテント遷移

インテントの遷移は、addDelegateDirectiveだけでなく、addElicitSlotDirectiveでも行うことができます。

addElicitSlotDirectiveは、もともと特定のスロットの入力を促すためのものですが、nameに遷移先のインテントを指定することで、別のインテントから強制的に遷移できます。

const LaunchRequestHandler = {
    canHandle(h) {
        return h.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(h) {
        const speechText = 'ようこそクラスメソッドカフェーへ、コーヒーと紅茶のどちらになさいますか';
        return h.responseBuilder
            .addElicitSlotDirective('drink', {
                name: 'OrderIntent',
                confirmationStatus: 'NONE',
                slots: {}
            })
            .speak(speechText)
            .reprompt(speechText)
            .getResponse();

    }
};

この時、返されるレスポンスは以下のとおりです。Dialog.ElicitSlotupdatedIntentが追加されていることが確認できます。

"outputSpeech": {
        "type": "SSML",
        "ssml": "<speak>ようこそクラスメソッドカフェーへ、コーヒーを紅茶をのどちらになさいますか</speak>"
    },
    "directives": [
        {
            "type": "Dialog.ElicitSlot",
            "updatedIntent": {
                "name": "OrderIntent",
                "confirmationStatus": "NONE",
                "slots": {}
            },
            "slotToElicit": "drink"
        }
    ],

コードを上記に変更した上での実行結果は、次のようになります。

ここで、注意が必要なのは、addElicitSlotDirectiveを使用する場合は、その入力を促す発話は、Lambdaから返す必要があることです。

ここでは「コーヒーと紅茶ののどちらになさいますか」が、それに当たります。

5 最後に

今回追加された別インテントへの遷移を使用すると、特定のインテントへの誘導が極めて簡単に、そして確実にできることになります。 会話の進行の支配を、ますますスキル側でやりやすくなったと言えると思います。

例えば、今回試したカフェのスキルでは、飲み物のオーダーを取るインテントの他に、デザートの注文をとるインテントを用意したとします。

この場合、飲み物のオーダが決定した時点で「ご一緒に、ケーキなどはいかがですか?」と返し、ユーザーが「はい」と返事したら、Amazon.YesIntentで受けて、デザート注文インテントへ遷移させるといった感じです。

いや〜、Alexaのダイアログモードの進化、しびれます。


弊社ではAmazon Connectのキャンペーンを行なっております。

3月に「無料Amazon Connectハンズオンセミナー」を開催致します。導入を検討されておられる方は、是非、お申し込み下さい。

また音声を中心とした各種ソリューションの開発支援も行なっております。