こんにちは。エンジニアの落合です。
こちらはAmazon Connect Advent Calendar 2025 23日目の記事です。
今回は、Amazon ConnectでAI音声対話システムを作成したので紹介します。
はじめに
Amazon ConnectがテーマのLT会への登壇のお話をいただいたので、初めてAmazon Connectを使ってみました。
Amazon Connectといえば「コールセンター」のイメージが強かったのですが、先日参加させていただいたイベントで、コールセンター以外のシステムにも使えることを知りました。
ということで、今回はLexと組み合わせて、音声対話ができるシステムを作成してみました。
アーキテクチャ
作成したアーキテクチャは以下のような簡単なものになります。
- Amazon Connect:電話受付、応答などの音声部分を担当
- Amazon Lex:音声認識を文字に変換してLambdaに渡す
- AWS Lambda:入力を受けてBedrockを呼び出し、プロンプトと入力内容を渡す
- Amazon Bedrock:Lambdaで設定したプロンプトに基づいて音声テキストを生成

各サービスの設定内容
Lambda
Lambdaコンソールを開いて、新しい関数を作成します。
設定した内容は以下の通りです。
- 関数名:PhonePartnerFunction
- ランタイム:Python3.14
- アーキテクチャ:x86_64
- 実行ロール:基本的なLambdaアクセス権限で新しいロールを作成
続いて必要な実行ロールを設定していきます。
作成した関数の設定 > アクセス権限 > ロール名から作成されたロールを開きます。
今回は以下のリソースとアクションを設定しました。
- CloudWatch:logs:CreateLogGroup、logs:CreateLogStream、logs:PutLogEvents
- Bedrock:bedrock:RetrieveAndGenerate、bedrock:Retrieve、bedrock:InvokeModel
リソースベースのポリシーステートメントにLexを追加する必要がありますが、こちらは後程LexでBotを作成した後に設定します。
コードは以下のように記載しました。
Bedrockのモデルは日本語に強いClaude 3 Haikuを利用しています。
今回話し相手として設定したプロンプトは
「あなたは「優しくて聞き上手なカウンセラー」です。相手の話に共感し、短く簡潔に(50文字以内)、温かい口調で返事をしてください。」
にしました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
import json import boto3 import os # Bedrockクライアントのみをグローバル初期化 try: bedrock = boto3.client(service_name='bedrock-runtime') except Exception as e: print(f"FATAL BEDROCK INIT ERROR: {e}") bedrock = None def invoke_claude(system, history, prompt): # グローバル変数bedrockの初期化チェック if bedrock is None: raise Exception("Bedrock client is not initialized.") # リクエストボディ作成 body = json.dumps({ "anthropic_version": "bedrock-2023-05-31", "max_tokens": 100, "system": system, "messages": [ {"role": "user", "content": f"History: {history}\n\nCurrent Input: {prompt}"} ] }) response = bedrock.invoke_model( body=body, modelId="anthropic.claude-3-haiku-20240307-v1:0", accept="application/json", contentType="application/json" ) response_body = json.loads(response.get('body').read()) return response_body['content'][0]['text'] def lambda_handler(event, context): # Lex V2からの入力テキストを取得 try: session_state = event.get('sessionState', {}) intent_data = session_state.get('intent', {}) slots = intent_data.get('slots', {}) free_input_slot = slots.get('FreeInput', {}) # スロットが存在し、かつ 'value' キーがあるか確認 if free_input_slot and free_input_slot.get('value'): user_input = free_input_slot['value'].get('originalValue', '(入力なし)') else: # スロット値がない場合は、イベント全体からテキストを探すか、デフォルト値を設定 user_input = "挨拶" # Lexがインテントにマッチしたことを示すだけのダミーテキスト session_id = event.get('sessionId', 'test-session-id') except Exception as e: print(f"ERROR OCCURRED DURING INPUT PARSE: {e}") user_input = "システムエラー" session_id = "error-session" # 履歴を空にする history ="" system_prompt = "あなたは「優しくて聞き上手なカウンセラー」です。相手の話に共感し、短く簡潔に(50文字以内)、温かい口調で返事をしてください。" try: # Bedrock呼び出し response_text = invoke_claude(system_prompt, history, user_input) except Exception as e: print(f"BEDROCK CALL FAILED: {e}") response_text = "ごめんなさい、AIとの接続に問題が発生しました。" # Lex/Connectへの返却 return { "sessionState": { "dialogAction": { "type": "ElicitIntent" }, "intent": { "name": intent_data.get('name'), "state": "Fulfilled" } }, "messages": [ { "contentType": "PlainText", "content": response_text } ] } |
これでLambdaの設定は完了です。
Lex
続いてLexの設定に移ります。
Lexのコンソールで「ボットの作成」を選択し、以下を設定します。
- 作成方法:空のボットを作成
- ボット名:PhonePartnerBot
- ランタイムロール:基本的な Amazon Lex 権限を持つロールを作成します。
- エラーログ:有効
- 児童オンラインプライバシー保護法:いいえ(はいを選択すると会話ログが使用できなくなるため)
参考:https://blog.usize-tech.com/amazon-lex-v2-selective-conversation-log-capture/#toc5
「次へ」をクリックし、同様に以下の設定をして「完了」をクリックします。
- 言語:Japanese(JP)
- 音声による対話:お好みで設定(今回はデフォルトのKazuhaを利用)
インテントを設定します。
- インテント名:AskDocument
「スロットの追加」をクリックして、スロットを設定します。
- スロット名:Question
- スロットタイプ:AMAZON.FreeFormInput
- プロンプト:(質問時に流したい音声を設定) どうされましたか?
- コードフック欄の「初期化と検証に Lambda 関数を使用」チェック
インテントを保存 > インテントリストに戻る の順にクリックします。
エイリアスの設定をします。
左メニューのデプロイ > エイリアス > TestBotAliasを選択して下記を設定します。
- 言語:Japanese(JP)
上で作ったLambda関数を選択して「保存」をクリックします。
インテント設定に戻り、「構築」をクリックすると設定完了、のはずでしたがエラーが出ました。
|
1 |
「The locale 'ja_JP' doesn't have any utterances. A locale must have at least one custom intent with a valid utterance. Add a custom intent and try your request again.」 |
どうやらLexには「最低でも1つは『普通のインテント(自作の意図)』があり、それに『サンプル発話』が登録されていないと、ボットとして認めない(ビルドさせない)」ルールがあるみたいです。
エラーを解決するためにダミーインテントを追加しておきます。
インテントを追加 > 空のインテントを追加の順にクリックして、以下の設定をします。
- インテント名:HelloIntent(何でもOK)
- サンプル発話:「こんにちは」を追加(ここも何でもOK)
インテントを保存 > 構築の順にクリックすると、今度は無事に構築ができました!
上記を設定後、作成したLambda関数を開き、設定 > アクセス権限 > リソースベースのポリシーステートメントの「アクセス権限を追加」をクリックして、作成したLexのBotのポリシーステートメントを追加しておきます。
※これをしないとLexからLambdaを呼び出せないので必ず設定します!
Connect
いよいよAmazon Connectの構築に移ります。
Amazon Connectのコンソールで「インスタンスを追加する」をクリックし、インスタンスエイリアスを設定して「次へ」をクリックします。
※Connectの管理画面のドメインになります
管理画面にログインするためのユーザーを作成します。
次の画面で、テレフォニーオプションの「着信を許可する」と「発信を許可する」の両方にチェックが入っていることを確認して「次へ」をクリックします。
その他の設定はデフォルトのまま確認画面まで行き「インスタンスを作成」をクリックします。
インスタンスの状態が「アクティブ」になればOKです!
LexボットをAmazon Connectで使えるように設定します。
作成したインスタンスのインスタンスエイリアスをクリックし、左メニューの「問い合わせフロー」をクリックします。
Amazon Lex設定欄を以下のように設定します。
- リージョン:Lexを作ったリージョン
- ボット:PhonePartnerBot(先程作成したボット名)
- エイリアス:TestBotAlias
「Amazon Lexボットを追加」をクリックして設定完了です。これでAmazon Connectのフローで追加したLexボットを選択できるようになります。
管理画面に遷移して、インスタンスの中身を設定します。
インスタンスエイリアスを再度クリックし、「Access URL」をクリックします。
別タブでログイン画面が開くので、先程作成した管理アカウントでログインします。
初期設定では言語が英語になっているので、右上のアカウントをクリックしてLanguageを「日本語」に変更すると便利です。

左メニューのチャネル(一番下の受話器アイコン) < 電話番号の順に選択して、「電話番号の取得」をクリックします。
電話番号の国/地域を「United States」に選択します。日本の番号は取得するために会社登録書類等が必要なためです。
表示された番号候補から好きなものを選んで画面右上の「保存」をクリックします。
番号は早いもの勝ちなので他の人に先に取られたみたいで、私は3回ほどエラーになってようやく番号が取れました……何度かエラーになっても諦めずに頑張ってください。
続いてコンタクトフローを作成します。
左メニューのルーティング > フローを選択し、「フローを作成」をクリックします。
今回作成したフローは以下の通りです。
最初はAIの固定音声を流し、その後はLexの処理をループさせています。
1つのブロックのみをループさせることはできなかったので、ダミーで「コンタクト属性の設定」ブロックを入れています。

電話番号画面に戻り、取得した電話番号を選択して、「コンタクトフロー/IVR」で作成したフローを選択して紐づけます。
これでAI音声対話システムの完成です!
まとめ
今回初めてAmazon Connectを利用しましたが、フロー作成がドラッグ&ドロップで簡単かつ直感的にできてしまうことや、電話番号取得からフロー作成までが数分でできることに驚きました。
電話番号取得や他サービスとの連携に手間取りましたが、実際にフローが通ると感動しますね…。
他サービスとの連携次第で当初想像していたよりも色々な用途に使えそうだったので、今後試してみようと思います!
- Amazon Connectで理想の相談相手をつくってみた - 2025-12-23
- 【Kiro・Playwright】社内でフルAI開発バトル!!「1行も書かずに」Todoアプリを完成させた話〜落合の場合〜 - 2025-12-02
- SageMakerの機能と料金体系を整理してみた - 2025-11-26
- Amazon Q Developerで理想の家計簿アプリを作ってみた - 2025-09-30
- 【夏の自由研究】Raspberry Piを使って色々試してみた② ~電子工作編~ - 2025-08-28
【採用情報】一緒に働く仲間を募集しています






