変更履歴
- 2026-11-03:公開
初めに
年内に AWS Certified Generative AI Developer – Professional(AIP-C01)を受ける。基盤モデル(FM)をアプリや業務に組み込み、本番の生成 AI を実装・運用できるかを測る Professional 級の試験で、出題は 75 問・180 分の選択式。範囲は Amazon Bedrock を中心に、データの扱い・安全とガバナンス・運用・評価まで広い(試験ガイド。2026-10-20 確認)。
出題分野は 5 つで、配点は以下の通り。
-
- 基盤モデルの統合・データ管理・コンプライアンス:31%
-
- 実装と統合:26%
-
- AI の安全・セキュリティ・ガバナンス:20%
-
- 運用の効率と最適化:12%
-
- テスト・検証・トラブルシュート:11%
その対策として、出題範囲のサービスを実際に動かす「AIP 基礎編」を全 7 本で書いていく。この記事はその 1 本目。2 本目以降の題は仮。
| # | テーマ | 型 | 主な分野 |
|---|---|---|---|
| 1 | 基盤モデルの呼び出し方と選び方(本記事) | 横断比較 | 1・2 |
| 2 | Knowledge Bases で作る RAG | 深掘り | 1・5 |
| 3 | Guardrails で防げること・防げないこと | 深掘り | 3・5 |
| 4 | エージェントの組み方(Strands Agents・MCP・Step Functions・Flows) | 横断比較 | 2・3 |
| 5 | 生成 AI に渡すデータの前処理と抽出 | 横断比較 | 1・2・3 |
| 6 | 推論のコスト・レイテンシ・ログ | 横断比較 | 2・4・5 |
| 7 | RAG と基盤モデルの評価 | 横断比較 | 3・5 |
この構成にしたのは、試験の中心が「要件に合うサービスや構成を選ぶ」問題で、しかも範囲が広いため。1 つのサービスを深く知るより、似た手段の違いを言えるほうが点になる。そこで、似た手段を 1〜3 回ずつ動かして使い分けをまとめる横断比較を中心にした。設定の違いで結果が大きく変わる RAG と Guardrails の 2 本だけは、条件をそろえて深く比べる。動かしている間ずっと料金がかかる SageMaker AI のエンドポイントや OpenSearch Serverless は動かさず、公式の文書で押さえる。各記事の最後には、要件ごとの選び方(試験の論点)を置く。
Amazon Bedrock で FM を呼ぶ方法は、API・モデル・処理するリージョンの組み合わせで何通りもある。試験で問われるのは「この要件ならどれを選ぶか」なので、同じ依頼を条件を変えて送り比べた。検証は 2026-11-03、東京リージョン(ap-northeast-1)、Python の boto3 1.43.114 で行った。
結論
API・答えの返し方・出力の形の縛り方・呼び先を変えて、同じ依頼を送り比べた。使い分けは次の 4 点にまとまった。
- 複数のモデルを比べる・替えるなら Converse。InvokeModel は依頼と応答の JSON の形がモデルごとに違い、Converse は同じコードで Nova と Mistral の両方を呼べた(3 章)。
- 答えを早く見せるならストリーミング。最初の文字は 0.3〜0.4 秒で届いた(4 章)。
- 決まった形で取り出すなら、API で形を縛る。プロンプトで頼むだけでは 5 回中 1 回崩れた。ただし Nova は構造化出力に対応していない(5 章)。
- 呼び先と機能は、先にモデルの対応を見る。東京では、Nova Micro をモデルの ID だけでは呼べなかった(7 章)。
構造化出力・推論プロファイル・プロンプトルーターは、モデルによって使えるかどうかが決まった。
Prompt Management・プロンプトルーター・AppConfig・サービスティアの結果は 6 章と 8〜10 章に、要件ごとの選び方は 11 章にまとめた。
本記事の構成
1 章で Bedrock で FM を呼ぶ方法の全体、2 章で検証環境を説明する。3〜10 章が手段ごとの結果で、11 章に要件ごとの選び方(試験の論点)をまとめた。
検証の全体像を図1に示す。呼び出しはすべて東京リージョンから行い、API・modelId に入れる呼び先・処理するリージョンの組み合わせを変えて比べた。箱の中の番号は、その結果を書いた章を指す。
1. Bedrock で FM を呼ぶ方法
本記事で比べるのは、テキストの会話に使う API の 4 つ。
- InvokeModel と InvokeModelWithResponseStream:モデルごとの形の JSON を
bodyに入れる。前者はまとめて返し、後者は少しずつ返す(ストリーミング)。 - Converse と ConverseStream:どのモデルでも同じ形(
messages)で書く。前者はまとめて返し、後者は少しずつ返す。
Converse は、メッセージを扱うすべてのモデルに同じ形で書ける API で、ツール呼び出しやガードレールもここで指定する(公式)。モデル固有の値は additionalModelRequestFields で渡す。
API を決めたら、次に呼び先(modelId)を決める。構造化出力やツールは、呼び出しに付ける設定になる。今回使った呼び先の指定は 2 通り。
- 基盤モデルの ID を直接指定する(例:
mistral.ministral-3-8b-instruct)。呼んだリージョンで処理する。以下、単一リージョンの呼び出しと書く。 - クロスリージョン推論プロファイルの ID を指定する(例:
jp.amazon.nova-2-lite-v1:0)。決まった複数のリージョンのどこかで処理する。この振り分けを Cross-Region Inference と呼ぶ。
推論プロファイルには、利用料を用途ごとに分けるために自分で作るアプリケーション推論プロファイルもあるが、今回は使っていない。modelId には、ほかにプロンプトルーターや Prompt Management のプロンプトの ARN も入る(6 章・8 章)。
2. 検証環境
使ったモデルは以下の通り。
- Amazon Nova 2 Lite(
jp.amazon.nova-2-lite-v1:0):主に使ったモデル。推論プロファイル経由で呼ぶ。 - Mistral AI の Ministral 3 8B(
mistral.ministral-3-8b-instruct):API の形の比較・構造化出力・サービスティアで使った。東京の単一リージョンで呼ぶ。 - Qwen3 32B(
qwen.qwen3-32b-v1:0):構造化出力で使った。東京の単一リージョンで呼ぶ。 - Amazon Nova Micro(
apac.amazon.nova-micro-v1:0):推論プロファイルの比較と、モデルの切り替え先に使った。 - Amazon Nova Lite と Nova Pro:既定の Nova Prompt Router が振り分ける先。
依頼には、架空の会社への問い合わせ文を 3 つ使った(ノートPC の故障・プリンタのインクの配送先の変更・クラウド会計の取り込みエラー)。どれも 150 字ほどの日本語。
3. InvokeModel と Converse
まず気になったのは、モデルを替えたときにコードのどこが変わるか。「次の問い合わせを、要件・期限・対応の希望の 3 行で要約してください」という同じ依頼を、Nova 2 Lite と Ministral 3 8B に 2 つの API で送った。boto3 では、どちらの API も bedrock-runtime のクライアントから呼ぶ。
InvokeModel の body は、モデルごとに形が違う。
rt = boto3.client("bedrock-runtime", region_name="ap-northeast-1")
BODIES = {
"jp.amazon.nova-2-lite-v1:0": {
"schemaVersion": "messages-v1",
"messages": [{"role": "user", "content": [{"text": PROMPT}]}],
"inferenceConfig": {"maxTokens": 300},
},
"mistral.ministral-3-8b-instruct": {
"messages": [{"role": "user", "content": PROMPT}],
"max_tokens": 300,
},
}
応答の形も違った。Nova は output.message.content[0].text に答えが入り、Ministral は choices[0].message.content に入る(OpenAI の API と同じ形)。
Converse は、modelId を替えるだけで両方を呼べた。
resp = rt.converse(
modelId=model_id, # Nova でも Ministral でも同じ
messages=[{"role": "user", "content": [{"text": PROMPT}]}],
inferenceConfig={"maxTokens": 300},
)
text = resp["output"]["message"]["content"][0]["text"]
応答の usage(入力と出力のトークン数)・metrics.latencyMs(Bedrock 側が返す処理時間)・stopReason(止まった理由)も、どちらのモデルでも同じ場所に返る。モデルを替える前提の用途なら、自分は Converse を使う。
4. 同期とストリーミング
次は、画面に答えを出す速さ。問い合わせ(クラウド会計の取り込みエラー)への返信の下書き(300 字ほど)を Nova 2 Lite に書かせ、4 つの API でそれぞれ 3 回続けて送った。出力の上限は 500 トークン。
時間は手元のスクリプトで測った。呼び出しの直前から、空でない最初の文字を受け取るまでと、応答を全部受け取るまで。同期の API は全部そろってから返すので、2 つの時間は同じになる。
| API | 最初の文字まで [s] | 全部が届くまで [s] | 出力トークン数 |
|---|---|---|---|
| Converse | 3.19・3.27・3.56 | 3.19・3.27・3.56 | 500・500・500 |
| ConverseStream | 0.38・0.42・0.32 | 2.09・3.07・2.70 | 292・500・387 |
| InvokeModel | 2.28・2.63・2.39 | 2.28・2.63・2.39 | 307・392・386 |
| InvokeModelWithResponseStream | 0.34・0.33・0.36 | 2.41・3.19・2.24 | 記録していない |
最初の文字は、ストリーミングなら 0.3〜0.4 秒で届いた。チャットの画面なら、書き始めをすぐ見せられる。全部が届くまでの時間は、出力の長さが回ごとに違う(292〜500 トークン)ので、この表から API ごとの速さの差は言えない。
5. ツール呼び出しと構造化出力
モデルの答えをプログラムで扱うには、外の処理を呼ばせる手段と、出力の形を縛る手段がある。
ツール呼び出し
Nova 2 Lite に、Converse の toolConfig で「型番を受け取って在庫と出荷日を返す」ツールを 1 つ渡し、「ノートPC『LX-500』の代替機をすぐ出せるか」と聞いた。ツールの中身は、自分のスクリプトの中で固定の在庫(3 台・11/7 出荷)を返す作り物にした。
1 往復目は、答えの代わりに stopReason: tool_use が返り、ツールの名前と入力({"model_number": "LX-500"})が入っていた。モデルは自分ではツールを動かさない。呼び出す側のコードが在庫を調べ、結果を toolResult として返すと、2 往復目で「在庫は 3 台あり、出荷予定日は 2026 年 11 月 7 日」と答えた。
ツールは外の処理を呼ぶための仕組みだが、ツールに渡す引数の形を決められる。そのため、出力の形を縛る用途にも使える(下の (b))。
出力の形を縛る
問い合わせから名字・製品名・緊急度を JSON で取り出させる依頼を、次のやり方で送り比べた。
- (a) プロンプトで「JSON だけを返して」と頼む
- (b) ツールの入力の形(
inputSchema)で縛り、そのツールを必ず使わせる(toolChoice) - (c) 構造化出力(
outputConfigの JSON Schema1)で縛る
使ったスキーマは以下の通り。キーは 3 つで、緊急度は「高・中・低」のどれかに限り、ほかのキーは許さない。
EXTRACT_SCHEMA = {
"type": "object",
"properties": {
"name": {"type": "string"},
"product": {"type": "string"},
"urgency": {"type": "string", "enum": ["高", "中", "低"]},
},
"required": ["name", "product", "urgency"],
"additionalProperties": False,
}
構造化出力の指定は以下の通り。スキーマは JSON の文字列にして渡す。
resp = rt.converse(
modelId=model_id,
messages=[{"role": "user", "content": [{"text": prompt}]}],
outputConfig={"textFormat": {"type": "json_schema", "structure": {"jsonSchema": {
"name": "inquiry_extract",
"schema": json.dumps(EXTRACT_SCHEMA),
}}}},
)
やり方とモデルの組ごとに 5 回呼んだ。入力は 3 つの問い合わせを順に回し、5 回の内訳はノートPC・インク・会計・ノートPC・インク。判定は、答えから { から } までを取り出して JSON として読み、キーが 3 つちょうどで、緊急度が高・中・低のどれかなら形どおりとした。Qwen3 32B は、構造化出力を試す 2 つ目のモデルとして (c) だけで使った。
形どおりにならなかった回数(5 回のうち)は以下の通り。
| やり方 | Nova 2 Lite | Ministral 3 8B | Qwen3 32B |
|---|---|---|---|
| (a) プロンプトで頼む | 0 | 1 | — |
| (b) ツールの形で縛る | 0 | 0 | — |
| (c) 構造化出力 | 対応していない | 0 | 0 |
(a) の Ministral は、1 回だけ {"response": [{…}]} と配列で包んで返した。また (a) は両モデルとも、5 回とも答えを ```json の囲みに入れて返した。判定では囲みを外して読んだが、そのまま JSON として使うなら、取り出す処理が要る。
Nova 2 Lite で (c) を試すと、エラーになった。
ValidationException: This model doesn't support the outputConfig field. Remove outputConfig and try again.
構造化出力に対応するのは、Anthropic・Mistral AI・Qwen・OpenAI など 9 社のモデルで、Amazon の Nova は入っていない(AWS のブログ。2026-11-03 確認)。Nova で形を縛るなら、(b) のツールの形を使う。
ただし、通常のツール呼び出しは、引数がスキーマに合うことを保証するものではない。保証が要るなら、対応するモデルでツールの定義に strict: true を付けるか(公式)、受け取った側でも検証する。今回の 0 回は 5 回の範囲の結果。
形を縛っても、中身の判断はモデル次第。Qwen3 32B は、急ぎではないインクの配送先の変更を「高」と判定した(形は崩れていない)。
6. Prompt Management
プロンプトの文面をコードから外に出し、バージョンで管理する機能。変数を {{inquiry}} のように書いておき、呼ぶときに値を入れる。
fmlab-summary というプロンプトを作った。モデルには Nova 2 Lite の推論プロファイルの ID(jp.amazon.nova-2-lite-v1:0)をそのまま指定できた。バージョン 1 は「3 行で要約」、バージョン 2 は「要件・期限・次にやることの箇条書き」にしている(図2・図3)。
呼ぶときは、Converse の modelId にバージョンつきの ARN(末尾が :1 や :2)を入れ、変数の値を promptVariables で渡す。messages は渡さなくてよかった。
resp = rt.converse(
modelId="arn:aws:bedrock:ap-northeast-1:<アカウント ID>:prompt/<プロンプト ID>:2",
promptVariables={"inquiry": {"text": INQUIRIES[0]}},
)
バージョン 1 は文章の要約、バージョン 2 は 3 項目の箇条書きが返った。
7. 推論プロファイルと Cross-Region Inference
推論プロファイルには、処理するリージョンの範囲が決まっている。
-
jp.amazon.nova-2-lite-v1:0:東京と大阪(図4) -
global.amazon.nova-2-lite-v1:0:商用のすべてのリージョン -
apac.amazon.nova-micro-v1:0:アジア太平洋の 6 リージョン
単一リージョンで呼べないモデル
東京から Nova Micro を、推論プロファイルを通さずにモデルの ID(amazon.nova-micro-v1:0)で呼ぶと、以下のエラーが返った。
ValidationException: Invocation of model ID amazon.nova-micro-v1:0 with on-demand throughput isn't supported. Retry your request with the ID or ARN of an inference profile that contains this model.
今回東京で試したモデルでは、Nova 2 Lite と Nova Micro は推論プロファイル経由でしか呼べず、Ministral 3 8B と Qwen3 32B は単一リージョンで呼べた。モデルとリージョンごとに違うので、使う前にモデルの説明のページで確かめる。コンソールのプレイグラウンドでモデルを選ぶと、この違いが「推論」の欄に出る(図5・図6)。
jp. と global. の違い
3 章と同じ形の要約の依頼を、Nova 2 Lite の jp. と global. で 3 回ずつ呼んだ。出力は 54〜67 トークン。時間は手元のスクリプトで、呼び出しから応答を受け取るまでを測った。出力の上限など条件が違うので、4 章の時間とは比べない。
| 推論プロファイル | 処理時間 [s] | 入力の単価 [USD/1,000 トークン] | 出力の単価 [USD/1,000 トークン] |
|---|---|---|---|
jp. |
0.72・0.59・0.61 | 0.000396 | 0.003311 |
global. |
0.87・1.09・0.76 | 0.00036 | 0.00301 |
単価は、2026-11-03 に AWS Price List API で東京の値を確認した。global は 1 割ほど安い。この日の 3 回では jp. の方が速かったが、3 回だけなので速さの優劣は言えない。
どのリージョンで処理されたかは、応答の本文にもヘッダーにも出なかった。処理したリージョンは、呼び出し元のリージョンの CloudTrail の記録の additionalEventData.inferenceRegion で分かる(公式。今回は見ていない)。
Geographic の推論プロファイル(jp. など)を使うには、推論プロファイルと、呼び出し元と処理先のすべてのリージョンのモデルに、呼び出しの権限が要る。SCP でリージョンを絞っている組織では、処理先のリージョンを許すか、推論プロファイルの例外を足す。global では aws:RequestedRegion が unspecified として評価される(公式。2026-11-03 確認)。
8. Intelligent Prompt Routing(プロンプトルーター)
プロンプトルーターは、同じ系統の 2 つのモデルのうち、どちらに回すかを依頼ごとに決める機能。2026-11-03 に東京で ListPromptRouters とコンソールを見ると、既定のルーターが 2 つあった。Nova Lite と Nova Pro の間で振り分ける Nova Prompt Router と、Claude 3 Haiku と Claude 3.5 Sonnet の間で振り分ける Anthropic Prompt Router(図7)。今回は Nova Prompt Router を使った。
ルーターには、フォールバックのモデルと、ルーティングの基準(応答の質の差)がある。フォールバックのモデルを基準にして、もう一方のモデルの予測の質がこの差より上回るときだけ、もう一方に回す(公式)。Nova Prompt Router は、フォールバックが Nova Pro、基準が 0% だった(図8)。
呼ぶときは、ルーターの ARN を modelId に入れるだけでよい。実際に使われたモデルは、応答の trace.promptRouter.invokedModelId に入る。コンソールのプレイグラウンドでも、答えの横に出る(図9)。
自分は、易しい問いは Nova Lite、難しい問いは Nova Pro に回ると予想していた。ただし、ルーターが見るのは問いの難しさではなく、2 つのモデルの答えの質の差の予測なので、この分け方と一致するとは限らない。
易しい問い・難しい問い・中くらいの問いを、英語と日本語で 1 回ずつ送った。難しい問いは、RPO(障害のときに失ってよいデータの時間幅)が 1 分の決済システムの災害対策の設計。結果は以下の通り。
| 問い | 英語 | 日本語 |
|---|---|---|
| 日本の首都はどこか | Nova Pro | Nova Lite |
| RPO 1 分の決済システムの複数リージョンの災害対策を設計し、案ごとのトレードオフを述べる | Nova Lite | Nova Pro |
| TCP と UDP の違いを 2 文で | Nova Lite | Nova Lite |
日本語は予想どおりに分かれた。英語は、首都の問いが Nova Pro に回って長い解説を返し、設計の問いは Nova Lite に回った。2 つのモデルの答えの質は比べていないので、英語の振り分けが誤りとも言えない。公式は、ルーティングが英語のプロンプトに最適化されていると書いている。6 問だけの観察なので、振り分けの傾向は言えない。使うなら、手元の依頼で振り分けを確かめてから決める。
9. AppConfig でモデルを切り替える
試験ガイドには、モデルを動的に切り替える手段として AWS AppConfig が出てくる。AppConfig は、設定をコードの外に置き、配り方(デプロイ戦略)を決めて配るサービス。アプリケーション・環境・設定プロファイルの 3 つを作り、設定の中身をデプロイする。
アプリケーション fmlab、環境 dev、自由形式の設定プロファイル model を作り、{"modelId": "jp.amazon.nova-2-lite-v1:0"} をデプロイした。アプリ側は appconfigdata の API で設定を読み、その modelId で Converse を呼ぶ。最初に StartConfigurationSession でセッションを始めて初めのトークンを受け取り、以後は GetLatestConfiguration が返す次のトークンで読む。
resp = data.get_latest_configuration(ConfigurationToken=self.token)
self.token = resp["NextPollConfigurationToken"]
body = resp["Configuration"].read()
if body: # 空なら前回から変わっていない
self.model_id = json.loads(body)["modelId"]
設定を apac.amazon.nova-micro-v1:0 に替えてデプロイし直すと、同じコードのまま Nova Micro に切り替わった(図10・図11)。次に読むまでの間隔は、応答の NextPollIntervalInSeconds に従う(下限は 15 秒)。今回は、2 回目のデプロイのあと 16 秒待ってから読み直した。
既定のデプロイ戦略 AppConfig.AllAtOnce には、配り終えたあと 10 分の様子見(ベイク)がある(図12)。今回は切り替えを続けて試すため、待ち時間 0 分の戦略を作った。様子見を含むデプロイの間に CloudWatch のアラームが鳴ると、AppConfig は元の設定に戻す(公式。切り戻しの権限の設定が要る)。今回は切り替えだけを確かめ、自動の切り戻しは試していない。
今回の 1 回では、切り替えたあとの Nova Micro は、「AppConfig とは何かを 1 文で」という問いに、Python の Web フレームワーク Django の AppConfig の説明を返した。切り替えの仕組みと、切り替え先のモデルの出来は、別に見る必要がある。
10. サービスティア(flex)
Converse では、serviceTier を指定すると、料金と処理の優先度の組み合わせを選べる。標準の default のほかに、混んでいるときに後回しにされうる代わりに安い flex と、優先して処理される代わりに高い priority がある。Ministral 3 8B の単価は、標準が入出力とも 1,000 トークンあたり 0.00018 USD、flex は 0.00009 USD だった(2026-11-03 確認)。
同じ要約の依頼を、標準と flex で 3 回ずつ送った。手元で測った時間は、標準が 0.62・0.57・0.69 秒、flex が 0.54・1.07・0.73 秒。flex の 2 回目は、出力が 200 トークンとほかの回(90〜126 トークン)より長かった。この日は、flex でもほぼ遅れなかった。応答の serviceTier には、実際に使われたティアが返ってくる。急がない処理なら、引数 1 つで単価を半分にできる。
11. 試験の論点
ここまでの結果と公式の説明から、要件ごとの選び方をまとめた。「(公式の説明)」と付けたところは、今回は動かしていない。
| こういう要件なら | 選ぶもの | 選ばないもの |
|---|---|---|
| 複数社のモデルを比べたい・後で替えたい | Converse | InvokeModel(依頼と応答の形がモデルごとに違う) |
| チャットで答えを早く見せたい | ConverseStream | 同期の Converse(全部そろうまで返さない) |
| 動画の生成など、時間のかかる処理を受け付けて後で結果を取りたい(公式の説明) | 非同期の呼び出し(StartAsyncInvoke。対応するモデルに限られ、結果は S3 に置かれる) |
同期の API(終わるまで呼び出しを待ち続ける) |
| 大量の依頼をまとめて安く流したい(公式の説明) | バッチ推論 | 1 件ずつの同期の呼び出し |
| 急がない処理を安くしたい | flex | priority |
| モデルに社内の処理を呼ばせたい | ツール呼び出し(toolConfig) |
構造化出力(形を縛るだけで、処理は呼ばない) |
| 決まった形で抽出したい | 構造化出力(対応モデル)、ツールの入力の形(受け取った側でも検証する。厳密に縛るなら strict: true) |
プロンプトで頼むだけ(崩れることがある) |
| プロンプトをバージョンで管理して差し替えたい | Prompt Management | コードにプロンプトを直書き |
| 処理を国内のリージョンに留めたい | Geographic の推論プロファイル(jp.) |
global の推論プロファイル |
| 処理するリージョンを限らず、単価を下げたい | global の推論プロファイル | Geographic の推論プロファイル |
| 同じ系統の大小 2 モデルを自動で使い分けたい | プロンプトルーター | AppConfig(自動では選ばない) |
| 再デプロイ無しでモデルを替え、デプロイ中に問題が出たら戻したい(戻す部分は公式の説明) | AppConfig(デプロイ戦略とアラームで戻す) | プロンプトルーター(決めた 2 つの間でしか動かない) |
最後に
Nova 2 Lite で構造化出力を指定するとエラーになり、Nova Micro は東京からモデルの ID だけでは呼べなかった。どちらも、手段の選び方より手前の、モデルの対応で止まった。
参考(2026-11-03 確認)
- Converse API でのモデルの呼び出し
- OutputConfig(Converse の構造化出力)
- Structured outputs on Amazon Bedrock(AWS のブログ)
- 推論プロファイル・Geographic の Cross-Region Inference・Global の Cross-Region Inference
- Intelligent Prompt Routing
- AppConfig の自動の切り戻し
- AIP-C01 の試験ガイド
-
JSON の形(キーの名前・型・必須か・選べる値)を書く決まり。 ↩











