Amazon Bedrock AgentCoreでAmazon Bedrock Knowledge Bases(S3 Vectors)連携する簡易的なRAGを実装してみた

Amazon Bedrock AgentCoreでAmazon Bedrock Knowledge Bases(S3 Vectors)連携する簡易的なRAGを実装してみた

2025.09.15

はじめに

お買い得なスーパーマーケットが大好きなコンサル部の神野です。

直近、Amazon Bedrock AgentCoreの機能を紹介してきましたが、自分でこれ作ろう!みたいなことをまだやっていなかったので、試しにRAGを作ってみたいと思い、本記事を書いてみました。

また、作ったものはGenUで確認して適切に動いているか確認してみたいと思います!

今回作成するもの

S3 Vectors + Amazon Bedrock Knowledge Bases + Strands Agentsを使って簡易的なRAGを作ってみようと思いました。

Strands AgentsにはDocumentを取得するためのToolでretrieveが用意されていたのでこれを試してみたいと思います!

https://strandsagents.com/latest/documentation/docs/user-guide/concepts/tools/community-tools-package/#available-tools

全体の構成としては下記のようなものを作ります。(ちょっと複雑な絵ですみません・・・)
Strands Agentsの検索部分をretrieveツールを使って Knowledge Basesに問い合わせして、その結果をLLMにコンテキストとして渡して回答させる仕組みです。

CleanShot 2025-09-15 at 10.06.21@2x

データ準備

S3のデータソース(RAGとして取り込みたいドキュメント)からベクトルデータベースにデータ同期を行います。
ここでベクトル化が行われます。

CleanShot 2025-09-15 at 10.08.57@2x

検索

ユーザーからの質問(例:「AgentCoreについて教えて」)を受けると、retrieveツールを実行してKnowledge Basesから類似するドキュメントを検索し、結果を取得します。

CleanShot 2025-09-15 at 10.08.12@2x

回答生成フェーズ

取得した検索結果をLLMのコンテキストに追加して、質問への回答を生成します。

CleanShot 2025-09-15 at 10.07.42@2x

このような仕組みでドキュメントを参照しながらLLMに回答してもらう、簡易的なRAGを作成します。

作ったAIエージェントはGenUで挙動を確認します。
GenUの連携周りは下記記事で詳細を書いているので、必要に応じてご参照ください。
GenUとの連携は本記事では割愛します。

https://dev.classmethod.jp/articles/generative-ai-use-cases-jp-genu-amazon-bedrock-agentcore/

また本記事のサンプルコードは下記レポジトリに格納しているのでこちらも必要に応じてご参照ください。

https://github.com/yuu551/rag-strands-sample

前提

  • AWS CLI 2.28.8
  • Python 3.12.6
  • AWSアカウント
    • 使用するリージョン:us-west-2
    • 使用するモデルはあらかじめ有効化する必要があります。
  • GenUの使用したバージョン:v5.1.1
  • Docker version 27.5.1-rd, build 0c97515
  • IAMロール
    • AgentCoreエージェント用に以下のポリシーをアタッチしたロールを使用します。configureコマンドで自動作成のロールだと、Bedrock Knowledege Basesの権限は付与されていないためです
IAMポリシー

以下のポリシー内のアカウントID(123456789012)は、ご自身のAWSアカウントIDに変更してください。

			
			{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ECRImageAccess",
            "Effect": "Allow",
            "Action": [
                "ecr:BatchGetImage",
                "ecr:GetDownloadUrlForLayer"
            ],
            "Resource": [
                "arn:aws:ecr:us-west-2:123456789012:repository/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogStreams",
                "logs:CreateLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:us-west-2:123456789012:log-group:/aws/bedrock-agentcore/runtimes/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogGroups"
            ],
            "Resource": [
                "arn:aws:logs:us-west-2:123456789012:log-group:*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-west-2:123456789012:log-group:/aws/bedrock-agentcore/runtimes/*:log-stream:*"
            ]
        },
        {
            "Sid": "ECRTokenAccess",
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords",
                "xray:GetSamplingRules",
                "xray:GetSamplingTargets"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": "cloudwatch:PutMetricData",
            "Condition": {
                "StringEquals": {
                    "cloudwatch:namespace": "bedrock-agentcore"
                }
            }
        },
        {
            "Sid": "GetAgentAccessToken",
            "Effect": "Allow",
            "Action": [
                "bedrock-agentcore:GetWorkloadAccessToken",
                "bedrock-agentcore:GetWorkloadAccessTokenForJWT",
                "bedrock-agentcore:GetWorkloadAccessTokenForUserId"
            ],
            "Resource": [
                "arn:aws:bedrock-agentcore:us-west-2:123456789012:workload-identity-directory/default",
                "arn:aws:bedrock-agentcore:us-west-2:123456789012:workload-identity-directory/default/workload-identity/agent-*"
            ]
        },
        {
            "Sid": "BedrockModelInvocation",
            "Effect": "Allow",
            "Action": [
                "bedrock:InvokeModel",
                "bedrock:InvokeModelWithResponseStream",
                "bedrock:ApplyGuardrail"
            ],
            "Resource": [
                "arn:aws:bedrock:*::foundation-model/*",
                "arn:aws:bedrock:us-west-2:123456789012:*"
            ]
        },
        {
            "Sid": "KBManagement",
            "Effect": "Allow",
            "Action": [
                "bedrock:CreateKnowledgeBase",
                "bedrock:GetKnowledgeBase",
                "bedrock:UpdateKnowledgeBase",
                "bedrock:DeleteKnowledgeBase",
                "bedrock:ListKnowledgeBases",
                "bedrock:TagResource",
                "bedrock:UntagResource"
            ],
            "Resource": "*"
        },
        {
            "Sid": "KBDataSourceManagement",
            "Effect": "Allow",
            "Action": [
                "bedrock:CreateDataSource",
                "bedrock:GetDataSource",
                "bedrock:UpdateDataSource",
                "bedrock:DeleteDataSource",
                "bedrock:ListDataSources",
                "bedrock:StartIngestionJob",
                "bedrock:GetIngestionJob",
                "bedrock:ListIngestionJobs",
                "bedrock:Retrieve"
            ],
            "Resource": "*"
        }
    ]
}

		

注意: このポリシーは動作確認用にかなりゆるゆるの権限設定になっています。本番環境では最小権限の原則に従って必要最小限の権限に絞ることを推奨します。

準備

データソース準備

S3バケット作成

まずはS3バケットを作成して、ドキュメントをアップロードします。
S3バケットの作成ですが、バケットタイプは汎用を選択して、任意の名前を入力してそれ以外の設定はデフォルトで作成します。

CleanShot 2025-09-13 at 17.07.45@2x

作成したら検索したいドキュメントをアップロードします。
今回は直近で作成したAgentCoreのPDFドキュメントをアップロードしておきます。

https://speakerdeck.com/yuu551/amazon-bedrock-agentcorewoshi-tutemiyou-ge-zhong-ji-neng-nohointowojie-shuo-4

Knowledge Base を手動作成

  1. Bedrock コンソール → ナレッジベース → 作成ボタンを選択します。
    CleanShot 2025-09-08 at 15.46.02@2x

  2. ナレッジベース名・IAM許可・データソースを選択します。

    • ナレッジベース名:任意の名前
    • IAM許可:今回は新しいサービスロールを作成して使用とします。
    • データソースを選択:Amazon S3を選択
      CleanShot 2025-09-08 at 15.46.19@2x 1
  3. データソース に 先ほど作成したS3 を選択してデータソース名に任意の名前を入力します。それ以外は今回はデフォルトの設定でベクトル化を行います。CleanShot 2025-09-08 at 15.47.22@2x

  4. 埋め込みモデルを選択します。今回はAmazonが提供しているTitan Text Embeddings v2を採用します。またベクトルデータベースは新しいベクトルストアをクイック作成を選択して、Amazon S3 Vectorsを選び自動作成します。
    CleanShot 2025-09-08 at 15.47.37@2x
    自動で作成されるの便利ですね。

  5. 最後に確認画面が表示されるので、問題なければナレッジベースを作成を選択します。
    CleanShot 2025-09-08 at 15.47.48@2x

無事作成できたら、データソースとベクトルストアの同期処理を行います。
作成したデータソース名を選択して、同期ボタンをクリックします。
CleanShot 2025-09-08 at 15.48.38@2x
しばらく待てば完了メッセージが表示されます。
CleanShot 2025-09-13 at 17.31.54@2x

完了したら、ナレッジベースをテストをクリックして期待通り返してくれるか確認してみます。
CleanShot 2025-09-13 at 17.33.38@2x

取得と応答生成を選択して任意のモデル(私はNova Pro)を選んで質問してみます。
CleanShot 2025-09-08 at 15.50.00@2x
しっかりとアップロードしたドキュメントが参照されていますね。
次からはこのナレッジベースを使ってAIエージェントを作成してみます。

後続ではナレッジベースIDが必要になるので、控えておきましょう。
CleanShot 2025-09-13 at 17.37.05@2x

控えたナレッジベースIDは、エージェント起動時に環境変数として設定します。
以下のようにコマンドに含めて実行してください。

			
			agentcore launch --env STRANDS_KNOWLEDGE_BASE_ID=your-knowledge-base-id

		

ライブラリインストール

依存パッケージは requirements.txt に記載してインストールします。

requirements.txt
			
			strands-agents
strands-agents-tools
bedrock-agentcore
bedrock-agentcore-starter-toolkit

		
			
			pip install -r requirements.txt

		

retrieve で実装してみた

まずは Strands Tools の retrieve を使って RAG を構築してみます。
コード全体の処理は下記となります。長いので折りたたんでポイントを解説していきます。

コード全量
			
			import os
import logging
from strands import Agent, tool
from strands.models import BedrockModel
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands_tools import retrieve as retrieve_module

LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
logging.basicConfig(
    level=getattr(logging, LOG_LEVEL, logging.INFO),
    format="%(asctime)s %(levelname)s %(name)s - %(message)s",
)
logger = logging.getLogger("strands")

app = BedrockAgentCoreApp()

SYSTEM_PROMPT = """
# RAGシステム用システムプロンプト

## 基本方針
あなたは検索結果に基づいて正確で有用な回答を提供するアシスタントです。以下のガイドラインに従って回答してください。

## 回答ルール

### 1. 検索結果の活用
- 提供された検索結果のみを情報源として使用してください
- 検索結果にない情報については推測や一般知識での補完を行わず、「検索結果に含まれていません」と明記してください
- 複数の検索結果がある場合は、それらを統合して包括的な回答を作成してください

### 2. 引用の方法
- 回答中の情報には必ず引用番号を付けてください(例:[1][2]- 回答の後に「## 参考文献」セクションを設け、以下の形式で引用元を明記してください:

		

[1] タイトル - 出典元(URL、日付等)
[2] タイトル - 出典元(URL、日付等)

			
			
### 3. 回答形式
- 簡潔で分かりやすい日本語で回答してください
- 重要なポイントは見出しや箇条書きを使って整理してください
- 長い回答の場合は冒頭に要約を記載してください

### 4. 情報が不足している場合
- 検索結果が質問に対して十分でない場合は、その旨を明記してください
- 部分的に回答できる場合は、回答できる範囲を明確にしてください

## 回答例

**質問:** 太陽光発電の仕組みについて教えてください。

**回答:**

太陽光発電は、太陽電池(ソーラーセル)を使って太陽光を直接電気エネルギーに変換するシステムです[1]。

### 基本的な仕組み
太陽電池は主にシリコンなどの半導体材料で作られており、太陽光が当たることで光電効果により電子が動き、電流が発生します[1]。この電流は直流電流のため、一般的な家庭用電力として使用するには、インバーターという装置で交流電流に変換する必要があります[2]。

### 主な構成要素
- **太陽電池パネル**: 太陽光を電気に変換[1]
- **インバーター**: 直流を交流に変換[2]
- **パワーコンディショナー**: 電力の調整・制御[2]

### 発電効率
現在の一般的な太陽電池の変換効率は15-20%程度です[1]。

## 参考文献
[1] 太陽光発電の基礎知識 - 新エネルギー財団(https://example.com/solar-basics, 2023年4月)
[2] 太陽光発電システムの構成 - エネルギー技術研究所(https://example.com/solar-system, 2023年3月)

---

## 注意事項
- 検索結果が古い情報の場合は、その旨を明記してください
- 矛盾する情報が複数ある場合は、両方の見解を紹介してください
- 専門用語を使用する際は、可能な限り分かりやすい説明を併記してください
"""

STRANDS_KNOWLEDGE_BASE_ID = os.environ.get("STRANDS_KNOWLEDGE_BASE_ID", "XXXXXXXXXX")

@app.entrypoint
async def entrypoint(payload):
  logger.info("処理開始")
  message = payload.get("prompt", "")
  logger.info("prompt=%r", message)
  str_message = str(message)
  logger.info("str_message=%r", str_message)
  model = payload.get("model", {})
  model_id = model.get("modelId","anthropic.claude-3-5-haiku-20241022-v1:0")
  model = BedrockModel(model_id=model_id, params={"max_tokens": 4096, "temperature": 0.7}, region="us-west-2")
  agent = Agent(model=model, system_prompt=SYSTEM_PROMPT, tools=[retrieve_module])

  # Knowledge Baseからの取得(環境変数が有効な場合のみ)
  augmented_prompt = str_message
  kb_id = STRANDS_KNOWLEDGE_BASE_ID
  logger.info("kb_id=%s", kb_id)
  try:
      if kb_id and kb_id != "your_kb_id":
          kb_results = agent.tool.retrieve(
              text=str_message,
              knowledgeBaseId=kb_id,
              numberOfResults=9,
              score=0.4,
              region="us-west-2",
          )
          logger.info("kb_results=%s", kb_results)
          kb_block = str(kb_results)
          logger.info("kb_block=%s", kb_block)
          if kb_block:
              augmented_prompt = (
                  "以下はKnowledge Baseからの検索結果です。回答中は必ず番号で引用してください。\n"
                  "検索結果:\n" + kb_block + "\n\n"
                  "ユーザーの質問:\n" + str_message
              )
  except Exception as e:
      # KB取得に失敗しても通常回答にフォールバック
      logger.exception("Knowledge Base 取得に失敗しました")
      augmented_prompt = str_message

  stream_messages = agent.stream_async(augmented_prompt)
  async for message in stream_messages:
      if "event" in message:
          yield message

if __name__ == "__main__":
  app.run()

		

まずはシステムプロンプトから確認していきます。
提供された検索結果のみを情報源として、参照元の情報を添えるように指示します。

システムプロンプト
			
			SYSTEM_PROMPT = """
# RAGシステム用システムプロンプト

## 基本方針
あなたは検索結果に基づいて正確で有用な回答を提供するアシスタントです。以下のガイドラインに従って回答してください。

## 回答ルール

### 1. 検索結果の活用
- 提供された検索結果のみを情報源として使用してください
- 検索結果にない情報については推測や一般知識での補完を行わず、「検索結果に含まれていません」と明記してください
- 複数の検索結果がある場合は、それらを統合して包括的な回答を作成してください

### 2. 引用の方法
- 回答中の情報には必ず引用番号を付けてください(例:[1][2]- 回答の後に「## 参考文献」セクションを設け、以下の形式で引用元を明記してください:
  ```
  [1] タイトル - 出典元(URL、日付等)
  [2] タイトル - 出典元(URL、日付等)
  ```

### 3. 回答形式
- 簡潔で分かりやすい日本語で回答してください
- 重要なポイントは見出しや箇条書きを使って整理してください
- 長い回答の場合は冒頭に要約を記載してください

### 4. 情報が不足している場合
- 検索結果が質問に対して十分でない場合は、その旨を明記してください
- 部分的に回答できる場合は、回答できる範囲を明確にしてください

## 回答例

**質問:** 太陽光発電の仕組みについて教えてください。

**回答:**

太陽光発電は、太陽電池(ソーラーセル)を使って太陽光を直接電気エネルギーに変換するシステムです[1]### 基本的な仕組み
太陽電池は主にシリコンなどの半導体材料で作られており、太陽光が当たることで光電効果により電子が動き、電流が発生します[1]。この電流は直流電流のため、一般的な家庭用電力として使用するには、インバーターという装置で交流電流に変換する必要があります[2]### 主な構成要素
- **太陽電池パネル**: 太陽光を電気に変換[1]
- **インバーター**: 直流を交流に変換[2]
- **パワーコンディショナー**: 電力の調整・制御[2]

### 発電効率
現在の一般的な太陽電池の変換効率は15-20%程度です[1]## 参考文献
[1] 太陽光発電の基礎知識 - 新エネルギー財団(https://example.com/solar-basics, 20234月)
[2] 太陽光発電システムの構成 - エネルギー技術研究所(https://example.com/solar-system, 20233月)

---

## 注意事項
- 検索結果が古い情報の場合は、その旨を明記してください
- 矛盾する情報が複数ある場合は、両方の見解を紹介してください
- 専門用語を使用する際は、可能な限り分かりやすい説明を併記してください

		

retrieveツールをtoolsに設定して、呼び出します。

			
			# import
from strands_tools import retrieve

# ~省略~

# retrieveを指定
agent = Agent(model=model, system_prompt=SYSTEM_PROMPT, tools=[retrieve])
# ~省略~

# toolを使用
kb_results = agent.tool.retrieve(
	text=str_message,
	knowledgeBaseId=kb_id,
	numberOfResults=9,
	score=0.4,
	region="us-west-2",
)

		

取得した結果をコンテキストに含ませてLLMに回答させます。

			
			augmented_prompt = (
	"以下はKnowledge Baseからの検索結果です。回答中は必ず番号で引用してください。\n"
	"検索結果:\n" + kb_block + "\n\n"
	"ユーザーの質問:\n" + str_message
)

		

これで実装完了です!シンプルですね。早速デプロイを進めていきます。

まずはagentcore configureコマンドで設定ファイルを作成します。
IAMロールは事前に作成したロールを指定するようにします。それ以外はデフォルトの設定で構いません。

			
			agentcore configure --entrypoint agent.py

# 事前に作成したAgentCore用のIAMロールを指定
🔐 Execution Role
Press Enter to auto-create execution role, or provide execution role ARN/name to use existing
Execution role ARN/name (or press Enter to auto-create):

		

設定が完了したらagentcore launchコマンドを実行してデプロイします。

			
			agentcore launch --env STRANDS_KNOWLEDGE_BASE_ID=your-knowledge-base-id

		

デプロイが完了したら早速GenUで動作確認してみます!
「AgentCoreについて教えて」と質問してみます。

CleanShot 2025-09-13 at 18.09.38@2x

回答結果
			
			# Amazon Bedrock AgentCoreについて

## 概要
Amazon Bedrock AgentCoreは、AIエージェントを展開・運用するために最適なマネージドサービスです[4]。2023年7月16日にパブリックプレビューとして公開されました[4][7]。

## 主な特徴

### サービスの目的
AgentCoreは、AIエージェント開発に必要な機能が揃ったマネージドサービスとして提供されています[1]。AIエージェントを使用する上で必要な認証・ツール連携などの便利な機能がマネージドサービスとして統合されています[7]。

### 対応フレームワーク
- Strands Agents
- LangGraph
など、多様なエージェントフレームワークに対応しています[7]。

## 主要機能

AgentCoreは以下の6つの主要機能から構成されています[1][8]:

### 1. Runtime(ランタイム)
- **機能**: ホスティング機能[8]
- **説明**: AIエージェントをデプロイするための基盤機能[8]

### 2. Identity(認証)
- **機能**: 認証機能[8]
- **説明**: AIエージェントへのアクセス制御を管理

### 3. Gateway(ゲートウェイ)
- **機能**: 外部処理のTool化機能[8]
- **説明**: 外部サービスとの連携を効率化

### 4. Memory(メモリ)
- **機能**: 記憶機能[8]
- **使用例**: 
  - Short-term Memory: 日々の会話履歴を保存[6]
  - Long-term Memory: 個人の苦手状況や学習内容のサマリーを保存[6]

### 5. Built-in Tools(組み込みツール)
以下の実行環境が提供されています[2][8]:
- **Code Interpreter**: コードを安全に実行できる環境[2]
- **Browser**: ブラウザを操作できる環境[2]

### 6. Observability(可観測性)
- **機能**: AIエージェントの動作を可視化[2]
- **特徴**: 
  - タイムライン上でAIエージェントの動きを確認可能[2]
  - ツール使用状況の追跡[2]
  - スパン単位での有効時間確認[2]
  - ボトルネックの特定が容易[2]

## AIエージェントとは
AIエージェントとは、自律的に判断・行動できるAIシステムのことです[7]。ユーザーの指示を理解し、必要なツールを自身で計画を立てて使いながらタスクを実行します[7]。まさに人間の代理として計画的に作業を行うシステムです[9]。

## プレビュー期間
9月16日までプレビュー期間中は無料で使用できます[4]。

## 参考文献
[1] 検索結果1 - Amazon Bedrock AgentCoreまとめ資料
[2] 検索結果2 - AgentCore可視化機能説明資料  
[3] 検索結果3 - 神野雄大氏プロフィール・登壇資料
[4] 検索結果4 - Amazon Bedrock AgentCore概要説明
[5] 検索結果5 - Amazon Bedrock AgentCore解説スライド
[6] 検索結果6 - AgentCore Memory機能使用例
[7] 検索結果7 - AIエージェントフレームワーク対応説明
[8] 検索結果8 - Amazon Bedrock AgentCore機能一覧
[9] 検索結果9 - AIエージェント活用事例


		

回答できている!!やった・・・があれ?引用元が適切に返却されていない・・・??
もしかしてツールの取得結果にS3リンクなどが取得できていないのかしらと気になりました。
ツールで取得した結果をログ出力して確認してみました。

ツールの取得結果(抜粋)
			
			{
  "content": [{
    "text": "Retrieved 9 results with score >= 0.4:\n\nScore: 0.5354\nDocument ID: Unknown\nContent: 私まとめ 79 Amazon Bedrock AgentCoreは、AIエージェント開発に必要 な機能が揃ったマネージドサービスです。...",
    "formatted_results": [
      {
        "score": 0.5354,
        "document_id": "Unknown",
        "content": "私まとめ 79 Amazon Bedrock AgentCoreは、AIエージェント開発に必要 な機能が揃ったマネージドサービスです。Runtime、Identity、Memory、Gateway、Built-in Tools、Observabilityを活⽤して、AIエージェントを構築してみましょう!!"
      },
      {
        "score": 0.5102,
        "document_id": "Unknown",
        "content": "具体的な可視化を⾒てみる 66 下記のようにタイムライン上でAIエージェントの動きを確認することができます。例えばtoolを使⽤したのは⾚枠のように確認できます。"
      }
    ]
  }]
}

		

ログを見るとやはり、Document ID: Unknownとなっていますね。
ここにs3のURLが入ってきて欲しかったのですが・・・
retrieveの具体的な処理も確認してみましょう。

https://github.com/strands-agents/tools/blob/main/src/strands_tools/retrieve.py

retrieve の整形ロジックは参照元を customDocumentLocation に限定してしまっています。今回のケースでは s3Location 側に URI が入るため、Document ID は常に "Unknown"となり、S3 の URL が取得できません。レスポンスと想定しているデータレイアウトが異なりパースできていないから、S3のURLも取得できていないといった原因でした。

注意: この動作は記事執筆時点(2025年9月)のretrieveツールの仕様です。Strands Toolsは活発に開発されているので、今後のアップデートで改善される可能性があります。最新の仕様は公式リポジトリをご確認ください。

retrieve実装

retrieve
			
			doc_id = result.get("location", {}).get("customDocumentLocation", {}).get("id", "Unknown")
...
text = content["text"]
formatted.append(f"Content: {text}\n")

		

S3をナレッジベースとした場合のレスポンス例

S3をナレッジベースとした場合のレスポンス例(抜粋)
			
			{
  "ResponseMetadata": {
    "RequestId": "xxxx-xxxx-xxxx-xxxx",
    "HTTPStatusCode": 200
  },
  "retrievalResults": [
    {
      "content": {
        "text": "私まとめ 79 Amazon Bedrock AgentCoreは、AIエージェント開発に必要な機能が揃ったマネージドサービスです。Runtime、Identity、Memory、Gateway、Built-in Tools、Observabilityを活用して、AIエージェントを構築してみましょう!!",
        "type": "TEXT"
      },
      "location": {
        "s3Location": {
          "uri": "s3://strands-sample-xxxxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf"
        },
        "type": "S3"
      },
      "metadata": {
        "x-amz-bedrock-kb-source-uri": "s3://strands-sample-xxxxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf",
        "x-amz-bedrock-kb-document-page-number": 78.0,
        "x-amz-bedrock-kb-chunk-id": "f47935bc-4296-426b-a6fa-f74f0d775244",
        "x-amz-bedrock-kb-data-source-id": "XXXXXXXXXX"
      },
      "score": 0.6020125842944019
    }
  ]
}

		

カスタムツールに切り替え

単純に情報を返却するだけならいいですが、やはり引用の正確性を担保したいですよね。Bedrock Knowledge Bases のレスポンスから必要な要素だけを抽出して JSON で返す ツールkb_search を自作することにしました。

kb_search の実装

コード全量は下記ですが長いので折りたたみます。
またポイントだけを解説していきます。

コード全量
			
			import os
import json
from typing import Optional
import boto3
from strands import Agent, tool
from strands.models import BedrockModel
from bedrock_agentcore.runtime import BedrockAgentCoreApp

app = BedrockAgentCoreApp()

SYSTEM_PROMPT = """
# RAGシステム用システムプロンプト

## 基本方針
あなたは検索結果に基づいて正確で有用な回答を提供するアシスタントです。以下のガイドラインに従って回答してください。

## 回答ルール

### 1. 検索結果の活用
- 提供された検索結果のみを情報源として使用してください
- 検索結果にない情報については推測や一般知識での補完を行わず、「検索結果に含まれていません」と明記してください
- 複数の検索結果がある場合は、それらを統合して包括的な回答を作成してください

### 2. 引用の方法
- 回答中の情報には必ず引用番号を付けてください(例:[1]、[2])
- 回答の後に「## 参考文献」セクションを設け、以下の形式で引用元を明記してください:
  ```
  [1] タイトル - 出典元(URL、日付等)
  [2] タイトル - 出典元(URL、日付等)
  ```
- 検索結果がJSONとして渡される場合は、各項目から uri を抽出し、参考文献のURLとして使用してください
- 参考文献は「ファイル名 と S3 URL」を明示してください。ファイル名はURIの末尾(例: s3://bucket/path/file.pdf → file.pdf)を用い、URLは location.s3Location.uri(なければ metadata.x-amz-bedrock-kb-source-uri)を使用してください。ページ番号があれば (p.<番号>) を付与してください。
  例:
  ```
  [1] s3://strands-sample-xxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf (p.78)
  [2] s3://strands-sample-xxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf (p.4)
  ```

### 3. 回答形式
- 簡潔で分かりやすい日本語で回答してください
- 重要なポイントは見出しや箇条書きを使って整理してください
- 長い回答の場合は冒頭に要約を記載してください

### 4. 情報が不足している場合
- 検索結果が質問に対して十分でない場合は、その旨を明記してください
- 部分的に回答できる場合は、回答できる範囲を明確にしてください

### 5. ツールの利用
- このエージェントは `kb_search(query, max_results?)` ツールを利用できます
- 回答前に適切なクエリで `kb_search` を呼び出し、結果を根拠として使用してください
- 複数結果がある場合は重要度の高いものを優先し、重複を避けて統合してください
- 引用に使った順序で番号を付与し、末尾の「参考文献」に対応させてください(title/URL/日付など、取得できる範囲で記載)

## 回答例

**質問:** 太陽光発電の仕組みについて教えてください。

**回答:**

太陽光発電は、太陽電池(ソーラーセル)を使って太陽光を直接電気エネルギーに変換するシステムです[1]。

### 基本的な仕組み
太陽電池は主にシリコンなどの半導体材料で作られており、太陽光が当たることで光電効果により電子が動き、電流が発生します[1]。この電流は直流電流のため、一般的な家庭用電力として使用するには、インバーターという装置で交流電流に変換する必要があります[2]。

### 主な構成要素
- **太陽電池パネル**: 太陽光を電気に変換[1]
- **インバーター**: 直流を交流に変換[2]
- **パワーコンディショナー**: 電力の調整・制御[2]

### 発電効率
現在の一般的な太陽電池の変換効率は15-20%程度です[1]。

## 参考文献
[1] 太陽光発電の基礎知識 - 新エネルギー財団(https://example.com/solar-basics, 2023年4月)
[2] 太陽光発電システムの構成 - エネルギー技術研究所(https://example.com/solar-system, 2023年3月)

---

## 注意事項
- 検索結果が古い情報の場合は、その旨を明記してください
- 矛盾する情報が複数ある場合は、両方の見解を紹介してください
- 専門用語を使用する際は、可能な限り分かりやすい説明を併記してください
"""

STRANDS_KNOWLEDGE_BASE_ID = os.environ.get("STRANDS_KNOWLEDGE_BASE_ID", "XXXXXXXXXX")

# =========================
# Bedrock KB ツール用セットアップ
# =========================
BEDROCK_CLIENT = None
KB_REGION = os.environ.get("AWS_REGION", "us-west-2")
KB_MAX_RESULTS = int(os.environ.get("BEDROCK_KB_MAX_RESULTS", "5"))

def _ensure_bedrock_client(region_name: Optional[str] = None):
    global BEDROCK_CLIENT
    if BEDROCK_CLIENT is None:
        region = region_name or KB_REGION
        BEDROCK_CLIENT = boto3.client("bedrock-agent-runtime", region_name=region)
    return BEDROCK_CLIENT

@tool
def kb_search(query: str, max_results: Optional[int] = None) -> str:
    """
    ナレッジベースから関連文書を検索(Retrieve)します。

    Args:
        query: 検索クエリ
        max_results: 取得する最大件数(省略時は環境変数の既定)

    Returns:
        JSON文字列(success, resultsなどを含む)
    """
    try:
        client = _ensure_bedrock_client()
        kb_id = STRANDS_KNOWLEDGE_BASE_ID
        if not kb_id:
            return json.dumps({
                "success": False,
                "error": "環境変数 STRANDS_KNOWLEDGE_BASE_ID が設定されていません",
                "results": [],
            }, ensure_ascii=False)

        num = max_results or KB_MAX_RESULTS
        response = client.retrieve(
            knowledgeBaseId=kb_id,
            retrievalQuery={"text": query},
            retrievalConfiguration={
                "vectorSearchConfiguration": {
                    "numberOfResults": num,
                    "overrideSearchType": "SEMANTIC",
                }
            },
        )

        items = []
        for r in response.get("retrievalResults", []):
            content = r.get("content", {})
            location = r.get("location", {})
            metadata = r.get("metadata", {})
            s3loc = location.get("s3Location", {})
            page = metadata.get("x-amz-bedrock-kb-document-page-number")
            if isinstance(page, float) and page.is_integer():
                page = int(page)
            items.append({
                "content": content.get("text", ""),
                "type": content.get("type"),
                "score": r.get("score", 0),
                "uri": s3loc.get("uri") or metadata.get("x-amz-bedrock-kb-source-uri"),
                "page": page,
                "chunkId": metadata.get("x-amz-bedrock-kb-chunk-id"),
                "dataSourceId": metadata.get("x-amz-bedrock-kb-data-source-id"),
            })
        return json.dumps({
            "success": True,
            "query": query,
            "results_count": len(items),
            "results": items,
        }, ensure_ascii=False)
    except Exception as e:
        return json.dumps({
            "success": False,
            "query": query,
            "error": str(e),
            "results": [],
        }, ensure_ascii=False)

@app.entrypoint
async def entrypoint(payload):
    message = payload.get("prompt", "")
    model = payload.get("model", {})
    model_id = model.get("modelId", "anthropic.claude-3-5-haiku-20241022-v1:0")
    model = BedrockModel(
        model_id=model_id,
        params={"max_tokens": 4096, "temperature": 0.7},
        region=KB_REGION,
    )
    agent = Agent(
        model=model,
        system_prompt=SYSTEM_PROMPT,
        tools=[kb_search],
    )

    stream_messages = agent.stream_async(message)
    async for message in stream_messages:
        if "event" in message:
            yield message

if __name__ == "__main__":
    app.run()

		

ツールを@toolデコレーターを使って定義します。
Knowledge Basesに問い合わせして、結果を加工してレスポンスを返却するシンプルな処理です。
先ほど抽出できていなかったS3のドキュメントURLを抽出します。

			
			@tool
def kb_search(query: str, max_results: Optional[int] = None) -> str:
    """
    ナレッジベースから関連文書を検索(Retrieve)します。

    Args:
        query: 検索クエリ
        max_results: 取得する最大件数(省略時は環境変数の既定)

    Returns:
        JSON文字列(success, resultsなどを含む)
    """
    try:
        client = _ensure_bedrock_client()
        kb_id = STRANDS_KNOWLEDGE_BASE_ID
        if not kb_id:
            return json.dumps({
                "success": False,
                "error": "環境変数 STRANDS_KNOWLEDGE_BASE_ID が設定されていません",
                "results": [],
            }, ensure_ascii=False)

        num = max_results or KB_MAX_RESULTS
        response = client.retrieve(
            knowledgeBaseId=kb_id,
            retrievalQuery={"text": query},
            retrievalConfiguration={
                "vectorSearchConfiguration": {
                    "numberOfResults": num,
                    "overrideSearchType": "SEMANTIC",
                }
            },
        )

        items = []
        for r in response.get("retrievalResults", []):
            content = r.get("content", {})
            location = r.get("location", {})
            metadata = r.get("metadata", {})
            s3loc = location.get("s3Location", {})
            page = metadata.get("x-amz-bedrock-kb-document-page-number")
            if isinstance(page, float) and page.is_integer():
                page = int(page)
            items.append({
                "content": content.get("text", ""),
                "type": content.get("type"),
                "score": r.get("score", 0),
                "uri": s3loc.get("uri") or metadata.get("x-amz-bedrock-kb-source-uri"),
                "page": page,
                "chunkId": metadata.get("x-amz-bedrock-kb-chunk-id"),
                "dataSourceId": metadata.get("x-amz-bedrock-kb-data-source-id"),
            })
        return json.dumps({
            "success": True,
            "query": query,
            "results_count": len(items),
            "results": items,
        }, ensure_ascii=False)
    except Exception as e:
        return json.dumps({
            "success": False,
            "query": query,
            "error": str(e),
            "results": [],
        }, ensure_ascii=False)

		

プロンプトを少し変更します。
ツールとURLを抽出するよう指示しておきます。

システムプロンプト
			
			SYSTEM_PROMPT = """
# RAGシステム用システムプロンプト

## 基本方針
あなたは検索結果に基づいて正確で有用な回答を提供するアシスタントです。以下のガイドラインに従って回答してください。

## 回答ルール

### 1. 検索結果の活用
- 提供された検索結果のみを情報源として使用してください
- 検索結果にない情報については推測や一般知識での補完を行わず、「検索結果に含まれていません」と明記してください
- 複数の検索結果がある場合は、それらを統合して包括的な回答を作成してください

### 2. 引用の方法
- 回答中の情報には必ず引用番号を付けてください(例:[1]、[2])
- 回答の後に「## 参考文献」セクションを設け、以下の形式で引用元を明記してください:
  ```
  [1] タイトル - 出典元(URL、日付等)
  [2] タイトル - 出典元(URL、日付等)
  ```
- 検索結果がJSONとして渡される場合は、各項目から uri を抽出し、参考文献のURLとして使用してください
- 参考文献は「ファイル名 と S3 URL」を明示してください。ファイル名はURIの末尾(例: s3://bucket/path/file.pdf → file.pdf)を用い、URLは location.s3Location.uri(なければ metadata.x-amz-bedrock-kb-source-uri)を使用してください。ページ番号があれば (p.<番号>) を付与してください。
  例:
  ```
  [1] s3://strands-sample-xxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf (p.78)
  [2] s3://strands-sample-xxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf (p.4)
  ```

### 3. 回答形式
- 簡潔で分かりやすい日本語で回答してください
- 重要なポイントは見出しや箇条書きを使って整理してください
- 長い回答の場合は冒頭に要約を記載してください

### 4. 情報が不足している場合
- 検索結果が質問に対して十分でない場合は、その旨を明記してください
- 部分的に回答できる場合は、回答できる範囲を明確にしてください

### 5. ツールの利用
- このエージェントは `kb_search(query, max_results?)` ツールを利用できます
- 回答前に適切なクエリで `kb_search` を呼び出し、結果を根拠として使用してください
- 複数結果がある場合は重要度の高いものを優先し、重複を避けて統合してください
- 引用に使った順序で番号を付与し、末尾の「参考文献」に対応させてください(title/URL/日付など、取得できる範囲で記載)

## 回答例

**質問:** 太陽光発電の仕組みについて教えてください。

**回答:**

太陽光発電は、太陽電池(ソーラーセル)を使って太陽光を直接電気エネルギーに変換するシステムです[1]。

### 基本的な仕組み
太陽電池は主にシリコンなどの半導体材料で作られており、太陽光が当たることで光電効果により電子が動き、電流が発生します[1]。この電流は直流電流のため、一般的な家庭用電力として使用するには、インバーターという装置で交流電流に変換する必要があります[2]。

### 主な構成要素
- **太陽電池パネル**: 太陽光を電気に変換[1]
- **インバーター**: 直流を交流に変換[2]
- **パワーコンディショナー**: 電力の調整・制御[2]

### 発電効率
現在の一般的な太陽電池の変換効率は15-20%程度です[1]。

## 参考文献
[1] 太陽光発電の基礎知識 - 新エネルギー財団(https://example.com/solar-basics, 2023年4月)
[2] 太陽光発電システムの構成 - エネルギー技術研究所(https://example.com/solar-system, 2023年3月)

---

## 注意事項
- 検索結果が古い情報の場合は、その旨を明記してください
- 矛盾する情報が複数ある場合は、両方の見解を紹介してください
- 専門用語を使用する際は、可能な限り分かりやすい説明を併記してください
"""

		

エージェントの設定はkb_searchをツールとして使うよう変更しておきます。

			
			# kb_searchを使うよう変更
agent = Agent(
        model=model,
        system_prompt=SYSTEM_PROMPT,
        tools=[kb_search],
)

		

これで準備完了です!再度AgentCoreにデプロイをします。

			
			agentcore launch --env STRANDS_KNOWLEDGE_BASE_ID=your-knowledge-base-id

		

GenUで確認してみます。

CleanShot 2025-09-14 at 11.31.46@2x
ツールも実行されていますね。
参考文献がどうなっているか確認してみます。

CleanShot 2025-09-14 at 11.33.02@2x 1

回答全文
			
			AgentCoreについて調べてみますね。
Amazon Bedrock AgentCoreについてご説明します。

## 概要

Amazon Bedrock AgentCoreは、AIエージェントを展開・運用するために最適なマネージドサービスです[1]。2024年7月16日にパブリックプレビューで公開されたサービスで、AIエージェント開発に必要な機能が揃っています[2]。

### 主な特徴
- **AIエージェントのホスティング**: Strands Agents、LangGraphなど多様なエージェントフレームワークに対応[3]
- **便利なマネージドサービス**: AIエージェントを使用する上で認証・ツール連携など便利な機能をマネージドサービスとして提供[3]

## 主要な機能

Amazon Bedrock AgentCoreには以下の6つの主要機能が備わっています[2]:

### 1. **Runtime(ランタイム)**
- ホスティング機能[2]
- AIエージェントをデプロイするための基盤機能

### 2. **Identity(認証機能)**
- AIエージェントへのアクセス制御と認証機能[2]

### 3. **Gateway(ゲートウェイ)**
- 外部処理のTool化機能[2]
- 外部サービスとの連携を可能にする

### 4. **Memory(記憶機能)**
- AIエージェントの会話履歴や状態を保持する機能[2]

### 5. **Built-in Tools(組み込みツール)**
AgentCoreには以下の便利な組み込みツールが用意されています[2]:
- **Code Interpreter**: コード実行環境
- **Browser**: ブラウザ実行環境

### 6. **Observability(監視・可観測性)**
- AIエージェントの動作状況を監視する機能[1]

## AIエージェントとは

AIエージェントとは、自律的に判断・行動できるAIシステムのことです。ユーザーの指示を理解し、必要なツールを自身で計画を立てて使いながらタスクを実行します[3]。

## まとめ

Amazon Bedrock AgentCoreは、Runtime、Identity、Memory、Gateway、Built-in Tools、Observabilityを活用して、効率的にAIエージェントを構築できるマネージドサービスです[1]。多様なエージェントフレームワークに対応しており、AIエージェント開発に必要な機能が統合的に提供されています。

## 参考文献
[1] Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf (p.78) - s3://strands-sample-xxxxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf
[2] Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf (p.12) - s3://strands-sample-xxxxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf  
[3] Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf (p.10) - s3://strands-sample-xxxxx/Amazon Bedrock AgentCoreを使ってみよう! 〜各種機能のポイントを解説〜 (5).pdf


		

おおお、参考文献リンク付きで返ってきました!!
これで簡易的なRAGが作成できました。

おわりに

今回はS3 Vectors + Knowledge Bases + Strands Agentsを使って簡易的なRAGを作ってみました。
retrieveツールは私が想定していた通りには動きませんでしたが、ドキュメントの情報を取得したいだけならいいのかなと思いました。
引用元のドキュメントをナレッジベースから取得したい場合はカスタムで作る必要が出てきましたがそこまで難しくなく作成できたので嬉しいですね。

本記事が少しでも参考になったら幸いです!最後までご覧いただきありがとうございましたー!!

この記事をシェアする

FacebookHatena blogX

関連記事