こんにちは、広野です。
生成 AI 界隈の技術の進化がすさまじく、以前開発したチャットボットのアーキテクチャも陳腐化が見えてきました。この記事を執筆している時点での最新のアーキテクチャで改めて作り直してみたので、いくつかの記事に分けて紹介します。
今回 (初回) はアーキテクチャ概要編です。実装編を以降執筆します。
インスピレーションを受けた記事
私がチャットボットを作り直そうと思ったきっかけは、以下の記事を読んだことでした。

re:Invent 2024: AWS AppSyncでAmazon Bedrockの AI Gateway構築

re:Invent 2024: AWS AppSync Eventsによるリアルタイムイベント処理
いずれも re:Invent 2024 のセッション動画から AWS さんが 生成 AI (Amazon Bedrock) で自動作成した記事なので、つまりは re:invent 2024 がインプットなわけですが、
を考えたときに、ああ、今だったらこうすればいいんだ というように腹落ちさせてくれた記事でした。
実際には、この記事の内容に改良を加えています。
つくったもの
以下のアニメーション GIF をご覧ください。
- テキスト問い合わせのみのチャットボットです。
- 自動スクロール機能はありません。
- 会話履歴は残りません。
- 上の画像ではわかりませんが、マークダウンに対応しています。
- UI パーツは MUI を使用しています。
- 生成 AI 基盤モデルは Amazon Nova micro です。
フロントエンドで使用している言語、モジュール等
- React 19.1.0 : 開発フレームワーク
- react-router 7.7.1 : 画面遷移制御
- @mui/material 7.2.0 : UI パーツ
- aws-amplify 6.15.4 : AWS リソース連携
- aws-amplify/ui-react 6.11.2 : UI パーツ
- axios 1.11.0 : API 呼出
- markdown-to-jsx 7.7.12: マークダウン
- vite 7.0.6 : ビルドツール
アーキテクチャ
以下のアーキテクチャで基盤を構築しています。
全体的な流れの解説
- アプリケーションは AWS Amplify Hosting で配信、認証システムには Amazon Cognito を使用しています。
- アプリ UI からチャットボットに問い合わせると、Amazon API Gateway にリクエストを投げます。
- API Gateway は問い合わせ内容を受け付けた後、背後にある AWS Lambda 関数にリクエストを渡した後、処理完了をアプリに返します。(非同期呼出)
- 呼び出された Lambda 関数は Amazon Bedrock の生成 AI 基盤モデルにリクエストを投げます。この部分の認証は IAM です。
- Amazon Bedrock はレスポンスを細切れに (チャンク分割して) AWS AppSync Events API にパブリッシュします。AWS AppSync Events はいわゆる Pub/Sub 機能を提供するサービスです。
- AppSync Events API は、パブリッシュされたメッセージ (細切れのレスポンス) を、クライアントからサブスクライブしてもらうエンドポイントを持っています。アプリがあらかじめ指定のエンドポイントをサブスクライブしておけば、メッセージがパブリッシュされたタイミングでリアルタイムにアプリに配信されます。
- アプリが受け取ったメッセージは細切れになっているので、受け取った順に結合してアプリ画面に表示します。これにより、テキストが順番に流れるような表現 (ストリームレスポンス) を実現できます。
特長(良いところ)
フルサーバーレスである
- 基盤がマネージドサービスなので、その辺りのメンテや拡張性を基本気にすることがありません。
- 利用料金が安いです。
認証を Amazon Cognito に統一している
- アプリの認証ができれば、その認証情報を元に Amazon API Gateway, AWS AppSync の認証が通るようになっています。
- アプリから認証に必要な ID 等を改ざん可能なパラメータとして Amazon API Gateway, AWS AppSync には渡さず、それぞれのリクエスト受け取り側リソースで証明書から ID を取得し、ID 偽装をチェックしています。
AppSync Events の Pub/Sub 権限設計が柔軟で使いやすい
- AWS AppSync Events API はチャンネルという単位で Pub/Sub メッセージ授受範囲を管理します。チャンネル名は / 区切りで階層構造を持たせ、それを利用した権限制御が可能です。
- チャンネルは最上位層だけ固定名で設定が必要ですが、以降はクライアントから Pub/Sub するときに無いものは自動で作成されます。あらかじめ、パブリッシュ側、サブスクライブ側で決めたチャンネル命名ルールを守っていればやり取りができます。チャンネル名のセキュアな共有と権限設定ができれば、1対多、多対1、多対多の Pub/Sub が容易に実装できます。
- チャンネル名に Amazon Cognito ユーザーの属性を含めることができます。今回の例ですと、Amazon Cognito ユーザー ID をチャンネル名に含めており、メッセージが自分だけに配信されるようにすることができます。
従来のアーキテクチャと比較して
- 一番嬉しいのは、GraphQL を一切使用しない点です。従来の AppSync GraphQL API でも Pub/Sub はできましたが、GraphQL のスキーマやリゾルバ設定が難解で、理解できたとしても複雑で面倒でした。AppSync Events API はそのストレスから解放してくれました。
以下は、従来のアーキテクチャを紹介したブログ記事です。AWS AppSync GraphQL API を使用していました。
- AWS Lambda 関数へのリクエストが非同期になり、行き (リクエスト) と帰り (レスポンス) で経路が異なります。これにより、API Gateway が持つレスポンスタイムアウト制限が無制限に解放されました。
とは言え、デメリット (と言うか未解決事項) として AWS Lambda 関数の実行時間がかさむことが残っています。レスポンスが終了するまで AWS Lambda 関数を実行し続けなければなりません。
以下は、従来の AWS Lambda 関数 URL を使用した同期呼出のアーキテクチャ紹介記事です。
AWS Lambda 関数を API 化するとセキュリティ設定が難しくなったり、面倒な設計をしないといけなくなったりするので、API が API Gateway REST API に戻ったのもセキュリティ面、可用性面でもメリットがあると感じています。
- 今時点の設計でイケてないと思うのは、サブスクリプションを張りっぱなしのため、Amazon Bedrock からのレスポンスの明確な終了がわからないところです。問い合わせに対するレスポンスの終了フラグがないんです。
そのため、例えばレスポンス生成中は 待ち状態のグルグルアイコン を表示して、レスポンスが完了したら消す、というエフェクトを入れたいのですが入れられず。実はやり方があるのかもしれませんが調べきれていません。Lambda 関数を閉じる直前に何か送る、というのを考えたいですね。
続編記事
実装編記事が出来次第、この章を更新します。
まとめ
いかがでしたでしょうか。
生成 AI 界隈は進化が速いので、この記事の賞味期限もいつまでなのやら・・・。でも、AWS AppSync Events は AI に関係なく使いやすいサービスに仕上がっているので、今後多用していきたいと思っています。
本記事が皆様のお役に立てれば幸いです。