Bedrock Agents 本番運用 Action Group Knowledge Base OpenAPI Lambda 統合入門

目次

1. なぜBedrock Agentsか — AI/LLM時代の本番運用課題 + IAM/EKS シリーズからの架橋

関連シリーズ ナビゲーション

  • AIシリーズ Vol1 (本記事): Bedrock Agents 本番運用 完全ガイド
  • AIシリーズ Vol2 (近日公開): RAG最適化・Multi-Agent 連携 (予告)

IAM入門4巻 (前提知識): Vol1 ポリシー設計 / Vol2 複数アカウント / Vol3 棚卸し自動化 / Vol4 STS×Cross-Account

EKS本番運用シリーズ (前提知識): Vol1 クラスタ設計×IRSA / Vol2 観測可能性 / Vol3 GitOps×ArgoCD

Bedrock 深掘り (本記事の発展版): Bedrock Agents 本番運用 深掘り (Session/Guardrails) / Bedrock RAG Knowledge Bases 単体入門

1-1. LLM 単独ではなぜ足りないのか

Claude 3.5 Sonnet や Amazon Nova Pro といった大規模言語モデル (LLM) は、質問への回答・文書要約・コード生成といった幅広いタスクをこなせる。しかし本番システムに組み込もうとすると、3つの本質的な壁にぶつかる。

壁1: 知識のカットオフと社内情報の不在

LLM の学習データには必ずカットオフが存在する。昨月リリースした自社製品の仕様変更、社内の承認フロー、最新の料金表 — これらはモデルの重みに含まれていない。「今月の在庫状況を教えて」「現在有効な社内規程は何か」という問いに対し、単体の LLM は根拠のある回答を返せない。

# 単体LLM の限界例
User: 「弊社の最新製品Xの仕様を教えてください」
LLM:  「私のトレーニングデータに弊社製品Xの情報は含まれていません。
 公式サイトをご確認ください。」
# → 社内ドキュメントを参照できず、実用的な回答ができない

壁2: リードオンリーという制約

LLM はテキストを「読んで生成する」ツールであり、外部システムに「書き込む」手段を持たない。「発注データをデータベースに登録してください」「会議室を予約してください」「Slack に通知を送ってください」— こうした実行を伴う要求に対して、LLM は手順を説明することはできても実際のアクションは一切起こせない。生成したコードや SQL 文を自ら実行することも不可能だ。

# 単体LLM の実行限界
User: 「在庫テーブルの stock_qty を 500 に更新してください」
LLM:  「以下のSQLを実行してください:
 UPDATE inventory SET stock_qty = 500 WHERE product_id = 'X';」
# → 提案はできるが、自分では一切実行できない

壁3: 単ターン制約と状態管理の欠如

LLM への入出力は原則として 1 ターン完結 (1プロンプト→1レスポンス) だ。「在庫を確認し、不足していれば発注し、担当者に完了通知を送る」という連鎖タスクには、ステップ間の状態保持と条件分岐が必要になる。単体 LLM はこうしたマルチステップのタスク遂行を自律的に行う仕組みを持たない。中断・再試行・エラーハンドリングも実装されていない。

# 複数ステップが必要なタスク
Step1: 在庫APIを呼び出して stock_qty を取得する
Step2: stock_qty < 100 なら発注APIに発注リクエストを送る
Step3: 発注完了後、担当者のSlackチャネルに通知する
# → 単体LLMにはこの一連の「計画→実行→確認→次のアクション」ができない

Agents for Amazon Bedrock が解決する 3 要素

Agents for Amazon Bedrock はこれら 3 つの壁を体系的に取り除く。

課題解決機能仕組み
知識のカットオフ・社内情報不在Knowledge BaseS3のドキュメントをベクトル化してリアルタイムRAG参照
リードオンリー制約Action GroupLambda経由で外部APIやデータベースに直接アクセス
単ターン制約・状態管理ReAct型 Multi-stepObserve→Think→Act ループで複数ステップを自律実行

この3要素が組み合わさることで、LLM は「会話ができるだけの道具」から「本番システムに組み込める自律エージェント」へと進化する。

単体 LLM vs Agents for Amazon Bedrock — 機能比較

観点単体 LLMAgents for Amazon Bedrock
知識の鮮度学習データのカットオフまでKnowledge Base でリアルタイム更新
外部操作テキスト生成のみ (リードオンリー)Action Group で API・DB・外部サービスを実行
タスク実行1ターン完結のみReAct ループで複数ステップを自律実行
セッション管理なし (ステートレス)セッションID単位でコンテキストを保持
権限制御なしIAMロール × Action Group スコープで制御
監査・追跡困難Bedrock Trace で全推論ステップを可視化

単体 LLM が「賢い検索エンジン」だとすれば、Agents for Amazon Bedrock は「自律的に仕事をこなすデジタルワーカー」だ。この違いを理解することが、本番導入の第一歩になる。


1-2. IAM4巻 + EKS3巻 の知識が Bedrock で活きる理由

IAM入門4巻と EKS本番運用3巻を読み進めてきた読者には朗報がある。それらで習得した知識は Bedrock Agents の設計・実装・運用に直接応用できる。

IAM 入門シリーズからの架橋

IAM入門 Vol1: ポリシー設計 で学んだ最小権限の原則は、Bedrock Agents の Action Group (Lambda) に付与する IAM ロール設計にそのまま適用する。bedrock:InvokeAgentlambda:InvokeFunctions3:GetObject など各アクションを必要最小限に絞り込む判断力が設計品質を左右する。

IAM入門 Vol2: マルチアカウント設計 で習得した Organizations × Service Control Policy の考え方は、Bedrock を組織全体の AWS 環境に統合する際の基盤となる。本番アカウントと Bedrock 基盤アカウントを分離し、SCP でデータ流出リスクを制御するアーキテクチャはこの知識なしに設計できない。

IAM入門 Vol3: 権限棚卸し自動化 で実践した Access Analyzer による継続的権限最適化は、Bedrock Agent が生成する CloudTrail ログの分析に応用できる。Agent が実際にどの API をどの頻度で呼び出しているかを可視化し、過剰な権限を定期的に削除する運用が実現できる。

IAM入門 Vol4: STS × Cross-Account は Bedrock の最重要架橋ポイントだ。Action Group のクロスアカウント Lambda 呼び出しでは、信頼ポリシーへの sts:AssumeRole 設定と一時認証情報の取得フローが必須になる。Confused Deputy 対策として aws:SourceAccount 条件キーを付与するパターンも Vol4 で学んだ知識が直結する。

EKS 本番運用シリーズからの架橋

EKS本番運用 Vol1: IRSA で理解した「ワークロードに IAM ロールを安全に付与する」設計思想は、Action Group で利用する Lambda 関数のロール設計に直接応用する。サービスアカウント単位で権限を分離するのか、Lambda 関数単位で分離するのか — 本番設計の判断軸は IRSA から転用できる。

EKS本番運用 Vol2: 観測可能性 で構築した CloudWatch Logs + ADOT の監視基盤は、§6 で解説する Bedrock Trace 解析 + CloudWatch 統合に直結する。FluentBit で培ったログ設計の思想が、Lambda 実行ログ・Bedrock Trace ログの収集・可視化に流用できる。

EKS本番運用 Vol3: GitOps × ArgoCD で実践した「Git を Single Source of Truth にする」アプローチは、Bedrock Agents の構成管理に応用する。Lambda 関数コード・OpenAPI スキーマ・Terraform による Bedrock 基盤設定をすべて Git で管理し、GitHub Actions でデプロイを自動化する設計がそのまま使える。

IAM × EKS → Bedrock Agents 対応表

シリーズ習得済みスキルBedrock Agents での応用先
IAM Vol1最小権限ポリシー設計Action Group (Lambda) IAMロール
IAM Vol2マルチアカウント × SCPBedrock基盤アカウント分離設計
IAM Vol3Access Analyzer 権限棚卸しCloudTrail × Bedrock Trace 継続分析
IAM Vol4STS AssumeRole × 信頼ポリシークロスアカウント Lambda 呼び出し
EKS Vol1IRSA 最小権限ロール割当Lambda Function 実行ロール設計
EKS Vol2CloudWatch + ADOT 可観測性Bedrock Trace + Lambda ログ収集
EKS Vol3GitOps / IaC 管理Lambda/OpenAPI/Terraform の Git 管理

この対応表を頭に入れておくと、§3〜§6 の実装解説が「初めて見る概念」ではなく「既知スキルの応用」として体系的に理解できる。

一文で宣言する

IAM 入門シリーズと EKS 本番運用シリーズで培った本番運用スキル — 最小権限設計・クロスアカウント認証・可観測性・IaC 管理 — はそのままAI基盤構築に直結する。Bedrock Agents は「新しい技術スタック」ではなく、これまでの AWS 本番運用スキルの自然な延長線上にある。


1-3. 本記事で到達できること

本記事は「Bedrock Agents を本番環境で動かす」ための実践ガイドだ。読了後に到達できる5つのゴールを明示する。

(a) Bedrock Agents の全体像を理解する

Agent / Action Group / Knowledge Base / Lambda / OpenAPI Schema という5要素の役割と相互関係を正確に把握する。§2 ではアーキテクチャ全体図と各要素の責務を解説する。AWS コンソールだけでなく Terraform によるコード化も視野に入れた設計イメージを持てる状態を目指す。

(b) Agent 設計を実践できる

Instruction prompt の設計原則・Foundation Model の選定基準 (Claude 3.5 Sonnet / Amazon Nova Pro / Llama 3) ・Tool / Function 設計の鉄則を習得する。§3 (山場1) では具体的な Instruction prompt のサンプルと、失敗しがちなプロンプトパターンの解説を通じて実践的な設計力を養う。

(c) Knowledge Base を構築できる

S3 データソース設定・OpenSearch Serverless によるベクトルストア構築・Embedding モデル選定 (Amazon Titan / Cohere) ・Chunking 戦略の最適化まで一連の実装手順を習得する。§4 (山場2) では実際の Terraform コードとともに KB のライフサイクル管理 (同期ジョブ・バージョニング) を解説する。

(d) Action Group を実装できる

Lambda 関数の実装パターン・OpenAPI 3.0 スキーマの記述方法・入出力検証・Idempotency 設計を習得する。§5 では実際の Lambda コードと OpenAPI スキーマを示しながら、Bedrock Agent が正確に関数を呼び出せる設計の条件を解説する。

(e) 詰まりポイント 7 選を乗り越えて本番稼動させられる

Bedrock Agents の導入で多くのエンジニアがつまずく7つのポイント (Action Group のスキーマ不整合 / KB 同期の失敗 / IAM 権限の見落とし / Trace でのデバッグ方法 / レイテンシ対策 / コスト可視化 / 本番デプロイ手順) を §7 で体系的に解説する。

これら5つのゴールを達成することで、Bedrock Agents を「触ったことがある」から「本番で運用できる」レベルに引き上げることが本記事の目標だ。


2. Bedrock Agents 全体像 — 5要素 (Agent / Action Group / Knowledge Base / Lambda / OpenAPI Schema)

Bedrock Agents は「自律的なAIエージェントをフルマネージドで構築・運用できる」サービスです。単なる LLM API 呼び出しと異なり、推論・ツール実行・知識参照・セッション管理を統合したオーケストレーション基盤を提供します。この章では、Bedrock Agents を構成する5要素の役割・相互関係・呼び出しフロー・Foundation Model の選定基準・Terraform によるプロビジョニングを整理します。

fig01: Bedrock Agents 全体アーキテクチャ — 5要素統合 (Agent / Action Group / Knowledge Base / Lambda / OpenAPI Schema)

2-1. 5要素の役割と相互関係

Bedrock Agents は以下の5要素が連携して動作します。各要素の責任範囲を明確に理解することが、本番品質のエージェント設計の起点になります。

【Bedrock Agents 5要素 構成図】

  ┌──────────────────────────────────────────────────────┐
  │  Amazon Bedrock Agents  │
  │  │
  │  ┌──────────────────────────────────────────────┐ │
  │  │  Agent (オーケストレーター)  │ │
  │  │  ・Instruction prompt 解釈  │ │
  │  │  ・Foundation Model 推論 │ │
  │  │  ・Session / ConversationID 管理  │ │
  │  └────┬──────────────┬─────────────────────────┘ │
  │ │  │  │
  │  ┌────▼──────┐  ┌───▼──────────────────────┐  │
  │  │ Action │  │  Knowledge Base (RAG)  │  │
  │  │ Group  │  │  ・S3 → ベクトルDB│  │
  │  │  │  │  ・Retrieve & Generate │  │
  │  └────┬──────┘  └───────────────────────────┘  │
  │ │ │
  │  ┌────▼──────────────────────────────┐  │
  │  │  Lambda Function │  │
  │  │  (Action Group バックエンド)  │  │
  │  └────────────────────────────────────┘  │
  │  │
  │  ┌────────────────────────────────────────────────┐  │
  │  │  OpenAPI 3.0 Schema (API定義)│  │
  │  └────────────────────────────────────────────────┘  │
  └──────────────────────────────────────────────────────┘

① Agent — オーケストレーター

Agent は Bedrock Agents の中枢です。ユーザーの入力を受け取り、Instruction prompt を解釈し、「どの Action Group を呼ぶか」「Knowledge Base を参照するか」を自律的に判断します。

属性内容
バックエンドFoundation Model (Claude / Nova 等)
セッション管理sessionId / conversationId で状態保持
推論ループReAct (Reason + Act) パターンで多段推論
Instructionシステムプロンプトに相当。精度を決定的に左右する

Agent の Instruction は「あなたは XX 社の在庫管理 AI です。ユーザーから依頼を受けたら必ず在庫 API を確認し、在庫がなければ発注 API を呼び出してください。」のように、役割・制約・行動ルールを明記します。Instruction の品質がエージェント精度の9割を決めると言っても過言ではありません。

② Action Group — ツール実行器

Action Group は Agent が外部システムを呼び出す窓口です。呼び出し仕様を OpenAPI 3.0 スキーマで定義し、バックエンド処理を Lambda Function が実行します。

属性内容
API 定義OpenAPI 3.0 YAML (S3 に配置)
バックエンドAWS Lambda Function
呼び出し判断Agent が FM 推論で「どの operationId を使うか」を決定
最大数1 Agent につき最大 20 Action Groups

重要なのは、OpenAPI スキーマの operationIddescriptionLLM が読む前提で書くことです。「get_inventory_by_sku: SKU コードで在庫数量を取得する」のように、FM が判断しやすい自然言語で記述します。

③ Knowledge Base — RAG エンジン

Knowledge Base は Retrieval-Augmented Generation (RAG) を提供するコンポーネントです。S3 に格納したドキュメントをベクトル化し、OpenSearch Serverless に保存します。Agent はユーザーの質問と関連性の高い情報を自動取得して回答に付与します。

属性内容
データソースS3 (PDF / TXT / HTML / CSV)
ベクトルDBAmazon OpenSearch Serverless / Aurora (pgvector)
Embedding モデルAmazon Titan Embeddings v2 / Cohere Embed
取得戦略Semantic / Hybrid (キーワード + セマンティック)

Chunk size の設定が RAG 精度に直結します。デフォルト (300 トークン) は汎用ですが、技術文書には 512-1024 トークン、FAQ には 128-256 トークンが適切な場合があります。

④ Lambda Function — 実行エンジン

Lambda Function は Action Group のバックエンドです。Agent からのリクエストを受け取り、実際のビジネスロジック (在庫 DB 検索・発注 API 呼び出し等) を実行します。

属性内容
イベント形式actionGroup / function / parameters を含む JSON
レスポンス形式actionGroup / httpStatusCode / responseBody を含む JSON
冪等性同一 sessionId での重複呼び出しに備えた設計が必須
タイムアウトBedrock 側は最大 60 秒。Lambda は余裕を持たせて 30 秒以内推奨

Lambda は冪等性 (Idempotency) を最初から設計することが重要です。Agent の多段推論で同一 Action が複数回呼ばれる場合があるため、DynamoDB の条件付き書き込みや冪等性トークンで重複実行を防ぎます。

⑤ OpenAPI Schema — API 定義書

OpenAPI Schema は Agent が Action Group の使い方を理解するための仕様書です。人間向けではなく FM が読む ことを意識して記述します。

属性内容
形式OpenAPI 3.0 YAML (S3 に配置、Agent に紐付け)
operationIdスネークケースで簡潔に (例: get_inventory_by_sku)
descriptionFM が判断に使う。「いつ使うか」を自然言語で明記
parameterstype / description を必ず記述。enum で選択肢を限定

2-2. 呼び出しフロー — ユーザー入力から応答生成まで

Bedrock Agents の呼び出しは ReAct (Reasoning + Acting) ループで処理されます。

【Bedrock Agents 呼び出しフロー】

① ユーザー → Agent (InvokeAgent API)
inputText: "SKU-001 の在庫を確認して残り10個以下なら発注して"

② Agent → Foundation Model 推論 (Reasoning)
"get_inventory_by_sku を呼んで在庫を確認する必要がある"

③ Agent → Action Group (get_inventory_by_sku)
→ Lambda → 在庫DB検索 → {"qty": 5}

④ Agent → Foundation Model 再推論
"在庫5個 < 10個 → create_purchase_order を呼ぶ必要がある"

⑤ Agent → Action Group (create_purchase_order)
→ Lambda → 発注API → {"order_id": "PO-9801", "status": "created"}

⑥ Agent → Knowledge Base Retrieve (必要時)
"発注ルールや承認フローをKBから取得"

⑦ Agent → Foundation Model 最終応答生成
"SKU-001 の在庫は5個でした。発注番号 PO-9801 で50個発注しました。"

Python SDK での呼び出し例:

import boto3

client = boto3.client("bedrock-agent-runtime", region_name="ap-northeast-1")
response = client.invoke_agent(
 agentId="AGENT_ID",
 agentAliasId="ALIAS_ID",
 sessionId="session-001",
 inputText="在庫数量を確認して発注してください"
)
for event in response["completion"]:
 if "chunk" in event:
  print(event["chunk"]["bytes"].decode())

sessionId を同じ値で連続呼び出しすると、Agent がセッション内の会話履歴を保持します。ユーザーが「さっきの発注をキャンセルして」と言った場合も、前のターンの order_id を参照して適切に処理できます。

2-3. Foundation Model 比較 — Agent 用途での選定基準

Bedrock Agents で利用可能な主要 FM を比較します。Agent の精度はモデルの推論能力に直結するため、用途に応じた選定が重要です。

モデル強みAgent 適性コスト目安 (1M tokens 入力/出力)
Claude 3.5 Sonnet v2推論精度・複雑指示遂行・長文対応◎ 最推奨$3 / $15
Claude 3 Haiku高速レスポンス・低コスト○ 単純タスク向き$0.25 / $1.25
Amazon Nova ProAWS統合・コスト最適化・マルチモーダル○ コスト重視$0.8 / $3.2
Amazon Nova Lite超低レイテンシ・低コスト△ シンプルツール利用$0.06 / $0.24
Llama 3.1 70BOSS・カスタマイズ可・コスト低△ 単純ルーティング$0.72 / $0.72

選定指針:

  • 複雑な多段推論・複数 Action Group の連鎖: Claude 3.5 Sonnet v2 一択。ReAct ループの精度が段違いで異なります。
  • 単純な1〜2ステップの処理・スループット重視: Claude 3 Haiku または Amazon Nova Lite でコストを抑えられます。
  • AWS サービスとの統合を優先・日本語精度を重視: Amazon Nova Pro が最適です。
  • プロトタイプ・検証フェーズ: Claude 3 Haiku で素早く動作確認し、本番移行時に Sonnet v2 へアップグレードする戦略が効果的です。
Bedrock Agents 5要素 設計原則

  • Agent: Instruction の明確性がエージェント精度の9割を決める。役割・制約・行動ルールを明文化する
  • Action Group: OpenAPI の operationId / description を FM が読む前提で書く。曖昧な命名は誤呼び出しの原因になる
  • Knowledge Base: Chunk size と Embedding モデルの選定が RAG 精度の要。ドキュメント種別ごとに最適値が異なる
  • Lambda: 冪等性 (Idempotency) とエラーハンドリングを最初から設計する。多段推論での重複呼び出しを想定すること
  • OpenAPI Schema: 人ではなく LLM が読む仕様書として記述する。description の質が Action Group の選択精度を左右する

2-4. Terraform による Agent / Knowledge Base 一括プロビジョニング

Bedrock Agents の全リソースを Terraform で管理することで、環境ごとの再現性と変更管理が確保できます。

# IAM ロール (Agent 実行用)
resource "aws_iam_role" "bedrock_agent" {
  name = "bedrock-agent-execution-role"
  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "bedrock.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })
}

# Bedrock Agent 本体
resource "aws_bedrockagent_agent" "main" {
  agent_name  = "inventory-agent"
  agent_resource_role_arn = aws_iam_role.bedrock_agent.arn
  foundation_model  = "anthropic.claude-3-5-sonnet-20241022-v2:0"
  instruction = "あなたはXXX社の在庫管理AIエージェントです。ユーザーからSKUコードで在庫確認・発注依頼を受け付けてください。"
  idle_session_ttl_in_seconds = 1800
}

# Alias (本番エイリアス)
resource "aws_bedrockagent_agent_alias" "prod" {
  agent_id= aws_bedrockagent_agent.main.agent_id
  agent_alias_name = "production"
}

Agent を作成したら、次のステップで Action Group (OpenAPI スキーマ + Lambda) と Knowledge Base を紐付けます。§3 では Instruction prompt の設計パターン・Foundation Model ごとのパラメータチューニング・Action Group の実装を詳解します。


3. Agent設計実践 (山場1) — Instruction prompts / Foundation Model選定 / Tool/Function設計

3-1. Instruction Prompt 設計

Bedrock Agent の品質は Instruction prompt で決まります。Instruction は Agent の「役割定義書」であり、以下の4要素を必ず記述します。

要素内容記述しない場合の問題
役割宣言Agent が何者で誰のために動くか汎用的な回答になり専門性が出ない
ツール利用方針いつ何のツールを使うかLLM が Action Group を使わず直接回答しようとする
応答スタイル回答の長さ・言語・形式ユーザーが期待する形式と乖離する
制約条件してはいけないこと・確認が必要な操作副作用のある操作を無確認で実行してしまう

悪い Instruction の例と改善例

【NG】あなたはAIアシスタントです。ユーザーの質問に回答してください。

問題点: 役割が不明確 / どのツールをいつ使うか不定 / 制約が0 / 応答スタイル未定義

【OK】
<role>
あなたはXXX株式会社の在庫管理AIエージェントです。在庫の照会・発注・キャンセルを担当します。
</role>
<tools>
- action_group_inventory: 在庫残数・入庫予定の確認に使用する
- action_group_order: 新規発注・発注キャンセルに使用する
- ユーザーが在庫・発注に関係しない質問をした場合は「在庫管理以外の質問には回答できません」と回答する
</tools>
<constraints>
- 1回の発注量が100個を超える場合は必ずユーザーに確認を取ること
- キャンセル操作は出荷済み注文には適用不可である旨を伝えること
- 在庫データは必ずaction_group_inventoryから取得し、LLMの学習データから回答しないこと
</constraints>
<style>
- 回答は日本語で簡潔に (3行以内)
- 数値はカンマ区切り (例: 1,234個)
</style>

XMLタグで4要素を構造化することで LLM が Instruction を正確に解釈します。特に <constraints> セクションは副作用のある操作(発注・削除・送金)の安全装置として重要です。

System Prompt vs User Message の役割分担

種別内容変更頻度
System Prompt (Instruction)Agent の役割・ツール方針・制約・スタイル低 (設計時に固定)
User Messageユーザーの要求・コンテキスト高 (毎リクエスト)
Session Attributesセッション固有のメタデータ (userId 等)中 (セッション単位)

System Prompt には変数を埋め込まず、ユーザー固有の情報は Session Attributes 経由で渡します。System Prompt にユーザーデータを直接埋め込むとプロンプトインジェクション攻撃のリスクが高まります。

Agent設計 3鉄則

  • 鉄則1 — Instruction 明確化: 役割 / ツール利用方針 / 応答スタイル / 制約の4要素を必ず記述する。「あなたはAIです」のような抽象的な役割宣言はLLMの判断を曖昧にする
  • 鉄則2 — FM選定はタスク特性で決める: 精度優先 = Claude 3.5 Sonnet v2 / 高速応答 = Claude 3 Haiku または Nova Micro / コスト最優先 = Nova Lite または Llama 3.1。Orchestration モデルと Generation モデルを分けて選定することも有効
  • 鉄則3 — Action Group は1責務1グループ: 粒度が大きすぎるとLLMが誤ったAction Groupを選択する。在庫照会・発注・キャンセルは別 Action Group に分割する

3-2. Foundation Model 選定実践

Bedrock Agent では Orchestration (ツール選択・計画立案) と Generation (最終回答生成) で異なるモデルを選択できます。用途とコスト特性に応じた選定フローを示します。

fig02: Agent設計実践 — Instruction × Foundation Model × Tool 関係図 (山場1)

ユースケース推奨モデル理由
複雑な多段推論・コード生成Claude 3.5 Sonnet v2高精度 / Function Calling の成功率が高い
高速応答・チャット補完Claude 3 Haiku / Nova Micro低レイテンシ (<1s) / コスト1/10以下
コスト最優先・バッチ処理Nova Lite / Llama 3.1 8B大量処理でもコスト抑制
日本語精度重視Claude 3.5 Sonnet v2日本語品質が最上位
AWS サービス統合Amazon Nova ProBedrock 最適化 / Knowledge Base と相性良

コスト見積もり計算式

月間コスト (USD) = 月間呼び出し数
  × (入力 tokens 平均 × 入力単価 + 出力 tokens 平均 × 出力単価)

例 (Claude 3.5 Sonnet v2):
  月間 10万回 × (2,000 tokens × $0.003/1K + 500 tokens × $0.015/1K)
  = 10万 × ($6.00 + $7.50) / 1000
  = $1,350/月

Orchestration に高精度モデル、Generation に軽量モデルを組み合わせるハイブリッド構成で精度とコストを両立できます。

mermaid01: Agent 呼び出しシーケンス

sequenceDiagram
 participant U as ユーザー
 participant A as Bedrock Agent
 participant FM as Foundation Model
 participant AG as Action Group (Lambda)
 participant KB as Knowledge Base

 U->>A: テキスト入力 (invokeAgent)
 A->>FM: Instruction + 会話履歴 + ツール定義
 FM->>A: Action Group 使用判断 (Tool Use)
 A->>AG: Lambda 呼び出し (input schema)
 AG-->>A: 実行結果 (output schema)
 A->>KB: Retrieve (必要時)
 KB-->>A: 関連チャンク (top-k)
 A->>FM: 最終応答生成
 FM-->>A: 回答テキスト
 A-->>U: 最終回答

ユーザー入力は invokeAgent API 経由で Bedrock Agent に渡され、Foundation Model がツール使用が必要かを判断します。Lambda(Action Group)の実行結果と Knowledge Base の検索結果を合わせて最終回答を生成します。1回の invokeAgent 呼び出し内で FM → Action Group → FM のループが最大10回実行されます。

Agent 動作テスト — AWS CLI で invokeAgent

# Bedrock Agent にテスト入力を送信
aws bedrock-agent-runtime invoke-agent--agent-id "AGENTID123"--agent-alias-id "TSTALIASID"--session-id "test-session-001"--input-text "在庫コードSKU-001の在庫残数を教えてください"--region ap-northeast-1--output json> /tmp/agent_response.json

# レスポンスのストリームから回答を抽出
jq -r '.completion[].chunk.bytes | @base64d' /tmp/agent_response.json

session-id を固定することで会話のコンテキスト(多段推論)が維持されます。本番では session-id にユーザー ID + セッション UUID を組み合わせて一意性を確保します。Agent が期待通りに Action Group を選択しない場合は、Bedrock コンソールの「トレース」機能でステップ単位のデバッグが可能です。FM が出力した Tool Use 判断・Lambda のレスポンス・最終生成テキストをすべて確認できます。

Bedrock Agent Terraform 定義

resource "aws_bedrockagent_agent" "main" {
  agent_name  = "${local.prefix}-inventory-agent"
  foundation_model  = "anthropic.claude-3-5-sonnet-20241022-v2:0"
  agent_resource_role_arn = aws_iam_role.bedrock_agent.arn
  instruction = file("${path.module}/agent_instruction.txt")
  idle_session_ttl_in_seconds = 600

  description = "在庫管理エージェント — 在庫照会・発注・配送追跡を担当"
}

resource "aws_bedrockagent_agent_alias" "production" {
  agent_alias_name = "production"
  agent_id= aws_bedrockagent_agent.main.agent_id

  routing_configuration {
 agent_version = aws_bedrockagent_agent_version.v1.agent_version
  }
}

3-3. Tool / Function 設計原則

Action Group は OpenAPI スキーマまたは Function definitions で定義します。LLM がツールを正しく選択・呼び出すためには、operationId と description の設計が最重要です。

1 Action Group = 1責務の原則

【NG設計】Action Group: inventory_all
  - getInventory
  - createOrder
  - cancelOrder
  - getShippingStatus
  → 4種類の責務が混在。LLMが誤ったFunctionを選択するリスクが高い

【OK設計】
  Action Group: inventory_query→ 在庫照会のみ
  Action Group: order_management  → 発注・キャンセルのみ
  Action Group: shipping_tracking → 配送追跡のみ

Function 設計チェックリスト

チェック項目良い例悪い例
operationId は動詞+名詞getInventoryStatusinventory, check
description に「いつ使うか」を記述「ユーザーが在庫残数の確認を求めた場合に使用する」「在庫を取得する」
副作用を名前に反映cancelOrderAndRefunddeleteOrder
必須 / 任意パラメータを区別required: [sku], optional: [warehouse]全て required
エラーレスポンスのスキーマ定義{"error": "string", "code": "integer"}スキーマなし

OpenAPI description の LLM 最適化

paths:
  /inventory/{sku}:
 get:
operationId: getInventoryStatus
description: >
  ユーザーが特定商品の在庫残数・入庫予定・在庫アラート状態を確認したい場合に使用する。
  在庫がない / 少ない場合の発注提案は別の action_group_order を使用すること。
parameters:
  - name: sku
 in: path
 required: true
 description: 商品SKUコード (例: ITEM-001)
 schema:
type: string
  - name: warehouse
 in: query
 required: false
 description: 特定倉庫の在庫のみ取得する場合に指定 (省略時は全倉庫合計)
 schema:
type: string

description には「いつ使うか」と「使ってはいけない場合」を記述することで LLM の誤選択を防ぎます。


3-4. IAM 権限設計 — IAM Vol4 STS 架橋

Bedrock Agent は Service-linked Role を使って Foundation Model の呼び出しと Lambda の実行を行います。この IAM 設計は IAM Vol4 (STS Cross-Account) で解説した sts:AssumeRole パターンの応用です。

# Bedrock Agent 実行 IAM Role
resource "aws_iam_role" "bedrock_agent" {
  name = "${local.prefix}-bedrock-agent-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "bedrock.amazonaws.com" }
Action = "sts:AssumeRole"
Condition = {
  StringEquals = {
 "aws:SourceAccount" = data.aws_caller_identity.current.account_id
  }
  ArnLike = {
 "aws:SourceArn" = "arn:aws:bedrock:${var.region}:${data.aws_caller_identity.current.account_id}:agent/*"
  }
}
 }]
  })
}

resource "aws_iam_role_policy" "bedrock_agent_policy" {
  name = "bedrock-agent-policy"
  role = aws_iam_role.bedrock_agent.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Effect= "Allow"
  Action= ["bedrock:InvokeModel"]
  Resource = "arn:aws:bedrock:${var.region}::foundation-model/anthropic.claude-*"
},
{
  Effect= "Allow"
  Action= ["lambda:InvokeFunction"]
  Resource = aws_lambda_function.action_group.arn
},
{
  Effect= "Allow"
  Action= ["bedrock:Retrieve"]
  Resource = aws_bedrockagent_knowledge_base.main.arn
}
 ]
  })
}

信頼ポリシーの Conditionaws:SourceAccountaws:SourceArn の両方を設定することで Confused Deputy 攻撃 を防ぎます(IAM Vol4 §3 参照)。

IAM Vol1 (IAM評価ロジック) で解説した 5 層評価(SCP → Permission Boundary → Identity-based → Resource-based → Session Policy)の観点では、Bedrock Agent Role に付与する Permission は Identity-based Policy(上記 aws_iam_role_policy)で制御します。Organization SCP で bedrock:* を全体許可しているかを事前に確認してください。


§3 では Agent の設計基盤(Instruction / FM 選定 / Tool 設計 / IAM)を整備しました。次の §4 では Agent が参照する Knowledge Base の設計(S3 / OpenSearch Serverless / Embeddings / Chunking 戦略)を解説します。RAG の精度は Knowledge Base のチャンク設計と Embeddings モデルの選択に大きく依存するため、§3 の Action Group 設計と合わせて全体最適を意識した設計を行います。

Bedrock Agent の設計フローをまとめると、Instruction Prompt 設計 → FM 選定 → Action Group 設計 → IAM Role 設定 の順序で進めることで、各工程でのフィードバックが後工程に影響しにくくなります。特に Instruction と Action Group の設計は LLM の動作精度に直結するため、最初に時間をかけて仕様を固めることを推奨します。

Agent の初期実装が完了したら、Bedrock コンソールの「エージェントテスト」画面でサンプル入力を複数試し、Action Group 選択の正確性・Lambda の入力スキーマ適用・最終回答の品質を確認してから本番エイリアスに昇格させてください。


4. Knowledge Base 設計 (山場2) — S3 / OpenSearch Serverless / Embeddings / Chunking戦略 / RAG最適化

Bedrock Agent が「記憶」を持つには Knowledge Base (以下 KB) が不可欠だ。KB は S3 バケット (データソース) → Bedrock Ingestion Engine (Chunking + Embedding) → OpenSearch Serverless (ベクトルDB) の3層で構成され、エージェントが自然言語で問い合わせると最適なドキュメントチャンクを Retrieve して回答を生成する。


4-1. Knowledge Base のアーキテクチャ

KB の3層構造を理解することが設計の出発点だ。

コンポーネント役割
Layer 1S3 バケット (DataSource)PDF / txt / md / html / docx / csv を格納
Layer 2Bedrock KB Ingestion EngineChunking → Embedding → ベクトルDBへの書き込み
Layer 3Retrieve & Generate APIエージェントが問い合わせ → 上位チャンクを取得 → FM で回答生成

Terraform による KB + S3 DataSource の作成:

# OpenSearch Serverless コレクション (ベクトル検索用)
resource "aws_opensearchserverless_collection" "kb" {
  name = "bedrock-kb-collection"
  type = "VECTORSEARCH"
}

# Bedrock Knowledge Base 本体
resource "aws_bedrockagent_knowledge_base" "main" {
  name  = "my-knowledge-base"
  role_arn = aws_iam_role.kb_role.arn

  knowledge_base_configuration {
 type = "VECTOR"
 vector_knowledge_base_configuration {
embedding_model_arn = "arn:aws:bedrock:ap-northeast-1::foundation-model/amazon.titan-embed-text-v2:0"
 }
  }

  storage_configuration {
 type = "OPENSEARCH_SERVERLESS"
 opensearch_serverless_configuration {
collection_arn = aws_opensearchserverless_collection.kb.arn
vector_index_name = "bedrock-kb-index"
field_mapping {
  vector_field= "bedrock-knowledge-base-default-vector"
  text_field  = "AMAZON_BEDROCK_TEXT_CHUNK"
  metadata_field = "AMAZON_BEDROCK_METADATA"
}
 }
  }
}

# KB 用 IAM Role (S3読み取り + OSS書き込み + Bedrock モデル呼び出し権限)
resource "aws_iam_role" "kb_role" {
  name = "bedrock-kb-role"
  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "bedrock.amazonaws.com" }
Action = "sts:AssumeRole"
Condition = {
  StringEquals = {
 "aws:SourceAccount" = data.aws_caller_identity.current.account_id
  }
}
 }]
  })
}

resource "aws_iam_role_policy" "kb_policy" {
  name = "bedrock-kb-policy"
  role = aws_iam_role.kb_role.id
  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Effect= "Allow"
  Action= ["s3:GetObject", "s3:ListBucket"]
  Resource = [aws_s3_bucket.kb_docs.arn, "${aws_s3_bucket.kb_docs.arn}/*"]
},
{
  Effect= "Allow"
  Action= ["aoss:APIAccessAll"]
  Resource = aws_opensearchserverless_collection.kb.arn
},
{
  Effect= "Allow"
  Action= ["bedrock:InvokeModel"]
  Resource = "arn:aws:bedrock:ap-northeast-1::foundation-model/amazon.titan-embed-text-v2:0"
}
 ]
  })
}

# S3 DataSource を KB に接続
resource "aws_bedrockagent_data_source" "s3" {
  name = "s3-datasource"
  knowledge_base_id = aws_bedrockagent_knowledge_base.main.id

  data_source_configuration {
 type = "S3"
 s3_configuration {
bucket_arn = aws_s3_bucket.kb_docs.arn
 }
  }

  vector_ingestion_configuration {
 chunking_configuration {
chunking_strategy = "FIXED_SIZE"
fixed_size_chunking_configuration {
  max_tokens= 300
  overlap_percentage = 20
}
 }
  }
}

4-2. Chunking 戦略 5軸選定基準

Chunking はRAG精度に最も影響する設計パラメーターだ。ドキュメントの特性に合わせて選択する。

戦略chunk_sizeoverlap適合ドキュメント
Fixed Size (推奨デフォルト)300 tokens20%汎用テキスト・技術文書
Semantic自動なし段落構造が明確なドキュメント
Hierarchical親300+子15010%長文PDF・仕様書・マニュアル
None (Whole Doc)ファイル全体短い FAQ / JSON / 単一ページ
Custom Lambda自由自由複雑なフォーマット (表・コード付きPDF)

選定フローチャート:

ドキュメントの平均ページ数は?
  ≤ 3ページ → None (Whole Doc)
  4 〜 20ページ→ Fixed Size (300 tokens / 20% overlap)
  ≥ 21ページ→ Hierarchical または Semantic
  構造が特殊 (表/コード混在) → Custom Lambda Chunking

まず Fixed Size 300tokens / 20% overlap から始め、Retrieve 精度を計測してから調整するのが本番設計のセオリーだ。

Chunking 設定の評価方法:

KB の Retrieve 精度を評価するには、代表的な質問セット (20〜50件) を用意し、実際に Retrieve API を呼んで返答チャンクを確認する。

# Retrieve API で精度を確認
aws bedrock-agent-runtime retrieve \
  --knowledge-base-id "KBXXXXXXXX" \
  --retrieval-query '{"text": "セキュリティグループの設定方法を教えてください"}' \
  --retrieval-configuration '{"vectorSearchConfiguration": {"numberOfResults": 5}}' \
  --query 'retrievalResults[].{Score:score,Content:content.text}' \
  --output table

スコアが 0.5 未満のチャンクが多い場合は chunk_size を小さくして再 Ingest する。スコアが高いのに回答品質が低い場合は Re-rank の導入を検討する。

Knowledge Base 設計 3鉄則

  • 鉄則1: Chunk size はデフォルト300 tokensから始める — 最初から細かく設定しすぎると文脈が失われ、大きすぎると無関係な内容が混入する。300 tokens / 20% overlap を基準に Retrieve 精度を測定して調整すること。
  • 鉄則2: Embedding モデルは言語で選ぶ — 日本語ドキュメントには Cohere Embed Multilingual v3 を使う。Titan Text v2 は英語専用のため日本語で精度が落ちる。
  • 鉄則3: Re-rank で精度を底上げする — Retrieve 件数を 20 件取得し、Cohere Re-rank モデルで上位5件に絞ることで回答品質が大幅に向上する。Re-rank はベクトル検索の弱点 (近似検索のノイズ) を補完する。

4-3. Embedding モデル選定

Embedding モデル次元数言語コスト
Titan Text Embeddings v21024英語$0.02 / 1M tokens
Cohere Embed Multilingual v31024多言語 (日本語対応)$0.10 / 1M tokens
Titan Multimodal1536英語 + 画像$0.06 / 1M tokens

日本語ドキュメントには Cohere Embed Multilingual v3 を強く推奨する。コスト差は5倍だが、日本語 Retrieve 精度の差は致命的になりうる。英語専用ドキュメントなら Titan Text v2 でコストを抑えられる。

mermaid02: KB 同期フロー (S3 → Bedrock → OpenSearch Serverless):

flowchart LR
 S3["S3 バケット<br/>.pdf/.txt/.md"]
 Bedrock["Bedrock KB<br/>Ingestion Engine"]
 OSS["OpenSearch Serverless<br/>Vector Index"]
 Agent["Bedrock Agent"]
 FM["Foundation Model<br/>(Claude 3.5 Sonnet)"]
 Response["最終応答"]
 CWL["CloudWatch Logs<br/>SyncStatus"]

 S3 -->|"StartIngestionJob"| Bedrock
 Bedrock -->|"Chunking + Embedding"| OSS
 OSS -->|"Retrieve API"| Agent
 Agent -->|"Generate"| FM
 FM --> Response
 Bedrock -->|"同期状態"| CWL

4-4. KB 同期と EKS Vol2 観測可能性との架橋

KB DataSource の同期は非同期ジョブとして実行される。CLI で同期を開始し、状態を監視する。

# KB DataSource の同期を開始
aws bedrock-agent start-ingestion-job \
  --knowledge-base-id "KBXXXXXXXX" \
  --data-source-id "DSXXXXXXXX"

# 同期状態の確認
aws bedrock-agent get-ingestion-job \
  --knowledge-base-id "KBXXXXXXXX" \
  --data-source-id "DSXXXXXXXX" \
  --ingestion-job-id "IJXXXXXXXX" \
  --query 'ingestionJob.{Status:status,Failed:failedDocumentCount,Complete:ingestionJobStatistics}'

CloudWatch Logs Insights でKB同期ログを分析する:

KB Ingestion のログは CloudWatch Logs に記録される。以下のクエリで同期エラーを素早く特定できる。

fields @timestamp, @message
| filter @message like /ingestion/
| filter @message like /FAILED|ERROR/
| sort @timestamp desc
| limit 20

EKS本番運用Vol2 §4 ADOTメトリクス収集 で構築した CloudWatch Logs Insights の活用手法を KB 同期監視にも応用できる。ログクエリを定型化して CloudWatch Alarm と組み合わせると、同期失敗を自動検知できる。


4-5. RAG 最適化テクニック

KBを構築した後は3つの最適化パターンで回答品質を向上させる。

① Re-ranking (最も効果的):

Retrieve 件数を多めに取得 (例: 20件) し、Re-rank モデルで関連性の高い上位5件に絞り込む。ベクトル検索は「意味的に近い」チャンクを返すが、Re-rank は「質問への回答として有用か」で再スコアリングする。

import boto3
import json

bedrock_runtime = boto3.client('bedrock-agent-runtime', region_name='ap-northeast-1')

# Step1: 20件 Retrieve
retrieve_resp = bedrock_runtime.retrieve(
 knowledgeBaseId='KBXXXXXXXX',
 retrievalQuery={'text': 'セキュリティグループの設定方法'},
 retrievalConfiguration={'vectorSearchConfiguration': {'numberOfResults': 20}}
)

# Step2: Re-rank で上位5件に絞る (Cohere Rerank v3.5 使用)
rerank_resp = bedrock_runtime.rerank(
 rerankingConfiguration={
  'type': 'BEDROCK_RERANKING_MODEL',
  'bedrockRerankingConfiguration': {
'modelConfiguration': {
 'modelArn': 'arn:aws:bedrock:ap-northeast-1::foundation-model/cohere.rerank-v3-5:0'
},
'numberOfResults': 5
  }
 },
 sources=[
  {'type': 'INLINE', 'inlineDocumentSource': {
'type': 'TEXT',
'textDocument': {'text': r['content']['text']}
  }}
  for r in retrieve_resp['retrievalResults']
 ],
 textSources=[{'type': 'QUERY', 'textQuery': {'text': 'セキュリティグループの設定方法'}}]
)

② Hybrid Search (ベクトル検索 + キーワード検索):

OpenSearch Serverless の BM25 (キーワード検索) とベクトル検索を組み合わせることで、固有名詞やコードスニペットなど意味ベクトルが弱いケースでも精度を維持できる。

③ Metadata Filtering:

S3 オブジェクトにメタデータを付与し、Retrieve 対象を絞り込む。例えば department=engineering のメタデータを付けた技術文書だけを検索対象にできる。

{
  "filter": {
 "equals": {
"key": "department",
"value": "engineering"
 }
  }
}

Retrieve API を呼ぶ際に retrievalConfiguration.vectorSearchConfiguration.filter に上記 JSON を渡すと、メタデータでフィルタリングされたチャンクのみが返される。


fig04: Knowledge Base 設計 — S3 × OpenSearch Serverless × Embeddings × RAG (山場2)


5. Action Group 実装 — Lambda + OpenAPI 3.0スキーマ / 入出力検証 / Idempotency

fig05: Action Group 実装 — Lambda × OpenAPI 3.0 × レスポンス連携

5-1. OpenAPI 3.0 スキーマ設計

Action Group の中核は OpenAPI 3.0 スキーマだ。Bedrock Agent は「どのエンドポイントをいつ呼ぶか」をスキーマの description から学習するため、スキーマ設計の質が Agent の精度に直結する。LLM がスキーマを読んで使い方を理解できるかを常に意識して書くこと。

LLM 精度を高める設計 3 原則

  1. operationId は動詞+名詞: getInventoryStatus, createPurchaseOrder のように、何をするかが一目でわかる命名にする
  2. description は LLM が読む前提で書く: 「〇〇をユーザーが求めた場合にこのエンドポイントを使う」という文脈説明を含める
  3. parameters の required を正確に設定する: LLM は required パラメーターを必ず渡すため、任意パラメーターを required にするとエラーが増える

OpenAPI 3.0 完全例 — 在庫管理 API

openapi: "3.0.0"
info:
  title: "InventoryManagementAPI"
  version: "1.0.0"
  description: "在庫管理システムへのアクセスを提供するAPI。在庫確認・発注・商品検索をサポートする。"
paths:
  /inventory/{productId}:
 get:
operationId: getInventoryStatus
description: "ユーザーが特定商品の在庫数量を確認したい場合に使用する。productIdが不明な場合はsearchProductsを先に呼ぶこと。"
parameters:
  - name: productId
 in: path
 required: true
 schema:
type: string
description: "商品ID (例: PROD-001)"
responses:
  "200":
 description: "在庫情報"
 content:
application/json:
  schema:
 type: object
 properties:
productId:
  type: string
quantity:
  type: integer
lastUpdated:
  type: string
  format: date-time
  "404":
 description: "商品が見つからない"
  /orders:
 post:
operationId: createPurchaseOrder
description: "ユーザーが特定商品の発注を依頼した場合に使用する。在庫不足時は発注前にgetInventoryStatusで確認すること。"
requestBody:
  required: true
  content:
 application/json:
schema:
  type: object
  required: [productId, quantity]
  properties:
 productId:
type: string
 quantity:
type: integer
minimum: 1
responses:
  "201":
 description: "発注完了"
 content:
application/json:
  schema:
 type: object
 properties:
orderId:
  type: string
status:
  type: string

5-2. Lambda Handler 設計

Bedrock Agents が Lambda を呼び出す際のリクエスト形式は固定されている。actionGroup / apiPath / httpMethod / parameters を解析し、正しいレスポンス形式で返すことが必須だ。

Lambda Handler 実装例 (Python)

import json
import boto3
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.idempotency import (
 idempotent_function, DynamoDBPersistenceLayer, IdempotencyConfig
)

logger = Logger()

persistence_store = DynamoDBPersistenceLayer(table_name="IdempotencyTable")
idempotency_config = IdempotencyConfig(event_key_jmespath="requestBody.content.application/json.body.orderId")

def lambda_handler(event, context):
 logger.info("Received event", extra={"event": event})

 action_group = event.get("actionGroup")
 api_path  = event.get("apiPath")
 http_method  = event.get("httpMethod")
 parameters= event.get("parameters", [])
 request_body = event.get("requestBody", {})

 # パラメーターを dict に変換
 params = {p["name"]: p["value"] for p in parameters}

 if api_path == "/inventory/{productId}" and http_method == "GET":
  product_id = params.get("productId")
  result = get_inventory(product_id)
  status_code = 200

 elif api_path == "/orders" and http_method == "POST":
  body = request_body.get("content", {}).get("application/json", {}).get("body", "{}")
  order_data = json.loads(body)
  result = create_order(order_data)
  status_code = 201

 else:
  result = {"error": "Unknown path or method"}
  status_code = 400

 return {
  "messageVersion": "1.0",
  "response": {
"actionGroup": action_group,
"apiPath": api_path,
"httpMethod": http_method,
"httpStatusCode": status_code,
"responseBody": {
 "application/json": {
  "body": json.dumps(result, ensure_ascii=False)
 }
}
  }
 }

@idempotent_function(data_keyword_argument="order_data", config=idempotency_config, persistence_store=persistence_store)
def create_order(order_data: dict) -> dict:
 # DynamoDB の idempotency ライブラリで重複発注を防止
 return {"orderId": "ORD-20260509-001", "status": "PENDING"}

def get_inventory(product_id: str) -> dict:
 return {"productId": product_id, "quantity": 150, "lastUpdated": "2026-05-09T00:00:00Z"}

aws_lambda_powertoolsidempotent_function デコレーターを使うと、同じ orderId のリクエストが複数回届いても最初の実行結果が返され、副作用が発生しない。Bedrock Agent は LLM の確率的な動作によって同じ Action Group を複数回呼ぶことがあるため、冪等性は必須の設計要件だ。

Action Group Lambda Idempotency チェックリスト

  • ☑ 同じリクエストが2回来ても副作用なし (発注の重複防止・在庫の二重引き落とし防止)
  • ☑ DynamoDB conditional write または aws-lambda-powertools idempotency で重複制御
  • ☑ Lambda タイムアウトを Agent タイムアウト (60秒) 以内に設定する
  • ☑ エラー時は HTTP 400/500 と分かりやすいエラーメッセージを返す (LLM がリトライ判断に使う)
  • ☑ リクエストボディの入力値バリデーションを Lambda 側で行う (OpenAPI スキーマだけに依存しない)

5-3. IAM 設計 + EKS 架橋

Lambda (Action Group) には最小権限の IAM ロールを付与する。Bedrock サービスプリンシパルが Lambda を呼び出す lambda:InvokeFunction 権限も必要だ。

Terraform による IAM Role + Lambda 権限設定

resource "aws_iam_role" "action_group_lambda" {
  name = "ActionGroupLambdaRole"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_basic" {
  role = aws_iam_role.action_group_lambda.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy" "lambda_dynamodb" {
  name = "IdempotencyTableAccess"
  role = aws_iam_role.action_group_lambda.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect= "Allow"
Action= ["dynamodb:PutItem", "dynamodb:GetItem", "dynamodb:UpdateItem"]
Resource = aws_dynamodb_table.idempotency.arn
 }]
  })
}

resource "aws_lambda_permission" "bedrock_invoke" {
  statement_id  = "AllowBedrockInvoke"
  action  = "lambda:InvokeFunction"
  function_name = aws_lambda_function.action_group.function_name
  principal  = "bedrock.amazonaws.com"
  source_arn = "arn:aws:bedrock:${var.region}:${data.aws_caller_identity.current.account_id}:agent/*"
}

EKS Vol1 (IRSA) との架橋

EKS Vol1 (IRSA) で解説した IAM ロールと信頼ポリシーの設計原則は、Action Group Lambda の IAM ロール設計にも直接応用できる。Principal.Service = "lambda.amazonaws.com" の信頼ポリシー設計は EKS IRSA の OIDC 連携と構造が対応している。最小権限・リソース ARN 絞り込み・SourceArn による Confused Deputy 対策の考え方は共通だ。

EKS Vol3 (GitOps × ArgoCD) との架橋

EKS Vol3 (GitOps × ArgoCD) で構築した Terraform + GitOps のワークフローを Lambda / OpenAPI 定義のバージョン管理にも活用する。Action Group の OpenAPI スキーマ変更は必ず Git PR を経由してレビューし、Terraform apply で適用することで変更履歴を Git に残せる。

OpenAPI 3.0 公式仕様


6. 詰まりポイント7選 図解

Bedrock Agents 本番導入で頻発する7つの詰まりポイントを解説する。各パターンは「なぜ詰まるか」→「どう解くか」の2段構成で整理する。

6-1. Prompt最適化 — Agentが正しいAction Groupを選ばない

なぜ詰まるか

Instruction promptが曖昧だと、AgentはどのAction GroupをいつCallすべきか判断できない。「You are a helpful assistant.」だけのInstructionでは、在庫確認リクエストに対してKB Retrieveを実行するかgetInventoryStatusを呼ぶかの判断基準がなく、毎回異なる動作をする。Foundation Modelは「どのツールをいつ使うか」を決定する際にInstructionを主な根拠として使う。Instructionが不明確だと誤ったAction Groupが選ばれ、ユーザー体験が一貫しなくなる。

どう解くか

Instructionを「役割 / ツール方針 / 制約 / 応答スタイル」の4要素で構成し、XMLタグで構造化する。各Action Groupの「いつ使うか」を明示することが特に重要。

<role>
あなたはXXX株式会社の在庫管理AIエージェントです。
</role>

<tools>
利用可能なAction Group:
- getInventoryStatus: ユーザーが在庫数量・在庫状況を確認したい場合に必ず使用する
- searchProducts: 商品IDが不明な場合はこちらで先に商品を検索する
- createOrder: ユーザーが明示的に「発注して」と依頼した場合のみ使用する
  (数量100個超は確認が必要。FAQや在庫確認だけなら呼ばない)
Knowledge Base: FAQ・製品仕様・取り扱い対応手順の検索に使用する。在庫数量は必ずgetInventoryStatusで取得する。
</tools>

<constraints>
- 在庫数量は推測で答えてはならない
- 発注実行前に商品名・数量をユーザーに確認する
- 不明な点は必ず質問してから先に進む
</constraints>

Instructionのテスト: enableTrace=TrueでAgentを呼び出し、OrchestrationTraceのinvocationInputフィールドで「どのAction Groupが選択されたか」を確認する。意図と異なるAction Groupが選ばれた場合はInstructionの該当ツール説明を修正する。

詰まり1 解決策: Instructionに「どのツールをいつ使うか」をXMLタグで構造化して明記する。曖昧なInstructionは誤Action Group選択の根本原因となる。enableTrace=TrueでOrchestrationTraceを確認しながらInstructionを調整する。

6-2. KB同期失敗 — Ingestion Jobが完了しない

なぜ詰まるか

Knowledge BaseのIngestion JobがFAILEDになる主な原因は3つある。①S3に配置したファイルが対応外の形式(対応形式: PDF / txt / md / html / docx / csv。JPG/PNG/xlsx等は直接非対応)、②OpenSearch ServerlessのData Accessポリシーにベースサービスプリンシパルが含まれていない、③KBロールのIAM権限にaoss:APIAccessAllが欠落している。

どう解くか

Ingestion JobのstatusをポーリングしてFAILED時はfailureReasonsフィールドで原因を特定する。

# Ingestion Job のステータスとエラー理由を確認
aws bedrock-agent get-ingestion-job \
  --knowledge-base-id KB_ID \
  --data-source-id DS_ID \
  --ingestion-job-id JOB_ID \
  --query 'ingestionJob.{status:status,reasons:failureReasons}' \
  --output json
# Terraform: KBロールに必要な最小権限を付与
resource "aws_iam_role_policy" "kb_aoss_access" {
  name = "kb-aoss-access"
  role = aws_iam_role.knowledge_base.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Effect= "Allow"
  Action= ["aoss:APIAccessAll"]
  Resource = aws_opensearchserverless_collection.kb.arn
},
{
  Effect = "Allow"
  Action = ["s3:GetObject", "s3:ListBucket"]
  Resource = [
 aws_s3_bucket.kb_source.arn,
 "${aws_s3_bucket.kb_source.arn}/*"
  ]
}
 ]
  })
}
詰まり2 解決策: StartIngestionJobのstatusをポーリングし、FAILED時はfailureReasonsフィールドで原因を特定する。S3ファイル形式・OSSのData Accessポリシー・KBロールのaoss:APIAccessAll権限の3点を必ず確認する。

6-3. Action Group遅延 — Agentの応答が60秒でタイムアウト

なぜ詰まるか

Bedrock AgentのデフォルトsessionTimeout(60秒)に対して、Lambda Functionのtimeoutがデフォルト(3秒)のままだったりコールドスタートが発生したりすると、AgentはLambdaの応答を待てずに処理を中断する。コンテナイメージ型のLambdaや重いライブラリを使用する場合は初回起動に5〜10秒かかることがある。

どう解くか

Lambda timeoutをAgentのsessionTimeout(60秒)より短く設定し、本番エイリアスにProvisioned Concurrencyを設定してコールドスタートを排除する。

# Lambda タイムアウト確認
aws lambda get-function-configuration \
  --function-name my-action-group \
  --query 'Timeout'

# Provisioned Concurrency 設定 (コールドスタート解消)
aws lambda put-provisioned-concurrency-config \
  --function-name my-action-group \
  --qualifier PROD \
  --provisioned-concurrent-executions 3
# Terraform: Lambda timeout と Provisioned Concurrency を設定
resource "aws_lambda_function" "action_group" {
  function_name = "my-action-group"
  timeout = 55  # sessionTimeout(60秒)より小さく設定
  memory_size= 512
}

resource "aws_lambda_provisioned_concurrency_config" "prod" {
  function_name= aws_lambda_function.action_group.function_name
  qualifier = aws_lambda_alias.prod.name
  provisioned_concurrent_executions = 3
}
詰まり3 解決策: Lambda timeoutをAgentのsessionTimeout(60秒)以下に設定する。コールドスタートが問題ならProvisioned Concurrencyを設定する。本番エイリアスのみへの適用でコストを抑制できる。

6-4. Trace解析 — Agentの意思決定プロセスが見えない

なぜ詰まるか

デフォルトではAgentの内部判断プロセス(どのAction Groupを選んだか、KBからどの情報を取得したか)が非表示となる。デバッグ時に「なぜその回答になったか」の根拠が分からず、Instructionの改善に手が出せない状態になる。

どう解くか

enableTrace=TrueでinvokeAgentを呼び出し、OrchestrationTraceイベントを解析する。

import boto3

client = boto3.client("bedrock-agent-runtime", region_name="ap-northeast-1")

response = client.invoke_agent(
 agentId="AGENT_ID",
 agentAliasId="ALIAS_ID",
 sessionId="debug-session-001",
 inputText="商品A001の在庫を確認して",
 enableTrace=True
)

for event in response["completion"]:
 if "trace" in event:
  trace = event["trace"]["trace"]
  if "orchestrationTrace" in trace:
orch = trace["orchestrationTrace"]
if "rationale" in orch:
 print("[判断根拠]", orch["rationale"]["text"])
if "invocationInput" in orch:
 inv = orch["invocationInput"]
 ag = inv.get("actionGroupInvocationInput", {})
 print("[呼び出し先]", ag.get("actionGroupName"), ag.get("apiPath"))

EKS Vol2の観測可能性設計で習得したCloudWatch Logs Insightsのクエリ構文を使えば、複数セッションにわたるAgentのトレースログを横断分析できる。以下のクエリでAgentの判断根拠を素早く絞り込める。

fields @timestamp, @message
| filter @message like /orchestrationTrace/
| parse @message '"text":"*"' as rationale
| sort @timestamp desc
| limit 50
詰まり4 解決策: enableTrace=TrueでOrchestrationTraceを取得し、AgentがどのAction GroupをなぜCallしたかをCloudWatch Logs Insightsで可視化する。EKS Vol2で習得した観測可能性設計がそのまま活用できる。

6-5. Memory永続化 — セッション間でコンテキストが失われる

なぜ詰まるか

invokeAgentのsessionIdを呼び出しごとに生成し直すと、Agentは毎回新規セッションとして初期化され、前回の会話コンテキストが引き継がれない。ユーザーが「さっきの発注を変更したい」と言っても、Agentは何の発注か分からない状態になる。

どう解くか

ユーザーIDとsessionIdをDynamoDBで紐付けて永続管理し、同一ユーザーには同一sessionIdを継続使用する。

import boto3, time

bedrock = boto3.client("bedrock-agent-runtime")
dynamodb = boto3.resource("dynamodb")
session_table = dynamodb.Table("AgentSessions")

def get_or_create_session(user_id: str) -> str:
 resp = session_table.get_item(Key={"userId": user_id})
 if "Item" in resp:
  last_active = resp["Item"].get("lastActive", 0)
  if time.time() - last_active < 3600:  # 1時間以内なら継続
return resp["Item"]["sessionId"]
 session_id = f"session-{user_id}-{int(time.time())}"
 session_table.put_item(Item={
  "userId": user_id,
  "sessionId": session_id,
  "lastActive": int(time.time())
 })
 return session_id

def chat(user_id: str, message: str) -> str:
 session_id = get_or_create_session(user_id)
 response = bedrock.invoke_agent(
  agentId="AGENT_ID",
  agentAliasId="ALIAS_ID",
  sessionId=session_id,
  inputText=message
 )
 session_table.update_item(
  Key={"userId": user_id},
  UpdateExpression="SET lastActive = :t",
  ExpressionAttributeValues={":t": int(time.time())}
 )
 return "".join(
  chunk["chunk"]["bytes"].decode()
  for chunk in response["completion"] if "chunk" in chunk
 )
詰まり5 解決策: sessionIdを維持してinvokeAgentを呼ぶことでセッション内のコンテキストが保持される。セッション間の永続化にはDynamoDBでsessionIdを管理し、一定時間経過後に新規セッションを発行する設計が堅実。

6-6. IAM権限ミス — AccessDeniedでAction GroupやKB Retrieveが失敗する

なぜ詰まるか

Bedrock AgentにはAgent本体のIAMロール / Lambda実行ロール / Knowledge BaseのIAMロールの3つが存在し、それぞれ異なる権限が必要。どれか1つでも不足するとAccessDeniedが発生する。特に見落としが多い権限: AgentロールのLambda InvokeFunction リソースARN指定漏れ、KBロールの aoss:APIAccessAll の欠落、AgentロールへのOpenAPI SchemaのS3アクセス権限不足。

どう解くか

CloudTrailのAccessDeniedイベントで不足権限を特定してから、Terraformで最小権限ポリシーを追加する。

# CloudTrail で直近のAccessDeniedを確認
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=AccessDenied \
  --query 'Events[].{time:EventTime,src:EventSource}' \
  --output table
# Bedrock Agent の最小権限IAMポリシー (Terraform)
resource "aws_iam_role_policy" "bedrock_agent_policy" {
  name = "bedrock-agent-minimal-policy"
  role = aws_iam_role.bedrock_agent.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Sid= "InvokeFoundationModel"
  Effect= "Allow"
  Action= ["bedrock:InvokeModel"]
  Resource = "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-*"
},
{
  Sid= "InvokeActionGroupLambda"
  Effect= "Allow"
  Action= ["lambda:InvokeFunction"]
  Resource = aws_lambda_function.action_group.arn
},
{
  Sid= "RetrieveFromKnowledgeBase"
  Effect= "Allow"
  Action= ["bedrock:Retrieve", "bedrock:RetrieveAndGenerate"]
  Resource = aws_bedrockagent_knowledge_base.main.arn
}
 ]
  })
}
詰まり6 解決策: CloudTrailのAccessDeniedイベントで不足権限を特定し、BedrockAgentロールにbedrock:InvokeModel / lambda:InvokeFunction / bedrock:Retrieve の3権限を追加する。ワイルドカード(*)は避け、ARNレベルで最小化する。

6-7. コスト最適化 — 月額費用が予想以上に膨らむ

なぜ詰まるか

Foundation Model呼び出しのトークン費用だけに注目し、OpenSearch Serverlessの固定コスト(最小2 OCU/月 ≈ $350)やKB Retrieve API費用を見落とすケースが多い。OSSの2 OCU最小課金は開発環境でも常時発生するため、月額見積もりが大幅に狂う。

どう解くか

コスト要因を4カテゴリに分解して把握し、規模・予算に応じた対策を選択する。

コスト要因課金形態対策
FM呼び出しinput/output token × 単価Claude Haiku / Amazon Nova Lite への切り替えで最大90%削減
KB RetrieveRetrieveAndGenerate API 呼び出し数numberOfResults削減 (10→3) でRetrieve費用を圧縮
Lambda実行実行時間 × 呼び出し数Graviton / メモリ最適化で10〜20%削減
OpenSearch ServerlessOCU時間課金 (最小2 OCU/月 ≒ $350)小規模ならInline KB (Titan Text Embeddings) でOSS不要化
# コスト削減: numberOfResults を最小化
response = client.retrieve(
 knowledgeBaseId="KB_ID",
 retrievalQuery={"text": "在庫確認の対応手順"},
 retrievalConfiguration={
  "vectorSearchConfiguration": {
"numberOfResults": 3  # デフォルト10 → 3に削減
  }
 }
)
# Terraform: Claude Haiku でFMコスト削減 (Sonnetと比較してトークン単価が約5分の1)
resource "aws_bedrockagent_agent" "main" {
  agent_name = "inventory-agent"
  foundation_model = "anthropic.claude-3-haiku-20240307-v1:0"
  instruction= "..."
}
詰まり7 解決策: OSS の最小コスト (2 OCU/月 ≈ $350) を事前に把握する。小規模ならInline KB (Titan Text Embeddings) でOSS不要化を検討する。FM呼び出しはClaude HaikuやNova Liteでコストを抑制できる。

7. アンチパターン→正解パターン変換演習 (Terraform + Bedrock SDK + OpenAPI yaml 3形式)

Bedrock Agentsで本番障害を起こしやすい5パターンを「壊れたコード → 解説 → 修正コード」の3段構成で学ぶ。すべて実際の本番環境で発生しやすい事象を元にした演習問題。

演習1: Instruction promptが曖昧でAgentが誤動作する

【問題コード】

You are a helpful AI assistant.

このInstructionでは以下のような誤動作が発生する: 在庫確認を求められてもKB Retrieveで回答しようとする / 発注依頼がなくてもcreateOrderを呼んでしまう / ユーザーが「前の発注を変えて」と言っても、どの発注か分からず止まる。

【解説】

Foundation ModelはInstructionを根拠にAction Groupの選択と使用タイミングを決定する。役割・利用可能ツール・制約・禁止事項が明記されていないと、Agentは毎回異なる判断をする。

【修正コード】

<role>
あなたはXXX株式会社の在庫管理AIエージェントです。社内オペレーター向けに在庫確認・発注業務を支援します。
</role>

<tools>
以下のAction Groupを用途に従って使い分けてください:
- getInventoryStatus: ユーザーが在庫数量・在庫状況を確認したい場合に必ず呼ぶ(推測で答えてはいけない)
- searchProducts: 商品IDが不明な場合はこちらで先に商品を検索する
- createOrder: ユーザーが明示的に「発注して」と依頼した場合のみ呼ぶ
  - 数量100個を超える場合は必ず確認する
  - FAQや在庫確認だけならcreateOrderを呼ばない
Knowledge Base: 製品仕様・FAQ・取り扱い対応手順の検索に使用する
</tools>

<constraints>
- 在庫数量は必ずgetInventoryStatusで取得する(知識で答えない)
- 発注実行前に商品名・数量をユーザーに確認する
- 不明な点は必ず質問してから進める
</constraints>

演習2: OpenAPI operationIdとdescriptionが不明確でLLMが誤選択する

【問題コード】

paths:
  /process:
 post:
operationId: process
description: "Processes the request."
parameters: []
requestBody:
  content:
 application/json:
schema:
  type: object

【解説】

Bedrock AgentはOpenAPI SchemaのdescriptionフィールドをLLMが読んで「このAPIをいつ呼ぶか」を判断する。Processes the request.のような汎用説明ではLLMが判断できず、毎回呼ぶか別のAction Groupを使うか迷う。operationIdもprocessのような動詞1語では不十分で、getInventoryStatusのような「動詞+目的語」形式にすることで推論精度が上がる。

【修正コード】

paths:
  /inventory/status:
 get:
operationId: getInventoryStatus
description: |
  指定した商品IDの在庫数量・在庫状況・最終入荷日を返す。
  ユーザーが特定商品の在庫を確認したい場合に使用する。
  商品IDが不明な場合はsearchProductsを先に呼ぶこと。
  このAPIは在庫確認のみ。発注にはcreateOrderを使う。
parameters:
  - name: productId
 in: query
 required: true
 schema:
type: string
 description: "商品ID (例: A001, B123)"

演習3: Lambda HandlerにIdempotency処理がなく重複実行が発生する

【問題コード】

import boto3

def lambda_handler(event, context):
 props = event["requestBody"]["content"]["application/json"]["properties"]
 product_id = next(p["value"] for p in props if p["name"] == "productId")
 quantity = int(next(p["value"] for p in props if p["name"] == "quantity"))

 order_id = create_order_in_db(product_id, quantity)

 return {
  "messageVersion": "1.0",
  "response": {
"actionGroup": event["actionGroup"],
"apiPath": event["apiPath"],
"httpMethod": event["httpMethod"],
"httpStatusCode": 200,
"responseBody": {
 "application/json": {"body": f'{{"orderId": "{order_id}"}}'}
}
  }
 }

【解説】

Bedrock Agentはタイムアウト後に同じリクエストを再試行することがある。このコードにはIdempotency処理がないため、同一の発注リクエストが2回以上実行され、同じ商品が重複発注される。

【修正コード】

from aws_lambda_powertools.utilities.idempotency import idempotent
from aws_lambda_powertools.utilities.idempotency.config import IdempotencyConfig

# DynamoDBでIdempotency管理 (requestIdをキーに重複実行防止)
config = IdempotencyConfig(
 event_key_jmespath=(
  "requestBody.content.\"application/json\""
  ".properties[?name=='requestId'].value | [0]"
 )
)

@idempotent(config=config)
def lambda_handler(event, context):
 props = {
  p["name"]: p["value"]
  for p in event["requestBody"]["content"]["application/json"]["properties"]
 }
 order_id = create_order_in_db(props["productId"], int(props["quantity"]))

 return {
  "messageVersion": "1.0",
  "response": {
"actionGroup": event["actionGroup"],
"apiPath": event["apiPath"],
"httpMethod": event["httpMethod"],
"httpStatusCode": 200,
"responseBody": {
 "application/json": {"body": f'{{"orderId": "{order_id}"}}'}
}
  }
 }

演習4: Terraform でKBのChunking戦略がデフォルト放置でRetrieve精度が低い

【問題コード】

resource "aws_bedrockagent_knowledge_base" "main" {
  name  = "product-kb"
  role_arn = aws_iam_role.kb_role.arn

  knowledge_base_configuration {
 type = "VECTOR"
 vector_knowledge_base_configuration {
# amazon.titan-embed-text-v1 は非推奨
embedding_model_arn = "arn:aws:bedrock:ap-northeast-1::foundation-model/amazon.titan-embed-text-v1"
 }
  }
  # chunking設定なし → デフォルト Fixed/300tokens が適用される
}

【解説】

デフォルトのFixed Chunking (300tokens) では、長い製品マニュアルや対応手順書が文脈の切れ目で分割され、Retrieveで不完全なチャンクが返ってくる場合がある。またamazon.titan-embed-text-v1 (v1) は非推奨でv2より精度が低い。

【修正コード】

resource "aws_bedrockagent_knowledge_base" "main" {
  name  = "product-kb"
  role_arn = aws_iam_role.kb_role.arn

  knowledge_base_configuration {
 type = "VECTOR"
 vector_knowledge_base_configuration {
# v2: 8192次元対応で精度向上 (v1から移行推奨)
embedding_model_arn = "arn:aws:bedrock:ap-northeast-1::foundation-model/amazon.titan-embed-text-v2:0"
 }
  }

  storage_configuration {
 type = "OPENSEARCH_SERVERLESS"
 opensearch_serverless_configuration {
collection_arn = aws_opensearchserverless_collection.kb.arn
vector_index_name = "bedrock-knowledge-base-default-index"
field_mapping {
  vector_field= "bedrock-knowledge-base-default-vector"
  text_field  = "AMAZON_BEDROCK_TEXT_CHUNK"
  metadata_field = "AMAZON_BEDROCK_METADATA"
}
 }
  }
}

resource "aws_bedrockagent_data_source" "s3" {
  knowledge_base_id = aws_bedrockagent_knowledge_base.main.id
  name  = "s3-datasource"

  data_source_configuration {
 type = "S3"
 s3_configuration {
bucket_arn = aws_s3_bucket.kb_source.arn
 }
  }

  vector_ingestion_configuration {
 chunking_configuration {
chunking_strategy = "HIERARCHICAL"
hierarchical_chunking_configuration {
  level_configurations { max_tokens = 1500 }  # 親chunk: 大きな文脈を保持
  level_configurations { max_tokens = 300 }# 子chunk: 検索精度向上
  overlap_tokens = 60
}
 }
  }
}

演習5: Bedrock Agent IAMロールに過剰権限が付与されている

【問題コード】

resource "aws_iam_role_policy" "bedrock_agent_policy" {
  name = "bedrock-agent-policy"
  role = aws_iam_role.bedrock_agent.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect= "Allow"
Action= "*"
Resource = "*"
 }]
  })
}

【解説】

Action = "*" / Resource = "*"は全AWSサービスへのフルアクセスを意味する。Bedrock AgentのIAMロールにこの権限があると、万が一Agentが侵害された場合に全AWSリソースへの不正アクセスが可能になる。本番環境では最小権限の原則を必ず適用する。

【修正コード】

resource "aws_iam_role_policy" "bedrock_agent_policy" {
  name = "bedrock-agent-minimal-policy"
  role = aws_iam_role.bedrock_agent.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Sid = "InvokeFoundationModel"
  Effect = "Allow"
  Action = ["bedrock:InvokeModel"]
  Resource = [
 "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0",
 "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-3-haiku-20240307-v1:0"
  ]
},
{
  Sid= "InvokeActionGroupLambda"
  Effect= "Allow"
  Action= ["lambda:InvokeFunction"]
  Resource = [aws_lambda_function.action_group.arn]
},
{
  Sid = "RetrieveFromKnowledgeBase"
  Effect = "Allow"
  Action = ["bedrock:Retrieve", "bedrock:RetrieveAndGenerate"]
  Resource = [aws_bedrockagent_knowledge_base.main.arn]
}
 ]
  })
}

演習解答セクションへ


8. まとめ + AIシリーズ Vol2予告 + 落とし穴10選 + IAM4巻+EKS3巻 双方向クロスリンク

8-1. 5ゴール達成チェック

本記事でカバーした学習ゴールを確認する。

  • [ ] (a) Bedrock Agents 5要素統合理解: Agent / Action Group / Knowledge Base / Lambda / OpenAPI Schemaの役割と相互関係を説明できる
  • [ ] (b) Agent設計: Instruction prompts (XMLタグ構造化) / Foundation Model選定 (Claude/Nova/Llama) / Tool設計の3要素を実装できる
  • [ ] (c) Knowledge Base設計: S3 datasource / OpenSearch Serverless / Embedding選定 (Titan v2/Cohere) / Chunking戦略 (Fixed/Hierarchical/Semantic) を設計できる
  • [ ] (d) Action Group実装: Lambda Handler (Bedrock形式) + OpenAPI 3.0 (operationId/description LLM最適化) + Idempotency処理を実装できる
  • [ ] (e) アンチパターン回避: 詰まりポイント7選+演習5問で本番でハマりやすい落とし穴を事前回避できる

これら5ゴールを達成したら、既存の深掘り記事で理解を深めることを推奨する:
Bedrock Agents 本番運用 深掘り (Session/Guardrails)
Bedrock RAG Knowledge Bases 単体入門

8-2. 落とし穴10選

Bedrock Agents本番導入で実際に踏まれやすい落とし穴を整理する。

  1. Instruction promptにツール使用タイミングを書かない → Agentが毎回異なるAction Groupを選択し動作が不安定になる
  2. OpenAPI operationIdをprocesshandleにする → LLMが判断できずAction Group選択ミスが頻発する
  3. Lambda timeoutをAgentのsessionTimeout(60秒)と同じか超える値に設定する → タイムアウト連鎖でAgentが応答を返せなくなる
  4. Lambda HandlerにIdempotency処理を入れない → Agentのリトライ時に重複実行(重複発注など)が発生する
  5. OSS最小コスト(2 OCU/月≈$350)を見落とす → 開発環境でも月額$700超が常時発生し予算超過する
  6. Knowledge BaseのIngestion Job障害を放置する → 古いデータや部分的なデータでRAGが動作し不正確な回答を返す
  7. KBロールのaoss:APIAccessAllを忘れる → Ingestion JobがFAILEDになりKBが空のままAgentが稼働する
  8. enableTraceを本番で常時有効にする → トレースデータが大量にCloudWatch Logsへ出力されコストが増大する (デバッグ時のみ有効化推奨)
  9. Embedding ModelをTitan v1のまま放置する → v2と比べてRetrieve精度が低下する。v2移行はほぼ全チャンクの再インデックスが必要で移行コストが高い
  10. AgentロールにAction=*を設定する → 最小権限原則違反。本番での不正アクセスリスクが高まる

8-3. 本番リリース前チェックリスト

本番環境にBedrock Agentsをリリースする前に確認すべき項目を整理する。

Agent設計チェック
– [ ] Instruction promptに役割・ツール方針・制約・応答スタイルの4要素が記載されている
– [ ] 各Action Groupに「いつ使うか」がInstructionに明記されている
– [ ] enableTraceをFalseに設定している(本番環境)

Action Group / Lambda チェック
– [ ] Lambda timeoutがAgentのsessionTimeout(60秒)以下に設定されている
– [ ] Lambda HandlerにIdempotency処理が実装されている
– [ ] OpenAPI operationIdが「動詞+目的語」形式で、descriptionに使用タイミングが記載されている

Knowledge Base チェック
– [ ] Ingestion JobのステータスがCOMPLETEであることを確認した
– [ ] Embedding ModelがTitan v2以降を使用している
– [ ] Chunking戦略がドキュメント種類に合わせて設定されている

IAM / セキュリティチェック
– [ ] BedrockAgentロールがワイルドカード(*)なしの最小権限ポリシーを使用している
– [ ] KBロールにaoss:APIAccessAllが付与されている
– [ ] CloudTrailでAccessDeniedが発生していないことを確認した

コスト確認
– [ ] OpenSearch Serverlessのコスト(最小2 OCU/月≈$350)を月額見積もりに含めた
– [ ] Foundation Modelの選定(Sonnet/Haiku/Nova)がユースケースに最適化されている
– [ ] KB RetrieveのnumberOfResultsが必要最小限に設定されている

8-4. AIシリーズ Vol2予告

fig06: AIシリーズ Vol1-N ロードマップ + IAM4巻+EKS3巻 完結図

AIシリーズ Vol2 近日公開: RAG最適化・Multi-Agent 連携

  • Advanced RAG: Re-ranking / Hybrid Search (ベクトル+全文) / Metadata Filtering / Contextual Retrieval
  • Multi-Agent: Supervisor Agent × Sub-Agent 設計パターン / オーケストレーション戦略
  • Guardrails: コンテンツフィルタ / PII マスキング / グラウンドチェック / 幻覚防止

本記事(Vol1)でBedrock Agentsの基礎を固めた読者が、Vol2でRAG最適化とMulti-Agent連携まで習得することで、エンタープライズ規模のAI基盤を設計・実装できるようになる。

8-5. IAM4巻 + EKS3巻 + Bedrock深掘り 双方向クロスリンク

本記事は以下のシリーズの知識を前提としている。未読の場合は各シリーズから読み始めることを推奨する。

IAM入門 4巻シリーズ (前提知識)

テーマリンク
Vol1IAMポリシー設計の基礎iam-policy-design-fundamentals
Vol2マルチアカウント設計iam-multi-account-design
Vol3権限棚卸し自動化iam-permission-inventory-automation
Vol4STS × Cross-Accountiam-sts-cross-account

EKS本番運用 3巻シリーズ (前提知識)

テーマリンク
Vol1クラスタ設計 × IRSA × ALB Ingresseks-production-cluster-design-irsa-alb-ingress
Vol2観測可能性 (FluentBit / Container Insights / ADOT)eks-production-observability-fluentbit-container-insights-adot
Vol3GitOps × ArgoCDeks-production-gitops-argocd

Bedrock 深掘りシリーズ (本記事の発展版)

記事テーマリンク
Bedrock Agents 本番運用 深掘りSession / Guardrails / 観測性 6軸bedrock-agents-production
Bedrock RAG Knowledge BasesKB単体入門bedrock-rag-knowledge-bases

AIシリーズ Vol1 (本記事)

Bedrock Agents 本番運用 完全ガイド — IAM4巻+EKS3巻読了者向けの統合入門版として、Action Group / Knowledge Base / RAG実践を1本で統合解説。


セキュリティ本格運用シリーズ (AWS本番運用5軸目)

本シリーズで習得した知識をセキュリティ運用に統合: セキュリティ本格運用 Vol1: Security Hub × GuardDuty × Audit Manager — Security Hub・GuardDuty・Audit Manager による脅威検出・コンプライアンス・ログ集約の3本柱を Terraform IaC で実装する。