はじめに

前回の記事では、AWS CDKを使ったインフラ構成の実装について解説しました。今回は最終回として、実際のデプロイ手順と動作確認、そして全体の振り返りを行います。

デプロイ手順

前提条件

事前に必要な設定やインストールを行います。AWS CLIの設定と、CDKおよびPython依存関係のインストールを済ませておいてください。

# AWS CLIの設定
aws configure

# CDKのインストール
npm install -g aws-cdk

# Python依存関係のインストール
pip install -r requirements.txt

Lambda Layerの準備

Lambda関数で使用する外部ライブラリをLayerとしてパッケージングします。PyPDF2とrequestsの2つのLayerを作成します。

# {プロジェクトTOP}/lambda に移動
cd lambda

# PyPDF2レイヤー
mkdir -p python
pip install PyPDF2 -t python/
zip -r pypdf2-layer.zip python/
rm -rf python/

# requestsレイヤー
mkdir -p python
pip install requests requests-aws4auth -t python/
zip -r requests-layer.zip python/
rm -rf python/

# プロジェクトルートに戻る
cd ..

CDKデプロイ

準備が整ったら、CDKを使ってAWSリソースをデプロイします。初回実行時はブートストラップが必要です。

# CDKブートストラップ(初回のみ)
cdk bootstrap

# スタックのデプロイ
cdk deploy

デプロイには15〜30分程度かかります(特にOpenSearchドメインの作成に時間がかかります)。

デプロイが完了すると、以下のような出力が表示されます。

✅  RagStack

✨  Deployment time: xxxx.xxs

Outputs:
RagStack.RagApiEndpoint12345678 = https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:123456789012:stack/RagStack/...

DynamoDBにサンプルデータ投入

AWSコンソールからDynamoDBにユーザー情報を登録します。

  1. AWSコンソールでDynamoDBを開く
  2. 「テーブル」から「rag-context-table」を選択
  3. 「項目を探索」タブを選択
  4. 「項目を作成」ボタンをクリック
  5. 以下のJSON形式でデータを入力
    {
      "user_id": "user_001",
      "age": 35,
      "family": "妻・子供2人",
      "occupation": "会社員",
      "income": "600万円",
      "current_insurance": "なし",
      "concerns": "家族の将来が心配"
    }
  6. 「項目を作成」ボタンをクリックして保存

同様の手順で、必要に応じて他のユーザーデータ(user_002、user_003など)も登録できます。

S3にPDFファイルをアップロード

S3バケットにPDFファイルをアップロードします。ここでは、生命保険プランなどのサンプルPDFを用意する必要があります。

PDFファイルの準備

今回のRAGシステムでは、以下のような内容のPDFファイルを任意で作成してください。

  • 生命保険のプラン情報(プラン名、保障内容、月額保険料など)
  • 医療保険のプラン情報
  • その他、検索対象としたいドキュメント

例: plan_001.pdfの内容イメージ

【プランA】
死亡保障: 3000万円
月額保険料: 8000円
対象: 家族向け
特徴: お子様の教育費と生活費をカバーできる標準的なプラン

WordやGoogleドキュメントなどで上記のような内容を記載し、PDF形式でエクスポートしてください。複数のプラン情報を含むPDFを3〜5件程度用意することをお勧めします。

AWSコンソールからアップロード

  1. AWSコンソールでS3を開く
  2. 「rag-datalake-bucket」バケットを選択
  3. 「アップロード」ボタンをクリック
  4. 「ファイルを追加」ボタンをクリック
  5. 作成したPDFファイルを選択(複数選択可)
  6. 「アップロード」ボタンをクリック
  7. アップロード完了を確認

インデックス処理の実行

AWSコンソールから、indexing-handler Lambda関数をテスト実行します。
Lambda関数のページで「テスト」タブを選択し、任意のテストイベント(空のJSONでも可)で実行します。

ログで確認

Indexed plan_001.pdf successfully
Indexed plan_002.pdf successfully
Indexed plan_003.pdf successfully
Indexed plan_004.pdf successfully
Indexed plan_005.pdf successfully

動作確認

RAG処理の実行

AWSコンソールから、rag-handler Lambda関数をテスト実行します。

テストイベント(sample.json)

{
  "user_id": "user_001",
  "query": "私に最適な保険のプランはどれですか?"
}

期待される出力

{
  "statusCode": 200,
  "body": "{\"prompt\": \"...\", \"answer\": \"35歳で会社員、妻とお子様2人をお持ちの方には...\"}"
}

API Gateway経由でのテスト

curl -X POST https://[API_ID].execute-api.ap-northeast-1.amazonaws.com/prod/ \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user_001",
    "query": "私に最適な保険のプランはどれですか?"
  }'

API GatewayのエンドポイントURLは、CDKデプロイ時の出力に表示されます。

コスト試算

今回の構成での月額コスト概算(東京リージョン、軽い負荷を想定)

サービス 構成 月額コスト
OpenSearch t3.small.search × 1(検証環境向け) 約 $30
Lambda RAG処理 1000回/月 約 $1
Bedrock Titan + Claude 1000回/月 約 $10
DynamoDB オンデマンド、低負荷 約 $1
S3 数GB 約 $1
API Gateway 1000リクエスト/月 約 $1
合計 約 $44/月

本番環境へのスケールアップ

今回は検証環境向けの低コスト構成(t3.small.search × 1ノード)を採用していますが、本番環境で高可用性が必要な場合は、以下のような構成に変更できます。

本番環境構成例

  • データノード: r5.large.search × 3(マルチAZ配置)
  • 専用マスターノード: m5.large.search × 3
  • 月額コスト: 約$600(OpenSearchのみ)
  • 合計コスト: 約$614/月

構成変更のポイント

第五弾の記事で解説したCDKコードのcluster_config部分を変更することで、簡単に本番環境向けの高可用性構成に切り替えられます。

  • 3ノード構成で高可用性を確保
  • マルチAZ(3つのアベイラビリティゾーン)に分散配置
  • 専用マスターノードでクラスター管理の安定性向上
  • メモリ最適化インスタンスでベクトル検索のパフォーマンス向上

コスト最適化のポイント

  • 検証・開発環境では今回の構成(約$44/月)で十分
  • トラフィックが少ない本番環境では、2ノード構成も検討可能
  • Lambda予約同時実行数を制限してコストを抑制
  • DynamoDBのアクセスパターンが予測可能な場合、プロビジョニング済みキャパシティモードに変更

ハマったポイントと対処法

OpenSearchへのインデックス作成が失敗する

問題: indexing-handler実行時に403 Forbiddenエラー
原因: Lambda関数のIAMロールにOpenSearchへのアクセス権限が不足
対処: 第五弾で設定したIAM権限が正しく適用されているか確認。特にaccess_policyとlambda_role.add_to_policyの設定を見直す

DynamoDBからデータが取得できない

問題: rag-handler実行時にユーザー情報が取得できない
原因: DynamoDBにデータが投入されていない、またはuser_idが一致していない
対処: DynamoDBコンソールでテーブルの内容を確認。リクエストのuser_idとテーブルのuser_idが完全一致しているか確認

ベクトル検索結果が0件

問題: OpenSearch検索は成功するが、結果が0件
原因: インデックス処理が正常に完了していない、またはインデックス名が一致していない
対処:

  1. indexing-handlerのCloudWatch Logsを確認
  2. 「Indexed xxx.pdf successfully」のログが出ているか確認
  3. 環境変数OPENSEARCH_INDEXの値が両Lambda関数で一致しているか確認

全体の振り返り

実装した機能

全6回の連載を通して、以下の機能を実装しました。

記事① RAGとは?AWS Summit参加の学びと狙い

  • AWS Summit Japan 2025での学び
  • 生成AIとRAGの重要性
  • プロジェクトの狙いと目標

記事② 構成設計と各AWSサービスの役割

  • RAGシステムのアーキテクチャ設計
  • 各AWSサービスの選定理由
  • データフローの全体像

記事③ インデックス作成とPDF埋め込み処理の実装

  • OpenSearchインデックスの初期化(create_index)
  • S3からPDFファイルの取得
  • PyPDF2によるテキスト抽出
  • テキストのチャンク分割(オーバーラップ付き)
  • Bedrockを使った埋め込みベクトル生成
  • OpenSearchへのドキュメント登録
  • Lambda Layerの準備と設定

記事④ RAG検索処理とLLM応答生成の実装

  • ライブラリのインポートとクライアント初期化
  • ユーザー情報の取得(DynamoDB)
  • 質問のベクトル化(Titan Embeddings)
  • 類似ドキュメントの検索(OpenSearch kNN)
  • プロンプトの構築(RAGの肝)
  • LLMでの回答生成(Claude 3.5 Sonnet v2)

記事⑤ CDKによるインフラ定義

  • IAMロール・ポリシーの設定
  • S3、DynamoDB、OpenSearchの作成
  • Lambda関数とLayerのデプロイ
  • API Gatewayの作成
  • Custom Resourceによる自動初期化

記事⑥ デプロイと動作確認と振り返り(今回)

  • 実際のデプロイ手順
  • サンプルデータの投入
  • 動作確認とテスト
  • コスト試算
  • トラブルシューティング

学びと気づき

RAGの効果

  • ハルシネーションの大幅な削減 – 事実に基づいた回答のみを生成
  • 情報の鮮度を保てる – LLM再学習不要で最新情報を反映
  • パーソナライズされた回答 – ユーザー情報に基づいた提案

AWSサービスの組み合わせ

  • サーバーレスで運用負荷を削減
  • Bedrockで最新のLLMを簡単に利用
  • OpenSearchのベクトル検索が強力
  • マネージドサービスによる高い可用性

CDKの利便性

  • インフラをコードで管理
  • 再現可能な環境構築
  • Custom Resourceで柔軟な初期化
  • TypeScriptやPythonで記述可能

今後の改善案

精度向上

  • Hybrid Search(ベクトル検索 + キーワード検索)の導入
  • リランキングモデルの追加
  • チャンクサイズの最適化

パフォーマンス向上

  • Lambda ProvisionedConcurrencyの活用(コールドスタート削減)
  • OpenSearchのインデックス最適化
  • ベクトルのキャッシング
  • 非同期処理の導入

ユーザー体験

  • ストリーミング応答(Claude Streamingを使用)
  • 会話履歴の管理(複数ターンの対話)
  • フィードバック機能(回答の品質向上)
  • フロントエンドの実装(WebアプリやSlack連携)

セキュリティ対策

  • API GatewayにCognito認証を追加
  • VPC内にOpenSearchを配置
  • KMSでの暗号化強化
  • IAMポリシーのさらなる最小化

スケーラビリティ

  • S3イベントトリガーによるインデックス自動更新
  • 複数の言語モデルへの対応
  • 他のファイル形式のサポート(Word、Excel、テキストなど)
  • マルチテナント対応

まとめ

全6回にわたって、AWSでRAGチャットボットを構築してきました。

RAGは、LLMの限界を補完する非常に強力な手法です。特に、企業の社内文書検索や専門知識が必要な業務において、大きな価値を発揮します。

今回の実装では、生命保険プランの提案というユースケースを通して、RAGシステムの実践的な構築方法を学びました。この仕組みは、他の多くの用途にも応用可能です。

  • カスタマーサポートのFAQシステム
  • 社内ナレッジベースの検索
  • 法律・医療などの専門分野の情報提供
  • 製品マニュアルの問い合わせ対応

今回の実装を参考に、ぜひ皆さんの業務でもRAGシステムを活用してみてください!

最後まで読んでいただき、ありがとうございました!

参考リンク