はじめに
こんにちは。皆さん生成AI触ってますか。
最近はAIの情報が何かと多いですね。まさに先日ChatGPT5.4モデルが出たり、Qwen3.5の軽量モデルがすごくいい感じに動いたり。
そんなAIAI言っている私ですが、恥ずかしながら”Amazon Bedrock”については聞いたことがあるものの、ちゃんと触ったことがない。という状態です。
そもそもAWS上で何か構築する…というのもEC2ちょっと立ててみたり、月額14円で実現。SwitchBot + AWS + LINEで作る洗濯機の完了通知(←ぜひ読んでみてね)を構築してみたぐらいであまりなじみがないのだけれど。
というわけで今回は、簡単な感じで使えそうなアーキテクチャを構築してみました。
本記事では、AWSの色々を触りながら、以下の構成を目指すための手順を紹介しようと思います。
本記事はお試しレベルの構成です。IAMポリシーとかPoC向けに緩く設定している箇所があります。
あと今回、途中までGUIで頑張って構築してたんですが、AWS Login → AWS Cliを使う流れが初心者にとって希望の光すぎたので、その話はまた別の記事で紹介します!
今回やりたいこと
- 生成AIが不動産情報を教えてくれるWEBチャットアプリを作りたい
- そこまでお金をかけずに、安価でかつ、わかりやすい構成で作りたい
- Amazon Bedrockをお試しで使ってみたい
構成の概要
| レイヤー | サービス | 役割 |
|---|---|---|
| フロントと配信 | Amazon S3 + Amazon CloudFront | 静的ファイル置き場とホスティング |
| API | API Gateway (HTTP API) | POST /chat を受け付け |
| バックエンド | AWS Lambda | チャット処理のロジックの部分 |
| LLM | Amazon Bedrock | LLMのテキスト生成 |
| 監視 | Amazon CloudWatch | ログの集約 |
-
index.htmlやfrontend-config.jsなどは CloudFront 経由で S3 から持ってくる - チャット送信時は、ブラウザから API Gateway の URL に直接
POST /chat - API Gateway から Lambda を呼び出し、Lambda が Bedrock に問い合わせる
多分、実際はCloudFrontにAPIも載せて、単一の入り口とかにするのかな…。とも思いましたが、今回は設定が良く分からなくなるのを防ぐためこのような構成にしてます。分離していたほうが何かとわかりやすい。(気がする)
Converse APIとは?
どうもBedrockには Invoke と Converse という二つの呼び出し方法があるようで。
InvokeModel – プロンプトを送信し、レスポンスを生成します。リクエスト本文はモデル固有です。ストリーミングレスポンスを生成するには、InvokeModelWithResponseStream を使用します。
Converse – プロンプトを送信し、すべてのモデルにわたって統合された構造でレスポンスを生成します。モデル固有のリクエストフィールドを additionalModelRequestFields フィールドで指定できます。コンテキストがわかるように、システムプロンプトと以前の会話を含めることもできます。ストリーミングレスポンスを生成するには、ConverseStream を使用します。
https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/inference-api.html
簡単にいうと、モデルごとの差をそのまま扱うタイプ(Invoke)と、モデルごとで統一した形式となるタイプか(Converse)。という話です。モデルを後から差し替えることを考えると、Converseを選ぶのがいいのかな、と思いました。
事前準備
以下の準備をしました。
用意したファイルたち
backend/src/
├── chat.js
├── package.json
└── package-lock.json
frontend/
├── index.html
├── frontend-config.js
└── error.html
htmlやjsのファイルについてはClaude Codeくんと一緒にやりました。chat.jsで諸々のレスポンスを管理したり、mockモード、bedrockモードの場合の挙動を管理したりしてます。index.htmlはclaudecodeくんがいい感じにChatっぽいUIをつくってくれました。
ちなみに、本プロジェクトでは、不動産アシスタントみたいなものを想定して作ったのでchat.jsの中に
'あなたは日本語で回答する不動産データアシスタントです。',
'以下の入力に対して、200〜400文字の簡潔な要約を作成してください。',
みたいなシステムプロンプトを挿入しています。
作成したバックエンド一式は Lambda にアップロードするため、backend/src で npm install を実行して、その後 zip化してデプロイ用ファイルを作成してます。
Step1:Bedrockでモデル利用申請?する
今回、この検証では、Claude Haiku 4.5を使います。以前までは、モデルアクセスの有効化というものがあったらしいですが、今は必須でないようです。
ただAnthropic社が提供するモデルを使用するには、アクセスをリクエストする前にユースケースが何か等送信する必要があります。
申請フォームが出てくるので、名前とかユースケースを入力したら使えるようになりました。
Step2: IAMロールを編集する
- IAM → ロール → ロール作成
- AWSサービスを選び、画面下部のプルダウンからLambdaを選択
- AWSLambdaBasicExecutionRoleを選んで付与して作成完了
こんな感じで設定しました。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BedrockInvoke",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "*"
}
]
}
ちなみに、Converse を呼ぶために必要な IAMはbedrock:InvokeModelで、ConverseStream なら bedrock:InvokeModelWithResponseStreamとのことで、bedrock:converseとかは記載しないらしい。
Step3: Lambdaの作成
こんな感じで設定しました。
- Function name: ai-chatbot-poc-chat
- Runtime: Node.js 22.x
- Memory: 256 MB
- Timeout: 15 秒
また、環境変数の例ですが
| キー | 値 | 備考 |
|---|---|---|
CHAT_MODE |
mock |
疎通確認用、後で bedrock に変更 |
MODEL_ID |
anthropic.claude-... |
CHAT_MODE=bedrockで使用 |
ALLOWED_ORIGIN |
* |
後でCloudFrontドメインに変更 |
訳もわからずトークン消費されるのがいやだったので、API疎通を確認するためにCHAT_MODEを用意。うまくいったらbedrockに変える感じで。ちなみにモデルはHaiku4.5を使いました。
あと、ALLOWED_ORIGIN = "*"って多分よくないので、お試しの利用ってことにしといたほうがいいと思います。
Step4: API Gatewayの作成
以下を行いました。
- APIを作成→HTTP APIを作成でAPI名を決定等々
-
POST /chatを作成して、Lambdaに繋げる - CORSの設定
- Allow origins:
*(先述しましたが、お試しなので許してください) - Allow methods:
POST,OPTIONS - Allow headers:
content-type,authorization
- Allow origins:
- 最終的に
$defaultにデプロイすると、 "https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/chat" みたいなURLが払い出されるので、記録しておきましょう
Step5: APIの疎通テストをしてみる(mock→bedrock)
curl -X POST "https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/chat" \
-H "Content-Type: application/json" \
-d '{"message":"test"}'
chat.jsの中でステータスがmockの場合このように定義してるので
if (errors.length === 0 && chatMode === 'mock') {
assistantSummary = 'PoC: backend is alive';
}
return response(200, {
assistant_summary: assistantSummary,
layers: [],
errors,
});
mockモードだとこんな感じでレスポンスが帰ってくるはずです。
{"assistant_summary":"PoC: backend is alive","layers":[],"errors":[]}
無事動いたら、Lambdaの環境変数から、CHAT_MODE = bedrockにして再度送信。
curl -X POST "https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/chat" \
-H "Content-Type: application/json" \
-d '{"message":"名古屋市の不動産情報をまとめて"}'
(一応序盤に書いたけど不動産アシスタントとして作ってるのでそういうmessageを挿入)
すると以下のようなレスポンスが帰ってきました。
{"assistant_summary":"# 名古屋市の不動産情報について\n\n名古屋市は愛知県の県庁所在地として、中部地方の経済・交通の中心地です。栄地区や名駅周辺は商業施設が集中し、オフィスビルと住宅需要が高い傾向にあります。\n\n市内の不動産相場は区によって異なり、中区や東区などの中心部は比較的高めですが、郊外の北区や守山区では手頃な価格帯が見られます。近年は地下鉄やJRなどの公共交通網の充実に伴い、駅周辺の開発が進んでいます。\n\n賃貸物件も豊富で、学生向けから高級マンションまで多様な選択肢があります。購入を検討される場合は、将来の都市計画や人口動態も考慮することをお勧めします。\n\n**注意点:不動産投資には市場変動や地域特性など多くの要因が影響するため、専門家への相談や十分な調査の上でご判断ください。**","layers":[],"errors":[]}
ちゃんと不動産情報をまとめてくれてます。安価なHaikuでもちゃんと動いてくれて嬉しいですね。あとはUIとか、そこに繋ぐための道を作ってあげればOKです。
Step6: S3バケットを作成してファイルを配置
ここで注意したいのは、今回は S3 の静的ウェブサイトホスティングの Website endpoint を使う構成ではない という点です。
今回は、通常の S3 バケットを CloudFront の origin にして、CloudFront からだけ参照できるようにするという構成を目指します。
一応よく言われる注意事項ですが、パブリックアクセスはチェックをつけないようにしておきましょう。S3へのルートはCloudFront経由でのみOKという状態を作るようにします。
Step7: CloudFrontを作成する
S3バケットとCloudFrontの組み合わせの方法についてはこちらの記事を参考に作成しました。
CloudFront と S3を利用した静的コンテンツ配信
S3 バケットを CloudFront の origin に設定し、静的ファイル配信用のディストリビューションを作成します。
今回の実装では、CloudFront の origin は S3 だけです。
API Gateway は CloudFront の配下には置かず、ブラウザから API Gateway を直接呼んでます。
(CloudFrontはindex.html、frontend-config.js、error.htmlを配信するだけです)
なお、関係ないページに飛んだ時エラーページを返すように設定してます。
| HTTPエラーコード | レスポンスページのパス | HTTPレスポンスコード |
|---|---|---|
| 403 | /error.html |
404 |
| 404 | /error.html |
404 |
Step8: frontend-config.jsでAPI GatewayのURLを設定する
今回の実装では、フロントから API Gateway を直接呼んでいます。
そのため、frontend-config.js では execute-api のフル URL を設定しています。
window.APP_CONFIG = {
// API Gateway directly, set full URL:
chatEndpoint: "https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/chat"
};
何度も申し上げますが、今回のアプリ構成は次の構成になってます。
- CloudFront は静的ファイル配信のみ担当
- ブラウザが API Gateway に直接リクエストを送る
- API Gateway が Lambda を呼び、Lambda が Bedrock を呼んでる
Step9: 動作確認
UIはClaudeCodeで作りました。
CloudFrontで吐き出されるURL(https://xxxxxx.cloudfront.net)にアクセスすると、以下のチャット画面が表示されます。
ユーザからのプロンプト送信に対して、応答が返ってきていることや、errorsが空の配列になっていることから、特に問題なくBedrockの呼び出しが完了していることがわかりました。
まとめ
今回はAmazon Bedrockを使って、S3 + CloudFront + Lambda + API Gatewayでチャットアプリを構築してみました。
やってみて感じたポイントをいくつか記載します。
- Converse APIを呼ぶためのIAM権限は Bedrock:InvokeModel だけでOK。 Bedrock:Converse みたいなアクションはなかったです
- S3はパブリックアクセスをブロックしたまま、CloudFront経由で配信する。お試しだからといってとりあえず適当にパブリックにするのはよくない
- Haiku 4.5、安くてちゃんと動く。 試すには十分すぎるモデル
- Difyとかその他サービスって、すごくいろいろを楽に触らせてくれるんだなと感動
「聞いたことはあるけど触ったことない」状態からでも、比較的簡単にAIからのレスポンスを得られるとこまではいけましたし、それっぽいUIも組み合わせればいかにもチャットアプリができるので楽しかったです。
次は、次はAWS CLIの aws login を使った構築フローが初心者のAWSハードルをグンと下げたなという話、と、ストリーミングのレスポンスも試してみようかと思います。




