はじめに
Amazon Bedrockは、AWSが提供する生成AIサービスであり、複数の基盤モデル(FM)をマネージドサービスとして利用できる点が大きな特徴です。しかし、「とりあえずLLMを呼ぶ」「Agentを作ってみる」といった使い方だけでは、その真価を十分に引き出せないばかりか、予期せぬ問題に直面する可能性もあります。本記事では、Amazon Bedrockを安全かつ効果的に活用するための考え方、主要機能、そして具体的なベストプラクティスについて、実務目線で解説します。
Amazon Bedrockとは?その本質的な価値
Amazon Bedrockは単なるAIモデルの呼び出しサービスではありません。その本質は、既存のシステムや業務にAIを安全に、そして継続的に組み込むための強固な土台を提供することにあります。モデルの選定や運用をAWSに任せつつ、IAMやVPCと統合された形でLLMを扱えるため、セキュリティと運用効率を両立させながら生成AIアプリケーションを構築できます。
Amazon Bedrockの主要機能と活用シナリオ
boto3による基盤モデルの呼び出し (InvokeModel)
Amazon Bedrockの最も基本的な機能は、boto3 SDKを使用して基盤モデルを直接呼び出すことです。これにより、テキスト生成、要約、翻訳など、様々なタスクを実行できます。以下は、Anthropic Claude 3 Sonnetモデルを呼び出すPythonコードの例です。
import boto3
import json
# Bedrockクライアントの初期化
bedrock_runtime = boto3.client(
service_name='bedrock-runtime',
region_name='us-east-1' # 利用可能なリージョンを指定
)
model_id = 'anthropic.claude-3-sonnet-20240229-v1:0'
# プロンプトの準備
body = json.dumps({
"messages": [
{
"role": "user",
"content": "Amazon Bedrockとは何ですか?簡潔に説明してください。"
}
],
"max_tokens": 300,
"temperature": 0.7,
"top_p": 0.9
})
# モデルの呼び出し
response = bedrock_runtime.invoke_model(
body=body,
modelId=model_id,
accept='application/json',
contentType='application/json'
)
# レスポンスの解析
response_body = json.loads(response.get('body').read())
print(response_body['content'][0]['text'])
このコードは、指定されたプロンプトを基にClaude 3 Sonnetモデルから応答を取得します。max_tokens、temperature、top_pなどのパラメータを調整することで、生成されるテキストの長さ、創造性、多様性を制御できます。
Amazon Bedrockは、多様な生成AIアプリケーションを構築するための豊富な機能を提供します。
1. Knowledge Bases (RAG構築)
社内のPDFやドキュメント、データベースなどの独自のデータソースを基に、LLMがより正確で関連性の高い回答を生成するための機能です。Retrieval-Augmented Generation (RAG)の構築を容易にし、幻覚(Hallucination)のリスクを低減します [1]。
retrieve_and_generateによるRAGの実装例
boto3のbedrock-agent-runtimeクライアントを使用すると、Knowledge Basesに対してクエリを実行し、関連情報を取得して応答を生成できます。これにより、LLMが企業のプライベートデータに基づいて回答を生成することが可能になります。
import boto3
import json
# Bedrock Agent Runtimeクライアントの初期化
bedrock_agent_runtime = boto3.client(
service_name="bedrock-agent-runtime",
region_name="us-east-1" # Knowledge Baseが作成されているリージョンを指定
)
knowledge_base_id = "YOUR_KNOWLEDGE_BASE_ID" # 自身のKnowledge Base IDに置き換える
model_arn = "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0" # 利用するモデルのARN
user_query = "最新のチケット販売ポリシーについて教えてください。"
response = bedrock_agent_runtime.retrieve_and_generate(
input={
"text": user_query
},
retrieveAndGenerateConfiguration={
"type": "KNOWLEDGE_BASE",
"knowledgeBaseConfiguration": {
"knowledgeBaseId": knowledge_base_id,
"modelArn": model_arn
}
}
)
print(response["output"]["text"])
# 参照されたソースも確認できる
for citation in response["citations"]:
print(f"Source: {citation["retrievedReferences"][0]["location"]["uri"]}")
この例では、指定されたKnowledge Baseから関連ドキュメントを検索し、その情報に基づいてLLMが回答を生成します。citationsからは、回答の根拠となったドキュメントのURIなどの情報を取得できるため、情報の信頼性を高めることができます。
2. Agents (AIエージェント)
ユーザーの指示に基づいて、複数ステップのタスクを自律的に計画・実行するAIエージェントを構築できます。外部APIの呼び出しや、複数のKnowledge Basesを連携させることで、複雑な業務プロセスを自動化することが可能です [1] [3]。
Action GroupとLambda関数による外部システム連携
Amazon Bedrock Agentsの強力な機能の一つが、Action Groupを介した外部システムとの連携です。これにより、LLMが外部APIを呼び出したり、特定のビジネスロジックを実行したりすることが可能になります。Action GroupはLambda関数と連携し、LLMが生成したアクションプランに基づいてLambda関数が実行されます。
Lambda関数の例 (lambda_handler.py):
import json
import datetime
def lambda_handler(event, context):
# エージェントからの入力イベントを解析
# event構造の詳細はAWSドキュメントを参照: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html
action_group = event["actionGroup"]
api_path = event["apiPath"]
http_method = event["httpMethod"]
parameters = event["parameters"]
response_body = {}
http_status_code = 200
if action_group == "OrderManagement" and api_path == "/orders" and http_method == "POST":
# 注文作成のロジックをここに実装
# 例: データベースに注文情報を保存、外部サービスに通知など
item = next(p["value"] for p in parameters if p["name"] == "item")
quantity = int(next(p["value"] for p in parameters if p["name"] == "quantity"))
order_id = f"ORDER-{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}"
message = f"{item}を{quantity}個注文しました。注文ID: {order_id}"
response_body = {
"orderId": order_id,
"message": message
}
elif action_group == "OrderManagement" and api_path == "/orders" and http_method == "GET":
# 注文参照のロジックをここに実装
order_id = next(p["value"] for p in parameters if p["name"] == "orderId")
# 例: データベースから注文情報を取得
# ここではダミーデータを返す
if order_id == "ORDER-20240101120000":
response_body = {
"orderId": order_id,
"item": "Laptop",
"quantity": 1,
"status": "Delivered"
}
else:
http_status_code = 404
response_body = {"message": f"Order ID {order_id} not found."}
else:
http_status_code = 400
response_body = {"message": "Invalid action or API path."}
return {
"messageVersion": "1.0",
"response": {
"actionGroup": action_group,
"apiPath": api_path,
"httpMethod": http_method,
"httpStatusCode": http_status_code,
"responseBody": {
"application/json": {
"body": json.dumps(response_body)
}
}
}
}
このLambda関数は、OrderManagementというAction Groupが呼び出された際に、POST /ordersで注文を作成したり、GET /ordersで注文情報を取得したりするロジックを処理します。エージェントは、ユーザーの意図を解釈し、適切なAction GroupとAPIパスを特定してこのLambda関数を呼び出します。
OpenAPIスキーマの定義例:
エージェントにAction Groupの機能を理解させるためには、OpenAPIスキーマでAPIの仕様を定義する必要があります。以下は、上記のLambda関数に対応するOpenAPIスキーマの抜粋です。
openapi: 3.0.0
info:
title: Order Management API
version: 1.0.0
paths:
/orders:
post:
summary: Create a new order
operationId: createOrder
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
item:
type: string
description: The item to order
quantity:
type: integer
description: The quantity of the item
responses:
'200':
description: Order created successfully
content:
application/json:
schema:
type: object
properties:
orderId:
type: string
message:
type: string
get:
summary: Get order details by ID
operationId: getOrder
parameters:
- name: orderId
in: query
required: true
schema:
type: string
description: The ID of the order to retrieve
responses:
'200':
description: Order details
content:
application/json:
schema:
type: object
properties:
orderId:
type: string
item:
type: string
quantity:
type: integer
status:
type: string
'404':
description: Order not found
このスキーマをAmazon Bedrock Agentsに登録することで、エージェントはユーザーの「〇〇を注文して」「注文ID〇〇の状況を教えて」といった自然言語の指示を、対応するAPI呼び出しに変換し、Lambda関数を実行できるようになります。
3. Guardrails (安全なAI利用)
有害なコンテンツのフィルタリング、機密情報の編集、特定のトピックの制限など、責任あるAIの原則に基づいた安全な利用を促進するための機能です。組織レベルでガードレールを定義し、複数の生成AIアプリケーションで再利用できます [1]。
4. モデル選択の最適化
コスト、レイテンシー、精度の要件に基づいて、Anthropic Claude 3 Haiku、Sonnet、Opusなど、利用可能な基盤モデルを柔軟に選択・評価できます。自動化されたテストパイプラインを実装することで、データに基づいた最適なモデル選択が可能です [1]。
5. プロンプトエンジニアリングのベストプラクティス
LLMの性能を最大限に引き出すためには、効果的なプロンプトエンジニアリングが不可欠です。特にAmazon Bedrockでは、多様なモデルを扱うため、モデルごとの特性を理解したプロンプト設計が重要になります。
5.1. 明確な指示と制約の提示
LLMに何をさせたいのか、どのような形式で出力してほしいのかを明確に指示します。曖昧な指示は、期待しない結果を招く可能性があります。
悪い例:
日本の経済について教えて。
良い例:
あなたは経済アナリストです。日本の現在の経済状況について、主要な指標(GDP成長率、インフレ率、失業率)を挙げ、それぞれの現状と今後の見通しを簡潔にまとめてください。出力は箇条書き形式でお願いします。
5.2. 役割の付与 (Persona)
LLMに特定の役割(ペルソナ)を与えることで、その役割に応じたトーンやスタイルの応答を引き出すことができます。これにより、より専門的で一貫性のある回答が得られます。
例:
あなたは経験豊富なソフトウェアエンジニアです。以下のPythonコードのバグを特定し、修正案を提示してください。
[Pythonコード]
5.3. Few-shot Learning (具体例の提示)
期待する出力形式や内容が複雑な場合、いくつかの具体例(入出力ペア)をプロンプトに含めることで、LLMはより正確に意図を理解し、同様の形式で応答を生成するようになります。
例:
以下の形式で、商品名と価格をJSONで抽出してください。
入力: 「最新のスマートフォンXが120,000円で発売中!」
出力: {"product_name": "スマートフォンX", "price": 120000}
入力: 「高性能ノートPC Yがセールで15万円!」
出力: {"product_name": "ノートPC Y", "price": 150000}
入力: 「新製品Z、驚きの8000円!」
出力:
5.4. Chain-of-Thought (思考プロセスの誘導)
複雑な問題に対しては、LLMに直接答えを求めるのではなく、段階的な思考プロセスを促すことで、推論能力を向上させることができます。「ステップバイステップで考えてください」といった指示が有効です。
例:
以下の問題を解決してください。ステップバイステップで思考プロセスを記述し、最終的な答えを導き出してください。
問題: [複雑な問題文]
これらのテクニックを組み合わせることで、Amazon Bedrock上のLLMをより効果的に活用し、高品質な生成AIアプリケーションを構築することが可能になります。
Amazon Bedrockを「間違えない」ための活用方法
Amazon Bedrockを効果的に活用するためには、いくつかの重要な考え方とベストプラクティスがあります。
1. 「LLMは信用しない」前提での設計 [2]
最も重要なのは、LLMが生成する内容を盲目的に信用せず、常に検証と制御の仕組みを組み込むことです。特に、システム操作やデータ変更を伴うアプリケーションでは、LLMにコード実行権限を直接与えるのではなく、アプリケーション側で厳密に制御することが不可欠です。
SafeExecutorの概念と実装例 [2]
AIが生成したコードを安全に実行するための仕組みとして、「SafeExecutor」のような概念が有効です。これは、LLMが生成したコードを実行する前に、以下のチェックを行うことで、意図しない危険な操作を防ぎます。
-
危険なキーワードの検出:
exec,eval,deleteなどの危険なキーワードが含まれていないかチェック。 -
書き込み系APIのブロック:
create_*,delete_*,update_*など、リソースの状態を変更するAPI呼び出しを原則として実行不可とする。 -
読み取り専用APIのみ許可:
describe_*,list_*,get_*など、参照系APIのみをホワイトリスト方式で許可する。 - コード構造の検証: boto3の呼び出しパターンを解析し、想定外の処理が含まれていないかを確認する。
これにより、IAMによる最終防衛ラインに加え、アプリケーションレイヤーで物理的に危険な操作を実行させない二段構えの防御を実現します。以下に、SafeExecutorの中核となるチェック処理の抜粋を示します。
import re
FORBIDDEN_KEYWORDS = [
"exec", "eval", "__import__", "delete", "terminate",
]
ALLOWED_API_PREFIXES = (
"describe_", "list_", "get_", "query_", "search_",
)
BOTO3_CALL_PATTERN = re.compile(r"client\\.([a-zA-Z0-9_]+)\\( ")
def validate_generated_code(code: str) -> None:
"""
AIが生成したコードを検証し、
危険な処理が含まれている場合は例外を送出する
"""
lowered = code.lower()
# 危険なキーワードの検出
for keyword in FORBIDDEN_KEYWORDS:
if keyword in lowered:
raise ValueError(f"Forbidden keyword detected: {keyword}")
# boto3 API呼び出しの検証
for match in BOTO3_CALL_PATTERN.finditer(code):
api_name = match.group(1)
if not api_name.startswith(ALLOWED_API_PREFIXES):
raise ValueError(f"Forbidden boto3 API call: {api_name}")
このvalidate_generated_code関数は、AIが生成したコードを実行する前に、危険なキーワードや許可されていないAPI呼び出しがないかをチェックします。これにより、AIの自律性を保ちつつも、システムへの不正な操作や意図しない変更を防ぐことが可能になります。
2. 包括的なログ記録とオブザーバビリティ [1]
エージェントのデバッグ、監査、トラブルシューティングには、徹底的なログ記録とオブザーバビリティが不可欠です。Amazon Bedrockのモデル呼び出しログを有効にし、エージェントのトレース機能(オーケストレーションステップ、FM呼び出しプロンプト、Knowledge Basesからの参照結果など)を活用することで、問題発生時の迅速な特定と解決が可能になります。
3. Infrastructure as Code (IaC)の利用 [1]
反復的で信頼性の高いデプロイを実現するために、AWS CloudFormationやAWS CDK、TerraformなどのIaCツールを使用します。これにより、エージェントや関連リソースの再現性、テスト容易性、監視容易性が向上し、堅牢なシステム構築に貢献します。
4. 堅牢なテストフレームワークの実装 [1]
エージェントや生成AIシステムの評価を自動化するテストフレームワークを実装します。コスト、レイテンシー、精度など、複数の側面で評価を行い、Agent Evaluationのようなツールを活用することで、開発プロセスを加速し、高品質なソリューションを提供できます。LLMを活用してテストケースを生成することも有効です。
5. 強固な確認とセキュリティメカニズムの設計 [1]
重要なアクション(特にデータを変更したり機密性の高い操作)に対しては、ユーザーの確認を求めるメカニズムを実装します。エージェントの指示に明確に記述するか、requireConfirmationフィールドを使用することで、意図しない操作を防ぎます。
6. 責任あるAIの実践の統合 [1]
Amazon Bedrock Guardrailsを実装し、倫理的で透明性が高く、説明責任のあるAIシステムを構築します。有害コンテンツのフィルタリング、プライバシー保護のための機密情報編集など、責任あるAIの原則をスケーラブルに適用します。
7. 再利用可能なアクションカタログの構築と段階的な拡張 [1]
アクショングループ、Knowledge Bases、Guardrailsなどの共通機能をIaCで作成・デプロイし、複数のアプリケーションで再利用可能なアクションカタログを構築します。また、「クロール・ウォーク・ラン」のアプローチで、内部アプリケーションから段階的に外部ユーザー向けに展開することで、リスクを最小限に抑えながらエージェントの利用を拡大します。
Amazon Bedrockを使わなくていいケース
Amazon Bedrockは強力なツールですが、すべてのケースで最適とは限りません。以下のような場合は、Bedrockにこだわる必要はないかもしれません [2]。
- 個人利用のチャットや一発ネタのデモ: オーバーヘッドが大きく、よりシンプルなAPIやライブラリで十分な場合があります。
- UI込みで完結するSaaS: 既存のSaaS機能で要件が満たせる場合、Bedrockを導入するメリットは小さいです。
- スピード最優先の検証: 迅速なプロトタイピングが目的の場合、Bedrockのセットアップや運用管理がボトルネックになる可能性があります。
まとめ
Amazon Bedrockは、単なるAIモデルの呼び出しツールではなく、生成AIをビジネスに安全かつ継続的に組み込むための強力なプラットフォームです。特に、「LLMは信用しない」という前提に立ち、アプリケーションレイヤーでの厳密な制御と検証機構を設けることが、成功への鍵となります。
本記事で紹介した主要機能とベストプラクティスを参考に、皆さんのプロジェクトでAmazon Bedrockを最大限に活用し、堅牢で価値ある生成AIアプリケーションを構築してください。
参考資料
[1] Amazon Bedrock Agents を使用して堅牢な生成 AI アプリケーションを構築するためのベストプラクティス – Part 2
[2] 間違えない。Amazon Bedrockの活用方法 #AWS - Qiita
[3] Amazon Bedrock Agentsを利用して複数のナレッジベースを元に回答する仕組みを作る - サーバーワークス エンジニアブログ