TL;DR
自作の AWS 運用エージェント (Converse API の tool use ループ + read-only ツール4種) を、同じコードのままローカル実行と Amazon Bedrock AgentCore Runtime の2通りで動かして比較しました。
- 移行作業は「Lambda の zip デプロイ」とほぼ同型でした。60行弱のラッパ + arm64 向け zip + Terraform で、Docker も ECR も不要 (直接コードデプロイ)。
- 同じコード・同じ質問なのに、ツールの選び方が変わりました。絞り込みのフォローアップに対し、ローカルではツールを呼ばず前回結果から回答 (steps=0)、Runtime では無料のログ検索ツールを自発的に追加。方式の差ではなく LLM の非決定性で、エージェントの出力は固定値の一致を前提にできない — 回帰テストは観点評価で設計する必要があることが、2回の実行で体感できます。
- 今回の構成では、Runtime のセッション内でプロセスメモリ (会話履歴) が生き残りました。アプリの会話履歴 (ただの Python リスト) が microVM のメモリに残り、コードを変えずにマルチターンが成立。アイドルタイムアウトが「会話の寿命」になります。
- レイテンシは今回も生成が支配。Runtime 化のオーバーヘッドは生成時間の揺れに沈み、アイドル後1回の観測ではコールドスタートも体感できませんでした。
- 背景: Bedrock Agents (Classic) は 2026-07-30 で新規顧客の受付を終了します。これからエージェントを作るなら AgentCore です (東京対応済み)。
- 検証環境一式 (Terraform + クライアント) は GitHub で公開: bedrock-lab (phase3 タグ)
この記事で扱うこと・扱わないこと
扱わないこと — tool use ループの作り方そのものは、@502_ さんのエージェントループ記事や @ren8k さんの詳細解説が既に丁寧です。AgentCore の直接コードデプロイ機能の紹介も AWS 公式ブログと DevelopersIO の記事があります (末尾の参考にまとめています)。
扱うこと — 本記事は「手元で動いているエージェントを、そのまま Runtime に持ち込む移行」の記録です。移行に何が必要で、移行の前後で何が同じで何が変わるのかを、同一の質問セットで実測します。この構図の比較は探した範囲で見つからなかったので、一次データとして残します。
背景: Bedrock Agents Classic が新規終了する
従来の Amazon Bedrock Agents (2023年11月〜) は「Bedrock Agents Classic」となり、公式ドキュメントに 2026年7月30日から新規顧客に開放されない旨が明記されました。既存利用者はそのまま使えますが、モデルカタログは凍結され、以後の新モデルは後継の AgentCore 側に提供されます。
AgentCore はコードファーストのエージェント実行基盤で、東京リージョンにほぼ全機能が対応済みです (公式リージョン表)。Classic が「エージェントの定義を AWS に登録する」方式だったのに対し、AgentCore は自分のコードを持ち込む方式 — つまり「エージェント」というリソースは登録せず、実体はただのコードです。だからこそ「ローカルで動くものをそのまま持ち込んで比較する」という本記事の実験が成立します。
作ったもの: AWS 運用エージェント
比較の題材は、自分の AWS アカウントを調べる運用エージェントです。

図1: 同じエージェントコード (橙) を2つの実行基盤で動かす。ツールの鍵束 (IAM ポリシー) も同一で、持ち主だけが違う
| 項目 | 内容 |
|---|---|
| エージェント本体 | Converse API の tool use ループ (toolConfig / toolUse / toolResult を自前で回す。最大8ステップ) |
| ツール (すべて read-only) | コスト照会 (Cost Explorer) / ログ調査 (CloudWatch Logs) / リソース棚卸し (Tagging API) / ナレッジ検索 (Knowledge Base) |
| モデル |
jp.anthropic.claude-sonnet-4-6 (東京/大阪ルーティング) |
| 実行基盤 | ② ローカル (Mac で python 実行) / ① AgentCore Runtime (東京、直接コードデプロイ) |
| 時期 | 2026年7月 |
安全設計として、ツールは照会系のみです。「FSx を削除して」と頼むと、照会専用である旨を説明して手順だけ案内します (実測済み)。エージェントに書き込み権限を持たせない線引きは、企業導入でも最初に問われるポイントだと思います。
移行作業: 実体は「Lambda の zip デプロイ」だった
ローカルで動いていたエージェント (agent_cli.py) を Runtime に持ち込むのにやったことは3つだけです。
1. エントリポイントのラッパを書く (60行弱)
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from agent_cli import AgentSession, build_clients, resolve_kb_id # ← 既存コードをそのまま import
app = BedrockAgentCoreApp()
_agent = None # microVM (セッション単位) のプロセスメモリに履歴が残る
def _get_agent():
global _agent
if _agent is None:
session = boto3.Session() # Runtime 実行ロールの一時クレデンシャル
_agent = AgentSession(clients=build_clients(session), ...)
return _agent
@app.entrypoint
def handler(payload: dict):
answer = _get_agent().ask(payload.get("prompt", ""))
return {"result": answer}
Lambda ハンドラを書く感覚そのものです。エージェント本体には一切手を入れていません。
2. arm64 向けの zip を作る
Runtime は ARM64 で動きます (Python はバージョン選択式、今回は 3.13 を指定)。依存は実行先アーキテクチャ向けに取得する必要がありますが、手元が Mac でも uv のクロスプラットフォーム指定で解決できます。
uv pip install \
--python-platform aarch64-manylinux2014 \
--python-version 3.13 \
--target=build/pkg \
--only-binary=:all: \
bedrock-agentcore boto3
# → 依存 + agent_cli.py + ラッパを zip (今回 19MB)
3. Terraform でデプロイ
直接コードデプロイは Terraform がネイティブ対応しています (aws_bedrockagentcore_agent_runtime の code_configuration)。Docker も ECR も出てきません。
resource "aws_bedrockagentcore_agent_runtime" "ops_agent" {
agent_runtime_name = "bedrock_lab_ops_agent"
role_arn = aws_iam_role.agent_runtime.arn # ツール権限はこのロールへ
agent_runtime_artifact {
code_configuration {
entry_point = ["agent_runtime.py"]
runtime = "PYTHON_3_13"
code {
s3 {
bucket = aws_s3_bucket.agent_code.id
prefix = aws_s3_object.agent_package.key # ← zip
}
}
}
}
network_configuration { network_mode = "PUBLIC" }
lifecycle_configuration {
idle_runtime_session_timeout = 300 # ← 後述の「会話の寿命」
max_lifetime = 1800
}
}
IAM は、ローカル実行で利用者ロールに付けていた同じポリシー2枚 (モデル呼び出し+KB / read-only ツール) を Runtime 実行ロールにアタッチしただけ。「運用端末の作業者権限を、バッチサーバのサービスアカウントに移す」あの定番作業と同型です。
実測比較
同一の質問セット (単一ツール / ナレッジ検索 / マルチステップ / 絞り込みフォローアップ) を両方式で実行しました。生成条件も両方式で同一です (inferenceConfig は maxTokens のみ指定、temperature は未指定 = API デフォルト)。
| ② ローカル | ① AgentCore Runtime | |
|---|---|---|
| 実行場所 | 手元の Mac | 東京の microVM (セッション単位で分離) |
| 認証・ツールの鍵 | 利用者ロール | Runtime 実行ロール (同一ポリシーを付け替え) |
| 会話文脈 | CLI プロセスのメモリ | セッション microVM のメモリ (idle 5分で消滅) |
| ツール実行の観測 |
--verbose で手元に表示 |
クライアントからは見えない。stdout が CloudWatch へ自動転送 |
| 同一質問のレイテンシ (棚卸し) | 18.2s | 14.1s (差は生成の揺れの範囲) |
| コールドスタート | なし | 体感差なし (アイドル後の初回も 14.0s) |
| 絞り込みフォローアップ | ✅ steps=0 (ツールを呼ばず前回回答から再構成) | ✅ ただしログ検索を自発追加してよりリッチに回答 |
| 追加コスト | なし | 実行秒課金 (vCPU $0.0895/h + メモリ $0.00945/GB-h。I/O 待機中の CPU は無課金、メモリはピーク分課金が継続) |
発見
1. 同じコード・同じ質問でも、ツールの選び方が変わった
タイトルの件です。「今月のコストは?」→「そのうち Bedrock 分だけ詳しく」という絞り込みのフォローアップに対して:
- ローカル: ツールを一切呼ばず (steps=0)、前回の回答に含まれる内訳から再構成。「追加のコスト照会は行っていません (前回取得データを再利用)。$0.01 の節約です」と自己申告までした
- Runtime: コスト照会 ($0.01) の再実行は同じく節約しつつ、無料のログ検索ツールを自発的に追加し、ログ考察付きのよりリッチな回答を返した (Runtime 側の CloudWatch ログでツール呼び出しを確認)
どちらも合理的ですが、同じではありません。方式の差というより LLM の非決定性で、「今回の2回の実行では、たまたま同じにならなかった」が正確なところです (temperature 未指定のデフォルト設定)。逆にいえば、エージェントの出力は固定値の一致を前提にできない。回帰テストは「出力の一致」では書けず、観点評価 (禁止操作をしていないか・ツール呼び出し回数が上限内か・回答に根拠があるか) で設計する必要があります。テスト計画を書く立場として、これが2回の実行であっさり観測できたのは収穫でした。
2. 今回の構成では、セッション内でプロセスメモリが生き残った
Runtime はセッション ID (runtimeSessionId) ごとに分離された microVM を立て、プロセスが数分生き残ります。ラッパでグローバル変数に置いたエージェント (会話履歴 = ただの Python リスト) がそのまま残るため、アプリコードを一切変えずにセッション内マルチターンが成立しました。別セッション ID にすると文脈は消えます (実測)。
ただしこの履歴の寿命は idle_runtime_session_timeout (今回 300 秒) まで。インフラの設定値が「会話の寿命」を決める運用パラメータになるのが面白いところです。恒久的な記憶が要件なら、プロセスメモリ頼みではなく AgentCore Memory 等の外部化が筋になります。
3. 観測性が逆転する
ローカルの --verbose (手元にツール実行が見える) は、Runtime ではクライアントに届きません。代わりに stdout が CloudWatch (/aws/bedrock-agentcore/runtimes/...) へ自動転送されます。発見1で「Runtime が実際に何のツールを呼んだか」を確認できたのも CloudWatch のログでした。
デバッグ出力がそのまま運用ログになるということです。エージェントの行動を後から説明できるか (監査・インシデント調査) はログ設計次第 — 運用化するなら、ツール呼び出しの構造化ログを最初から仕込んでおくべきでした。
4. レイテンシは生成が支配 — Runtime 化のオーバーヘッドは誤差
同一質問でローカル 18.2s vs Runtime 14.1s — Runtime 化のオーバーヘッドは生成時間の揺れに沈みます。ツール実行は 0.1〜1.1 秒 (最も遅いのは Cost Explorer)。アイドルタイムアウト後の初回呼び出しも 14.0s (1回の観測) で、直接コードデプロイのセッション生成は速いという仕様どおりでした。
実行基盤の選択はレイテンシではなく、権限・観測性・共用性の要件で決めるのがよさそうです。個人の使い分けとしては「開発・実験はローカル、共用・常設は Runtime」で、移行コストが小さい (ラッパ数十行) ので両対応にしておくのが現実解でした。
おまけ: Gateway でツールを MCP 化 — IAM 認証なら Cognito 不要
仕上げに、エージェント専用だったツール4種を AgentCore Gateway で MCP ツールとして公開しました (構成は「API Gateway + Lambda」と同型)。詳細な手順は DevelopersIO の記事群に譲りますが、1点だけ:
Gateway のインバウンド認証は IAM (SigV4) が選べます (authorizer_type = "AWS_IAM")。個人・社内用途なら Cognito や外部 IdP を立てずに、利用者ロールへ bedrock-agentcore:InvokeGateway を付与するだけで MCP サーバをマネージド公開できました。ツール名が <ターゲット名>___<ツール名> 形式になるので、Lambda 側でプレフィックスを剥がす小細工だけ必要です。
これで同じ read-only ツールの「鍵束」の持ち主が3人になりました: 利用者ロール (ローカル) / Runtime 実行ロール / Lambda 実行ロール (Gateway)。実行基盤が増えても鍵束は同じ、持ち主が変わるだけ — エージェント運用の権限設計は、結局いつもの IAM 設計でした。
まとめ
| 学び | 内容 |
|---|---|
| 移行の実体 | Lambda の zip デプロイと同型 (ラッパ60行弱 + arm64 zip + Terraform)。Docker/ECR 不要 |
| ツール選択 | 同一コード・同一質問でも出力の固定一致は前提にできない。回帰テストは観点評価で設計 |
| セッション | 今回の構成ではプロセスメモリに履歴が残存。idle timeout が会話の寿命 |
| 観測性 | verbose → CloudWatch へ逆転。ログ設計 = エージェントの説明責任 |
| レイテンシ | 生成が支配。Runtime 化のオーバーヘッドとコールドスタートは誤差 |
| 権限 | 同じポリシーの持ち主が変わるだけ。read-only の線引きが企業導入の第一関門 |
Terraform 一式・エージェント実装・比較の生データは GitHub で公開しています。
シリーズ前作: モデルアクセス編 (Phase 1) / RAG 3方式比較編 (Phase 2)
参考
AWS 公式
- Amazon Bedrock Agents Classic maintenance mode — 2026-07-30 新規終了の一次情報
- Direct code deployment for Python (AgentCore) — zip デプロイの公式手順 (arm64 要件含む)
- Iterate faster with Amazon Bedrock AgentCore Runtime direct code deployment (AWS Blog)
- Supported AWS Regions (AgentCore) — 東京対応状況
- Amazon Bedrock AgentCore Pricing — 消費ベース課金の詳細
先行記事 (tool use ループの作り方・機能紹介はこちらが詳しいです)