電話での問い合わせを、製品名に応じて担当者へ振り分けるAIチャットボットの作成と精度検証 [Amazon Lex カスタムスロットタイプ(スロット値に制限)]
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
本記事では、Amazon Connect と Amazon Lex のカスタムスロットタイプ(スロット値に制限)を組み合わせて、電話での問い合わせを製品カテゴリーに応じて適切な担当者へ振り分けるチャットボットを作成し、その精度を検証した結果をまとめました。
振り分けは、Amazon Lex のカスタムスロットタイプ(スロット値に制限)に複数の製品カテゴリー名を事前に登録し、ユーザーの発話内容から特定の製品カテゴリーを判定させることで行います。
製品ごとにお問い合わせ対応担当者が異なる場合でも、AWS Lambda や Amazon Bedrock などの追加サービスを使用せず、Lex のみで振り分け対応できる点がこの方法のメリットです。
今回検証に使用した製品カテゴリーは以下の25種類です
- Wifi
- HDMI
- LED
- スマートホームデバイス
- スマートプラグ
- スマートウォッチ
- スマートスピーカー
- スマートドアベル
- スマートガーデニングセット
- スマートミラー
- スマート体重計
- ポータブルソーラーパネル
- ポータブルバッテリー
- ポータブルエアコン
- ポータブルプロジェクター
- 電動自転車
- 電動ロボット掃除機
- 電動歯ブラシ
- 電動キックスクーター
- ノイズキャンセリング付きヘッドセット
- ヘッドセット
- ワイヤレスヘッドセット
- ワイヤレスキーボード
- エアフライヤー
- ウォーターサーバー
Amazon Lex のカスタムスロットタイプ(値を展開)を利用した場合の精度検証は、以下の記事をご覧ください。
Lexの作成
Lex のチャットボットは CloudFormation で作成します。今回は25種類の製品カテゴリーを聞き分けるため、手動でカスタムスロットタイプのスロット値を作成するのは手間がかかります。そのため、CloudFormation を使用して効率的に作成します。
CloudFormationテンプレート
テンプレートの主要な構成要素は以下の通りです。
- パラメータ:
- LexBotName: ボットの名前
- SlotName: スロットの名前
- CustomSlotTypeName: カスタムスロットタイプの名前
- AliasName: ボットのエイリアス名
 
- リソース:
- MyLexBot: Lexボットの定義
- MyLexBotAlias: ボットのエイリアス
- LexBotRole: Lexボットが使用するIAMロール
- CloudWatchLogGroup: ログ用のCloudWatchロググループ
- S3Bucket: 音声ログ保存用のS3バケット
 
- ボットの設定:
- 日本語(ja_JP)ロケールの設定
- インテント(ProductName)の定義
- カスタムスロットタイプ(productname)の定義と25種類の製品カテゴリーの登録
 
AWSTemplateFormatVersion: 2010-09-09
Description: Amazon Lex Bot with Intent creation (Japanese)
Parameters:
  LexBotName:
    Type: String
    Default: cm-hirai-product-name-2
    Description: The name of the Lex bot
  SlotName:
    Type: String
    Default: name
    Description: The name of the slot
  CustomSlotTypeName:
    Type: String
    Default: productname
    Description: The name of the custom slot type
  AliasName:
    Type: String
    AllowedValues:
      - dev
      - prd
    Default: dev
    Description: The alias name for the Lex bot
Resources:
  MyLexBot:
    Type: AWS::Lex::Bot
    Properties:
      Name: !Ref LexBotName
      Description: !Ref LexBotName
      DataPrivacy: 
        ChildDirected: false
      IdleSessionTTLInSeconds: 300
      RoleArn: !GetAtt LexBotRole.Arn
      BotLocales:
        - LocaleId: ja_JP  
          NluConfidenceThreshold: 0.40
          VoiceSettings:
            VoiceId: Kazuha
          Intents:
            - Name: FallbackIntent
              ParentIntentSignature: AMAZON.FallbackIntent
            - Name: ProductName
              SampleUtterances:
                - Utterance: '{name}'
                - Utterance: 製品カテゴリー名は、{name}です。
                - Utterance: '{name}です。'
                - Utterance: 聞きたいのは、{name}についてです。
              Slots:
                - Name: !Ref SlotName
                  SlotTypeName: !Ref CustomSlotTypeName
                  ValueElicitationSetting:
                    SlotConstraint: Required
                    PromptSpecification:
                      MaxRetries: 3
                      MessageGroupsList:
                        - Message: 
                            PlainTextMessage: 
                              Value: 製品カテゴリー名をお伝え下さい。
              IntentConfirmationSetting: 
                PromptSpecification:
                  MaxRetries: 3
                  MessageGroupsList:
                    - Message:
                        PlainTextMessage:
                          Value: 製品カテゴリー名は、{name}、ですね。よろしければ、はい、と、異なる場合、いいえ、とお伝え下さい。
              SlotPriorities:
                - Priority: 1
                  SlotName: !Ref SlotName
          SlotTypes:
            - Name: !Ref CustomSlotTypeName
              ValueSelectionSetting:
                ResolutionStrategy: TOP_RESOLUTION
              SlotTypeValues:
                - SampleValue: 
                    Value: Wifi
                  Synonyms:
                    - Value: Wifi
                    - Value: wifi
                - SampleValue: 
                    Value: HDMI
                  Synonyms:
                    - Value: HDMI
                    - Value: h d m i
                - SampleValue: 
                    Value: LED
                  Synonyms:
                    - Value: LED
                    - Value: l e d
                - SampleValue: 
                    Value: スマートホームデバイス
                  Synonyms:
                    - Value: スマートホームデバイス
                    - Value: スマート ホーム デバイス
                - SampleValue: 
                    Value: スマートプラグ
                  Synonyms:
                    - Value: スマートプラグ
                    - Value: スマート プラグ
                - SampleValue: 
                    Value: スマートウォッチ
                  Synonyms:
                    - Value: スマートウォッチ
                    - Value: スマート ウォッチ
                - SampleValue: 
                    Value: スマートスピーカー
                  Synonyms:
                    - Value: スマートスピーカー
                    - Value: スマート スピーカー
                - SampleValue: 
                    Value: スマートドアベル
                  Synonyms:
                    - Value: スマートドアベル
                    - Value: スマート ドア ベル
                - SampleValue: 
                    Value: スマートガーデニングセット
                  Synonyms:
                    - Value: スマートガーデニングセット
                    - Value: スマート ガーデニング セット
                - SampleValue: 
                    Value: スマートミラー
                  Synonyms:
                    - Value: スマートミラー
                    - Value: スマート ミラー
                - SampleValue: 
                    Value: スマート体重計
                  Synonyms:
                    - Value: スマート体重計
                    - Value: スマート 体重 計
                - SampleValue: 
                    Value: ポータブルソーラーパネル
                  Synonyms:
                    - Value: ポータブルソーラーパネル
                    - Value: ポータブル ソーラー パネル
                - SampleValue: 
                    Value: ポータブルバッテリー
                  Synonyms:
                    - Value: ポータブルバッテリー
                    - Value: ポータブル バッテリー
                - SampleValue: 
                    Value: ポータブルエアコン
                  Synonyms:
                    - Value: ポータブルエアコン
                    - Value: ポータブル エアコン
                - SampleValue: 
                    Value: ポータブルプロジェクター
                  Synonyms:
                    - Value: ポータブルプロジェクター
                    - Value: ポータブル プロジェクター	
                - SampleValue: 
                    Value: 電動自転車
                  Synonyms:
                    - Value: 電動自転車
                    - Value: 電動 自転 車
                - SampleValue: 
                    Value: 電動ロボット掃除機
                  Synonyms:
                    - Value: 電動ロボット掃除機
                    - Value: 電動 ロボット 掃除 機
                - SampleValue: 
                    Value: 電動歯ブラシ
                  Synonyms:
                    - Value: 電動歯ブラシ
                    - Value: 電動 歯 ブラシ
                - SampleValue: 
                    Value: 電動キックスクーター
                  Synonyms:
                    - Value: 電動キックスクーター
                    - Value: 電動 キック スクーター
                - SampleValue: 
                    Value: ノイズキャンセリング付きヘッドセット
                  Synonyms:
                    - Value: ノイズキャンセリング付きヘッドセット
                    - Value: ノイズ キャン セリング 付き ヘッドセット
                - SampleValue: 
                    Value: ヘッドセット
                  Synonyms:
                    - Value: ヘッドセット
                    - Value: ヘッド セット
                - SampleValue: 
                    Value: ワイヤレスヘッドセット
                  Synonyms:
                    - Value: ワイヤレスヘッドセット
                    - Value: ワイヤレス ヘッドセット
                - SampleValue: 
                    Value: ワイヤレスキーボード
                  Synonyms:
                    - Value: ワイヤレスキーボード
                    - Value: ワイヤレス キーボード
                - SampleValue: 
                    Value: エアフライヤー
                  Synonyms:
                    - Value: エアフライヤー
                    - Value: エア フライヤー
                - SampleValue: 
                    Value: ウォーターサーバー
                  Synonyms:
                    - Value: ウォーターサーバー
                    - Value: ウォーター サーバー
      TestBotAliasSettings:
        BotAliasLocaleSettings:
          - LocaleId: ja_JP
            BotAliasLocaleSetting:
              Enabled: true
        ConversationLogSettings:
          TextLogSettings:
            - Enabled: true
              Destination: 
                CloudWatch: 
                  CloudWatchLogGroupArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogGroup}"
                  LogPrefix: TestBotAlias/
          AudioLogSettings:
            - Enabled: true
              Destination:
                S3Bucket:
                  S3BucketArn: !GetAtt S3Bucket.Arn
                  LogPrefix: TestBotAlias/
  MyLexBotAlias:
    Type: AWS::Lex::BotAlias
    Properties:
      BotAliasName: dev
      BotId: !Ref MyLexBot
      ConversationLogSettings:
        TextLogSettings:
          - Enabled: true
            Destination: 
              CloudWatch: 
                CloudWatchLogGroupArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogGroup}"
                LogPrefix: dev/
        AudioLogSettings:
          - Enabled: true
            Destination:
              S3Bucket:
                S3BucketArn: !GetAtt S3Bucket.Arn
                LogPrefix: dev/
  LexBotRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${LexBotName}-lex-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: lexv2.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: !Sub ${LexBotName}-policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - polly:SynthesizeSpeech
                Resource: '*'
              - Effect: Allow
                Action: 
                  - s3:PutObject
                Resource: 
                  - !Sub "arn:aws:s3:::${S3Bucket}/*"
              - Effect: Allow
                Action:
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: 
                  - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogGroup}:*"
  CloudWatchLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lex/${LexBotName}
      RetentionInDays: 365
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${LexBotName}-${AWS::AccountId}
このテンプレートでスタックを作成する際、パラメータはデフォルトのまま作成します。

作成したLexボットでは、1つのカスタムスロットタイプ(productname)に25種類の製品カテゴリー名がスロットタイプ値として設定されます。以下の画像の左側がカスタムスロットに定義された値で、右が同義語です。

インテント名(ProductName)では、サンプル発話に、カスタムスロットタイプ(productname)を含めています。

スロット(name)には、カスタムスロットタイプ(productname)を設定しています。そのため、発話時に製品カテゴリー名を伝えると、インテントが誘発されると同時にスロットにも製品カテゴリー名が入り、確認プロンプトが引き出されます。


カスタムスロットタイプの登録について
テンプレートのカスタムスロットタイプ(productname)には、各製品カテゴリー名について、スペースを含む形式と含まない形式の両方を登録しています。

例えば、「スマートスピーカー」の場合:
- 「スマート スピーカー」(スペースあり)
- 「スマートスピーカー」(スペースなし)
この両方の形式を登録することが重要な理由は以下の通りです
- Lexの音声認識による文字起こしでは、複合語がスペースで区切られることがあります。
- 「スマートスピーカー」(スペースなし)のみを登録した場合、Lexの文字起こしが「スマート ウォッチ」(スペースあり)となると、完全一致しないためスロットが正しく認識されません。
- 両方の形式を登録することで、スペースの有無に関わらず正確なスロット認識が可能になります。
この方法により、音声認識の揺らぎに対応し、より高精度な製品カテゴリーの判定を実現しています。
Connectフロー
Connect フローは以下の通りです。

Connectフロー json
{
  "Version": "2019-10-30",
  "StartAction": "50e274c4-cb71-435e-87c7-721dc2e375da",
  "Metadata": {
    "entryPointPosition": {
      "x": -108,
      "y": 93.6
    },
    "ActionMetadata": {
      "50e274c4-cb71-435e-87c7-721dc2e375da": {
        "position": {
          "x": 6.4,
          "y": 44
        }
      },
      "b408fe22-753f-4414-84c7-1a6f413fe461": {
        "position": {
          "x": 948.8,
          "y": 16
        },
        "conditions": [],
        "conditionMetadata": [
          {
            "id": "e9dc74e8-5078-48c1-9d5d-cebc34d2e915",
            "operator": {
              "name": "Starts with",
              "value": "StartsWith",
              "shortDisplay": "starts with"
            },
            "value": "スマート"
          },
          {
            "id": "ee169f86-bc86-4390-9e40-9ac8374954e8",
            "operator": {
              "name": "Starts with",
              "value": "StartsWith",
              "shortDisplay": "starts with"
            },
            "value": "ポータブル"
          },
          {
            "id": "8dbe3d7e-73d7-4098-82fd-c6edba872ad2",
            "operator": {
              "name": "Starts with",
              "value": "StartsWith",
              "shortDisplay": "starts with"
            },
            "value": "電動"
          }
        ]
      },
      "25fb5cce-3b55-4437-ac92-762fc10075eb": {
        "position": {
          "x": 1184,
          "y": -273.6
        }
      },
      "59634578-ccd2-4611-b712-157387e57421": {
        "position": {
          "x": 1192,
          "y": 267.2
        }
      },
      "63dc1a56-814e-4fcd-99a5-4d996d53b969": {
        "position": {
          "x": 1188,
          "y": -100
        }
      },
      "c2f5a2bc-70b8-46c4-8e1c-f83c5f0c9859": {
        "position": {
          "x": 1188.8,
          "y": 78.4
        }
      },
      "c4b8c59e-b442-412f-a61d-b814228b9d35": {
        "position": {
          "x": 1674.4,
          "y": 495.2
        }
      },
      "1bfc1f5d-3d25-4df5-aebf-a07fa038e6c7": {
        "position": {
          "x": 217.6,
          "y": 40
        },
        "children": [
          "44c4f4fd-dad3-4e9f-b143-ee21a9de3f6b"
        ],
        "overrideConsoleVoice": true,
        "fragments": {
          "SetContactData": "44c4f4fd-dad3-4e9f-b143-ee21a9de3f6b"
        },
        "overrideLanguageAttribute": true
      },
      "44c4f4fd-dad3-4e9f-b143-ee21a9de3f6b": {
        "position": {
          "x": 217.6,
          "y": 40
        },
        "dynamicParams": []
      },
      "d91c47e9-e290-41bd-ac9c-6cec01fa2d53": {
        "position": {
          "x": 703.2,
          "y": 17.6
        },
        "parameters": {
          "Attributes": {
            " ProductName": {
              "useDynamic": true
            }
          }
        },
        "dynamicParams": [
          " ProductName"
        ]
      },
      "aa614095-6077-495c-a43e-6a804ff15e17": {
        "position": {
          "x": 712,
          "y": 585.6
        }
      },
      "68fde90b-0556-4346-a7af-0b04c793511e": {
        "position": {
          "x": 714.4,
          "y": 396
        }
      },
      "c5c8cd2b-ce74-48a2-a386-52079e55cfb0": {
        "position": {
          "x": 1449.6,
          "y": 279.2
        }
      },
      "1834c1dc-7366-4de8-91ba-e9abcf6d90a4": {
        "position": {
          "x": 432.8,
          "y": 46.4
        },
        "parameters": {
          "LexV2Bot": {
            "AliasArn": {
              "displayName": "TestBotAlias",
              "useLexBotDropdown": true,
              "lexV2BotName": "cm-hirai-product-name-2"
            }
          }
        },
        "useLexBotDropdown": true,
        "lexV2BotName": "cm-hirai-product-name-2",
        "lexV2BotAliasName": "TestBotAlias",
        "conditionMetadata": [
          {
            "id": "868dcfc6-7643-48da-a7c6-a1f42ec83528",
            "operator": {
              "name": "Equals",
              "value": "Equals",
              "shortDisplay": "="
            },
            "value": " ProductName"
          }
        ]
      }
    },
    "Annotations": [],
    "name": "cm-hirai-product-name-by-lex",
    "description": "",
    "type": "contactFlow",
    "status": "PUBLISHED",
    "hash": {}
  },
  "Actions": [
    {
      "Parameters": {
        "FlowLoggingBehavior": "Enabled"
      },
      "Identifier": "50e274c4-cb71-435e-87c7-721dc2e375da",
      "Type": "UpdateFlowLoggingBehavior",
      "Transitions": {
        "NextAction": "1bfc1f5d-3d25-4df5-aebf-a07fa038e6c7"
      }
    },
    {
      "Parameters": {
        "ComparisonValue": "$.Attributes. ProductName"
      },
      "Identifier": "b408fe22-753f-4414-84c7-1a6f413fe461",
      "Type": "Compare",
      "Transitions": {
        "NextAction": "59634578-ccd2-4611-b712-157387e57421",
        "Conditions": [
          {
            "NextAction": "25fb5cce-3b55-4437-ac92-762fc10075eb",
            "Condition": {
              "Operator": "TextStartsWith",
              "Operands": [
                "スマート"
              ]
            }
          },
          {
            "NextAction": "63dc1a56-814e-4fcd-99a5-4d996d53b969",
            "Condition": {
              "Operator": "TextStartsWith",
              "Operands": [
                "ポータブル"
              ]
            }
          },
          {
            "NextAction": "c2f5a2bc-70b8-46c4-8e1c-f83c5f0c9859",
            "Condition": {
              "Operator": "TextStartsWith",
              "Operands": [
                "電動"
              ]
            }
          }
        ],
        "Errors": [
          {
            "NextAction": "59634578-ccd2-4611-b712-157387e57421",
            "ErrorType": "NoMatchingCondition"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "スマート関連担当者"
      },
      "Identifier": "25fb5cce-3b55-4437-ac92-762fc10075eb",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
        "Errors": [
          {
            "NextAction": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "その他担当者"
      },
      "Identifier": "59634578-ccd2-4611-b712-157387e57421",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
        "Errors": [
          {
            "NextAction": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "ポータブル関連担当者"
      },
      "Identifier": "63dc1a56-814e-4fcd-99a5-4d996d53b969",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
        "Errors": [
          {
            "NextAction": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "電動関連担当者"
      },
      "Identifier": "c2f5a2bc-70b8-46c4-8e1c-f83c5f0c9859",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
        "Errors": [
          {
            "NextAction": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {},
      "Identifier": "c4b8c59e-b442-412f-a61d-b814228b9d35",
      "Type": "DisconnectParticipant",
      "Transitions": {}
    },
    {
      "Parameters": {
        "TextToSpeechVoice": "Takumi",
        "TextToSpeechEngine": "Neural",
        "TextToSpeechStyle": "None"
      },
      "Identifier": "1bfc1f5d-3d25-4df5-aebf-a07fa038e6c7",
      "Type": "UpdateContactTextToSpeechVoice",
      "Transitions": {
        "NextAction": "44c4f4fd-dad3-4e9f-b143-ee21a9de3f6b"
      }
    },
    {
      "Parameters": {
        "LanguageCode": "ja-JP"
      },
      "Identifier": "44c4f4fd-dad3-4e9f-b143-ee21a9de3f6b",
      "Type": "UpdateContactData",
      "Transitions": {
        "NextAction": "1834c1dc-7366-4de8-91ba-e9abcf6d90a4",
        "Errors": [
          {
            "NextAction": "1834c1dc-7366-4de8-91ba-e9abcf6d90a4",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          " ProductName": "$.Lex.Slots.name"
        },
        "TargetContact": "Current"
      },
      "Identifier": "d91c47e9-e290-41bd-ac9c-6cec01fa2d53",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "b408fe22-753f-4414-84c7-1a6f413fe461",
        "Errors": [
          {
            "NextAction": "b408fe22-753f-4414-84c7-1a6f413fe461",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "エラー"
      },
      "Identifier": "aa614095-6077-495c-a43e-6a804ff15e17",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "c4b8c59e-b442-412f-a61d-b814228b9d35",
        "Errors": [
          {
            "NextAction": "c4b8c59e-b442-412f-a61d-b814228b9d35",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "デフォルト"
      },
      "Identifier": "68fde90b-0556-4346-a7af-0b04c793511e",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "c4b8c59e-b442-412f-a61d-b814228b9d35",
        "Errors": [
          {
            "NextAction": "c4b8c59e-b442-412f-a61d-b814228b9d35",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "LoopCount": "10"
      },
      "Identifier": "c5c8cd2b-ce74-48a2-a386-52079e55cfb0",
      "Type": "Loop",
      "Transitions": {
        "NextAction": "c4b8c59e-b442-412f-a61d-b814228b9d35",
        "Conditions": [
          {
            "NextAction": "1834c1dc-7366-4de8-91ba-e9abcf6d90a4",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "ContinueLooping"
              ]
            }
          },
          {
            "NextAction": "c4b8c59e-b442-412f-a61d-b814228b9d35",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "DoneLooping"
              ]
            }
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "製品カテゴリーをお伝え下さい。",
        "LexV2Bot": {
          "AliasArn": "arn:aws:lex:ap-northeast-1:123456789012:bot-alias/DAHYQ8GDO1/TSTALIASID"
        }
      },
      "Identifier": "1834c1dc-7366-4de8-91ba-e9abcf6d90a4",
      "Type": "ConnectParticipantWithLexBot",
      "Transitions": {
        "NextAction": "aa614095-6077-495c-a43e-6a804ff15e17",
        "Conditions": [
          {
            "NextAction": "d91c47e9-e290-41bd-ac9c-6cec01fa2d53",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                " ProductName"
              ]
            }
          }
        ],
        "Errors": [
          {
            "NextAction": "68fde90b-0556-4346-a7af-0b04c793511e",
            "ErrorType": "NoMatchingCondition"
          },
          {
            "NextAction": "aa614095-6077-495c-a43e-6a804ff15e17",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    }
  ]
}
このフローでは、発話から Lex による製品カテゴリー名の判定に基づいて、振り分け先(スマート関連、ポータブル関連、電動関連、その他)が決定されます。
今回の検証では、振り分け先をプロンプトの再生ブロックとしていますが、実際の運用では転送先となるキューを指定することで、適切な担当者に着信を振り分けることができます。
また、検証のため、フローの最後にループを設定しています。
Lex を呼び出すブロックの設定は以下の通りです

コンタクト属性の設定ブロックは以下の通りです。ここでは、Lex のスロットの値をコンタクト属性として定義しています。

検証結果1
発話内容が製品カテゴリー名のみの場合の判定結果を以下の表にまとめました。
判定基準:発話内容とスロット値に入る製品カテゴリーが一致する場合を「◯」、一致しない場合を「✕」としています。
| 発話内容(製品カテゴリー名) | 文字起こし (inputTranscript) | スロット値 | 判定 | 
|---|---|---|---|
| Wifi | wifi | Wifi | ◯ | 
| LED | l e d | LED | ◯ | 
| HDMI | h d m i | HDMI | ◯ | 
| スマートホームデバイス | スマート ホーム デバイス | スマートホームデバイス | ◯ | 
| スマートプラグ | スマート プラグ | スマートプラグ | ◯ | 
| スマートウォッチ | スマート ウォッチ | スマートウォッチ | ◯ | 
| スマートスピーカー | スマート スピーカー | スマートスピーカー | ◯ | 
| スマートドアベル | スマート ドア ベル | スマートドアベル | ◯ | 
| スマートガーデニングセット | スマート ガーデニング セット | スマートガーデニングセット | ◯ | 
| スマートミラー | スマート ミラー | スマートミラー | ◯ | 
| スマート体重計 | スマート 体重 計 | スマート体重計 | ◯ | 
| ポータブルソーラーパネル | ポータブル ソーラー パネル | ポータブルソーラーパネル | ◯ | 
| ポータブルバッテリー | ポータブル バッテリー | ポータブルバッテリー | ◯ | 
| ポータブルエアコン | ポータブル エアコン | ポータブルエアコン | ◯ | 
| ポータブルプロジェクター | ポータブル プロジェクター | ポータブルプロジェクター | ◯ | 
| 電動自転車 | 電動 自転 車 | 電動自転車 | ◯ | 
| 電動ロボット掃除機 | 電動 ロボット 掃除 機 | 電動ロボット掃除機 | ◯ | 
| 電動歯ブラシ | 電動 歯 ブラシ | 電動歯ブラシ | ◯ | 
| 電動キックスクーター | 電動 キック スクーター | 電動キックスクーター | ◯ | 
| ノイズキャンセリング付きヘッドセット | ノイズ キャン セリング 付き ヘッドセット | ノイズキャンセリング付きヘッドセット | ◯ | 
| ヘッドセット | ヘッドセット | ヘッドセット | ◯ | 
| ワイヤレスヘッドセット | ワイヤレス ヘッドセット | ワイヤレスヘッドセット | ◯ | 
| ワイヤレスキーボード | ワイヤレス キーボード | ワイヤレスキーボード | ◯ | 
| エアフライヤー | エア フライヤー | エアフライヤー | ◯ | 
| ウォーターサーバー | ウォーター サーバー | ウォーターサーバー | ◯ | 
この結果から、以下のことが分かりました。
- 25問中25問が適切に判定されました。
- 「ワイファイ」と発話すると、文字起こしでは「wifi」と英語表記になります
- 文字起こし内容からカスタムスロット内で設定した製品カテゴリー名がスロット値になりました。
- また、文字起こしされた製品カテゴリー名とスロット値には、一部スペースが存在しましたが、スロット値には影響しませんでした。
 
会話ログ例も載せます。
会話ログ
{
    "timestamp": "2024-07-31T05:12:54.073Z",
    "messages": [
        {
            "contentType": "PlainText",
            "content": "製品カテゴリー名は、スマートプラグ、ですね。よろしければ、はい、と、異なる場合、いいえ、とお伝え下さい。"
        }
    ],
    "messageVersion": "2.0",
    "requestAttributes": {
        "x-amz-lex:accept-content-types": "PlainText,SSML",
        "x-amz-lex:channels:platform": "Connect"
    },
    "sessionId": "44bec88f-88f6-4efc-916f-449fbf0c9c65",
    "dialogEventLogs": [
        {
            "nextStep": {
                "dialogAction": {
                    "type": "InvokeDialogCodeHook"
                }
            },
            "dialogStepLabel": "Intent/ProductName/StartIntent"
        },
        {
            "nextStep": {
                "dialogAction": {
                    "type": "ElicitSlot",
                    "slotToElicit": "name"
                }
            },
            "dialogStepLabel": "Intent/ProductName/StartIntent/CodeHook/Success"
        },
        {
            "nextStep": {
                "dialogAction": {
                    "type": "ConfirmIntent"
                }
            },
            "dialogStepLabel": "Intent/ProductName/Slot/name/Success"
        }
    ],
    "requestId": "4e6ee1f9-027a-4485-96a1-b4b468b59c70-ut-0",
    "isTestWorkbenchTraffic": false,
    "inputMode": "Speech",
    "bargeIn": "true",
    "operationName": "StartConversation",
    "interpretations": [
        {
            "nluConfidence": "1.00",
            "interpretationSource": "Lex",
            "intent": {
                "name": "ProductName",
                "state": "InProgress",
                "confirmationState": "None",
                "slots": {
                    "name": {
                        "value": {
                            "originalValue": "スマート プラグ",
                            "interpretedValue": "スマートプラグ",
                            "resolvedValues": [
                                "スマートプラグ"
                            ]
                        },
                        "shape": "Scalar"
                    }
                }
            }
        },
        {
            "interpretationSource": "Lex",
            "intent": {
                "name": "FallbackIntent",
                "slots": {}
            }
        }
    ],
    "developerOverride": false,
    "bot": {
        "name": "cm-hirai-product-name-2",
        "version": "DRAFT",
        "id": "DAHYQ8GDO1",
        "aliasName": "TestBotAlias",
        "aliasId": "TSTALIASID",
        "localeId": "ja_JP"
    },
    "sessionState": {
        "sessionAttributes": {},
        "dialogAction": {
            "type": "ConfirmIntent"
        },
        "originatingRequestId": "17bcba04-b5af-4a65-9200-0c5547b95449",
        "intent": {
            "name": "ProductName",
            "state": "InProgress",
            "confirmationState": "None",
            "slots": {
                "name": {
                    "value": {
                        "originalValue": "スマート プラグ",
                        "interpretedValue": "スマートプラグ",
                        "resolvedValues": [
                            "スマートプラグ"
                        ]
                    },
                    "shape": "Scalar"
                }
            }
        }
    },
    "inputTranscript": "スマート プラグ",
    "missedUtterance": false,
    "audioProperties": {
        "contentType": "audio/lpcm; sample-rate=8000; sample-size-bits=16; channel-count=1; is-big-endian=false",
        "duration": {
            "total": 1520,
            "silence": 188,
            "voice": 1332
        },
        "s3Path": "cm-hirai-product-name-2-540835513398/TestBotAlias/ja_JP/44bec88f-88f6-4efc-916f-449fbf0c9c65/4e6ee1f9-027a-4485-96a1-b4b468b59c70-ut-0.wav"
    },
    "utteranceContext": {}
}
会話ログ
    "interpretations": [
        {
            "nluConfidence": "1.00",
            "intent": {
                "name": "ProductName",
                "state": "InProgress",
                "confirmationState": "None",
                "slots": {
                    "name": {
                        "value": {
                            "originalValue": "スマート プラグ",
                            "interpretedValue": "スマートプラグ",
                            "resolvedValues": [
                                "スマートプラグ"
                            ]
                        },
    ##~中略~
    "sessionState": {
        "sessionAttributes": {},
        "intent": {
            "name": "ProductName",
            "state": "InProgress",
            "confirmationState": "None",
            "slots": {
                "name": {
                    "value": {
                        "originalValue": "スマート プラグ",
                        "interpretedValue": "スマートプラグ",
                        "resolvedValues": [
                            "スマートプラグ"
                        ]
                    },
                    "shape": "Scalar"
                }
            }
        },
    ##~中略~
    "inputTranscript": "スマート プラグ",
inputTranscriptは、発話の文字起こし内容です。
slotsのvalue内の3つの値は、AWSドキュメントでは以下の通り説明されています。
- originalValue(元の値)- ユーザー入力のうち、Lexがスロット値に対応していると判断した値です。
 
- interpretedValue(解釈された値)- Lexがユーザー入力に基づいてスロットに対して決定する値。実際の値は、ボットの値選択戦略の設定によって異なります。ユーザーが入力した値(originalValue)を使用するか、resolvedValuesリストの最初の値を Lexに選択させるかを選択できます。
- interpretedValueがスロットに入る
 
- Lexがユーザー入力に基づいてスロットに対して決定する値。実際の値は、ボットの値選択戦略の設定によって異なります。ユーザーが入力した値(
- resolvedValues(解決された値)- Lex がユーザー入力の可能な解決策であると判断した値のリスト。
 
また、2つのカスタムスロットタイプ違いは以下の通りです。
- 値を展開:ORIGINAL_VALUE- ユーザーが入力した値が、スロットの値に類似している場合、ユーザーが入力した値(originalValue)を返します。- つまり、originalValueの値がそのままinterpretedValueの値に入ります。
 
- つまり、
 
- ユーザーが入力した値が、スロットの値に類似している場合、ユーザーが入力した値(
- スロット値に制限:TOP_RESOLUTION- 解決された値のリスト(resolvedValues)がある場合、最初の値をスロットタイプの値として返します。解決リストがない場合は、nullが返されます。- つまり、resolvedValuesの値がそのままinterpretedValueの値に入ります。resolvedValuesの値が複数であれば、最初の値がinterpretedValueの値となります。
 
- つまり、
 
- 解決された値のリスト(
いくつか会話ログをみてみます。
スマートスピーカーのログ
文字起こし内容であるinputTranscriptとユーザー入力値のoriginalValueは、「スマート スピーカー」とスペースが存在します。
resolvedValuesとinterpretedValueは、スペースが存在せず、カスタムスロットで定義した「スマートスピーカー」になっています。
                "slots": {
                    "name": {
                        "value": {
                            "originalValue": "スマート スピーカー",
                            "interpretedValue": "スマートスピーカー",
                            "resolvedValues": [
                                "スマートスピーカー"
                            ]
                        },
    "inputTranscript": "スマート スピーカー",
スマートウォッチのログ
スマートスピーカーと同様です。
                "slots": {
                    "name": {
                        "value": {
                            "originalValue": "スマート ウォッチ",
                            "interpretedValue": "スマートウォッチ",
                            "resolvedValues": [
                                "スマートウォッチ"
                            ]
                        },
    "inputTranscript": "スマート ウォッチ",
ヘッドセットのログ
カスタムスロットタイプ(スロット値に制限)には、ヘッドセット、ワイヤレスヘッドセット、ノイズキャンセリング付きヘッドセットの3つがリストアップされています。
スロットに解決リストがある場合、解決リストの最初の値をスロットタイプの値として返します
AWSドキュメントの記載通り、resolvedValuesの最初の値である「ヘッドセット」がinterpretedValueの値になります。
                        "value": {
                            "originalValue": "ヘッドセット",
                            "interpretedValue": "ヘッドセット",
                            "resolvedValues": [
                                "ヘッドセット",
                                "ワイヤレスヘッドセット",
                                "ノイズキャンセリング付きヘッドセット"
                            ]
                        },
    "inputTranscript": "ヘッドセット",
検証結果2
発話内容に製品カテゴリー名だけでなく、付随情報も含めた場合の判定結果を以下の表にまとめました。この検証では、より実際の問い合わせに近い状況を想定しています。
| 発話内容 | 文字起こし (inputTranscript) | スロット値 | 判定 | 
|---|---|---|---|
| 製品カテゴリー名は、スマート体重計です。 | 製品 カテゴリー 名 は 、 スマート 体重 計 です 。 | スマート体重計 | ◯ | 
| ポータブルバッテリーです。 | ポータブル バッテリー です 。 | ポータブルバッテリー | ◯ | 
| 聞きたいのは、ワイヤレスヘッドセットについてです。 | 聞き たい の は 、 ワイヤレス ヘッドセット に つい て です 。 | ワイヤレスヘッドセット | ◯ | 
| スマートホームデバイスに関してです | スマート ホーム デバイス に 関し て です | スマートホームデバイス | ◯ | 
| スマートプラグについて詳しく知りたいのですが。 | スマート プラグ に つい て 詳しく 知り たい の です か | スマートプラグ | ◯ | 
| スマートウォッチの件です | スマート ウォッチ の 件 です | スマートウォッチ | ◯ | 
| スマートスピーカーについてです。 | スマート スピーカー に つい て です | スマートスピーカー | ◯ | 
| スマートドアベルの機能について聞きたいです。 | スマート ドア ベル の 機能 に つい て 聞き たい です | - | ✕ スロット値が入らず聞き返される | 
| スマートガーデニングセットついて聞きたいです。 | スマート ガーデニング セット に つい て 聞き たい です | スマートガーデニングセット | ◯ | 
| スマートミラーについて話したいのですが | スマート ミラー に つい て 話し たい の です が | スマートミラー | ◯ | 
| スマート体重計のことについてお話しします | スマート 体重 計 の こと に つい て お 話し ます | スマート体重計 | ◯ | 
| ポータブルソーラーパネルに関する内容です。 | ポータブル ソーラー パネル に 関する 内容 です | ポータブルソーラーパネル | ◯ | 
| 電動自転車について教えてください。 | 電動 自転 車 に つい て 教え て ください | 電動自転車 | ◯ | 
| 電動ロボット掃除機についてご相談があります | エンドウ ロボット 掃除 機 に つい て ご 相談 が あり ます | - | ✕ スロット値が入らず聞き返される | 
| 電動歯ブラシの効果について知りたいです。 | 電動 歯 ブラシ の 効果 に つい て 知り たい です | 電動歯ブラシ | ◯ | 
| 電動キックスクーターについて述べたいです | 電動 キック スクーター に つい て 述べ たい です | 動キックスクーター | ◯ | 
| ノイズキャンセリング付きヘッドセットについて教えてください。 | ノイズ キャン セリング 付き で と セット に つい て 教え て ください | ノイズキャンセリング付きヘッドセット | ◯ | 
| エアフライヤーついてお願いします。 | いや フライヤー に つい て お 願い し ま | - | ✕ スロット値が入らず聞き返される | 
この結果から、以下のことが分かりました
- 18問中15問が正しく判定されました。
- 検証結果1と比較し、不要な発話があると精度が下がることが分かりました。
- サンプル発話の種類を増やすことで、正答数が上がる可能性が高いです。
- サンプル発話に設定していた以下の3つのパターンは、全て正しく判定されました。
- 製品カテゴリー名は、{name}です。:製品カテゴリー名は、スマート体重計です。
- {name}です。:ポータブルバッテリーです。
- 聞きたいのは、{name}についてです。:聞きたいのは、ワイヤレスヘッドセットについてです。
 
 
- サンプル発話に設定していた以下の3つのパターンは、全て正しく判定されました。
スマートウォッチのログ
文字起こし内容であるinputTranscriptからユーザー入力値(originalValue)は、「スマート ウォッチ」と判定されています。
resolvedValuesとinterpretedValueは、スペースが存在せず、カスタムスロットで定義した「スマートウォッチ」になっています。
            "slots": {
                "name": {
                    "value": {
                        "originalValue": "スマート ウォッチ",
                        "resolvedValues": [
                            "スマートウォッチ"
                        ],
                        "interpretedValue": "スマートウォッチ"
                    },
                }
            }
        },
    },
    "inputTranscript": "スマート ウォッチ の 件 です",
スマートミラーのログ
インテントは誘発されましたが、スマートミラーのスが文字起こしされていないため、スロット値が入らず、聞き返されました。
    "sessionState": {
        "sessionAttributes": {},
        "dialogAction": {
            "type": "ElicitSlot",
            "slotToElicit": "name"
        },
        "intent": {
            "name": "ProductName",
            "state": "InProgress",
            "confirmationState": "None",
            "slots": {
                "name": null
            }
        },
        "originatingRequestId": "9ef383c7-034f-4c2f-a152-b1898a9944ed"
    },
    "inputTranscript": "マーク ミラー に つい て 話し たい の です が",
2回目を試すと、インテントが誘発し、正しい製品カテゴリーを認識しました。
            "slots": {
                "name": {
                    "value": {
                        "originalValue": "スマート ミラー",
                        "interpretedValue": "スマートミラー",
                        "resolvedValues": [
                            "スマートミラー"
                        ]
                    },
                    "shape": "Scalar"
                }
            }
        }
    },
    "inputTranscript": "スマート ミラー に つい て 話し たい の です が",
電動ロボット掃除機のログ
適切に文字起こしされなかったため、インテントは誘発されましたが、スロット値が入らず、聞き返されました。
    "sessionState": {
        "sessionAttributes": {},
        "originatingRequestId": "9ef383c7-034f-4c2f-a152-b1898a9944ed",
        "intent": {
            "name": "ProductName",
            "state": "InProgress",
            "confirmationState": "None",
            "slots": {
                "name": null
            }
        },
        "dialogAction": {
            "type": "ElicitSlot",
            "slotToElicit": "name"
        }
    },
    "inputTranscript": "エンドウ ロボット 掃除 機 に つい て ご 相談 が あり ます",
2回目を試すと、インテントが誘発し、正しい製品カテゴリーを認識しました。
            "slots": {
                "name": {
                    "value": {
                        "originalValue": "電動 ロボット 掃除 機",
                        "resolvedValues": [
                            "電動ロボット掃除機"
                        ],
                        "interpretedValue": "電動ロボット掃除機"
                    },
                    "shape": "Scalar"
                }
            }
        },
        "originatingRequestId": "8565eb72-fd49-49c2-90de-1c507f879356"
    },
    "inputTranscript": "電動 ロボット 掃除 機 に つい て ご 相談 が あり ます",
電動歯ブラシのログ
適切に電動歯ブラシがスロット値になっています。
            "slots": {
                "name": {
                    "value": {
                        "originalValue": "電動 歯 ブラシ",
                        "interpretedValue": "電動歯ブラシ",
                        "resolvedValues": [
                            "電動歯ブラシ"
                        ]
                    },
                    "shape": "Scalar"
                }
            }
        },
    },
    "inputTranscript": "電動 歯 ブラシ の 効果 に つい て 知り たい です",
ノイズキャンセリング付きヘッドセットのログ
適切にノイズキャンセリング付きヘッドセットがスロット値になっています。
            "slots": {
                "name": {
                    "value": {
                        "originalValue": "ノイズ キャン セリング 付き ヘッド セット",
                        "interpretedValue": "ノイズキャンセリング付きヘッドセット",
                        "resolvedValues": [
                            "ノイズキャンセリング付きヘッドセット"
                        ]
                    },
                    "shape": "Scalar"
                }
            }
        },
    },
    "inputTranscript": "ノイズ キャン セリング 付き ヘッド セット に つい て 教え て ください",
エアフライヤーのログ
適切に文字起こしされなかったため、スロット値が入らず、聞き返されました。
    "sessionState": {
        "sessionAttributes": {},
        "originatingRequestId": "9ef383c7-034f-4c2f-a152-b1898a9944ed",
        "intent": {
            "name": "ProductName",
            "state": "InProgress",
            "confirmationState": "None",
            "slots": {
                "name": null
            }
        },
        "dialogAction": {
            "type": "ElicitSlot",
            "slotToElicit": "name"
        }
    },
    "inputTranscript": "いや フライヤー に つい て お 願い し ます",
2回目を試すと、インテントが誘発し、正しい製品カテゴリーを認識しました。
            "slots": {
                "name": {
                    "value": {
                        "originalValue": "エアー フライヤー",
                        "interpretedValue": "エアーフライヤー",
                        "resolvedValues": [
                            "エアーフライヤー"
                        ]
                    },
                    "shape": "Scalar"
                }
            }
        }
    },
    "inputTranscript": "エアー フライヤー に つい て お 願い し ます",
最後に
本検証を通じて、以下のことが明らかになりました。
- 製品カテゴリー名のみの発話であれば、高い精度で判定できます。
- サンプル発話の種類を増やすことで、発話に他の情報が含まれていた場合も精度が向上する可能性があります。
- カスタムスロットタイプ(値を展開)の場合、スロットに入る値にはスペースが入ることが多いです(参考記事)。対して、カスタムスロットタイプ(スロット値に制限)の場合、設定した製品カテゴリー名と同じ値がスロット値に入るという違いがあります。注意点として、スロット値に制限の場合、スペースを含めた製品カテゴリー名を事前に登録しておく必要があります。
今回は Amazon Lex のカスタムスロットタイプ(スロット値に制限)と(スロット値に制限)の違いも理解することができました。










