Amazon BedrockをPythonスクリプトから利用してみた

# はじめに

こんにちは、はやぴー（@HayaP）です。

ついに、Amazon BedrockがGAされましたね！
東京リージョンでも、一部のモデルが使用可能になりました。

今回はPythonスクリプトでAmazon Bedrockを利用してみます。
理由として、Lambdaから実行するケースや、Webアプリケーションに組み込むケースが多そうだなぁと感じているからです。（Lambdaで実行するハンズオンは別で記事を書く予定です）

# 対象読者

- Amazon Bedrockに興味がある方
- Pythonスクリプトで、Amazon Bedrockを利用したい方
- AWS Lambdaでの実装を考えている方(Lambdaのハンズオンではありません)

# TL;DR (忙しい人用)
- Amazon Bedrockは、モデル毎に（マネージメントコンソールなどで）初期設定が必要
- Boto3を使えば、比較的簡単に実装できる（基本コピペでOK）
- Claude系は、全リージョン共通で許可制（現時点）
- 東京リージョンで使えるモデルは、us-east-1と比べてまだまだ少ない（現時点）

# 概要
使用するモデルは、Jurassic-2 Midとします。
（Claudeは現在許可制となっているから）


Regionは、us-east-1です。東京リージョンでは、現在使用できないモデルだからです。

## 前提
- 使用OS
    - Linux(Ubuntu 22.04.2 LTS)
- AWS region
    - us-east-1
- 使用するモデル
    - [Jurassic-2 Mid](https://aws.amazon.com/marketplace/pp/prodview-ivk4wjg6gbr26)
# 詳細

## セットアップ
セットアップに関しては、AWS公式が出している
[Amazon Bedrock boto3 Setup](https://github.com/aws-samples/amazon-bedrock-workshop/blob/b43299e8220f2b6b026ad2b02881c4d2732d3472/00_Intro/bedrock_boto3_setup.ipynb)
を参考にしています。こちらも併せてご確認ください。(Github上のファイルに遷移します。)

### 1. Python環境の確認とセットアップ
まず、Pythonのバージョンを確認します。AWS BedrockのSDKはPython 3.6以上で動作します。
```bash
$ python3 --version
```
もし、要求されているバージョンがインストールされていない場合は、Pythonをアップデートまたはインストールしてください。

### 2. 必要なライブラリのインストール
依存するライブラリをダウンロードします。
```bash
$ pip install --no-build-isolation --force-reinstall \
    "boto3>=1.28.57" \
    "awscli>=1.29.57" \
    "botocore>=1.31.57"
```

### 3. AWS CLIのセットアップ
AWS CLIは、Amazon Web Servicesのサービスをコマンドラインから操作するためのツールです。本スクリプトでは、AWS CLIのセットアップが必要です。

Ubuntu 22.04.2 LTS上でAWS CLIをインストールするには、次のコマンドを使用します。
```bash
sudo apt-get install awscli
```
インストールが正しく完了したことを確認するため、バージョンをチェックします。
```bash
aws --version
```

AWS CLIを使用するには、AWSの認証情報を設定する必要があります。以下のコマンドを実行して設定を開始します。

```bash
aws configure
```
コマンドを実行すると、AWS Access Key ID、AWS Secret Access Key、デフォルトのリージョン名、デフォルトの出力形式を順に入力するプロンプトが表示されます。これらの情報は、AWS Management Consoleから取得できます。

- AWS Access Key ID: IAMユーザーのアクセスキーID
- AWS Secret Access Key: IAMユーザーのシークレットアクセスキー
- Default region name: 使用するデフォルトのAWSリージョン（例: us-east-1）
- Default output format: 出力形式（例: json）

以上で、AWS CLIの準備ができました。
### 4. ヘルパーファイルの作成と設定
AWS Bedrockの効率的な利用のために、２つのヘルパーファイル (bedrock.py と init.py) を作成します。これにより、Bedrockのクライアントの取得やテキストのフォーマットを簡単に行うことができます。

:::note warn
全てのコードを理解する必要はありません。コメント文で補足している箇所を、利用条件に合わせて変更してください
:::

まずは、bedrock.pyを作成します。
```python
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
"""General helper utilities the workshop notebooks"""
import os  # OS操作のためのモジュール
from typing import Optional  # タイプヒントのためのモジュール

# External Dependencies:
import boto3  # AWS SDK for Python
from botocore.config import Config  # botocoreからのConfigクラスのインポート


def get_bedrock_client(
    assumed_role: Optional[str] = None,
    region: Optional[str] = None,
    runtime: Optional[bool] = True,
):
    """
    Amazon Bedrock用のboto3クライアントを作成し、任意の設定でオーバーライドします

    Parameters
    ----------
    assumed_role : str, optional
        Bedrockサービスを呼び出すためのIAMロールのARNを仮定します。指定されていない場合、現在のアクティブな資格情報が使用されます。

    region : str, optional
        サービスを呼び出すべきAWSリージョンの名前（例: "us-east-1"）。
        指定されていない場合、AWS_REGIONまたはAWS_DEFAULT_REGION環境変数が使用されます。

    runtime : bool, optional
        Amazon Bedrockサービスで操作を実行するための異なるクライアントを取得する選択。
    """
    # ターゲットリージョンの設定
    if region is None:
        target_region = "us-east-1"
    else:
        target_region = region

    print(f"Create new client\n  Using region: {target_region}")

    # セッション引数の定義
    session_kwargs = {"region_name": target_region}
    client_kwargs = {**session_kwargs}

    # 環境変数からプロファイル名を取得
    profile_name = os.environ.get("AWS_PROFILE")
    if profile_name:
        print(f"  Using profile: {profile_name}")
        session_kwargs["profile_name"] = profile_name

    # リトライ設定の作成
    retry_config = Config(
        region_name=target_region,
        retries={
            "max_attempts": 10,
            "mode": "standard",
        },
    )

    # boto3セッションの作成
    session = boto3.Session(**session_kwargs)

    # IAMロールを仮定
    if assumed_role:
        print(f"  Using role: {assumed_role}", end='')
        sts = session.client("sts")
        response = sts.assume_role(
            RoleArn=str(assumed_role),
            RoleSessionName="langchain-llm-1"
        )
        print(" ... successful!")
        client_kwargs["aws_access_key_id"] = response["Credentials"]["AccessKeyId"]
        client_kwargs["aws_secret_access_key"] = response["Credentials"]["SecretAccessKey"]
        client_kwargs["aws_session_token"] = response["Credentials"]["SessionToken"]

    # サービス名の決定
    if runtime:
        service_name = 'bedrock-runtime'
    else:
        service_name = 'bedrock'

    # Bedrockクライアントの作成
    bedrock_client = session.client(
        service_name=service_name,
        config=retry_config,
        **client_kwargs
    )

    print("boto3 Bedrock client successfully created!")
    print(bedrock_client._endpoint)
    return bedrock_client
```

次に、init.py を作成し、以下の内容を追加します
```python
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
"""General helper utilities the workshop notebooks"""
# Python Built-Ins:
from io import StringIO
import sys
import textwrap


def print_ww(*args, width: int = 100, **kwargs):
    """Like print(), but wraps output to `width` characters (default 100)"""
    buffer = StringIO()
    try:
        _stdout = sys.stdout
        sys.stdout = buffer
        print(*args, **kwargs)
        output = buffer.getvalue()
    finally:
        sys.stdout = _stdout
    for line in output.splitlines():
        print("\n".join(textwrap.wrap(line, width=width)))
```
以上で、セットアップは完了です。



### 5. モデルのアクセス設定
Amazon Bedrockの仕様上、新たにモデルを使用する際に設定変更を行う必要があります。

まず、AWS マネジメントコンソールを開き「Amazon Bedrock」を選択してください。（このとき、regionがus-east-1であることを確認してください）

![Screenshot 2023-10-06 005058.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478323/55338ce8-5485-4dae-c5e7-38fc7874f832.png)


次に、ハンバーガーボタンを押下し「Model access」を押下します。
![Screenshot 2023-10-06 005224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478323/be74afdb-2fd9-ab92-5d40-a5af2d58c1ec.png)

Editを押下し、使用したいモデル（今回は、Jurassic-2 Mid）にチェックボックスを入れ「Save changes」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478323/d610888c-eb36-4aee-91cd-71f0bc86be3a.png)


Access grantedになったら、モデルが利用可能となります。

## Pythonスクリプトの作成
では、メインとなるスクリプトを作成していきます。
bedrock_tutorial.pyという名前でファイルを作成し、以下の内容を追加します。

```python
# 必要なモジュールをインポート
import json
import boto3
from bedrock import get_bedrock_client

# Amazon Bedrockクライアントを初期化
boto3_bedrock = get_bedrock_client()

# 質問の指定
prompt = "what is aws"

# モデルのIDの指定: ai21.j2-mid-v1は、例として指定されたモデルのIDです
modelId = 'ai21.j2-mid-v1'

# 応答形式と内容形式の指定
# JSON形式でのリクエストとレスポンスを期待しています
accept = 'application/json'
contentType = 'application/json'

# リクエストBODYの生成
# maxTokensは応答の最大トークン数を指定します
# temperatureはサンプリングの「ランダム性」を制御します。値が大きいほどランダム性が高まります
# topPはトークンのサンプリング確率を制御します。1に設定すると全てのトークンがサンプリングされます
body = json.dumps({
    "prompt": prompt,
    "maxTokens": 100,
    "temperature": 0.7,
    "topP": 1,
})

# Bedrock APIを使用してモデルを呼び出し
response = boto3_bedrock.invoke_model(
    modelId=modelId,
    accept=accept,
    contentType=contentType,
    body=body
)

# APIのレスポンスから実際のボディ部分を取得
response_body = json.loads(response.get('body').read())

# 応答テキストを取得: 'completions'は応答のリストを含んでおり、最初の応答のテキスト部分を取得します
outputText = response_body.get('completions')[0].get('data').get('text')

# 応答テキストを出力
print(outputText)
```
質問ですが、"what is aws"と入力していますが随時変更してください。
以上で、スクリプトの作成が完了です。

## スクリプトの実行
では、実際にスクリプトを実行してみましょう。

```bash
$ python3 bedrock_tutorial.py 
Create new client
  Using region: us-east-1
boto3 Bedrock client successfully created!
bedrock-runtime(https://bedrock-runtime.us-east-1.amazonaws.com)

AWS stands for Amazon Web Services. It is a collection of cloud computing services provided by Amazon. These services are designed to help businesses, organizations, and individuals store and access data, run applications, and build sophisticated computing solutions without the need for physical infrastructure.

AWS offers a wide range of tools and services, including:

1. Compute Services: These services include Elastic Compute Cloud (EC2), which allows customers to launch and manage virtual machines (VMs) in the cloud.
2. Storage Services: These services include Simple Storage Service (S3), which is an object storage service used to store and retrieve data
```

成功しました！

# 最後に
今回は、PythonスクリプトからAmazon Bedrockを利用してみました。
冒頭で説明した通り、LambdaやWebアプリケーション経由で利用する用途が多いと思います。

Amazon Bedrockの感想としては、使用できるモデルは限られているものの今後が楽しみなサービスです。
（個人的に、Amazon Titanシリーズが楽しみです！）

皆さんも、ぜひ自分のアプリケーションに組み込んでみてください！