はじめに
AI エージェントを Amazon Bedrock AgentCore Runtime に載せていると、「最初の 1 回だけ妙に遅い」 という現象に出会うことがあるかと思います。いわゆる コールドスタートです。
2026 年 9 月、この起動の仕組みを作り直した新しい AgentCore Runtime(プラットフォームバージョン V2)が発表されました。
この記事では、同じコードを V1 と V2 にデプロイして、コールドスタートの時間を比べて みました。あわせて、V2 ならではの「スナップショット」の挙動も確かめています。
先に結論
- 初期化に 10 秒かかるエージェントで、コールドスタートが V1 の約 13 秒 → V2 の約 2.4 秒 になりました
- その代わり 作成・更新に数分かかり(今回は約 4 分)、起動時に作った値は全セッションで同じになります
新しい AgentCore Runtime とは
ひとことで言うと、「起動済みの状態を写真に撮っておき、次からはその写真から再開する」 仕組みです。
これまで(V1)は、新しいセッションが来るたびに Python の起動 → ライブラリの import → モデルの読み込み といった初期化を毎回やり直していました。
V2 では、デプロイ時に一度だけ初期化を済ませて、そのメモリの状態を保存します。この保存したものを スナップショット と呼びます。新しいセッションは、このスナップショットを復元するだけで始まります。
What's New と AWS ブログ によると、うれしい点は主に 2 つのようです。
| 観点 | V1 | V2 |
|---|---|---|
| コールドスタート(P75、200MB〜2GB のイメージ) | 5.4〜30 秒(イメージが大きいほど遅い) | 1.9〜2.0 秒(ほぼ一定) |
| メモリの課金 | セッション中のピークを確保し続ける | 使っていないメモリは回収され、実際の使用量に課金(単価は V1 より高い) |
重いライブラリや大きなモデルを抱えたエージェントほど恩恵が大きい 、ということかと思います。
やってみた
公式ドキュメントの Platform versions を参考に、東京リージョンで V1 と V2 のランタイムを 1 つずつ作って比べます。
なお、本記事の執筆時点ではCloudFormation・CDK は現時点で platformVersion の指定に未対応 と公式ドキュメントに書かれています。
手元で確認したところ、AgentCore CLI(@aws/agentcore 0.31.1)にもまだオプションがありませんでした。
そのため今回は AWS CLI で直接作ります。--platform-version は AWS CLI 2.36.46 以降 で使えるので、先にバージョンを確認しておきます。
aws --version # aws-cli/2.36.46 以上であること
手順 0:変数の準備
あとの手順で使う値をまとめて決めておきます。アカウント ID は自動で取得するので、そのままコピペで大丈夫です。
export AWS_REGION=ap-northeast-1
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
BUCKET=agentcore-v2-demo-${ACCOUNT_ID}-${AWS_REGION}
ROLE_NAME=AgentCoreV2DemoRole
mkdir -p agentcore-v2-demo && cd agentcore-v2-demo
手順 1:「起動が重い」エージェントを作る
違いがわかりやすいように、起動時に 10 秒スリープ するエージェントを用意します。モデルの読み込みなど、重い初期化の代わりです。
もう 1 つの仕掛けとして、起動時に 1 回だけ作るランダムな ID(startup_id) と、リクエストごとに作る ID(request_id) を両方返すようにしておきます。V2 で起動時の値がどう扱われるかを見るためです。
cat > main.py <<'EOF'
import os, socket, time, uuid
from bedrock_agentcore.runtime import BedrockAgentCoreApp
# ここは起動時に1回だけ実行される(V2ではスナップショットに焼き込まれる)
time.sleep(10) # モデル読み込みなど重い初期化のつもり
STARTUP_ID = uuid.uuid4().hex[:8]
STARTED_AT = time.time()
app = BedrockAgentCoreApp()
@app.entrypoint
def invoke(payload):
# ここはリクエストごとに実行される
return {
"startup_id": STARTUP_ID,
"request_id": uuid.uuid4().hex[:8],
"started_ago_sec": round(time.time() - STARTED_AT),
"hostname": socket.gethostname(),
"pid": os.getpid(),
}
app.run()
EOF
Direct code deployment を使います。AgentCore Runtime は arm64 の Linux で動くので、それに合わせたライブラリを uv で取得して zip にまとめます。
uv pip install \
--python-platform aarch64-manylinux2014 \
--python-version 3.13 \
--target=deployment_package \
--only-binary=:all: \
bedrock-agentcore
(cd deployment_package && zip -qr ../deployment_package.zip .)
zip -q deployment_package.zip main.py
手順 2:S3 バケットと実行ロールを作る
zip を置く S3 バケットと、ランタイムが使う IAM ロールを作ります。ロールの中身は IAM Permissions for AgentCore Runtime を参考に、zip の読み取りとログ出力だけ に絞っています。
aws s3 mb s3://${BUCKET}
aws s3 cp deployment_package.zip s3://${BUCKET}/deployment_package.zip
cat > trust.json <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "bedrock-agentcore.amazonaws.com"},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {"aws:SourceAccount": "${ACCOUNT_ID}"},
"ArnLike": {"aws:SourceArn": "arn:aws:bedrock-agentcore:${AWS_REGION}:${ACCOUNT_ID}:*"}
}
}]
}
EOF
cat > policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::${BUCKET}/*"},
{"Effect": "Allow",
"Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams"],
"Resource": "arn:aws:logs:${AWS_REGION}:${ACCOUNT_ID}:log-group:/aws/bedrock-agentcore/runtimes/*"}
]
}
EOF
ROLE_ARN=$(aws iam create-role --role-name ${ROLE_NAME} \
--assume-role-policy-document file://trust.json --query Role.Arn --output text)
aws iam put-role-policy --role-name ${ROLE_NAME} \
--policy-name runtime --policy-document file://policy.json
sleep 10 # IAM の反映待ち
手順 3:V1 と V2 のランタイムを作る
同じ zip から、--platform-version だけを変えて 2 つのランタイムを作ります。
cat > artifact.json <<EOF
{
"codeConfiguration": {
"code": {"s3": {"bucket": "${BUCKET}", "prefix": "deployment_package.zip"}},
"runtime": "PYTHON_3_13",
"entryPoint": ["main.py"]
}
}
EOF
for V in V1 V2; do
aws bedrock-agentcore-control create-agent-runtime \
--agent-runtime-name v2demo_${V} \
--role-arn ${ROLE_ARN} \
--agent-runtime-artifact file://artifact.json \
--network-configuration '{"networkMode": "PUBLIC"}' \
--lifecycle-configuration '{"idleRuntimeSessionTimeout": 60}' \
--platform-version ${V} \
--query agentRuntimeId --output text > ${V}.id
done
create-agent-runtime は作成完了を待たずに返ってきます。READY になるまで状態を確認しながら待ち、かかった時間を表示します。
for V in V1 V2; do
SECONDS=0
until aws bedrock-agentcore-control get-agent-runtime \
--agent-runtime-id $(cat ${V}.id) --query status --output text | grep -qE 'READY|FAILED'; do
sleep 10
done
aws bedrock-agentcore-control get-agent-runtime --agent-runtime-id $(cat ${V}.id) \
--query '[agentRuntimeName,platformVersion,status]' --output text
echo " -> 待ち時間 ${SECONDS} 秒"
done
V1 は 11 秒で READY になり、V2 はそこからさらに 221 秒(作成からは約 4 分)かかりました。 V2 は作成時に「初期化してスナップショットを撮る」ぶん、時間がかかります。
手順 4:新しいセッションで呼び出して比べる
毎回ちがうセッション ID で呼び出す と、毎回コールドスタートになります。V1・V2 それぞれ 3 回ずつ呼び出し、AWS CLI の呼び出しにかかった時間を計ります。
invoke() { # $1=V1|V2 $2=セッションID
local ARN=$(aws bedrock-agentcore-control get-agent-runtime \
--agent-runtime-id $(cat $1.id) --query agentRuntimeArn --output text)
local START=$(python3 -c 'import time; print(time.time())')
aws bedrock-agentcore invoke-agent-runtime \
--agent-runtime-arn ${ARN} --runtime-session-id $2 \
--payload '{}' --cli-binary-format raw-in-base64-out out.json > /dev/null
printf "%s %5.1f秒 %s\n" $1 $(python3 -c "import time; print(time.time()-${START})") "$(cat out.json)"
}
for V in V1 V2; do
for i in 1 2 3; do
invoke ${V} $(uuidgen)-cold-${i} # 毎回新しいセッション = コールドスタート
done
done
見るところは、行頭の秒数と startup_id です。 手元の結果をまとめるとこうなりました(秒数は AWS CLI 自体の起動時間も含みます)。
| 応答時間 | startup_id |
pid |
started_ago_sec |
|
|---|---|---|---|---|
| V1 | 14.0 / 13.4 / 13.1 秒 | 毎回ちがう | 339 など | 0〜1 |
| V2 | 2.9 / 2.5 / 2.9 秒 | 3 回とも同じ | 1 | 206〜212 |
V1 は毎回 10 秒の初期化をやり直すので、13 秒前後かかっています。一方 V2 は初期化済みのスナップショットから始まるので、10 秒のスリープが丸ごと消えています。
ここで気になるのが、V2 の startup_id が 3 回とも同じ という点です。別々のセッション(=別々の microVM)なのに、起動時に作ったランダム値がスナップショットごとコピーされている ことがわかります。started_ago_sec が 150 秒を超えているのも、「起動した時刻」がスナップショットを撮ったときのまま固定されているためです。
手順 5:後片付け
ランタイム・ログ・S3 バケット・IAM ロールを削除します。
for V in V1 V2; do
aws bedrock-agentcore-control delete-agent-runtime --agent-runtime-id $(cat ${V}.id) > /dev/null
for LG in $(aws logs describe-log-groups \
--log-group-name-prefix /aws/bedrock-agentcore/runtimes/$(cat ${V}.id) \
--query 'logGroups[].logGroupName' --output text); do
aws logs delete-log-group --log-group-name ${LG}
done
done
aws s3 rb s3://${BUCKET} --force
aws iam delete-role-policy --role-name ${ROLE_NAME} --policy-name runtime
aws iam delete-role --role-name ${ROLE_NAME}
気をつけるポイント
| ポイント | 今回見えたこと | どうするか |
|---|---|---|
| 作成・更新に数分かかる |
READY まで V1 は 11 秒、V2 は約 4 分 |
デプロイの待ち時間やタイムアウトを長めにとる |
| 起動時の値が全セッション共通になる |
startup_id・localhost・pid 1 が全セッションで同じ |
乱数・トークン・時刻・識別子は リクエストの処理の中で 作る |
| CFN/CDK と AgentCore CLI が未対応 |
platformVersion を指定する手段がない |
当面は AWS CLI / SDK で指定する |
逆に、ライブラリの import やクライアントの作成は起動時にやっておく方が得 です(起動から 120 秒以内)。詳しくは Optimize your agent for AgentCore Runtime V2 にまとまっています。


