はじめに
生成AIアプリケーションを開発していると、こんな課題にぶつかりませんか?
- プロンプトがコードにハードコードされていて、修正のたびにデプロイが必要
- チームメンバーごとに違うプロンプトを使っていて、品質がバラバラ
- 「前のバージョンのプロンプトのほうが良かった」と言われても戻せない
- モデルやパラメータを変えて比較したいが、検証環境を毎回用意するのが面倒
これらの課題を解決するのがAmazon Bedrock Prompt Managementです。
本記事では、カスタマーサポートBotのプロンプトを管理するという実務シナリオをベースに、Prompt Managementの主要機能をハンズオン形式で解説します。
Prompt Managementとは
Amazon Bedrock Prompt Managementは、プロンプトの作成・テスト・バージョン管理・デプロイを一元的に行うための機能です。
イメージとしてはSSM Parameter Store + モデル設定 + 実行がセットになったものです。SSM Parameter Storeはパラメータの値を管理しますが、Prompt Managementはプロンプト・モデル・推論パラメータをまとめて管理し、ARN一つで実行まで完了します。
# 従来: プロンプトをコードに埋め込み → 修正のたびにデプロイ
response = bedrock.converse(
modelId="jp.anthropic.claude-sonnet-4-5-20250929-v1:0",
system=[{"text": "あなたはカスタマーサポート担当です..."}],
messages=[{"role": "user", "content": [{"text": prompt_text}]}],
inferenceConfig={"temperature": 0.3, "maxTokens": 1024},
)
# Prompt Management: ARNを指定するだけ → プロンプト改善時にデプロイ不要
response = bedrock.converse(
modelId=prompt_version_arn,
promptVariables={"customer_name": {"text": "田中太郎"}, "issue": {"text": "..."}},
)
主要コンセプト
| 概念 | 説明 |
|---|---|
| Prompt | モデルへの入力テンプレート。変数を含めて再利用可能にできる |
| Variable |
{{variable_name}}の形式で定義するプレースホルダー。実行時に値を差し込める |
| Variant | 同一プロンプトの異なる構成(モデル・パラメータ・プロンプト文面の組み合わせ) |
| Draft | 編集中の作業バージョン。何度でも上書き保存できる |
| Version | 特定時点のスナップショット。本番デプロイ用の不変なバージョン |
全体ワークフロー
Step 1 Step 2 Step 3 Step 4
プロンプト作成 → Variant追加&比較 → Version作成&API呼び出し → プロンプト改善&Version更新
↑ |
└────────────────────────┘
改善サイクル
実務シナリオ:カスタマーサポートBot
今回は以下のシナリオで進めます。
ECサイトのカスタマーサポートBotを構築する。
顧客の名前と問い合わせ内容を受け取り、丁寧かつ的確に回答するプロンプトを、チームで管理・運用したい。
ハンズオン
前提条件
- AWSアカウントとクレデンシャル設定済み
- Bedrockモデルアクセスが有効(Claude Sonnet 4.5など)
- Python 3.10以上
- boto3インストール済み
pip install boto3
Bedrockの一部モデルはon-demandのモデルIDでの呼び出しがサポートされていません。その場合は推論プロファイルID(例: jp.anthropic.claude-sonnet-4-5-20250929-v1:0)を使用してください。利用可能な推論プロファイルはaws bedrock list-inference-profilesで確認できます。
Step 1: プロンプトを作成する
まず、カスタマーサポートBot用のプロンプトをAPIで作成します。
import boto3
# Bedrock Agentクライアントを作成
client = boto3.client("bedrock-agent", region_name="ap-northeast-1")
# カスタマーサポート用プロンプトを作成
response = client.create_prompt(
name="CustomerSupportBot",
description="ECサイトのカスタマーサポート用プロンプト",
variants=[
{
"name": "Claude_Sonnet",
"modelId": "jp.anthropic.claude-sonnet-4-5-20250929-v1:0",
"templateType": "CHAT",
"inferenceConfiguration": {
"text": {
"temperature": 0.3,
"maxTokens": 1024,
}
},
"templateConfiguration": {
"chat": {
"system": [
{
"text": "あなたはECサイトのカスタマーサポート担当です。以下のルールに従って回答してください。\n1. 顧客の名前を使って丁寧に対応する\n2. 問題の解決策を具体的に提示する\n3. 解決できない場合はエスカレーション先を案内する\n4. 回答は簡潔に、3文以内にまとめる"
}
],
"messages": [
{
"role": "user",
"content": [
{
"text": "顧客名: {{customer_name}}\n問い合わせ内容: {{issue}}"
}
]
}
]
}
},
}
],
)
prompt_id = response["id"]
prompt_arn = response["arn"]
print(f"プロンプトID: {prompt_id}")
print(f"プロンプトARN: {prompt_arn}")
ポイントは以下の通りです。
-
templateTypeをCHATにすることで、システムプロンプトとユーザーメッセージを分離できる -
{{customer_name}}と{{issue}}を変数として定義し、実行時に値を差し込める -
temperature: 0.3で安定した回答を生成するよう設定
Step 2: Variantを追加してモデルを比較する
同じプロンプトに対して、異なるモデルやパラメータの構成(Variant)を追加して比較できます。update_promptで既存のプロンプトにVariantを追加します。
# 既存のプロンプト情報を取得
prompt_info = client.get_prompt(promptIdentifier=prompt_id)
# 現在のVariantリストを取得
variants = prompt_info["variants"]
# 新しいVariantを追加(Haikuモデル + 高めのtemperature)
variants.append(
{
"name": "Claude_Haiku",
"modelId": "apac.anthropic.claude-3-haiku-20240307-v1:0",
"templateType": "CHAT",
"inferenceConfiguration": {
"text": {
"temperature": 0.7,
"maxTokens": 1024,
}
},
"templateConfiguration": {
"chat": {
"system": [
{
"text": "あなたはECサイトのカスタマーサポート担当です。以下のルールに従って回答してください。\n1. 顧客の名前を使って丁寧に対応する\n2. 問題の解決策を具体的に提示する\n3. 解決できない場合はエスカレーション先を案内する\n4. 回答は簡潔に、3文以内にまとめる"
}
],
"messages": [
{
"role": "user",
"content": [
{
"text": "顧客名: {{customer_name}}\n問い合わせ内容: {{issue}}"
}
]
}
]
}
},
}
)
# プロンプトを更新
client.update_prompt(
promptIdentifier=prompt_id,
name="CustomerSupportBot",
description="ECサイトのカスタマーサポート用プロンプト",
variants=variants,
)
print("Variant追加完了")
同じ入力(customer_name = 田中太郎、issue = 3日前に注文した商品がまだ届きません。注文番号はORD-12345です。)で比較した結果は以下の通りです。
Claude Sonnet 4.5(temperature 0.3)の回答:
田中太郎様、お問い合わせいただきありがとうございます。
注文番号ORD-12345の配送状況を確認いたしましたところ、現在配送センターから発送済みで、
明日中にはお届けできる予定となっております。万が一明日中に届かない場合は、配送業者への
調査を開始いたしますので、再度ご連絡いただけますでしょうか。
Claude 3 Haiku(temperature 0.7)の回答:
田中様
大変申し訳ございません。ご注文のORD-12345は通常3-5営業日での配送となっておりますが、
配送が遅延しているようです。早急に配送状況を確認し、できるだけ早くお届けできるよう
手配させていただきます。
| 比較観点 | Claude Sonnet 4.5 (temperature 0.3) | Claude 3 Haiku (temperature 0.7) |
|---|---|---|
| 回答の正確さ | 高い(具体的な配送状況を提示) | やや汎用的な回答 |
| レスポンス速度 | 約3.8秒 | 約2.3秒 |
| コスト | 高め | 低め |
| 適したユースケース | 正確性重視の問い合わせ対応 | FAQ的な定型回答 |
Variantを比較し、ユースケースに最も適した構成を選んでDraftに保存します。
Step 3: Version作成&Converse APIで呼び出し
最適なVariantが決まったら、Versionを作成して本番アプリケーションから呼び出します。
Draftはあくまで作業用なので、Converse APIで呼び出すにはVersionの作成が必要です。
# Versionを作成(現在のDraftのスナップショット)
version_response = client.create_prompt_version(
promptIdentifier=prompt_id,
description="v1: 初回リリース - Sonnet 4.5 + temperature 0.3"
)
version_arn = version_response["arn"]
print(f"Version ARN: {version_arn}")
# 出力例: Version ARN: arn:aws:bedrock:ap-northeast-1:123456789012:prompt/XXXXXXXXXX:1
# Bedrock Runtimeクライアントを作成
runtime_client = boto3.client("bedrock-runtime", region_name="ap-northeast-1")
# プロンプトをConverse APIで呼び出し
response = runtime_client.converse(
modelId=version_arn, # VersionのARNを指定
promptVariables={
"customer_name": {"text": "田中太郎"},
"issue": {"text": "3日前に注文した商品がまだ届きません。注文番号はORD-12345です。"},
},
)
# 回答を表示
print(response["output"]["message"]["content"][0]["text"])
# 出力例
田中太郎様、お問い合わせいただきありがとうございます。
注文番号ORD-12345の配送状況を確認いたしましたところ、現在配送センターから発送済みで、
明日中にはお届けできる予定となっております。万が一明日中に届かない場合は、配送業者の
追跡番号をお送りいたしますので、再度ご連絡ください。
本番アプリケーションでは、このVersion ARNを環境変数等に設定し、modelIdに指定するだけです。プロンプトの内容はアプリケーションコードに一切含まれません。
Converse APIでPrompt ManagementのプロンプトARNを使用する場合、additionalModelRequestFields、inferenceConfig、system、toolConfigフィールドはリクエストに含めることができません。これらの設定はプロンプト側で定義されたものが使用されます。また、modelIdにはDraftのARNではなくVersionのARNを指定する必要があります。
Step 4: プロンプトを改善してVersion 2をリリースする
運用開始後、「もっと共感的な対応にしてほしい」というフィードバックがあったとします。
# Draftを更新(システムプロンプトを改善)
prompt_info = client.get_prompt(promptIdentifier=prompt_id)
variants = prompt_info["variants"]
# Sonnet Variantのシステムプロンプトを更新
for variant in variants:
if variant["name"] == "Claude_Sonnet":
variant["templateConfiguration"]["chat"]["system"] = [
{
"text": "あなたはECサイトのカスタマーサポート担当です。以下のルールに従って回答してください。\n1. まず顧客の状況に共感を示す\n2. 顧客の名前を使って丁寧に対応する\n3. 問題の解決策を具体的に提示する\n4. 解決できない場合はエスカレーション先を案内する\n5. 回答は簡潔に、3文以内にまとめる"
}
]
client.update_prompt(
promptIdentifier=prompt_id,
name="CustomerSupportBot",
description="ECサイトのカスタマーサポート用プロンプト",
variants=variants,
)
# テスト後、新しいVersionを作成
response = client.create_prompt_version(
promptIdentifier=prompt_id,
description="v2: 共感表現を追加"
)
new_version_arn = response["arn"]
print(f"Version 2 ARN: {new_version_arn}")
# アプリケーションのPROMPT_VERSION_ARNを更新するだけで切り替え完了
この運用フローにより、アプリケーションコードを変更せずにプロンプトの改善・デプロイが可能になります。
問題が発生した場合は、アプリケーションが参照するARNをVersion 1に戻すだけでロールバックできます。
実務で活きるポイントまとめ
DraftとVersionの使い分け
| Draft(開発用) | Version(本番用) | |
|---|---|---|
| 役割 | 自由に編集・テスト可能 | 不変のスナップショット |
| 用途 | チーム内でプロンプトを検討 | 本番アプリから参照 |
| 流れ | 最適な構成が決まったら → | 新Version作成でリリース |
Prompt Managementを導入するメリット
| 課題 | 従来の方法 | Prompt Management |
|---|---|---|
| プロンプト修正 | コード変更 + デプロイ | プロンプト更新 + Version作成のみ |
| バージョン管理 | Git管理 or ドキュメント | 自動的にVersion管理される |
| A/Bテスト | 独自実装が必要 | Variantで即座に比較可能 |
| チーム共有 | ファイル共有 or Wiki | コンソールで一元管理 |
| ロールバック | Gitリバート + デプロイ | 旧VersionのARNに切り替え |
まとめ
Amazon Bedrock Prompt Managementを使うことで、プロンプトをコードから分離し、作成→比較→デプロイ→改善のライフサイクルを一元管理できます。
特に実務では以下の点が効果的です。
- Variableにより、1つのプロンプトを複数のユースケースで再利用
- Variantにより、モデルやパラメータの違いを素早く比較
- Versionにより、本番環境の安定性を保ちながらプロンプトを継続改善
プロンプトがアプリケーションの中核を担う生成AIシステムにおいて、Prompt Managementは「プロンプトのCI/CD」とも言える存在です。ぜひ実務のプロンプト運用に取り入れてみてください。