TsukiOps
ホーム>ブログ>検証ログ>Bedrock AgentCoreを東京リージョンで動かす——us.は失敗、global.は動く、jp.を選ぶ理由
検証ログ

Bedrock AgentCoreを東京リージョンで動かす——us.は失敗、global.は動く、jp.を選ぶ理由

Bedrock AgentCoreを東京リージョンで動かすとき、モデルIDのプレフィックスで何が変わるかを実測しました。us.は失敗し、global.は動きます。それでもjp.を選ぶ理由を、推論プロファイルの宛先リージョンから説明します。

2026年8月20日 14分で読める
Bedrock AgentCoreを東京リージョンで動かす——us.は失敗、global.は動く、jp.を選ぶ理由

医療クラウド — AIエージェント基盤編

  • 1.Bedrock AgentCoreを東京リージョンで動かす——us.は失敗、global.は動く、jp.を選ぶ理由

30分で課題を整理しませんか?

記事の内容についてのご質問や、自社への適用についてお気軽にご相談ください。

30分ヒアリングを予約

「サンプルのまま東京で動かしたら、エラーも出ずに普通に返ってきました」

Bedrock AgentCore を東京リージョン(ap-northeast-1)で試したとき、いちばん厄介だったのはこれです。落ちれば原因を調べます。でも動いてしまうと、誰も調べません。

この記事では、モデルIDのプレフィックスを us. / global. / jp. と変えたときに、東京で何が起きるかを実測しました。あわせて、推論プロファイルの宛先リージョンを AWS API で確認した数値も示します。医療情報のようにデータの所在地を説明する必要がある場合、「動く」だけでは足りない理由がここにあります。

この記事で分かること

  • 東京リージョンで us. プレフィックスのモデルIDが失敗する理由と、そのエラーメッセージの読み方
  • 同一モデルでプレフィックスだけを変えた対照実験の結果(us. 3回中3回失敗 / jp. 6回中6回成功)
  • jp. / apac. / global. それぞれの推論プロファイルが、実際にどのリージョンへルーティングされるか
  • AWS 公式CLI @aws/agentcore が生成する雛形の既定値と、Strands Agents SDK 本体の既定値
  • 東京で jp. に直す具体的な書き換えと、それでも残る IAM 側の穴

前提知識

  • Amazon Bedrock でモデルを呼び出したことがある(converse または SDK 経由)
  • AWS CLI でプロファイルを切り替えて操作できる
  • クロスリージョン推論という言葉を聞いたことがある(詳細は本文で説明します)

検証した範囲と、していない範囲

先に線を引いておきます。この記事の主張がどこまで裏付けられているかを、読者が判断できるようにするためです。

実際に手を動かして確認したのは、次の範囲です。

  • 東京リージョンからの Bedrock 呼び出し(us. / jp. / global. の各プレフィックス)
  • get-inference-profile / list-inference-profiles による宛先リージョンの確認(2026年8月18日時点)
  • @aws/agentcore v0.27.0 での雛形生成と deploy --dry-run(CloudShell と macOS の2環境)
  • 合成された CloudFormation テンプレートの読解

逆に、次のことはしていません。

  • AgentCore Runtime への実デプロイと invoke この記事で作成リソースに触れる箇所は、--dry-run が合成した CloudFormation を読んだ結果です
  • global. が実際にどのリージョンで推論したかの特定。 宛先の範囲は AWS 公式ドキュメントの記述で確認しましたが、実際の経路を観測したわけではありません(後述しますが、そもそもログに残りません)
  • Strands Agents SDK の既定値の動作確認。 該当箇所はソースコードを読んだ結果であり、実行して確かめてはいません

検証にかかった AWS 料金は、モデル呼び出しの数円のみです。--dry-run でリソースは作成していません。

それでは、最初に起きたことから順に見ていきます。

東京で最初に起きること(us.プレフィックスは通らない)

AWS のサンプルコードやチュートリアルでは、モデルIDが us. 付きで書かれていることがよくあります。

model = BedrockModel(
    model_id="us.anthropic.claude-sonnet-4-5-20250929-v1:0",
    streaming=True,
)

この us.クロスリージョン推論プロファイルの接頭辞です。単一リージョンではなく、複数リージョンにまたがって推論をルーティングする仕組みで、us. は米国内のリージョン群を指します。

これを東京リージョンでそのまま呼ぶと、次のエラーになります。

ValidationException: The provided model identifier is invalid.

エラーメッセージから読み取れること

このメッセージは「権限がない」とは言っていません。「識別子が不正だ」と言っています。つまり東京リージョンから見て、そのIDのリソースは存在しないということです。

実際、権限の問題と切り分ける必要があります。Bedrock で東京リージョンが絡むと、少なくとも3種類のエラーが出ます。

出るエラー 意味
ValidationException: The provided model identifier is invalid. そのリージョンにそのIDが存在しない
AccessDeniedException: ... is not authorized to perform: bedrock:InvokeModel IAM で許可されていない
AccessDeniedException: Model access is denied ... AWS Marketplace actions モデルの利用契約が未締結

us. のケースは1番目です。IAM ポリシーをいくら直しても解決しません。この切り分けは次回の記事で詳しく扱いますが、いまは「ValidationException は権限の話ではない」とだけ押さえてください。

では、本当にプレフィックスだけが原因なのでしょうか。ここを詰めます。

プレフィックスだけを変えた対照実験

最初の検証では、うまくいかないときに複数の要素を同時に変えてしまいました。モデルを Sonnet から Haiku に変え、同時にプレフィックスも us. から jp. に変えたのです。これでは、どちらが効いたのか分かりません。

同一モデル・同一リージョンで3文字だけ変える

そこで、条件を揃え直しました。

  • モデル: anthropic.claude-sonnet-4-5-20250929-v1:0 に固定
  • リージョン: ap-northeast-1 に固定
  • 変えるもの: プレフィックスの us.jp. のみ(3文字)

結果です。

プレフィックス 試行 結果
us.anthropic.claude-sonnet-4-5-20250929-v1:0 3回 3回とも ValidationException
jp.anthropic.claude-sonnet-4-5-20250929-v1:0 6回 6回とも成功

同じモデル、同じリージョン、同じ認証情報です。違うのはプレフィックスの3文字だけでした。

IAM を疑う前に確認したこと

「結局は権限不足では」という反論はもっともなので、そこも潰しました。

IAM ポリシーで bedrock:InvokeModel を明示的に許可する前と後で、us. のエラーメッセージを比較しました。変わりませんでした。 どちらも ValidationException のままです。権限が原因なら、付与後に AccessDeniedException へ変わるか、成功するはずです。

これで「東京では us. プレフィックスのIDが存在しない」ことが確定しました。

ここまでは、日本語の技術記事でも触れられている内容です。問題はこの先にあります。

global. は動く。だから気づかない

us. が使えないと分かったとき、代替としてよく挙がるのが global. です。

日本語で東京リージョンへのデプロイ手順をまとめた記事に、Qiita「Dockerなし、Windows、東京リージョンでAmazon Bedrock AgentCore FASTをデプロイする」があります。us. が東京から使えない理由を、こう説明しています。

FAST のデフォルトでは us. プレフィックス付きのクロスリージョン推論プロファイルが使われています。これは US リージョン専用で、ap-northeast-1 からは利用できません。

そのうえで global.anthropic.claude-sonnet-4-5-20250929-v1:0 へ差し替える手順が示されています。東京で動かすという目的に対して、これは有効な解です。 実際に動きますし、エラーも出ません。Docker を使わない構成まで踏み込んでいて、同じところで詰まったときに助かる記事です。

この記事が扱いたいのは、そこに条件をもう一つ足した場合です。医療情報のようにデータの所在地を説明する必要があると、「動く」だけでなく「どこで処理されたか」も問われます。同じ global. という選択が、条件次第で意味を変えます。

そして厄介なのは、確認するきっかけが生まれにくいことです。us. は失敗するので全員が調べます。global. は成功するので、そこで手が止まります。「動かない既定値」より「静かに動いてしまう既定値」のほうが、後から効いてきます。

global. を選ぶと何が決まるのか。推測ではなく AWS API の応答と公式ドキュメントで確認しました。

推論プロファイルの宛先を実測で比べる(jp. / apac. / global.

推論プロファイルには、ルーティング先のモデルARNが登録されています。get-inference-profile で取得できます。以下はすべて2026年8月18日に東京リージョンから実行した結果です。

diagram

jp. は東京と大阪の2つ

aws bedrock get-inference-profile \
  --inference-profile-identifier "jp.anthropic.claude-sonnet-4-5-20250929-v1:0" \
  --query 'models[].modelArn' --output text

返ってきたのは2件だけです。

arn:aws:bedrock:ap-northeast-3::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0
arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0

東京(ap-northeast-1)と大阪(ap-northeast-3)です。どちらも日本国内で、それ以外の宛先はありません。AWS Japan による解説記事「Amazon Bedrock の JP Cross-Region Inference で日本国内に閉じた推論を実現するぞ!」でも、この2リージョンに閉じることが目的として説明されています。

apac. は8リージョン

同じ確認を apac. に対して行うと、範囲が大きく広がります。なお apac.anthropic.claude-sonnet-4-5-20250929-v1:0ResourceNotFoundException になったため、プロファイルが存在する apac.anthropic.claude-sonnet-4-20250514-v1:0 で確認しました。

ap-northeast-1  ap-northeast-2  ap-northeast-3
ap-south-1      ap-south-2
ap-southeast-1  ap-southeast-2  ap-southeast-4

8リージョンです。日本の3つに加えて、韓国・インド・シンガポール・オーストラリアが含まれます。ap-northeast-2 がソウル、ap-south-1 と ap-south-2 がインド、ap-southeast-1 がシンガポール、ap-southeast-2 と ap-southeast-4 がオーストラリアです。

範囲は広いものの、どこへ行きうるかは完全に列挙できます。これは重要な性質です。

global. はリージョン欄が空のARNを含む

同じことを global. でやると、応答の形が変わります。

arn:aws:bedrock:::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0
arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0

2行目は東京です。問題は1行目です。

arn:aws:bedrock:::foundation-model/...
                ^^ リージョンを書く位置が空

ARN のリージョン欄が空になっています。jp.apac. のように具体的なリージョン名が並ぶのではなく、リージョンを特定しない宛先が含まれている状態です。

API では宛先を列挙できませんが、AWS 公式ドキュメントには範囲が明記されています。Global cross-Region inference のページでは、次のように説明されています。

Global cross-Region inference extends cross-Region inference beyond geographic boundaries, enabling the routing of inference requests to supported commercial AWS Regions worldwide.

地理的な境界を越えて、世界中の商用 AWS リージョンへルーティングされるというのが公式の説明です。リージョン欄が空の ARN についても、「グローバルな FM ARN にはリージョンもアカウントも指定されておらず、これはクロスリージョン機能のために意図されたもの」と明記されています。

つまり global. は「宛先が不明」なのではなく、**「宛先が世界中の商用リージョン」**です。そのうえで、実際にどこで処理されたかは追跡できません。AgentCore のクロスリージョン推論のページには、こう書かれています。

Amazon CloudWatch and AWS CloudTrail logs won't specify the AWS Region in which data inference occurs.

CloudWatch にも CloudTrail にも、推論が行われたリージョンは記録されません。 事後に確認する手段がない、ということです。

医療情報を扱う場合、データの所在地を説明できることが求められます。範囲が世界中で、ログにも残らない構成では、その説明ができません。動くかどうかとは別の話です。

AWS 自身も注意を促しています。AgentCore のドキュメントには、データレジデンシーやコンプライアンス要件を持つ顧客は、グローバルクロスリージョン推論が自社のコンプライアンスフレームワークに適合するかを評価すべきと書かれています。評価したうえで選ぶもの、という位置づけです。

関連記事 Bedrock Guardrailのデプロイが2回失敗した話——日本語トピック名が引き金だった 同じく Bedrock を日本語・東京リージョンで扱ったときに詰まった記録です。

ここまではモデルIDを自分で書く前提の話でした。次は、書かない場合に何が入るかを見ます。

AgentCore の公式CLIが生成する雛形は global. だった

AWS 公式の @aws/agentcore CLI(v0.27.0)には、プロジェクトの雛形を生成する agentcore create があります。実行してみました。

agentcore create --project-name uniprotTokyo --name uniprot \
  --defaults --build CodeZip --language Python --framework Strands \
  --model-provider Bedrock --memory none --protocol HTTP \
  --idle-timeout 60 --max-lifetime 600

モデルIDは一切指定していません。 指定したのはプロバイダが Bedrock であることだけです。

なお --memory none を付けているのは、検証時の課金を抑えるためですが、結果的にもう一つの経路も避けています。AgentCore Memory はクロスリージョン推論を使います。公式ドキュメントによると、Asia Pacific の推論先には東京のほかにソウル・ムンバイ・シンガポール・シドニーが含まれます。モデルIDとは別に、Memory を有効にした時点で日本国外が宛先に入ります。 この記事では扱いませんが、有効にする場合は確認が必要な箇所です。

生成されたファイルを開くと、こう書かれていました。

# app/uniprot/model/load.py:6
from strands.models.bedrock import BedrockModel


def load_model() -> BedrockModel:
    """Get Bedrock model client using IAM credentials."""
    return BedrockModel(model_id="global.anthropic.claude-sonnet-4-5-20250929-v1:0")

AWS 公式のCLIが、既定値として global. を書き込みます。

これは AWS CloudShell と手元の macOS の2環境で実行し、どちらでも同じ結果になりました。環境依存ではなく CLI の仕様です。

ここで先ほどの話が効いてきます。この雛形をそのまま東京にデプロイすると、動きます。エラーは出ません。そして宛先は世界中の商用リージョンです。利用者が明示的に直さない限り、その状態のまま本番へ進みます。

雛形を疑う必要があるのは分かりました。では、雛形を使わずに Strands SDK を直接書けば安全でしょうか。

Strands SDK 本体の既定も global.(警告にも到達しない)

雛形に同梱されていた Strands Agents SDK v1.52.0 のソースコードを読みました。strands/models/bedrock.py の冒頭にこうあります。

# strands/models/bedrock.py:42-44
DEFAULT_BEDROCK_MODEL_ID  = "global.anthropic.claude-sonnet-4-6"
_DEFAULT_BEDROCK_MODEL_ID = "{}.anthropic.claude-sonnet-4-6"
DEFAULT_BEDROCK_REGION    = "us-west-2"

model_id を指定せずに BedrockModel() を作った場合の既定値が global. です。CLI の雛形とは別に、ライブラリ層でも同じ選択がされています

興味深いのは、この SDK にリージョン別の判定ロジックが実装されている点です。_get_default_model_with_warning() には、リージョン名からプレフィックスを導く処理と、対応していないリージョンへの警告が書かれています。ところが、その手前で早期リターンします。

model_config = model_config or {}
if model_config.get("model_id"):
    return model_config["model_id"]

if DEFAULT_BEDROCK_MODEL_ID != _DEFAULT_BEDROCK_MODEL_ID.format("us"):
    return DEFAULT_BEDROCK_MODEL_ID

DEFAULT_BEDROCK_MODEL_ID"global.anthropic.claude-sonnet-4-6" で、_DEFAULT_BEDROCK_MODEL_ID.format("us")"us.anthropic.claude-sonnet-4-6" です。両者は一致しないため、この条件は常に真になります。

その結果、以降にあるリージョン判定も、"You're using default model '...', which is subject to change." という警告も実行されません。モデルIDを指定しなければ、警告なしで global. が使われるというのが、ソースを読む限りの挙動です。

なお、この節はソースコードの読解であり、実際に model_id を省略して東京リージョンで実行し、選ばれたIDを確認したわけではありません。

つまり、雛形を使っても、SDK を素で使っても、何も指定しなければ global. に落ち着きます。「CLI の雛形が悪い」という話ではなく、エコシステム全体の既定がそこにある、というのが実態でした。

だからこそ、使う側が明示的に指定する必要があります。

東京リージョン向けに jp. へ直す(書き換えは1箇所)

雛形に対して加えた変更は1ファイルだけです。

import os

from strands.models.bedrock import BedrockModel

DEFAULT_MODEL_ID = "jp.anthropic.claude-haiku-4-5-20251001-v1:0"
DEFAULT_REGION = "ap-northeast-1"
DEFAULT_MAX_TOKENS = 1024


def load_model() -> BedrockModel:
    """東京リージョン + jp. 推論プロファイルに固定する。"""
    return BedrockModel(
        model_id=os.environ.get("BEDROCK_MODEL_ID", DEFAULT_MODEL_ID),
        region_name=os.environ.get("AWS_REGION", DEFAULT_REGION),
        max_tokens=int(os.environ.get("MAX_TOKENS", DEFAULT_MAX_TOKENS)),
    )

環境変数で上書きできるようにしつつ、既定値を日本国内ルーティングに寄せるのが趣旨です。上書きされなかったときに安全側へ倒れる形にしています。検証段階ではコストを抑えるため Haiku を既定にしました。

max_tokens を明示しているのは、既定が無制限だとトークン予算の上限がなくなるためです。

東京で使える jp. プロファイルの一覧

自分の環境で何が使えるかは、コマンドで確認できます。

aws bedrock list-inference-profiles --region ap-northeast-1 \
  --query "inferenceProfileSummaries[?starts_with(inferenceProfileId,'jp.')].inferenceProfileId" \
  --output text

2026年8月18日時点で返ってきたのは6件でした。

jp.anthropic.claude-sonnet-4-5-20250929-v1:0
jp.anthropic.claude-haiku-4-5-20251001-v1:0
jp.amazon.nova-2-lite-v1:0
jp.anthropic.claude-sonnet-4-6
jp.anthropic.claude-opus-4-7
jp.anthropic.claude-opus-4-8

us.global. で使えるモデルすべてに jp. があるわけではありません。先にこの一覧を確認してから、使うモデルを決めるほうが手戻りがありません。

モデルIDを直せば終わり、と言いたいところですが、もう一段あります。

直してもまだ残る穴(実行ロールのIAMはリージョンワイルドカード)

agentcore deploy --dry-run を実行すると、CloudFormation テンプレートが合成されます。実デプロイはしていませんが、何が作られるかはこの時点で読めます。

作成されるのは AWS::BedrockAgentCore::RuntimeAWS::IAM::RoleAWS::IAM::Policy の3つでした。その IAM Policy の中身がこれです。

関連記事 源内(genai-web)をAWSにCDKでデプロイする手順とハマりやすい注意点 AgentCore CLI も内部は CDK です。CDK デプロイ全般でつまずきやすい点はこちらにまとめています。

[Allow] bedrock:CountTokens, bedrock:InvokeModel, bedrock:InvokeModelWithResponseStream
   Resource:
     arn:aws:bedrock:*:<アカウントID>:inference-profile/*
     arn:aws:bedrock:*::foundation-model/*

リージョンの位置がワイルドカードです。 このロールは全リージョンの全モデルを呼び出せます。

通常、モデルIDの指定を誤ってもIAMが最後の砦になります。リージョンを絞ったポリシーにしておけば、意図しないリージョンでの推論はIAMで止まります。ところが CLI が生成する既定のロールは、リージョンを絞っていません。

整理するとこうなります。

東京の外での推論を止められるか
モデルID(既定の global. 止められない(宛先が世界中の商用リージョン)
IAM(CLI 既定の実行ロール) 止められない(リージョンが *

2つの既定値が重なって、どちらの層でも止まりません。 モデルIDを jp. に直すのは必要ですが、それだけでは IAM 側は開いたままです。

なお、ここを絞るときに注意点が2つあります。

1つ目は宛先の数です。jp. の宛先は先ほど実測したとおり東京と大阪の2つです。IAM を ap-northeast-1 だけに絞ると、大阪へルーティングされた呼び出しが弾かれます。公式ドキュメントの Geographic cross-Region inference でも、必要な許可は3つと明記されています。推論プロファイル、ソースリージョンの基盤モデル、そしてプロファイルに列挙されたすべての宛先リージョンの基盤モデルです。

2つ目は、リージョン指定の Deny が global. には効かないことです。公式ドキュメントにこう書かれています。

The service sets this field to global rather than the actual destination AWS Region.

aws:RequestedRegion に実際の宛先リージョンが入らないため、"aws:RequestedRegion": "us-west-2" のようなリージョン名を指定した Deny ポリシーは期待どおりに動きませんglobal. を明示的に塞ぎたい場合は、"aws:RequestedRegion": "unspecified" という条件を使うと公式に案内されています。「リージョンを絞る既存のガードレールがあるから安全」とは言えない、ということです。

実行ロールのポリシー修正は次回以降に実際にやってみて、結果を記録する予定です。

まとめ

Bedrock AgentCore を東京リージョンで動かすとき、モデルIDのプレフィックスは3通りの振る舞いを見せました。us.ValidationException で失敗し、同一モデルでプレフィックスだけを jp. に変えると6回中6回成功しました。global. はエラーを出さずに動きます。公式ドキュメントによれば、その宛先は世界中の商用 AWS リージョンで、CloudWatch にも CloudTrail にも処理されたリージョンは記録されません。

そして、明示的に指定しなければ global. が選ばれます。AWS 公式CLI @aws/agentcore v0.27.0 の雛形は global. を書き込みます。Strands Agents SDK v1.52.0 も、ソースを読む限り既定を global. に置いています。東京で動かす手順として global. が広まっているのは、実際に動くからです。

医療情報のようにデータの所在地を説明する必要がある場合、この既定値のままでは説明ができません。jp. の宛先は東京と大阪の2リージョンに限られ、そこは実測でも公式の説明でも確認できます。ただしモデルIDを直すだけでは足りません。実行ロールのIAMはリージョンワイルドカードのまま残りますし、global. に対してはリージョン名を指定した Deny ポリシーが効きません。Memory を有効にすれば、そこにも別の経路が生まれます。

まずは aws bedrock list-inference-profiles で、自分の環境で使える jp. プロファイルを確認するところから始めてみてください。次回は、モデルIDを直した後に待っている3つの関門(モデルIDの不一致、IAM、そしてモデルの利用契約)を、エラーメッセージで区別する方法を扱います。

参考文献

この記事を書いた人

鈴木 正明

大手通信キャリア・大手SIer等でエンタープライズ向けAWS基盤の設計・構築、セキュリティ監視基盤構築、IaC推進に一貫して従事。現在はAWS運用へのAI活用(AIOps)にも取り組んでいる。

メールマガジン(不定期)

AWS運用自動化・AIOps・生成AI活用の実装事例や知見を不定期にお届けします。いつでも配信停止できます。