AWS

Amazon Bedrockプロンプト最適化|2方式の違い・料金試算・東京リージョン対応【2026年11月】

Amazon Bedrockプロンプト最適化|2方式の違い・料金試算・東京リージョン対応【2026年11月】

Amazon Bedrockのプロンプト最適化は、性格の違う2つの機能に分かれています。プレイグラウンドの杖アイコンを押すと数秒で書き換わる「シンプル最適化」と、評価データで採点しながら最大5モデル分のプロンプトを書き換える「Advanced Prompt Optimization(AdvPO)」です。対応リージョン・料金体系・APIがすべて別物で、東京リージョンで使えるのはAdvPOだけです。この記事は2026年11月3日時点の公式ドキュメントとAPIモデルを突き合わせ、どちらを選ぶか、評価件数ごとにいくらかかるか、最適化したプロンプトを本番でどう呼ぶかまでを整理します。

まとめ

  • シンプル最適化は1プロンプト・1モデルの即時書き換え、AdvPOは評価で採点しながら最大5モデルを比較する非同期ジョブです。モデル移行の判断に使えるのはAdvPOです。
  • 東京リージョン(ap-northeast-1)で使えるのはAdvPOだけです。シンプル最適化の対応表には東京が1件もありません。
  • シンプル最適化は1,000トークンあたり0.03ドル。AdvPOは機能料金がなく、推論トークンとLambda実行費だけがかかります。料金ページの式でClaude Sonnet 4.6を当てると、評価10件で約3.7ドル、100件で約26ドルです(最適化器と採点モデルの出力トークン代は含まない)。
  • 2026年10月20日にAdvPOへプロンプト短縮(shortenPrompt)が加わり、採点に使えるモデルは9種に増えました。一方でコスト概算は結果ファイルから外れ、コンソールで単価を入力して計算する方式になっています。
  • AdvPOのジョブAPIにはbotocore 1.43.8以降が必要です。公式ドキュメントのコード例には、APIモデルに存在しないパラメータ名とメソッド名が2026年11月時点でも残っています。

シンプル最適化とAdvanced Prompt Optimizationの違い

プロンプト最適化は2024年11月にプレビュー公開され、2025年4月23日に一般提供になりました。当時の機能が現在の「シンプル最適化」です。2026年5月14日に評価駆動のAdvanced Prompt Optimizationが追加され、公式ドキュメントも「Optimize and migrate prompts in Amazon Bedrock」の下に2方式を並べる構成になりました。

2方式の比較表

観点 シンプル最適化 Advanced Prompt Optimization
用途 短いプロンプト1本の書き換え モデル移行と性能調整
入力サイズ およそ1,000トークン以下 コンテキスト長に収まれば不問
入力単位 プロンプト文1本 テンプレート最大10本+評価サンプル
モデル数 1 最大5(現行1+候補4)
評価 なし 既定/ステアリング基準/LLM判定/Lambda
実行方式 同期(数秒) 非同期ジョブ(15分〜数時間)
マルチモーダル 非対応 画像とPDF
プロンプト短縮 なし テンプレートごとに任意
東京リージョン 不可 可
料金 1,000トークン0.03ドル 推論とLambdaの実費のみ

どちらを選ぶかの判断基準

判断は「良い応答とは何かを自分で書き下せるか」で切れます。AdvPOは採点結果を手がかりに書き換えを繰り返すため、採点基準が具体的なほど効きます。正解応答(referenceResponse)は入力スキーマ上は任意で、正解データを作れないタスクでもステアリング基準という正規の道が残ります。

シンプル最適化を選ぶべきでないのは、モデル移行の判断材料が欲しいときです。公式の比較表もモデル移行への対応を「Partial(書き換えはできるが横並び比較はない)」としています。「Claude Sonnet 4.5のプロンプトを4.6に移して品質が落ちないか」を確かめるなら最初からAdvPOを使い、プレイグラウンドの下書きを整えたいだけならシンプル最適化で足ります。

シンプル最適化の対応モデルと実行手順

対応モデルと単一リージョンでの利用可否

シンプル最適化の対応表は、モデルごとに「そのリージョン単体で使えるか」を定義しています。2026年11月時点の全22行は次のとおりで、8月から変わっていません。Claude 4.5以降の世代は1行も追加されていません。

プロバイダ モデル モデルID 単一リージョン対応
Amazon Nova Lite amazon.nova-lite-v1:0 us-east-1・eu-west-2・ap-southeast-2
Amazon Nova Micro amazon.nova-micro-v1:0 us-east-1・eu-west-2・ap-southeast-2
Amazon Nova Pro amazon.nova-pro-v1:0 us-east-1・eu-west-2・ap-southeast-2
Amazon Nova Premier amazon.nova-premier-v1:0 なし
Anthropic Claude 3 Haiku anthropic.claude-3-haiku-20240307-v1:0 10リージョン(注1)
Anthropic Claude 3 Sonnet anthropic.claude-3-sonnet-20240229-v1:0 10リージョン(注1)
Anthropic Claude 3 Opus anthropic.claude-3-opus-20240229-v1:0 なし
Anthropic Claude 3.5 Haiku anthropic.claude-3-5-haiku-20241022-v1:0 us-west-2
Anthropic Claude 3.5 Sonnet anthropic.claude-3-5-sonnet-20240620-v1:0 us-east-1・us-west-2・eu-central-1
Anthropic Claude 3.5 Sonnet v2 anthropic.claude-3-5-sonnet-20241022-v2:0 us-west-2・ap-southeast-2
Anthropic Claude 3.7 Sonnet anthropic.claude-3-7-sonnet-20250219-v1:0 eu-west-2
Anthropic Claude Opus 4 anthropic.claude-opus-4-20250514-v1:0 なし
Anthropic Claude Sonnet 4 anthropic.claude-sonnet-4-20250514-v1:0 なし
DeepSeek DeepSeek-R1 deepseek.r1-v1:0 なし
Meta Llama 3 70B Instruct meta.llama3-70b-instruct-v1:0 us-east-1・us-west-2・ap-south-1・ca-central-1・eu-west-2
Meta Llama 3.1 70B Instruct meta.llama3-1-70b-instruct-v1:0 us-west-2
Meta Llama 3.2 11B Instruct meta.llama3-2-11b-instruct-v1:0 なし
Meta Llama 3.3 70B Instruct meta.llama3-3-70b-instruct-v1:0 なし
Meta Llama 4 Maverick 17B Instruct meta.llama4-maverick-17b-instruct-v1:0 なし
Meta Llama 4 Scout 17B Instruct meta.llama4-scout-17b-instruct-v1:0 なし
Mistral AI Mistral Large (24.02) mistral.mistral-large-2402-v1:0 9リージョン(注2)
Mistral AI Mistral Large (24.07) mistral.mistral-large-2407-v1:0 us-west-2

注1は us-east-1・us-west-2・ap-south-1・ap-southeast-2・ca-central-1・eu-central-1・eu-west-1・eu-west-2・eu-west-3・sa-east-1 の10リージョン、注2はそこから eu-central-1 を除いた9リージョンです。「なし」の行は公式表で空欄になっており、意味は説明されていません。該当するのはNova Premier・Claude Opus 4・Claude Sonnet 4・DeepSeek-R1・Llama 4系など、クロスリージョン推論プロファイル前提で提供されているモデルです。

日本の開発者が最初につまずくのは、東京が1行も出てこない点です。プロンプトを保管するPrompt management自体は22リージョン(商用20+AWS GovCloud 2)で動き、ap-northeast-1も含まれます。東京でプロンプトを作ったのに最適化ボタンだけ使えない、という組み合わせが起きます。シンプル最適化を試すなら、us-east-1かus-west-2にプロンプトを置くのが手早い回避策です。

コンソールとOptimizePrompt APIでの実行

コンソールでは2か所から呼べます。プレイグラウンドでモデルを選んでプロンプトを書き、杖アイコンを押すと最適化ダイアログが開いて元のプロンプトと並べて比較できます。Prompt managementの画面では、最適化結果がバリアントとして横に並びます。比較ビューに3本ある状態でさらに最適化すると、どれを上書きするか聞かれます。

APIでは bedrock-agent-runtime の OptimizePrompt を使います。レスポンスはイベントストリームで、分析完了の analyzePromptEvent と書き換え完了の optimizedPromptEvent が順に流れます。

import boto3
from botocore.exceptions import EventStreamError

client = boto3.client("bedrock-agent-runtime", region_name="us-west-2")

response = client.optimize_prompt(
    input={"textPrompt": {"text": "Summarize the following meeting minutes in 200 characters."}},
    targetModelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
)

try:
    for event in response["optimizedPrompt"]:
        if "analyzePromptEvent" in event:
            print("[analyze]", event["analyzePromptEvent"]["message"])
        elif "optimizedPromptEvent" in event:
            text = event["optimizedPromptEvent"]["optimizedPrompt"]["textPrompt"]["text"]
            print("[optimized]", text)
except EventStreamError as e:
    # throttlingException / validationException などはストリームの途中で例外として届く
    print("[stream error]", e.response["Error"]["Code"], e.response["Error"].get("Message"))

反復をtry/exceptで囲む部分は省略しないでください。OptimizePromptのストリームには、throttlingException・validationException・accessDeniedException・internalServerException・dependencyFailedException・badGatewayExceptionの6種がイベントとして定義されています(botocore 1.43.123のサービスモデル)。boto3はこれらを辞書として渡さず、反復の途中でEventStreamErrorとして送出するため、if文の分岐では拾えません。分析イベントとthrottlingExceptionのイベントを組み立ててbotocoreのEventStreamに流すと、上のコードは「[analyze] …」を表示した後に「[stream error] throttlingException Rate exceeded」と出力しました。公式のコード例も、エラーイベントが来るとEventStreamErrorで止まります。

Advanced Prompt Optimizationのジョブ設計

AdvPOは、評価サンプルをテンプレートのプレースホルダに差し込んでターゲットモデルに推論させ、指定した方法で採点し、その結果を見てプロンプトを書き換えるループを内部で回します。対応リージョンはus-east-1、us-east-2、us-west-2、ca-central-1、sa-east-1、eu-west-1、eu-west-2、eu-central-1、eu-central-2、ap-south-1、ap-northeast-1、ap-northeast-2、ap-southeast-1、ap-southeast-2の14です。ターゲットにできるのはテキストを出力するBedrockモデルで、シンプル最適化のような限定リストはありません。ただしジョブを作るリージョンで提供されているモデルに限られ、新しいモデルはBedrockでの公開からAdvPOで選べるようになるまで少し遅れることがあります。

データの所在を気にするなら、評価と書き換えにクロスリージョン推論が使われる点も確認しておきます。欧州リージョンではeuのクロスリージョン推論、ap-south-1・sa-east-1・ap-northeast-2・ap-southeast-1ではグローバルのクロスリージョン推論が使われる場合があると明記されています。東京はこの列挙に含まれていません。

入力JSONLの必須フィールドと書式

入力は1行1テンプレートのJSONLで、ジョブごとに1ファイルです。必須はversion(固定値bedrock-2026-05-14)、templateId、promptTemplate、evaluationSamples(1〜100件)の4つ。プレースホルダは二重の中かっこで書き、inputVariablesは「1オブジェクト1キー」の配列にします。

{"version": "bedrock-2026-05-14", "templateId": "minutes-summary-v1", "promptTemplate": "You are a meeting assistant.\n\nMinutes:\n{{minutes}}\n\nSummarize the decisions and the owner of each action item.", "optimizationConfig": {"shortenPrompt": true}, "customEvaluationMetricLabel": "decisioncoverage", "evaluationMetricLambdaArn": "arn:aws:lambda:us-west-2:123456789012:function:advpo-decision-coverage", "evaluationSamples": [{"inputVariables": [{"minutes": "Sato: ship the billing fix by Friday. Tanaka: owns the migration script."}], "referenceResponse": "Decision: ship the billing fix by Friday (owner: Sato). Action: migration script (owner: Tanaka)."}]}

クォータは、1ジョブあたりテンプレート10本・モデル5つ、1テンプレートあたり評価サンプル100件・テキスト変数20個・ステアリング基準5個、1サンプルあたりマルチモーダルファイル100件、入力ファイル50MB、同時ジョブ20(アカウント・リージョンあたり)です。マルチモーダルはJPG・JPEG・PNG・GIF・WebPとPDFに対応しますが、アニメーションGIFとWebPは多くのモデルが先頭フレームしか読みません。複数フレームを見せたいなら、画像を分割して別ファイルで渡します。

評価方法4種の選び方

評価方法はテンプレートごとに1つ選びます。何も指定しなければシステム既定の評価になり、Claude Sonnet 4.6が正確性(Answer Accuracy)・網羅性(Answer Completeness)・表現(Expression Quality)の3軸で採点します。重みはタスクに応じて決まり、決められないときの既定値は0.35・0.30・0.35です。既定の採点プロンプトは「特別な指示がない限り簡潔な回答ほど良い」と明記しており、冗長な応答は減点されます。

  • ステアリング基準:steeringCriteriaに短い自然言語を最大5個並べます。PROFESSIONALやCONCISEのような単語でも数文でも構いません。正解データを用意しにくいタスク向けです。
  • LLM-as-a-judge:customLLMJConfigに採点プロンプトと採点モデルを渡します。採点プロンプトでは prompt・response・referenceResponse を二重中かっこのプレースホルダとして使えます。採点の書き方はLLM-as-a-Judgeとは?評価プロンプトの書き方・3つのバイアス対策と人手との一致率の測り方が参考になります。
  • Lambda評価器:evaluationMetricLambdaArnに関数ARNを渡し、採点ロジックを自分で書きます。JSONスキーマへの適合のように機械的に判定できる指標に向きます。

採点モデルの対応リストは8月の3種から増え、2026年11月時点ではOpus 4.6・4.7・4.8・5・5.5、Sonnet 4.5・4.6・5・5.5の9種です(Supported judge models)。customLLMJModelIdには基盤モデルID、クロスリージョン推論プロファイルID、アプリケーション推論プロファイルARNのいずれかを書き、リスト外のモデルはジョブ作成時にValidationExceptionになります。

LLM-as-a-judgeとLambdaではcustomEvaluationMetricLabelが必須です。採点結果は元の尺度に関係なく正規化され、大きいほど良い扱いです。カスタムの採点プロンプトはサービス側の既定プロンプトと結合されるため、1〜5の刻みを定義しても数値が一致しないことがあり、二値判定や完全一致ならLambda評価器が確実です。

Lambda評価器の実装契約

Lambda評価器の要件は、全部入りの単一.pyファイル、ハンドラはlambda_function.lambda_handler、compute_score(preds, golds)が集約スコアscoreと件数分のscoresを返すこと、の3点です。タイムアウトは最大の900秒に寄せ、bedrock.amazonaws.comからの呼び出しを許可するリソースベースポリシーを付けます。referenceResponseを渡していなければgoldsは不要です。

実装で効くのは次の3つです。例外を投げず、失敗時は0.0と診断メッセージを返すこと。0か1の二値ではなく連続値を返すこと(最適化器はサンプル平均を上げにいくので、部分点があるほうが収束が速い)。そしてcompute_scoreのdocstringに高得点の条件を書くことです。公式ドキュメントによれば、docstringとソースコード自体が指標の説明として読み込まれます。値域を0.0〜1.0に収める必要はなく、大きいほど良いという向きだけが要件です。

import logging
import re
from typing import Any, Dict, List

logger = logging.getLogger()
logger.setLevel(logging.INFO)

STOPWORDS = {"the", "a", "an", "of", "to", "by", "and", "is", "are", "will", "for"}


def _content_words(text: str) -> set:
    return {w for w in re.findall(r"[a-z0-9]+", text.lower()) if w not in STOPWORDS}


def compute_score(preds: List[str], golds: List[str]) -> Dict[str, Any]:
    """正解文の内容語を応答がどれだけ再現できたかを 0.0-1.0 で採点する。

    1.0 は正解文の内容語をすべて含む応答、0.0 は 1 つも含まない応答を指す。
    決定事項と担当者名の取りこぼしを減らす方向にプロンプトを誘導するための指標。
    """
    scores = []
    for pred, gold in zip(preds, golds):
        gold_words = _content_words(str(gold))
        if not gold_words:
            scores.append(0.0)
            continue
        scores.append(len(gold_words & _content_words(str(pred))) / len(gold_words))
    return {"score": sum(scores) / len(scores) if scores else 0.0, "scores": scores}


def lambda_handler(event, context):
    try:
        preds = event.get("preds", [])
        golds = event.get("golds", [])
        if not preds:
            return {"score": 0.0, "scores": []}
        if len(golds) != len(preds):
            # この評価器は全サンプルに referenceResponse がある前提
            return {"score": 0.0, "scores": [0.0] * len(preds),
                    "error": "golds count %d does not match preds count %d" % (len(golds), len(preds))}
        return compute_score(preds, golds)
    except Exception as e:
        logger.error("scoring failed: %s", e, exc_info=True)
        return {"score": 0.0, "scores": [0.0] * len(event.get("preds", [])), "error": str(e)}


# 動作確認に使った 3 本の応答(gold は上の JSONL の referenceResponse と同じ文)
#   0.73: "Sato will ship the billing fix by Friday. Tanaka owns the migration script."
#   0.45: "Sato will ship the billing fix by Friday."
#   0.00: "No decisions were recorded."

公式ドキュメントは「明らかに悪い出力を採点して、指標が減点するか確かめる」ことを勧めています。上のコードをPythonで実行すると、コメントの3本の応答に0.73・0.45・0.00と段階が付き、goldsが欠けた呼び出しには予測件数分の0点と診断メッセージを返します。ただし英数字の単語集合を比べるだけの例なので、担当者の取り違え(SatoとTanakaを入れ替えた応答も正しい応答と同じ0.73)や日本語の内容語は判別できません。業務では、決定事項と担当者の組を突き合わせるような指標に置き換えてください。

プロンプト短縮(shortenPrompt)の効き方と限界

既定のAdvPOは品質だけを見て書き換えるため、最適化後のプロンプトが元より長くなることがあります。クラスメソッドの東京リージョンでの検証記事でも入力トークンが増えたと報告されています。入力トークン代とTTFTを抑えるために、2026年10月20日に追加されたのがプロンプト短縮です。

有効にするには、入力JSONLのテンプレートの行に "optimizationConfig": {"shortenPrompt": true} を足します(上のJSONL例に入れてあります)。ジョブ作成APIにもコンソールにも切り替えはなく、テンプレート単位でファイル側に書く方式です。短縮は反復のたびに少しずつ進み、返ってくるのは「元より短く、かつ評価スコアが元以上」の両方を満たしたプロンプトだけです。どちらかを満たさなければ元のプロンプトがそのまま返り、compressionRatio(最適化後トークン数÷元のトークン数)は1.0になります。

効かない条件もあります。元のプロンプトが評価サンプルで満点を取っている場合や候補同士でスコアの差が出ない場合は、短い候補を選ぶ根拠がなく1.0で返ります。評価に影響しない重複文も、それだけでは削られません。目標トークン数は指定できず、advpo:optimizeで囲んだ範囲はすべて短縮の対象です。一字も変えたくない安全上の制約や法務文言はoptimizeタグの外に置いてください。縮むのはテンプレートで、モデルの応答ではありません。

ジョブ作成と結果ファイルの読み取り

ジョブはbedrockクライアントから作成します。評価方法も短縮も入力JSONL側で決まるため、リクエストに入るのはジョブ名・モデル・入出力先だけです。S3バケットはジョブと同じリージョンに置きます。下の例は、Claude Sonnet 4.5で動いているプロンプトを4.6へ移す場合の比較です。

import boto3

client = boto3.client("bedrock", region_name="us-west-2")

response = client.create_advanced_prompt_optimization_job(
    jobName="minutes-summarizer-migration",
    modelConfigurations=[
        {"modelId": "us.anthropic.claude-sonnet-4-5-20250929-v1:0"},  # 現行(ベースライン)
        {"modelId": "us.anthropic.claude-sonnet-4-6"},                # 移行候補
    ],
    inputConfig={"s3Uri": "s3://my-advpo-bucket/input/templates.jsonl"},
    outputConfig={"s3Uri": "s3://my-advpo-bucket/output/"},
)
job_arn = response["jobArn"]

status = client.get_advanced_prompt_optimization_job(jobIdentifier=job_arn)
print(status["jobStatus"], status.get("failureMessage"))

modelConfigurationsは1〜5件で、modelIdには基盤モデルID・クロスリージョン推論プロファイルID・アプリケーション推論プロファイルARNを書けます。推論プロファイルの接頭辞(us.・jp.・global.など)はリージョンで変わるので、モデルの詳細ページで確認してください。

jobStatusはInProgress、Completed、Failed、PartiallyCompleted、Stopping、Stopped、Deletingの7値です。PartiallyCompletedは、たとえば5モデルのうち一部でモデルアクセスが有効になっていない場合に出ます。Completed以外を一律で失敗扱いにすると、使える結果まで捨てます。モデル単位の成否は、結果ファイルの各要素のstatus(SUCCESSかFAILED)で見分けます。

結果は出力先の下に、ジョブARNの末尾をジョブIDとしたディレクトリが切られ、advanced_prompt_optimization_results.jsonlとして書き出されます。1行がテンプレート1本で、モデルごとに最適化後テンプレート、サンプル別スコア、TTFTとレイテンシの平均値が入ります。中央値のTTFTと平均・中央値のレイテンシは、2026年8月4日以降に作成したジョブにだけ付きます。

import json
import sys

# advanced_prompt_optimization_results.jsonl をダウンロードしたものを渡す
for line in open(sys.argv[1], encoding="utf-8"):
    result = json.loads(line)
    print("template:", result["promptTemplateId"])
    for opt in result.get("promptOptimizationResults", []):
        if opt["status"] != "SUCCESS":
            print("  ", opt["modelId"], "FAILED")
            continue
        before = opt["originalPromptMetrics"]
        after = opt["optimizedPromptMetrics"]
        print("  ", opt["modelId"],
              "score", before["averageScore"], "->", after["averageScore"],
              "| TTFT", before.get("averageTtftInSec"), "->", after.get("averageTtftInSec"),
              "| compression", opt.get("compressionRatio", "-"))

公式の結果例(スコア2.1→2.6、compressionRatio 0.72)を1行にして読ませると「score 2.1 -> 2.6 … compression 0.72」と表示され、FAILEDのモデルは飛ばします。compressionRatioは短縮を有効にしたテンプレートにだけ入るため、getで読んでいます。

コストは結果ファイルに入りません。結果ページは「コストは入力した単価からコンソールで計算され、出力ファイルには含まれない」としており、比べたいときは結果画面のConfigure pricingでモデルごとの入出力単価を入力します。また結果ファイルを別の場所へ移すとコンソールの結果画面が描画されなくなるため、ライフサイクルルールで自動移動する構成は避けてください。

書き換え範囲を絞る選択的最適化

既定では、最適化器はテンプレート全体を書き換えます。役割定義や禁止事項のように動かしたくない部分があるなら、advpo名前空間のタグで範囲を指定します。挙動はタグの組み合わせで4通りです。

タグの状態 書き換え対象
タグなし テンプレート全体
optimizeが1つ以上ある optimize内だけ(タグ外は保全)
excludeだけがある exclude内を除く全体
両方ある optimize内だけ(excludeは冗長)

守りたい箇所をexcludeで囲む必要は基本的になく、改善したい箇所をoptimizeで囲めば残りは保全されます。次は公式ドキュメントの例です。

You are a helpful customer service agent for Acme Corp. Always be polite and professional.

<advpo:optimize>When responding to a complaint, acknowledge the customer's frustration, summarize the issue, and propose exactly one concrete resolution. Use bullet points for clarity.</advpo:optimize>

Never disclose internal pricing or employee information.

空のoptimizeブロックを置くと、その位置に最適化器が新しい指示文を生成して挿入します。タグの入れ子、閉じ忘れ、optmizeのような綴り間違いはValidationExceptionです。タグの解析は変数置換の前に行われるため、ユーザー入力にタグ文字列が混ざっても最適化指示とは解釈されません。最終出力ではタグが取り除かれます。

プロンプト最適化の料金と費用試算

シンプル最適化の従量課金

シンプル最適化は、入力プロンプトと最適化後プロンプトの合計トークンに対して1,000トークンあたり0.03ドルです。料金ページの試算例では、429トークンのプロンプトを511トークンに最適化し、そこからClaude 3.7とNova Pro向けに582トークンと579トークンのバリアントを作ると、合計3,123トークンで0.09ドルになります。バリアントを作るたびに元の511トークンも入力として数え直される点が見落としやすいところです。

Advanced Prompt Optimizationの見積り式と金額

AdvPOに機能料金はなく、推論はすべて利用者のアカウント内でオンデマンド料金で課金されます。Lambda評価器の実行費も自己負担です。ループの回数は公表されていませんが、料金ページに1テンプレートあたりの見積り式があります。評価サンプル数をN、テンプレートの入力トークン数をP、ターゲットモデルの出力トークン数の見込みをO、正解応答のトークン数をGとします。

項目 見積り式
ターゲットモデルの総トークン数 16 x N x (P + O)
最適化器(Claude Sonnet 4.6)の入力トークン数 101 x (3700 + 0.35 x P)
採点側の総トークン数 16 x N x (P + O + G + 採点プロンプト)
Lambda呼び出し回数 16 x N

3行目は、料金ページの原文ではLLM-as-a-judgeとステアリング基準の両方に適用される式です。ステアリング基準は1行渡すだけでも、採点のためのモデル呼び出しは同じだけ発生します。

この式に、Price List(AmazonBedrockFoundationModels)にあるClaude Sonnet 4.6のGlobal単価(100万トークンあたり入力3ドル・出力15ドル)を当てはめたのが次の表です。前提はP=800、O=400、G=200、採点プロンプト1,000トークン(既定の採点プロンプトは英語493語で、約1,000トークンと仮定)、ターゲットと採点もSonnet 4.6です。ターゲットの総トークンは入力16NP・出力16NOに分け、採点トークンは入力単価で計算しました。

評価サンプル数N 最適化器 ターゲット 採点 合計 最適化器の比率
10 1.21ドル 1.34ドル 1.15ドル 約3.7ドル 33%
50 1.21ドル 6.72ドル 5.76ドル 約13.7ドル 9%
100 1.21ドル 13.44ドル 11.52ドル 約26.2ドル 5%

読み取れることは2つあります。1つ目は、最適化器の入力(この前提で約40万トークン)がNに依存しない固定分だという点です。少ない件数で試すほど、費用の3割前後が最適化器のSonnet 4.6に消えます。クラスメソッドの検証で「Sonnet 4.6の料金がかなり発生した」と書かれているのと符合します。2つ目は、Nを増やすとターゲットと採点が比例して増えることです。最初は10件程度で回し、スコアの伸びを見てから件数を足すのが安全です。

この試算には、式に含まれない出力トークン(最適化器が書く候補プロンプト、採点モデルの講評)が入っていないため、実費は上振れします。jp.のような地域内クロスリージョン推論は単価が入力3.3ドル・出力16.5ドルで、合計も1割増えます。式は1テンプレートあたりで、モデルを複数選んだときの増え方は書かれていません。5モデルで比べるなら、ターゲット分がモデル数に応じて増える前提で見積もってください。

最適化したプロンプトを本番で使う手順

AdvPOの結果はS3のJSONLとコンソールの結果画面で受け取ります。本番のアプリケーションへ載せる方法は、コードに直接書くか、Prompt managementにバージョンとして保存して呼ぶかの2つです。プロンプトを差し替えるたびにデプロイしたくないなら、Prompt managementを使います。

Prompt managementへの保存とバージョン作成

Prompt managementでは、保存するたびに下書き(draft)が更新され、本番に出すときはバージョンを作ります。バージョンはその時点のスナップショットで、アプリケーション側はバージョン番号付きのARNを指定して呼びます。最適化後のテンプレートを下書きに貼り、最適化に使っていない評価データで元のテンプレートと品質を比べて、悪化がなければバージョンを作ります。プレースホルダは二重の中かっこで、AdvPOのテンプレートと同じ書式です。

Converse APIでのプロンプトARN指定

呼び出しは、Converse(またはConverseStream)のmodelIdにプロンプトのARNを入れ、promptVariablesで変数の値を渡します。messagesやsystemはプロンプト側に定義済みなので不要です。

import boto3

runtime = boto3.client("bedrock-runtime", region_name="ap-northeast-1")

response = runtime.converse(
    modelId="arn:aws:bedrock:ap-northeast-1:123456789012:prompt/PROMPT12345:2",  # 末尾:2 がバージョン
    promptVariables={
        "minutes": {"text": "佐藤:請求の修正を金曜までに出す。田中:移行スクリプトを担当。"},
    },
)
print(response["output"]["message"]["content"][0]["text"])

この形には制約があります。additionalModelRequestFields・inferenceConfig・system・toolConfigはリクエストに含められず、温度や最大トークン数はプロンプト側の設定で決まります。messagesを渡すと、プロンプトに定義したメッセージの後ろに追加されます。InvokeModel系で呼べるのは、プロンプトの設定がAnthropic ClaudeかMeta Llamaのモデルの場合だけです。Converse APIの基本はAmazon Bedrock Converse APIの使い方|boto3実装・ConverseStream・Tool Use・IAM権限【2026年10月】、フローのノードとして組み込む方法はAmazon Bedrock Flowsとは|ノード14種・料金・上限とboto3実装【2026年11月】で扱っています。

Bedrock以外のプロンプト最適化手段との使い分け

評価データと指標で指示文を自動で書き換える考え方は、OSSのDSPyが先行しています。DSPyはPythonでプログラムと評価関数を書き、MIPROv2やGEPAといったオプティマイザが指示文や例示を探索するライブラリで、接続先のモデルも最適化のループも自分で持ちます(DSPyとは?チュートリアルで学ぶシグネチャ・モジュール・最適化の使い方【2026年版】)。

AdvPOを選ぶのは、ターゲットがBedrockのモデルで、ループの実行基盤を持たずにJSONLだけで回したいときです。複数段の処理を通しで最適化したい、Bedrockにないモデルを最適化したい、探索の手順を制御したいなら、DSPyのほうが向いています。

Bedrock外のモデルからの移行を比べる手順は公式ドキュメントにあります。移行前のモデルで評価サンプルを別に推論してLambda評価器で採点し、同じLambda評価器でAdvPOのジョブを流せば、旧モデルと新モデルの最適化前後を同じ物差しで並べられます。

社内の業務にBedrockの生成AIを組み込む段階で、評価データの作り方や移行判断から相談したい場合は、生成AI導入支援でも対応しています。

日本語プロンプトの扱い

公式ドキュメントはシンプル最適化について「最良の結果を得るには英語でプロンプトを最適化することを推奨します」と書いています。推奨にとどまり、日本語のプロンプトについての動作条件や品質は書かれていません。

実務では、テンプレートの指示部分(役割・出力形式・制約)を英語で書き、日本語はユーザー入力の変数値に留める形が扱いやすく、プレースホルダで変数を切り出すAdvPOの構造とも合います。LLM-as-a-judgeで採点するなら、応答・採点プロンプト・正解データの言語も揃えます。言語を混在させた場合の影響は公式に記載がないため、採用前に人手の評価と採点結果が一致するかを確かめておくと安全です。

公式ドキュメントとAPI仕様の食い違いと入力ミスの防ぎ方

AdvPOのドキュメントのコード例と実際のAPIモデルには、ずれが残っています。2026年10月30日公開のbotocore 1.43.123に同梱されたbedrockのサービスモデルで再確認したところ、8月に見つけた3点はいずれも直っていませんでした。

ドキュメントの記述 実際のAPI・別ページの記述 起きること
encryptionConfig パラメータ encryptionKeyArn(KMSキーARN) ParamValidationError
batch_delete_advanced_prompt_optimization_jobs 末尾 job の単数形 AttributeError
上位ページは正解応答を必須と記述 スキーマ表では任意(推奨) 不要な正解データ作成

1点目はencryptionConfigを渡すと送信前に「Unknown parameter」で止まり、2点目は複数形のメソッドがクライアントに存在しません。AWS CLIのコマンド名も正しくは batch-delete-advanced-prompt-optimization-job です。IAMの前提条件ページは該当アクションの表記にタブや空白が混入しており、正しくはbedrock:BatchDeleteAdvancedPromptOptimizationJobです。3点目は、上位ページの「It also requires ground truth answers」と、入力スキーマ表の「referenceResponse … Required = No」の食い違いで、実際は推奨です。

AdvPOのAPIが入ったのはbotocore 1.43.8(2026年5月14日)からで、1つ前の1.43.7にはオペレーションがありません。create_advanced_prompt_optimization_jobが見つからないと言われたら、コードを疑う前にpip listでバージョンを確認してください。

もう1つの事故源は入力JSONLの無言の失敗です。ドキュメントが「silent failure」と明記しているのは、1つのinputVariablesオブジェクトに複数キーを入れた場合で、エラーにならず意図しない結果が返ります。一重の中かっこ、評価方法の併用、customEvaluationMetricLabelの欠落、リスト外の採点モデルはValidationExceptionです。次のスクリプトで、これらをアップロード前に機械的に検出できます。

import json
import re
import sys

EVAL_KEYS = ("steeringCriteria", "customLLMJConfig", "evaluationMetricLambdaArn")
JUDGE_MODELS = {
    "anthropic.claude-opus-4-6-v1", "anthropic.claude-opus-4-7", "anthropic.claude-opus-4-8",
    "anthropic.claude-opus-5", "anthropic.claude-opus-5-5",
    "anthropic.claude-sonnet-4-5-20250929-v1:0", "anthropic.claude-sonnet-4-6",
    "anthropic.claude-sonnet-5", "anthropic.claude-sonnet-5-5",
}


def check(obj):
    errors = []
    for key in ("version", "templateId", "promptTemplate", "evaluationSamples"):
        if key not in obj:
            errors.append("必須フィールド " + key + " が無い")
    if obj.get("version") != "bedrock-2026-05-14":
        errors.append("version が固定値と違う: " + repr(obj.get("version")))
    if re.search(r"(?<!\{)\{[A-Za-z_]\w*\}(?!\})", obj.get("promptTemplate", "")):
        errors.append("プレースホルダが一重の中かっこになっている")
    placeholders = set(re.findall(r"\{\{(\w+)\}\}", obj.get("promptTemplate", "")))
    samples = obj.get("evaluationSamples", [])
    if not 1 <= len(samples) <= 100:
        errors.append("evaluationSamples は1〜100件: " + str(len(samples)) + "件")
    for no, sample in enumerate(samples, 1):
        keys = set()
        for pair in sample.get("inputVariables", []):
            if len(pair) != 1:
                errors.append(str(no) + "件目: inputVariables の 1 オブジェクトに複数キー: " + str(sorted(pair)))
            keys |= set(pair)
        if placeholders != keys:
            errors.append(str(no) + "件目: プレースホルダと inputVariables が不一致")
    used = [k for k in EVAL_KEYS if k in obj]
    if len(used) > 1:
        errors.append("評価方法を併用している: " + str(used))
    if used and used != ["steeringCriteria"] and "customEvaluationMetricLabel" not in obj:
        errors.append("customEvaluationMetricLabel が無い")
    judge = obj.get("customLLMJConfig", {}).get("customLLMJModelId")
    if judge and not judge.startswith("arn:") and judge.split(".", 1)[-1] not in JUDGE_MODELS and judge not in JUDGE_MODELS:
        errors.append("採点モデルが対応リストに無い: " + judge)
    shorten = obj.get("optimizationConfig", {}).get("shortenPrompt", False)
    if not isinstance(shorten, bool):
        errors.append("shortenPrompt は true か false で書く: " + repr(shorten))
    return errors


ng = 0
for line_no, line in enumerate(open(sys.argv[1], encoding="utf-8"), 1):
    if not line.strip():
        continue
    try:
        obj = json.loads(line)
    except json.JSONDecodeError as e:
        print(line_no, "行目: JSONとして壊れている", e)
        ng += 1
        continue
    for message in check(obj):
        print(line_no, "行目:", message)
        ng += 1

print("簡易検査の指摘は0件(型・上限・ARNの実在・権限は未検査)。" if ng == 0 else "NG " + str(ng) + "件。修正してください。")
sys.exit(1 if ng else 0)

一重の中かっこ、inputVariablesの複数キー、ステアリング基準とLLM判定の併用、ラベル欠落、リスト外の採点モデル(Claude 3 Haiku)、文字列「yes」を入れたshortenPromptの6か所を仕込んだ1行を読ませると、指摘は7件出て終了コード1で止まります。一重の中かっこは、それ自体の指摘に加えてプレースホルダとinputVariablesの不一致も引き起こすためです。この記事のJSONL例とLLM判定の正常な1行は指摘0件で通り、2件目だけinputVariablesが空の行や評価サンプル0件の行も検出します。型・上限・Lambda ARNの実在・IAM権限までは見ないので、通過してもジョブが必ず動くわけではありません。

ジョブが動き出してから落ちる原因で、トラブルシューティング表の先頭にあるのはモデルアクセスです。「No inference API is accessible for model」が出たら、モデルアクセスとIAMのbedrock:InvokeModelWithResponseStreamの両方を確認します。AdvPOは現在ConverseStream経由で推論するため、bedrock:InvokeModelだけでは足りません。

よくある質問

Amazon Bedrockのプロンプト最適化は無料ですか?

無料ではありません。シンプル最適化は入力と最適化後の合計トークンに1,000トークンあたり0.03ドルがかかります。Advanced Prompt Optimizationは機能料金がない代わりに、最適化中の推論トークンとLambda実行費がオンデマンド料金でかかり、本文の条件でClaude Sonnet 4.6を当てた試算は評価10件で約3.7ドルで、最適化器と採点モデルの出力トークン代は別にかかります。

東京リージョンでプロンプト最適化は使えますか?

Advanced Prompt Optimizationはap-northeast-1(東京)に対応しています。シンプル最適化は対応表に東京が含まれないため、us-east-1やus-west-2など対応リージョンで実行します。

プロンプト管理(Prompt management)とプロンプト最適化はどう違いますか?

Prompt managementはプロンプトの作成・バージョン管理・本番からの呼び出しを担う機能で、シンプル最適化はその画面から呼べる書き換え機能です。最適化したプロンプトをPrompt managementのバージョンにしておけば、ConverseのmodelIdにプロンプトARNを指定して呼べます。Prompt managementは東京を含む22リージョンで使えるため、保管場所と最適化を実行できる場所が一致しないことがあります。

最適化するとプロンプトは長くなりますか?

Advanced Prompt Optimizationは既定では品質だけを見るため、長くなることがあります。入力トークン代を抑えたい場合は、入力JSONLでshortenPromptをtrueにすると、元より短く評価スコアも元以上のプロンプトだけが返り、満たせなければ元のプロンプトが返ります。

プロンプトキャッシュと組み合わせられますか?

別々の機能なので併用できます。最適化はプロンプトの中身を書き換えて品質を上げるもの、キャッシュは同じ接頭辞を繰り返し送るときの入力料金とレイテンシを下げるものです。最適化で確定したプロンプトの共通部分をキャッシュ対象にする順で使います。対応モデルと実装はAmazon Bedrockのプロンプトキャッシュ|対応モデル・料金・cachePointの書き方【2026年10月】にまとめています。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.11.09 テックブログ エディオン不正アクセス第2報:カード番号の対象確認とログ・決済画面の改ざん対策
  2. 2026.11.09 テックブログ LANSCOPE不正アクセス第2報:製品への影響と偽連絡の確認、停止中のライセンス認証の窓口
  3. 2026.11.09 テックブログ ステップゴルフ不正アクセス:口座情報の対象確認と偽連絡・引き落としの注意点
  4. 2026.11.10 テックブログ Claude Fable 5.2とは:料金・破壊的変更4点とFable 5.1からの移行手順【2026年11月】
  5. 2026.11.10 テックブログ ニトリの情報漏洩:最大3,762万件の対象確認となりすまし連絡の見分け方

RELATED POSTS 関連記事

目次