💬

AWS Bedrock の converse API の使い方

2024/12/07に公開

以前のスクラップを記事に移行しました。

Bedrock の converse API、コードサンプル全然見つからん

と思ったので備忘録をここに。

参考になったリンク先:
Getting started with the Amazon Bedrock Converse API
https://community.aws/content/2hHgVE7Lz6Jj1vFv39zSzzlCilG/getting-started-with-the-amazon-bedrock-converse-api

訳を載せておきます。

Amazon Bedrock Converse APIの使い方

Amazon Bedrockで大規模言語モデルを使用してAmazon Bedrock Converse APIの基本を学びます。

はじめに

この記事は、Amazon Bedrockでのツール使用に関するシリーズの第1部です。ツール使用について詳しく説明する前に、Amazon Bedrock Converse APIの簡単なチュートリアルを提供します。

Amazon Bedrock Converse APIは、Amazon Bedrockを使用して大規模言語モデル(LLM)にアクセスする一貫した方法を提供します。ユーザーと生成AIモデル間でメッセージを交互にやり取りする手法ができます。また、ツール使用をサポートするモデルについては、ツール定義の一貫した形式を提供します(または「関数呼び出し」として知られています)。

なぜConverse APIが重要なのでしょうか?以前のInvokeModel APIでは、各モデルプロバイダーごとにリクエストもレスポンスも異なるJSON構造を使用する必要がありました。Converse APIを使用すると、Amazon Bedrockのすべての大規模言語モデルに対して単一のリクエストとレスポンス形式を使用できます。

この記事の執筆時点で、Converse APIはテキスト生成モデルのみをサポートしています。埋め込みモデルと画像生成モデルは、依然としてInvokeModelが必要です。サポートされているモデルと機能のリストは、公式ドキュメント | Converse API supported models and featuresを参照してください。

開発環境とAWSアカウントの設定

これ以降を行う前に、最新のAWS SDKとAmazon Bedrockモデルアクセスを設定しておくとよいでしょう。

  • Boto3 AWS SDKとPythonの設定:Boto3クイックスタートガイド
  • Anthropic Claude 3 SonnetモデルをサポートするAWSリージョンを選択する。私はus-west-2(オレゴン)を使用しています。リージョンごとのモデルサポートについては、ドキュメント| model support by regionを確認してください。
  • ご自身のアカウントとリージョンで、Amazon Bedrockモデルアクセスを設定します。例:Bedrock設定
  • 自分のローカル統合開発環境がない場合は、AWS Cloud9を試してみてください。設定手順:Cloud9設定

免責事項

  • 大規模言語モデルは非決定的です。この記事で示されている結果とは異なる結果が得られることがあります。
  • 自分のAWSアカウントからこのコードを実行すると、消費されたトークンに対して課金されます。
  • 私は一般的に「最小限のプロンプト」の哲学に従っています。使用ケースに応じて、より詳細なプロンプトを書く必要がある場合があります。
  • すべてのモデルがConverse APIのすべての機能をサポートしているわけではないため、公式ドキュメントでサポートされているモデル機能を確認することが重要です。

コードの説明:Amazon Bedrock Converse APIの使用

コマンドラインから実行できるPythonスクリプトを書いてみましょう。基本的なテキストメッセージや画像ベースのメッセージ、システムプロンプト、レスポンスメタデータを実装して紹介します。

Converse APIの基本的な呼び出し

まず、単純なメッセージを定義し、空のメッセージリストに追加します。「user」ロールからのメッセージを作成します。そのメッセージ内に、コンテンツブロックのリストを含めることができます。この例では、モデルに「今日はお元気ですか?」と尋ねる一つのtextコンテンツブロックがあります。

これで、そのメッセージをAmazon Bedrockに渡す準備が整いました。AnthropicのClaude 3 Sonnetをターゲットモデルとして指定します。モデルのレスポンスのトークン数を制限するには、maxTokens値を設定します。また、レスポンスの変動を最小限に抑えるために、temperatureをゼロに設定します。

import boto3, json

session = boto3.Session()
bedrock = session.client(service_name='bedrock-runtime')

message_list = []

initial_message = {
    "role": "user",
    "content": [
        { "text": "How are you today?" } 
    ],
}

message_list.append(initial_message)

response = bedrock.converse(
    modelId="anthropic.claude-3-sonnet-20240229-v1:0",
    messages=message_list,
    inferenceConfig={
        "maxTokens": 2000,
        "temperature": 0
    },
)

response_message = response['output']['message']
print(json.dumps(response_message, indent=4))

これにより、次のようなレスポンスが生成されます。

{
    "role": "assistant",
    "content": [
        {
            "text": "I'm doing well, thanks for asking! I'm an AI assistant created by Anthropic to be helpful, harmless, and honest."
        }
    ]
}

ユーザーとアシスタントのメッセージを交互に送信

Converse APIを使用して、LLMに新しいメッセージとともに、過去のメッセージリストを送信して会話を続けることができます。「user」と「assistant」のロールのメッセージを交互に送信する必要があります。リストの最後のメッセージは「user」ロールからのものである必要があります。そうすることで、LLMが最後のメッセージに回答することができます。

message_list.append(response_message)

print(json.dumps(message_list, indent=4))

これにより、これまでの会話が表示されます。

リストに新しい「user」メッセージを追加する必要があります。

[
    {
        "role": "user",
        "content": [
            {
                "text": "How are you today?"
            }
        ]
    },
    {
        "role": "assistant",
        "content": [
            {
                "text": "I'm doing well, thanks for asking! I'm an AI assistant created by Anthropic to be helpful, harmless, and honest."
            }
        ]
    }
]

メッセージに画像を含める

注:以下のコードには、「image.webp」という名前のローカルWebP形式のファイルが必要です。この画像をダウンロードしてコードフォルダに保存するか、自分の選択した画像とフォーマットを使用するようにコードを変更してください。サポートされている画像タイプのリストについては、Converse API ImageBlockドキュメントを参照してください。画像サイズの制約については、Anthropicの画像認識ドキュメントを参照してください。

それでは、ローカル画像ファイルを読み込み、そのバイト形式のデータを画像コンテンツブロックに追加します。Anthropicのビジョンプロンプトのヒントに従い、画像の前に「Image 1:」というラベルをつけます。その後、リクエストに画像をおきます。

with open("image.webp", "rb") as image_file:
    image_bytes = image_file.read()

image_message = {
    "role": "user",
    "content": [
        { "text": "Image 1:" },
        {
            "image": {
                "format": "webp",
                "source": {
                    "bytes": image_bytes #no base64 encoding required!
                }
            }
        },
        { "text": "Please describe the image." }
    ],
}

message_list.append(image_message)

response = bedrock.converse(
    modelId="anthropic.claude-3-sonnet-20240229-v1:0",
    messages=message_list,
    inferenceConfig={
        "maxTokens": 2000,
        "temperature": 0
    },
)

response_message = response['output']['message']
print(json.dumps(response_message, indent=4))

message_list.append(response_message)

これにより、次のようなレスポンスが生成されます。

{
    "role": "assistant",
    "content": [
        {
            "text": "The image shows a miniature model of a house, likely a decorative ornament or toy. The house has a blue exterior with white window frames and a red tiled roof. It appears to be made of ceramic or a similar material. The miniature house is placed on a surface with some greenery and yellow flowers surrounding it, creating a whimsical and natural setting. The background is slightly blurred, allowing the small house model to be the focal point of the image."
        }
    ]
}

注:バイトデータの画像を含むメッセージを出力しないことにします。それは、非常に長く長くなってしまいますし、本当に本当に関心がないことだからです。

Claude 3の画像認識能力をこちらで学習することができます:
https://docs.anthropic.com/en/docs/vision

システムプロンプトの設定

通常の会話の外で、基本的な指示を大規模言語モデルに伝えるため、システムプロンプトを設定することができます。システムプロンプトはたいてい、開発者が会話のトーンや制約を定義するために使用されます。今回は、Claudeに海賊のように動作するよう指示します。

summary_message = {
    "role": "user",
    "content": [
        { "text": "Can you please summarize our conversation so far?" } 
    ],
}

message_list.append(summary_message)

response = bedrock.converse(
    modelId="anthropic.claude-3-sonnet-20240229-v1:0",
    messages=message_list,
    system=[
        { "text": "Please respond to all requests in the style of a pirate." }
    ],
    inferenceConfig={
        "maxTokens": 2000,
        "temperature": 0
    },
)

response_message = response['output']['message']
print(json.dumps(response_message, indent=4))

message_list.append(response_message)

これにより、次のようなレスポンスが生成されます。

{
    "role": "assistant",
    "content": [
        {
            "text": "Arr, matey! Let me spin ye a tale of our conversatin' thus far. Ye greeted me shipshape, askin' how I was farin' on this fine day. I replied that I be doin' well as yer trusty AI pirate mate, ready to lend a hand. Then ye showed me a pretty little image of a wee house ornament, all blue an' red with windows an' surrounded by greenery. I described to ye what I spotted in that thar image, not lettin' any details go unnoticed by me eagle eyes. Now ye be askin' ol' Claude to summarize our whole parley up to this point. I aimed to give ye a full account, regaled in true pirate style, of how our voyage has gone so far. Arrr, how'd I do wit' that summary, matey?"
        }
    ]
}

横スクロールしたくない方々のために、以下が海賊風のこれまでの会話の要約です:

Arr, matey! Let me spin ye a tale of our conversatin' thus far. Ye greeted me shipshape, askin' how I was farin' on this fine day. I replied that I be doin' well as yer trusty AI pirate mate, ready to lend a hand. Then ye showed me a pretty little image of a wee house ornament, all blue an' red with windows an' surrounded by greenery. I described to ye what I spotted in that thar image, not lettin' any details go unnoticed by me eagle eyes. Now ye be askin' ol' Claude to summarize our whole parley up to this point. I aimed to give ye a full account, regaled in true pirate style, of how our voyage has gone so far. Arrr, how'd I do wit' that summary, matey?
訳:
アーッ、仲間よ!これまでの会話の物語を語らせてくれ。お前さんは立派に挨拶をして、この素晴らしい日にどう過ごしているかを尋ねた。私は、お前さんの信頼できるAI海賊の仲間として元気にしていて、手助けする準備ができていると答えた。それからお前さんは、小さな家の飾りの可愛らしい画像を見せてくれた。青と赤で、窓があって、緑に囲まれていた。私はその画像で見たものを、鷹の目で見逃さずに細部まで描写した。今、お前さんは古いクロードにこれまでの会話全体をまとめるよう求めている。私は、これまでの航海がどのように進んできたかを、真の海賊スタイルで完全に説明しようと努めた。アーッ、この要約はどうだった、仲間よ?

システムプロンプトについて、こちらでより詳しく知ることができます:
https://docs.anthropic.com/en/docs/system-prompts

レスポンスメタデータとトークン数の取得

Converseメソッドは、APIコールのメタデータも返却します。
stopReasonプロパティにより、モデルがメッセージ出力を完了した理由を知ることができます。これはアプリケーションロジックやエラーハンドリング、トラブルシューティングに便利です。
usageプロパティは入力と出力トークンの詳細を含み、これを使用すればAPIコールの料金を理解することができます。

print("Stop Reason:", response['stopReason'])
print("Usage:", json.dumps(response['usage'], indent=4))

これにより、次のようなレスポンスが生成されます。

Stop Reason: end_turn
Usage: {
    "inputTokens": 629,
    "outputTokens": 154,
    "totalTokens": 783
}

今回は、Claudeが停止した理由は、特に言うことが残っていないということでした。停止する他の理由には、レスポンスのトークン上限に達した(max_tokens)や、ツールをリクエストした(tool_use)、コンテンツフィルターが起動した(content_filtered)などがあります。完全な停止理由のリストについては、公式ドキュメントを参照してください。
なお、表示された使用状況の数字は、最後に実行したAPIコールのみだということを覚えておきましょう。これらのトークン数はAPIコールの費用を特定するのに使用できます。Amazon Bedrockウェブサイトで、トークンベースの料金を知ることができます。

結論

これで、基礎的なConverse APIの使用方法が分りましたね。そうしたら、シリーズの次の記事に進んで、ツール使用に踏み込みましょう!

Learn more

Continue reading articles in this series about tool use / function calling:

続き:
Intro to Tool Use with the Amazon Bedrock Converse API
訳すかもしれません...

Discussion