Amazon BedrockをBoto3から使ってみた
こんにちは。サービス開発室の武田です。
AWSの生成AIサービスであるAmazon BedrockがGAとなりましたね。
このビッグウェーブに乗って行こうぜってことで、今回はBoto3を使ってPythonのコードでサービスを利用する手順を確認してみました。
ライブラリのバージョン
さてGAしたばかりのサービスですので、Boto3も最新にする必要があります。具体的にサポートされたバージョンは 1.28.57 です。このエントリを書いている9時間ほど前にリリースされていました。
そんなわけでライブラリをアップグレードしましょう。
$ pip list | grep boto3 boto3 1.28.53 $ pip3 install boto3 --upgrade $ pip list | grep boto3 boto3 1.28.57
準備OK!
モデルの有効化
さて、Bedrockを試していくわけですが、実はデフォルトでは提供されているモデルを使用できません。明示的に有効化が必要で、これはマネジメントコンソールから行います。手順は前述したsuzuki.ryoのエントリで解説しているため参考にしてください。
Boto3でアクセスしてみた
Boto3でサービスにアクセスする場合、対応したクライアントを作成してメソッドを呼び出すことでアクセスできます。Bedrockは次の2種類のクライアントが提供され、それぞれできることが違います。
- bedrock
- bedrock-runtime
実際に生成AIを利用するためにはbedrock-runtime
を利用する必要があります。
それではさっそくREPLを使用して試してみましょう。
>>> import boto3 >>> bedrock = boto3.client("bedrock", region_name="us-east-1") >>> bedrock. bedrock.can_paginate( bedrock.close( bedrock.create_model_customization_job( bedrock.delete_custom_model( bedrock.delete_model_invocation_logging_configuration( bedrock.exceptions bedrock.generate_presigned_url( bedrock.get_custom_model( bedrock.get_foundation_model( bedrock.get_model_customization_job( bedrock.get_model_invocation_logging_configuration( bedrock.get_paginator( bedrock.get_waiter( bedrock.list_custom_models( bedrock.list_foundation_models( bedrock.list_model_customization_jobs( bedrock.list_tags_for_resource( bedrock.meta bedrock.put_model_invocation_logging_configuration( bedrock.stop_model_customization_job( bedrock.tag_resource( bedrock.untag_resource( bedrock.waiter_names
まずはbedrock
から。東京リージョンではまだ利用できないため、明示的にus-east-1
を指定しています。こちらはモデルの一覧取得や、カスタムモデルの管理などができるようです。
試しにモデルの一覧を取得してみましょう。
>>> import pprint >>> pprint.pprint(bedrock.list_foundation_models()["modelSummaries"]) [{'customizationsSupported': ['FINE_TUNING'], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-tg1-large', 'modelId': 'amazon.titan-tg1-large', 'modelName': 'Titan Text Large', 'outputModalities': ['TEXT'], 'providerName': 'Amazon', 'responseStreamingSupported': True}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-e1t-medium', 'modelId': 'amazon.titan-e1t-medium', 'modelName': 'Titan Text Embeddings', 'outputModalities': ['EMBEDDING'], 'providerName': 'Amazon'}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-g1-text-02', 'modelId': 'amazon.titan-embed-g1-text-02', 'modelName': 'Titan Text Embeddings v2', 'outputModalities': ['EMBEDDING'], 'providerName': 'Amazon'}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-text-express-v1', 'modelId': 'amazon.titan-text-express-v1', 'modelName': 'Titan Text G1 - Express', 'outputModalities': ['TEXT'], 'providerName': 'Amazon', 'responseStreamingSupported': True}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v1', 'modelId': 'amazon.titan-embed-text-v1', 'modelName': 'Titan Embeddings G1 - Text', 'outputModalities': ['EMBEDDING'], 'providerName': 'Amazon', 'responseStreamingSupported': True}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT', 'IMAGE'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/stability.stable-diffusion-xl', 'modelId': 'stability.stable-diffusion-xl', 'modelName': 'Stable Diffusion XL', 'outputModalities': ['IMAGE'], 'providerName': 'Stability AI'}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT', 'IMAGE'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/stability.stable-diffusion-xl-v0', 'modelId': 'stability.stable-diffusion-xl-v0', 'modelName': 'Stable Diffusion XL', 'outputModalities': ['IMAGE'], 'providerName': 'Stability AI'}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/ai21.j2-grande-instruct', 'modelId': 'ai21.j2-grande-instruct', 'modelName': 'J2 Grande Instruct', 'outputModalities': ['TEXT'], 'providerName': 'AI21 Labs', 'responseStreamingSupported': False}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/ai21.j2-jumbo-instruct', 'modelId': 'ai21.j2-jumbo-instruct', 'modelName': 'J2 Jumbo Instruct', 'outputModalities': ['TEXT'], 'providerName': 'AI21 Labs', 'responseStreamingSupported': False}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/ai21.j2-mid', 'modelId': 'ai21.j2-mid', 'modelName': 'Jurassic-2 Mid', 'outputModalities': ['TEXT'], 'providerName': 'AI21 Labs', 'responseStreamingSupported': False}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/ai21.j2-mid-v1', 'modelId': 'ai21.j2-mid-v1', 'modelName': 'Jurassic-2 Mid', 'outputModalities': ['TEXT'], 'providerName': 'AI21 Labs', 'responseStreamingSupported': False}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/ai21.j2-ultra', 'modelId': 'ai21.j2-ultra', 'modelName': 'Jurassic-2 Ultra', 'outputModalities': ['TEXT'], 'providerName': 'AI21 Labs', 'responseStreamingSupported': False}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/ai21.j2-ultra-v1', 'modelId': 'ai21.j2-ultra-v1', 'modelName': 'Jurassic-2 Ultra', 'outputModalities': ['TEXT'], 'providerName': 'AI21 Labs', 'responseStreamingSupported': False}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-instant-v1', 'modelId': 'anthropic.claude-instant-v1', 'modelName': 'Claude Instant', 'outputModalities': ['TEXT'], 'providerName': 'Anthropic', 'responseStreamingSupported': True}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v1', 'modelId': 'anthropic.claude-v1', 'modelName': 'Claude', 'outputModalities': ['TEXT'], 'providerName': 'Anthropic', 'responseStreamingSupported': True}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2', 'modelId': 'anthropic.claude-v2', 'modelName': 'Claude', 'outputModalities': ['TEXT'], 'providerName': 'Anthropic', 'responseStreamingSupported': True}, {'customizationsSupported': [], 'inferenceTypesSupported': ['ON_DEMAND'], 'inputModalities': ['TEXT'], 'modelArn': 'arn:aws:bedrock:us-east-1::foundation-model/cohere.command-text-v14', 'modelId': 'cohere.command-text-v14', 'modelName': 'Command', 'outputModalities': ['TEXT'], 'providerName': 'Cohere', 'responseStreamingSupported': True}]
それでは続いてbedrock-runtime
です。
>>> bedrock_runtime = boto3.client("bedrock-runtime", region_name="us-east-1") >>> bedrock_runtime. bedrock_runtime.can_paginate( bedrock_runtime.get_waiter( bedrock_runtime.close( bedrock_runtime.invoke_model( bedrock_runtime.exceptions bedrock_runtime.invoke_model_with_response_stream( bedrock_runtime.generate_presigned_url( bedrock_runtime.meta bedrock_runtime.get_paginator( bedrock_runtime.waiter_names
おそらく一番使っていくのがinvoke_model
になるのでしょうか。またinvoke_model_with_response_stream
も覚えておくと良さそうですね。
今回はJurassic-2 Mid
のモデルを使ってみましょう。invoke_model
はモデル名ではなく モデルID を指定します。先ほどの一覧で確認してみると、IDはai21.j2-mid-v1
のようです。
なんとなく日本の初代総理大臣を知りたくなったので聞いてみました。
>>> resp = bedrock_runtime.invoke_model(modelId="ai21.j2-mid-v1", body=json.dumps({"prompt":"日本の初代総理大臣は誰ですか。"})) >>> json.loads(resp["body"].read())["completions"] [{'data': {'text': '\n日本の初代総理大臣は清治四年', 'tokens': [{'generatedToken': {'token': '<|newline|>', 'logprob': -0.001190906623378396, 'raw_logprob': -0.001190906623378396}, 'topTokens': None, 'textRange': {'start': 0, 'end': 1}}, {'generatedToken': {'token': '▁', 'logprob': -0.33202117681503296, 'raw_logprob': -0.33202117681503296}, 'topTokens': None, 'textRange': {'start': 1, 'end': 1}}, {'generatedToken': {'token': '日', 'logprob': -0.11673896014690399, 'raw_logprob': -0.11673896014690399}, 'topTokens': None, 'textRange': {'start': 1, 'end': 2}}, {'generatedToken': {'token': '本', 'logprob': -0.0002172949316445738, 'raw_logprob': -0.0002172949316445738}, 'topTokens': None, 'textRange': {'start': 2, 'end': 3}}, {'generatedToken': {'token': 'の', 'logprob': -0.30525633692741394, 'raw_logprob': -0.30525633692741394}, 'topTokens': None, 'textRange': {'start': 3, 'end': 4}}, {'generatedToken': {'token': '初', 'logprob': -0.0029284947086125612, 'raw_logprob': -0.0029284947086125612}, 'topTokens': None, 'textRange': {'start': 4, 'end': 5}}, {'generatedToken': {'token': '代', 'logprob': -2.7656173188006505e-05, 'raw_logprob': -2.7656173188006505e-05}, 'topTokens': None, 'textRange': {'start': 5, 'end': 6}}, {'generatedToken': {'token': '総', 'logprob': -0.0014261561445891857, 'raw_logprob': -0.0014261561445891857}, 'topTokens': None, 'textRange': {'start': 6, 'end': 7}}, {'generatedToken': {'token': '理', 'logprob': -1.6927575416048057e-05, 'raw_logprob': -1.6927575416048057e-05}, 'topTokens': None, 'textRange': {'start': 7, 'end': 8}}, {'generatedToken': {'token': '大', 'logprob': -0.00010752100206445903, 'raw_logprob': -0.00010752100206445903}, 'topTokens': None, 'textRange': {'start': 8, 'end': 9}}, {'generatedToken': {'token': '臣', 'logprob': -0.022740887477993965, 'raw_logprob': -0.022740887477993965}, 'topTokens': None, 'textRange': {'start': 9, 'end': 10}}, {'generatedToken': {'token': 'は', 'logprob': -0.0009258274803869426, 'raw_logprob': -0.0009258274803869426}, 'topTokens': None, 'textRange': {'start': 10, 'end': 11}}, {'generatedToken': {'token': '清', 'logprob': -1.1000699996948242, 'raw_logprob': -1.1000699996948242}, 'topTokens': None, 'textRange': {'start': 11, 'end': 12}}, {'generatedToken': {'token': '治', 'logprob': -0.8374251127243042, 'raw_logprob': -0.8374251127243042}, 'topTokens': None, 'textRange': {'start': 12, 'end': 13}}, {'generatedToken': {'token': '四', 'logprob': -6.17655611038208, 'raw_logprob': -6.17655611038208}, 'topTokens': None, 'textRange': {'start': 13, 'end': 14}}, {'generatedToken': {'token': '年', 'logprob': -0.6831862330436707, 'raw_logprob': -0.6831862330436707}, 'topTokens': None, 'textRange': {'start': 14, 'end': 15}}]}, 'finishReason': {'reason': 'length', 'length': 16}}]
なるほど。なるほど?まぁレスポンスの内容は気にせず、ちゃんと返って来たことに安心しましょう。
ちなみにモデルを有効化していない場合、次のようなエラーが表示され失敗します。このメッセージが出た場合は、有効化をしてあげてください。
botocore.errorfactory.AccessDeniedException: An error occurred (AccessDeniedException) when calling the InvokeModel operation: Your account is not authorized to invoke this API operation.
まとめ
ひとまず一覧の取得と、モデルの実行をBoto3から試してみました。いろいろと試していきましょう!