13
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【サンタと話そう🎄🎁🎅】子どもの欲しいものをこっそり保護者に通知するシステムを作ってみた《前編》

13
Last updated at Posted at 2025-12-24

はじめに

こんにちは。株式会社ウフルの鈴木です!
本記事は、Japan AWS Jr. Champions Advent Calendar 2025 シリーズ1・24日目の記事となります。
本アドベントカレンダーは、2025年のJapan AWS Jr. Championsメンバーの有志が募ってチャレンジしている企画です。

(アドベントカレンダーのカレンダー一覧はこちら↓)

みなさんは、子どもの頃にクリスマスプレゼントで「これが欲しい」と親に直接言うのが、なんとなく恥ずかしかった経験はありませんか?
私は、欲しいプレゼントがあっても親に直接言えず、紙に書いてツリースカートにこっそり隠した経験があります。
一方で保護者側としては、「今年は何を欲しがっているんだろう?」「直接聞くと夢を壊しそうで聞けない」と悩んでいる方もいらっしゃると思います。
そこで今回は、子どもが「AIサンタ」と電話で話した内容(= 欲しいもの)を、夢を壊さずにこっそり保護者へ通知するクリスマス用コンタクトセンターを、Amazon Connectを使って構築してみました。

本記事では、全体のアーキテクチャ構成と、保護者による「お子様情報の事前登録機能」までの構築を紹介します。

本記事の情報は2025年12月時点のものです。
最新情報については公式ドキュメントをご確認ください。

目次

  1. 前提条件
  2. システム構成図
  3. 構築方法
  4. 動作確認
  5. まとめ

1.前提条件

本記事では以下を前提とします。

  • 東京(ap-northeast-1)リージョンで構築していること
  • Amazon Connectの初期設定(電話番号の取得やキューの設定など)が完了していること
  • 対象のインスタンスでAmazon Q in Connectが有効化されていること

2.システム構成図

以下は、本記事で扱うAIサンタの全体アーキテクチャ構成図です。
背景が黄色で示されている部分が、本記事(第1部)で紹介する構築範囲になります。

サンタConnect-overview.drawio.png

本システムでは、Amazon Connect AI Agents(旧 Amazon Q in Connect)の「カスタマーセルフサービス」機能を利用し、子どもとAIサンタ(AIエージェント)との自然な対話を実現しています。また、保護者やお子様の情報管理には、Amazon Connectが提供するデータテーブルを利用しています。
外部データベースを用意せず、Amazon Connect内で完結する構成とすることで、構築の手軽さと運用負荷の低減を重視しています。

2.1システム全体の流れ

本システムは、保護者による事前登録と、お子様によるAIサンタとの通話の2つの流れで構成されています。

お子様情報の事前登録 (本記事で実装)

image.png

  1. 保護者が「登録用電話番号」に発信
  2. Amazon Connectが着信を受け付け、Amazon Connect AI Agents(カスタマーセルフサービス)に接続
  3. Connect AI Agentsがお子様の名前や発信元番号などの情報をヒアリング
  4. 収集した情報をAmazon Connectデータテーブル(SantaRegistration2025)に保存

この事前登録により、後続のお子様からの通話時に
「どの保護者・どのお子様の通話か」を判別できるようになります。

AIサンタとの通話 (次の記事で実装)

image.png

  1. お子様がAIサンタ用の電話番号に発信(発信先電話番号は保護者が伝える想定)
  2. 発信元電話番号をキーとしてAmazon Connectデータテーブル(SantaRegistration2025)を参照し、事前に登録された情報(お子様の名前や保護者情報)を取得
  3. コンタクトに紐づくAmazon Connect AI Agents(事前登録窓口)をAIサンタに切り替え、お子様情報をカスタムデータとして追加
  4. 取得した情報をもとに、AIサンタに接続
  5. AIサンタが音声対話を開始し、自然な会話の中でプレゼントの希望をヒアリング
  6. Amazon Connectデータテーブル(SantaWishList2025)にプレゼントの情報を登録する
  7. 会話内容から取得した「欲しいもの」を後続の通知処理(Lambda + SNS)に引き渡す

この流れにより、お子様は「サンタさんとお話ししている」体験だけを楽しみつつ、
裏側では会話内容から取得した情報をもとに、欲しいものが保護者へ自動的に通知される仕組みを実現しています。

3.構築方法

以下の流れでお子様情報の事前登録機能を作成します。

  1. Amazon Connectデータテーブルの作成
  2. Amazon Connect AI Agents(カスタマーセルフサービス)の作成
  3. セルフサービス用Lexボットの作成
  4. 事前登録用コンタクトフローの作成

3.1.Amazon Connectデータテーブルの作成

セキュリティプロファイルの更新

「Amazon Connect管理者ワークスペース」>「ユーザー」>「セキュリティプロファイル」をクリックし、ログインユーザーに紐づいているセキュリティプロファイルを編集します。

  • 「ルーティング」> 「データテーブル」のアクセスを許可し、「保存」をクリック

image.png

データテーブルの作成

「Amazon Connect管理者ワークスペース」>「ルーティング」>「データテーブル」をクリックし、「新しいデータテーブルを追加」をクリックします。

image.png

  • データテーブルの設定
    • 名前:有効な文字からなる任意の文字列(例:SantaRegistration2025)
    • 説明:オプション
    • タイムゾーン:Asia/Tokyo
    • ロックレベル:なし
      上記設定後、「保存」をクリックします。

image.png

属性を追加

image.png

  • 属性を追加(1つ目)
    • 名前:ChildPhoneNumber (AIサンタへかける発信元電話番号)
    • 説明:オプション
    • タイプ:テキスト
    • プライマリ属性として使用:オン
    • 基本検証 - オプションオプション
    • コレクションの検証:なし
      上記設定後、「保存」をクリックします。

同様の手順で、以下の値を設定していきます。

  • 属性を追加(2つ目)

    • 名前:CallName (お子様の呼び名)
    • 説明:オプション
    • タイプ:テキスト
    • プライマリ属性として使用:オフ
    • 基本検証 - オプションオプション
    • コレクションの検証:なし
  • 属性を追加(3つ目)

    • 名前:ParentPhoneNumber (保護者様の電話番号)
    • 説明:オプション
    • タイプ:テキスト
    • プライマリ属性として使用:オフ
    • 基本検証 - オプションオプション
    • コレクションの検証:なし
  • 属性を追加(4つ目)

    • 名前:NotificationPhoneNumber (希望プレゼントの通知先電話番号)
    • 説明:オプション
    • タイプ:テキスト
    • プライマリ属性として使用:オフ
    • 基本検証 - オプションオプション
    • コレクションの検証:なし

上記設定後、以下のようなテーブルが作成されていれば完了です。

image.png

通知の送信管理や、Eメールによる通知を実装したい場合は、別途属性を追加してください。

3.2.Amazon Connect AI Agents(カスタマーセルフサービス)の作成

AIエージェントの作成

「Amazon Connect管理者ワークスペース」 > 「AIエージェントデザイナー」 > 「AIエージェント」より、「AIエージェントを作成」をクリックします。

image.png

  • AIエージェントの初期設定
    • 名前:有効な文字からなる任意の文字列(例:SantaRegistrationAgent)
    • AIエージェントタイプ:セルフサービス
    • 説明:オプション
      上記設定後、「作成」をクリックします。

image.png

  • AIプロンプトの追加
    「プロンプトを作成」>「新しいAIプロンプトを作成」をクリックします。
    • 名前:有効な文字からなる任意の文字列(例:SantaRegistrationPreProcessing)
    • AIプロンプト:セルフサービスの前処理
    • 説明-オプション:オプション
      上記設定後、「作成」をクリックします。

image.png

  • AIプロンプト
    • モデル:apac.amazon.nova-pro-v1:0(クロスリージョン)(システムのデフォルト)

    • AIプロンプト
      system: |
        あなたは「AIサンタ登録窓口」です。
        音声通話を前提に、聞き取りやすく、言い間違い・聞き取りミスに強い対話で、保護者の登録情報を正確に受け付けます。
        収集した情報は Amazon Connect のデータテーブル属性に合わせて保存します(必ず下記の4項目のみ)。
        丁寧で親しみやすい会話を行い、虚偽や攻撃的表現は禁止。不適切な活動・発言の関与や助長も禁止。
        必ず日本語で会話してください。
      
        【目的】
        - 保護者から「AIサンタ」利用の事前登録情報を収集し、内容を復唱して明示的な同意を得てから登録完了とする。
        - コンタクトフロー側で分岐できるように、完了状態をフラグ(RegistrationStatus)で返す。
      
        【保存するフィールド(データテーブル属性と一致)】
        - ParentPhoneNumber(プライマリ属性。保護者の電話番号)
        - CallName(お子様の呼び名)
        - ChildPhoneNumber(お子様が掛けてくる電話番号)
        - NotificationPhoneNumber(通知先電話番号)
      
        【返却フラグ(コンタクトフロー分岐用)】
        - RegistrationStatus:
          - "COMPLETED":登録確定(最終確認で肯定を得て CONFIRM_REGISTRATION を呼んだ)
          - "IN_PROGRESS":収集中(FOLLOW_UP_QUESTION を継続している)
          - "ESCALATED":取得困難のため有人へ(ESCALATION を呼んだ)
      
        【音声通話前提の発話設計】
        - 数字はゆっくり・区切って読み上げる(例:電話番号「ゼロ・キュー・ゼロ…」)。
        - ハイフンや空白が混じっても良いが、格納は数字のみへ正規化して保存する。
        - 発話と格納の形式は一致させなくてよい。発話は自然な日本語、格納は所定のフォーマットに正規化して保存する。
        - お客様には格納用の内部形式を読み上げない。
      
        【収集順序(推奨)】
        1) ParentPhoneNumber
        2) CallName
        3) ChildPhoneNumber
        4) NotificationPhoneNumber
      
        【逐次復唱(1項目ごと)】
        - 各項目を取得した直後に短く復唱し、次の質問へ進む。
      
        【電話番号の表現ルール(読み上げと保存の分離)】
        - 音声で読み上げる場合や、message に出力する場合は必ず国内形式(090 / 080 など)で表現する。
        - データテーブルへ保存する際は、E.164 形式(+81xxxxxxxxxx)に正規化して保存する。
        - 正規化ルール:
          - 全角・ハイフン・空白を除去して数字のみを抽出する
          - 先頭が「0」の場合は「+81」に置換する
            例:09012345678 → +819012345678
          - すでに「+81」で始まっている場合はそのまま使用する
        - ユーザーへの発話では +81 形式を読み上げてはいけない
        - 発話と保存形式は一致していなくてよい(発話=国内形式、保存=+81)
      
        【電話番号に関する注意事項】
        - ParentPhoneNumber / ChildPhoneNumber / NotificationPhoneNumber はすべて同じ正規化ルールを使う
        - 数字が 10 桁または 11 桁でない場合は取得失敗として再質問する
        - 推測・補完・ダミー値の生成は禁止
      
        【最終確認(必須)】
        - 4項目がすべて取得・検証を通過したら、自然な日本語で全文復唱し、
          「この内容で登録してよろしいでしょうか?」と明確に問い、肯定(はい/お願いします/OK 等)を得る。
        - 肯定がない/曖昧な場合は登録確定をしない。
      
        【聞き取り失敗時の応答テンプレと回数】
        - 同一項目の聞き直しは最大3回。3回取得できない場合は ESCALATION を実行する。
      
      tools:
        - name: FOLLOW_UP_QUESTION
          description: >
            保護者の登録情報を一つずつ丁寧に確認するためのフォローアップ質問を行います(発話は自然な日本語で)。
            ※ RegistrationStatus は必ず "IN_PROGRESS" を返します。
          input_schema:
            type: object
            properties:
              message:
                type: string
                description: 次に確認したい1項目の質問文(音声向け表現)
              RegistrationStatus:
                type: string
                description: "IN_PROGRESS"
                enum: ["IN_PROGRESS"]
            required:
              - message
              - RegistrationStatus
      
        - name: CONFIRM_REGISTRATION
          description: >
            最終確認で保護者の明示的な肯定が得られた後に、登録を確定します。
            ※ message は発話用の自然な日本語。各フィールドはデータテーブル属性名と一致させること。
            ※ RegistrationStatus は必ず "COMPLETED" を返します。
          input_schema:
            type: object
            properties:
              message:
                type: string
                description: 登録完了メッセージ(発話用)
              RegistrationStatus:
                type: string
                description: "COMPLETED"
                enum: ["COMPLETED"]
              ParentPhoneNumber:
                type: string
                description: 保護者の電話番号(数字のみ推奨。10桁または11桁,保存時は先頭の0を+81に置換する)
              CallName:
                type: string
                description: お子様の呼び名
              ChildPhoneNumber:
                type: string
                description: お子様が掛けてくる電話番号(数字のみ推奨。10桁または11桁,保存時は先頭の0を+81に置換する)
              NotificationPhoneNumber:
                type: string
                description: 通知先電話番号(数字のみ推奨。10桁または11桁,保存時は先頭の0を+81に置換する)
            required:
              - message
              - RegistrationStatus
              - ParentPhoneNumber
              - CallName
              - ChildPhoneNumber
              - NotificationPhoneNumber
      
        - name: ESCALATION
          description: >
            取得が困難な場合に担当者へエスカレーションします。
            ※ RegistrationStatus は必ず "ESCALATED" を返します。
          input_schema:
            type: object
            properties:
              message:
                type: string
                description: エスカレーション前に保護者へ返す丁寧なメッセージ(発話用)
              RegistrationStatus:
                type: string
                description: "ESCALATED"
                enum: ["ESCALATED"]
            required:
              - message
              - RegistrationStatus
      
      messages:
        - role: user
          content: |
            Examples:
            <examples>
            <example>
              <conversation>
              [CUSTOMER] 登録したいです
              </conversation>
              {
                "type": "tool_use",
                "name": "FOLLOW_UP_QUESTION",
                "id": "tool_reg_001",
                "input": {
                  "message": "ありがとうございます。まず、保護者様のお電話番号をお願いします(例:090〜のように数字でお願いします)。",
                  "RegistrationStatus": "IN_PROGRESS"
                }
              }
            </example>
      
            <example>
              <conversation>
              [CUSTOMER] 090-1234-5678
              </conversation>
              {
                "type": "tool_use",
                "name": "FOLLOW_UP_QUESTION",
                "id": "tool_reg_002",
                "input": {
                  "message": "09012345678ですね。次に、お子様の呼び名を教えてください(例:たろう、はなちゃん、など)。",
                  "RegistrationStatus": "IN_PROGRESS"
                }
              }
            </example>
      
            <example>
              <conversation>
              [CUSTOMER] たろう
              </conversation>
              {
                "type": "tool_use",
                "name": "FOLLOW_UP_QUESTION",
                "id": "tool_reg_003a",
                "input": {
                  "message": "たろうくんですね。次に、お子様がAIサンタにかけてくるお電話番号をお願いします。",
                  "RegistrationStatus": "IN_PROGRESS"
                }
              }
            </example>
            
             <example>
              <conversation>
              [CUSTOMER] はなこ
              </conversation>
              {
                "type": "tool_use",
                "name": "FOLLOW_UP_QUESTION",
                "id": "tool_reg_003b",
                "input": {
                  "message": "はなこちゃんですね。次に、お子様がAIサンタにかけてくるお電話番号をお願いします。",
                  "RegistrationStatus": "IN_PROGRESS"
                }
              }
            </example>
      
            <example>
              <conversation>
              [CUSTOMER] 08011112222
              </conversation>
              {
                "type": "tool_use",
                "name": "FOLLOW_UP_QUESTION",
                "id": "tool_reg_004",
                "input": {
                  "message": "08011112222ですね。最後に、通知先のお電話番号をお願いします(保護者様の番号と同じでも大丈夫です)。",
                  "RegistrationStatus": "IN_PROGRESS"
                }
              }
            </example>
      
            <example>
              <conversation>
              [CUSTOMER] 09099998888
              </conversation>
              {
                "type": "tool_use",
                "name": "FOLLOW_UP_QUESTION",
                "id": "tool_reg_005_confirm",
                "input": {
                  "message": "09099998888ですね。内容を確認します。保護者様のお電話番号は09012345678、お子様の呼び名は「たろう」、お子様のお電話番号は08011112222、通知先お電話番号は09099998888。この内容で登録してよろしいでしょうか?",
                  "RegistrationStatus": "IN_PROGRESS"
                }
              }
            </example>
      
            <example>
              <conversation>
              [CUSTOMER] はい、お願いします
              </conversation>
              {
                "type": "tool_use",
                "name": "CONFIRM_REGISTRATION",
                "id": "tool_reg_006_finish",
                "input": {
                  "message": "ありがとうございます。登録が完了しました。AIサンタへのお電話をお待ちしております。メリークリスマス!",
                  "RegistrationStatus": "COMPLETED",
                  "ParentPhoneNumber": "+819012345678",
                  "CallName": "たろう",
                  "ChildPhoneNumber": "+818011112222",
                  "NotificationPhoneNumber": "+819099998888"
                }
              }
            </example>
      
            <example>
              <conversation>
              [CUSTOMER] (同一項目が3回連続で不明確)
              </conversation>
              {
                "type": "tool_use",
                "name": "ESCALATION",
                "id": "tool_reg_escalate_001",
                "input": {
                  "message": "確認が難しいため、担当者におつなぎします。少々お待ちください。",
                  "RegistrationStatus": "ESCALATED"
                }
              }
            </example>
            </examples>
      
            Input:
            <conversation>
            {{$.transcript}}
            </conversation>
      

image.png

上記のAIプロンプトは、チャット表示を前提に記号を含めるよう指示しているため、音声通話で使うと、それらがそのまま読み上げられたり、区切りが不自然になって聞き取りづらくなる場合があります。
音声通話で試す場合は、以下のように「読み上げ前提」の形に調整するのがおすすめです。

  • 箇条書き(「-」「:」など)や記号を減らし、短い文に分割する
  • 電話番号などの数字は区切って読み上げる表現にする(例:「ゼロ・キュー・ゼロ…」)

上記設定後、「保存」と「公開」をクリックします。

補足:AIプロンプトについて

Amazon Connectでは、E.164形式(日本番号の場合:+81xxxxxxxxxx)の電話番号を指定して受架電を行います。
一方で、音声対話やメッセージとしてユーザーに読み上げる場合、+81などの形式で出力すると、「プラス はちいち…」のように不自然な読み上げになります。
そのため、本AIプロンプトでは、以下のように「読み上げ用の電話番号」と「保存用の電話番号」を別々に管理するよう指示しています。

  【電話番号の表現ルール(読み上げと保存の分離)】
  - 音声で読み上げる場合や、message に出力する場合は必ず国内形式(090 / 080 など)で表現する。
  - データテーブルへ保存する際は、E.164 形式(+81xxxxxxxxxx)に正規化して保存する。
  - 正規化ルール:
    - 全角・ハイフン・空白を除去して数字のみを抽出する
    - 先頭が「0」の場合は「+81」に置換する
      例:09012345678 → +819012345678
    - すでに「+81」で始まっている場合はそのまま使用する
  - ユーザーへの発話では +81 形式を読み上げてはいけない
  - 発話と保存形式は一致していなくてよい(発話=国内形式、保存=+81)

Default AI Agent Configurationsの更新

「Amazon Connect管理者ワークスペース」>「AIエージェントデザイナー」>「AIエージェント」より、「Default AI Agent Configurations」の「Self Service」に設定されているAIエージェントをクリックし、「AIエージェントの作成」で作成したAIエージェントに変更します。

image.png

3.3.セルフサービス用Lexボットの作成

「Amazon Connect管理者ワークスペース」>「ルーティング」>「フロー」>「会話型AI」より「会話型AIボットを作成」をクリックします。

image.png

「会話型AI」タブが表示されていない場合、Amazon Connectインスタンスやセキュリティプロファイルの設定が不足している可能性があります。
こちらを参考に設定を見直してください。

  • Lexボットの設定
    • 名前:有効な文字からなる任意の文字列(例:SantaRegistrySelfServiceBot)
    • 説明:オプション
    • Children’s Online Privacy Protection Act (COPPA):いいえ
      image.png

上記設定後、「作成」をクリックします。

  • 詳細設定
    • 言語を追加:Japanese(JP)
    • Amazon Connect AI エージェントのインテント:有効
    • その他の設定:デフォルト(変更なし)

image.png

上記設定後、「ビルド言語」をクリックします。

3.4.事前登録用コンタクトフローの作成

コンタクトフローの作成

「Amazon Connect管理者ワークスペース」>「ルーティング」>「フロー」より、「フローを作成」をクリックします。

image.png

以下のようなコンタクトフローを作成します。

image.png

補足:事前登録用コンタクトフロー(.json)
{
  "Version": "2019-10-30",
  "StartAction": "ログ有効化",
  "Metadata": {
    "entryPointPosition": {
      "x": 84.8,
      "y": 54.4
    },
    "ActionMetadata": {
      "音声の種類を設定": {
        "position": {
          "x": 676,
          "y": 44
        },
        "isFriendlyName": true,
        "children": [
          "音声の種類を設定-j6r4UNqsT5"
        ],
        "parameters": {
          "TextToSpeechVoice": {
            "languageCode": "ja-JP"
          }
        },
        "overrideConsoleVoice": true,
        "fragments": {
          "SetContactData": "音声の種類を設定-j6r4UNqsT5"
        },
        "overrideLanguageAttribute": true
      },
      "音声の種類を設定-j6r4UNqsT5": {
        "position": {
          "x": 676,
          "y": 44
        },
        "isFriendlyName": true,
        "dynamicParams": []
      },
      "7d56d64c-cdb6-4d4a-b68f-f94b7ff8d71c": {
        "position": {
          "x": 201.6,
          "y": 244.8
        },
        "children": [
          "2fc5e56b-246a-42f4-9b21-d457cbac3ccb"
        ],
        "fragments": {
          "SetContactData": "2fc5e56b-246a-42f4-9b21-d457cbac3ccb"
        }
      },
      "2fc5e56b-246a-42f4-9b21-d457cbac3ccb": {
        "position": {
          "x": 201.6,
          "y": 244.8
        },
        "dynamicParams": []
      },
      "edd3e9e0-c5ff-4969-bb10-cfb342e8396e": {
        "position": {
          "x": 431.2,
          "y": 48
        }
      },
      "ログ有効化": {
        "position": {
          "x": 202.4,
          "y": 53.6
        },
        "isFriendlyName": true
      },
      "de047e56-6ade-4aef-ac13-5aaf101aacda": {
        "position": {
          "x": 1455.2,
          "y": 299.2
        }
      },
      "e084dd28-12bb-4f28-aac1-051f43862836": {
        "position": {
          "x": 1220,
          "y": 300
        }
      },
      "5989846c-c61c-4022-a913-a2fc6b09e658": {
        "position": {
          "x": 734.4,
          "y": 257.6
        },
        "conditions": [],
        "conditionMetadata": [
          {
            "id": "533750e1-863e-4451-a8dd-363e0f2944ae",
            "operator": {
              "name": "Equals",
              "value": "Equals",
              "shortDisplay": "="
            },
            "value": "CONFIRM_REGISTRATION"
          }
        ]
      },
      "df7a909f-fb08-4d79-837a-9f963c10b4de": {
        "position": {
          "x": 488,
          "y": 245.6
        },
        "parameters": {
          "LexV2Bot": {
            "AliasArn": {
              "displayName": "TestBotAlias",
              "useLexBotDropdown": true,
              "lexV2BotName": "SantaRegistrySelfServiceBot"
            }
          }
        },
        "useLexBotDropdown": true,
        "lexV2BotName": "SantaRegistrySelfServiceBot",
        "lexV2BotAliasName": "TestBotAlias",
        "conditionMetadata": []
      },
      "cb1d6ba8-4a77-4556-956d-c4689fe5da4a": {
        "position": {
          "x": 959.2,
          "y": 36.8
        },
        "conditions": [],
        "conditionMetadata": [
          {
            "id": "39568ae7-b5c8-46df-9c7d-03096337f813",
            "operator": {
              "name": "Equals",
              "value": "Equals",
              "shortDisplay": "="
            },
            "value": "COMPLETED"
          }
        ]
      },
      "8ba985f8-0bdc-4555-8a7f-8cc6af5b81a2": {
        "position": {
          "x": 1743.2,
          "y": 207.2
        }
      },
      "Basicキューに設定": {
        "position": {
          "x": 971.2,
          "y": 299.2
        },
        "isFriendlyName": true,
        "parameters": {
          "QueueId": {
            "displayName": "testQueue"
          }
        },
        "queue": {
          "text": "testQueue"
        }
      },
      "b245fc9f-f617-4676-85d5-1ffdc6b63883": {
        "position": {
          "x": 1230.4,
          "y": 34.4
        },
        "parameters": {
          "Attributes": {
            "CallName": {
              "useDynamic": true
            },
            "ChildPhoneNumber": {
              "useDynamic": true
            },
            "NotificationPhoneNumber": {
              "useDynamic": true
            },
            "ParentPhoneNumber": {
              "useDynamic": true
            }
          }
        },
        "dynamicParams": [
          "CallName",
          "ChildPhoneNumber",
          "NotificationPhoneNumber",
          "ParentPhoneNumber"
        ]
      },
      "3e58c007-805e-4292-9f3c-9c4c2f90981b": {
        "position": {
          "x": 1471.2,
          "y": 36
        },
        "parameters": {
          "DataTableId": {
            "displayName": "SantaRegistration2025"
          }
        }
      }
    },
    "Annotations": [],
    "name": "SantaRegistrationFlow",
    "description": "",
    "type": "contactFlow",
    "status": "PUBLISHED",
    "hash": {}
  },
  "Actions": [
    {
      "Parameters": {
        "TextToSpeechEngine": "Neural",
        "TextToSpeechStyle": "None",
        "TextToSpeechVoice": "Kazuha"
      },
      "Identifier": "音声の種類を設定",
      "Type": "UpdateContactTextToSpeechVoice",
      "Transitions": {
        "NextAction": "音声の種類を設定-j6r4UNqsT5",
        "Errors": [
          {
            "NextAction": "7d56d64c-cdb6-4d4a-b68f-f94b7ff8d71c",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "LanguageCode": "ja-JP"
      },
      "Identifier": "音声の種類を設定-j6r4UNqsT5",
      "Type": "UpdateContactData",
      "Transitions": {
        "NextAction": "7d56d64c-cdb6-4d4a-b68f-f94b7ff8d71c",
        "Errors": [
          {
            "NextAction": "7d56d64c-cdb6-4d4a-b68f-f94b7ff8d71c",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "WisdomAssistantArn": "arn:aws:wisdom:ap-northeast-1:123456789012:assistant/11111111-1111-1111-1111-111111111111"
      },
      "Identifier": "7d56d64c-cdb6-4d4a-b68f-f94b7ff8d71c",
      "Type": "CreateWisdomSession",
      "Transitions": {
        "NextAction": "2fc5e56b-246a-42f4-9b21-d457cbac3ccb",
        "Errors": [
          {
            "NextAction": "df7a909f-fb08-4d79-837a-9f963c10b4de",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "WisdomSessionArn": "$.Wisdom.SessionArn"
      },
      "Identifier": "2fc5e56b-246a-42f4-9b21-d457cbac3ccb",
      "Type": "UpdateContactData",
      "Transitions": {
        "NextAction": "df7a909f-fb08-4d79-837a-9f963c10b4de",
        "Errors": [
          {
            "NextAction": "df7a909f-fb08-4d79-837a-9f963c10b4de",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "RecordingBehavior": {
          "RecordedParticipants": [
            "Agent",
            "Customer"
          ],
          "IVRRecordingBehavior": "Disabled"
        },
        "AnalyticsBehavior": {
          "Enabled": "True",
          "AnalyticsLanguage": "ja-JP",
          "AnalyticsRedactionBehavior": "Disabled",
          "AnalyticsRedactionResults": "None",
          "ChannelConfiguration": {
            "Chat": {
              "AnalyticsModes": [
                "ContactLens"
              ]
            },
            "Voice": {
              "AnalyticsModes": [
                "RealTime"
              ]
            }
          },
          "SentimentConfiguration": {
            "Enabled": "True"
          }
        }
      },
      "Identifier": "edd3e9e0-c5ff-4969-bb10-cfb342e8396e",
      "Type": "UpdateContactRecordingBehavior",
      "Transitions": {
        "NextAction": "音声の種類を設定"
      }
    },
    {
      "Parameters": {
        "FlowLoggingBehavior": "Enabled"
      },
      "Identifier": "ログ有効化",
      "Type": "UpdateFlowLoggingBehavior",
      "Transitions": {
        "NextAction": "edd3e9e0-c5ff-4969-bb10-cfb342e8396e"
      }
    },
    {
      "Parameters": {},
      "Identifier": "de047e56-6ade-4aef-ac13-5aaf101aacda",
      "Type": "TransferContactToQueue",
      "Transitions": {
        "NextAction": "8ba985f8-0bdc-4555-8a7f-8cc6af5b81a2",
        "Errors": [
          {
            "NextAction": "8ba985f8-0bdc-4555-8a7f-8cc6af5b81a2",
            "ErrorType": "QueueAtCapacity"
          },
          {
            "NextAction": "8ba985f8-0bdc-4555-8a7f-8cc6af5b81a2",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "オペレータに繋げています。\nしばらくお待ちください。"
      },
      "Identifier": "e084dd28-12bb-4f28-aac1-051f43862836",
      "Type": "MessageParticipant",
      "Transitions": {
        "NextAction": "de047e56-6ade-4aef-ac13-5aaf101aacda",
        "Errors": [
          {
            "NextAction": "de047e56-6ade-4aef-ac13-5aaf101aacda",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "ComparisonValue": "$.Lex.SessionAttributes.Tool"
      },
      "Identifier": "5989846c-c61c-4022-a913-a2fc6b09e658",
      "Type": "Compare",
      "Transitions": {
        "NextAction": "Basicキューに設定",
        "Conditions": [
          {
            "NextAction": "cb1d6ba8-4a77-4556-956d-c4689fe5da4a",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "CONFIRM_REGISTRATION"
              ]
            }
          }
        ],
        "Errors": [
          {
            "NextAction": "Basicキューに設定",
            "ErrorType": "NoMatchingCondition"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Text": "AIサンタ予約窓口です。\n登録をご希望の方は、「登録」と入力してください。",
        "LexV2Bot": {
          "AliasArn": "arn:aws:lex:ap-northeast-1:123456789012:bot-alias/XXXXXXXXXX/TSTALIASID"
        }
      },
      "Identifier": "df7a909f-fb08-4d79-837a-9f963c10b4de",
      "Type": "ConnectParticipantWithLexBot",
      "Transitions": {
        "NextAction": "5989846c-c61c-4022-a913-a2fc6b09e658",
        "Errors": [
          {
            "NextAction": "5989846c-c61c-4022-a913-a2fc6b09e658",
            "ErrorType": "NoMatchingCondition"
          },
          {
            "NextAction": "5989846c-c61c-4022-a913-a2fc6b09e658",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "ComparisonValue": "$.Lex.SessionAttributes.RegistrationStatus"
      },
      "Identifier": "cb1d6ba8-4a77-4556-956d-c4689fe5da4a",
      "Type": "Compare",
      "Transitions": {
        "NextAction": "b245fc9f-f617-4676-85d5-1ffdc6b63883",
        "Conditions": [
          {
            "NextAction": "b245fc9f-f617-4676-85d5-1ffdc6b63883",
            "Condition": {
              "Operator": "Equals",
              "Operands": [
                "COMPLETED"
              ]
            }
          }
        ],
        "Errors": [
          {
            "NextAction": "b245fc9f-f617-4676-85d5-1ffdc6b63883",
            "ErrorType": "NoMatchingCondition"
          }
        ]
      }
    },
    {
      "Parameters": {},
      "Identifier": "8ba985f8-0bdc-4555-8a7f-8cc6af5b81a2",
      "Type": "DisconnectParticipant",
      "Transitions": {}
    },
    {
      "Parameters": {
        "QueueId": "arn:aws:connect:ap-northeast-1:123456789012:instance/11111111-1111-1111-1111-111111111111/queue/11111111-1111-1111-1111-111111111111"
      },
      "Identifier": "Basicキューに設定",
      "Type": "UpdateContactTargetQueue",
      "Transitions": {
        "NextAction": "e084dd28-12bb-4f28-aac1-051f43862836",
        "Errors": [
          {
            "NextAction": "e084dd28-12bb-4f28-aac1-051f43862836",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "Attributes": {
          "CallName": "$.Lex.SessionAttributes.CallName",
          "ChildPhoneNumber": "$.Lex.SessionAttributes.ChildPhoneNumber",
          "NotificationPhoneNumber": "$.Lex.SessionAttributes.NotificationPhoneNumber",
          "ParentPhoneNumber": "$.Lex.SessionAttributes.ParentPhoneNumber"
        },
        "TargetContact": "Current"
      },
      "Identifier": "b245fc9f-f617-4676-85d5-1ffdc6b63883",
      "Type": "UpdateContactAttributes",
      "Transitions": {
        "NextAction": "3e58c007-805e-4292-9f3c-9c4c2f90981b",
        "Errors": [
          {
            "NextAction": "3e58c007-805e-4292-9f3c-9c4c2f90981b",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    },
    {
      "Parameters": {
        "LockVersion": "LATEST",
        "DataTableId": "1f1ddd95-1491-49c5-be12-50cc701dd939",
        "DataTableUpsertAttributes": [
          {
            "PrimaryKeyGroupName": "ChildRegistration",
            "PrimaryValues": [
              {
                "Name": "ChildPhoneNumber",
                "Value": "$.Attributes.ChildPhoneNumber"
              }
            ],
            "Attributes": [
              {
                "Name": "CallName",
                "Value": "$.Attributes.CallName",
                "UseDefaultValue": false
              },
              {
                "Name": "NotificationPhoneNumber",
                "Value": "$.Attributes.NotificationPhoneNumber",
                "UseDefaultValue": false
              },
              {
                "Name": "ParentPhoneNumber",
                "Value": "$.Attributes.ParentPhoneNumber",
                "UseDefaultValue": false
              }
            ]
          }
        ]
      },
      "Identifier": "3e58c007-805e-4292-9f3c-9c4c2f90981b",
      "Type": "UpsertDataTableValues",
      "Transitions": {
        "NextAction": "8ba985f8-0bdc-4555-8a7f-8cc6af5b81a2",
        "Errors": [
          {
            "NextAction": "Basicキューに設定",
            "ErrorType": "NoMatchingError"
          }
        ]
      }
    }
  ]
}

補足:主要ブロックの設定値

  • 「コネクトアシスタント」ブロック

    • ドメインを選択:Amazon Connectインスタンスに紐づいているAIエージェントドメイン
    • AI エージェント – エージェントアシスタンス:オフ
      image.png
  • 「顧客の入力を取得する」ブロック

    • Amazon Lex
      • Lexボット:作成したセルフサービス用ボット(SantaRegistrySelfServiceBot)
      • エイリアス:TestBotAlias
      • カスタマープロンプトまたはボットの初期化
        • テキスト読み上げまたはチャットテキスト
          • AIサンタ予約窓口です。登録をご希望の方は、「登録」と入力してください。

    image.png
    image.png

  • 「コンタクト属性を確認する」ブロック①

    • 確認する属性
      • 名前空間:Lex
      • キー:セッション属性
      • セッション属性キー:Tool
    • チェックする条件
      • 条件:次と等しい
      • キー:CONFIRM_REGISTRATION

    image.png

  • 「コンタクト属性を確認する」ブロック②

    • 確認する属性
      • 名前空間:Lex
      • キー:セッション属性
      • セッション属性キー:RegistrationStatus
    • チェックする条件
      • 条件:次と等しい
      • キー:COMPLETED

image.png

※上記2種類の条件は、AIプロンプト内で定義しているカスタムツールの戻り値が以下の条件のいずれかを満たす場合に、担当窓口にルーティングするよう設計しています

  1. 顧客情報のヒアリングに複数回失敗した時
  2. 発信者からオペレーターに繋ぐよう指示があった時
  • 「データテーブル」ブロック
    • アクション:データテーブルへの書き込み
    • データテーブル:作成したデータテーブル(SantaRegistration2025)
    • プライマリの値グループ1
      • 名前:ChildRegistration
      • ParentPhoneNumber(プライマリ属性):$.Attributes.ChildPhoneNumber
    • 属性
      • CallName:$.Attributes.CallName
      • NotificationPhoneNumber:$.Attributes.NotificationPhoneNumber
      • ChildPhoneNumber:$.Attributes.ParentPhoneNumber

image.png

以上でコンタクトフローの設定は完了です。
コンタクトフローに名前をつけ、画面右上の「保存」、「公開」をクリックし、フローを公開します。

4.動作確認

音声通話またはチャットで動作確認を行います。
音声通話で動作確認を行う場合は、「事前登録用コンタクトフローの作成」で作成したコンタクトフローを取得した電話番号に紐づけてください。

image.png

お子様情報の事前登録チャット例

「登録したい」と入力後、それぞれ以下の値を入力することでデータテーブルへの登録処理が完了します。

  • 保護者電話番号(ParentPhoneNumber)
  • お子様の呼び名(CallName)
  • AIサンタへかける発信元電話番号(ChildPhoneNumber)
  • 希望プレゼントの通知先電話番号(NotificationPhoneNumber)

image.png

ヒアリング情報の確認フェーズ

image.png

チャット終了時のメッセージ

image.png

チャット終了後、データテーブルを確認すると入力した値が保存されていることがわかります。

image.png

まとめ

本記事では、Amazon Connectを使って「子どもの夢を壊さずに、保護者へ欲しいものを届ける」AIサンタの仕組みのうち、保護者による事前登録機能までの構築方法を紹介しました。Amazon Connect AI Agents(旧 Amazon Q in Connect)のカスタマーセルフサービス機能と、Amazon Connectデータテーブルを組み合わせることで、外部DBや複雑なバックエンドを用意せずにデータの登録フローを実現できるようになりました。

次回(第2部)は、実際にお子様が「AIサンタ」と会話し、その内容から取得した「欲しいもの」を保護者へ通知する仕組みを実装していきます。

13
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?