Amazon Bedrock APIにアクセスする：cURL、Postman、awscurlの比較

## はじめに

本記事では、特別なツールのインストールやコーディングなしでAmazon Bedrock APIを利用する方法について、3つのアプローチを試して比較します。

# 目的
- 手軽にAmazon Bedrock APIを試す
- Embeddingの前処理として画像ファイル等、複数のファイルをコマンドラインから処理する

# 前提条件

- AWSコンソールの AWS Bedrock モデルアクセスから該当のモデルのアクセス権が有効になっていること
- [Amazon Bedrock model IDs](https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html) を参照してモデルIDを確認していること
- aws_access_key_id と aws_secret_access_key を設定しており、適切な権限が付与されていること


## 3つのアプローチ

1. [Terminal などにて curl コマンドを使う方法](#curl)
2. [Postman を使う方法](#postman)
3. [awscurl を利用する方法](#awscurl)

しかし、1つ目の curl については、Claude-v2は利用できますが、Claude-v3 Sonnet、Haiku は MacOS、WSL/Ubuntu のいずれの環境においても動作しないことが確認できています。2024/04/11 現在、解決できそうにありません。Postman か awscurl の利用をご検討ください。Claude 2 は $0.008 / 1k token、Claude 3 と $0.003 / 1k token よりも高額です。

## curl

cURLの `--aws-sigv4` オプションを利用します。

```sh
# Credentials
aws_access_key_id=<Your AWS access key>
aws_secret_access_key=<Your AWS secret access key>

# Endpoint
region=us-west-2
service=bedrock

# Model
modelid=anthropic.claude-v2 

# Invoke Model
curl "https://bedrock-runtime.${region}.amazonaws.com/model/${modelid}/invoke" \
  --aws-sigv4 "aws:amz:${region}:${service}" \
  --user "${aws_access_key_id}:${aws_secret_access_key}" \
  -H "Content-Type: application/json" \
  -X POST \
  --data '{
        "anthropic_version": "bedrock-2023-05-31", 
        "max_tokens": 2000,
        "messages": [
          {"role": "user", "content": [
            {"type": "text", "text": "Hello, who are you?"}     
        ]
      }
    ]
  }'
```

結果
```json
{
   "id":"compl_01WxghaWVij9UtvS7kvKihqd",
   "type":"message",
   "role":"assistant",
   "content":[
      {
         "type":"text",
         "text":"Hello! I'm Claude, an AI assistant created by Anthropic."
      }
   ],
   "model":"claude-2.0",
   "stop_reason":"end_turn",
   "stop_sequence":null,
   "usage":{
      "input_tokens":15,
      "output_tokens":19
   }
}
```

### Note

この方法では、Claude 3 Sonnet 等、modelid の最後が':0'のようになる場合、動作せず、以下のような結果となります。
```json
{
   "message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."
}
```

```sh
modelid=anthropic.claude-v2    # OK
modelid=anthropic.claude-v2:1   # NG
modelid=anthropic.claude-3-sonnet-20240229-v1:0  # NG
modelid=anthropic.claude-3-haiku-20240307-v1:0  # NG
modelid=anthropic.claude-3-5-sonnet-20240620-v1:0  # NG
modelid=meta.llama2-13b-chat-v1  # OK
```

curlを最新版にしても結果は変わらない。
```sh
curl -V
curl 8.7.1 (aarch64-apple-darwin23.4.0) libcurl/8.7.1 (SecureTransport) OpenSSL/3.2.1 zlib/1.2.12 brotli/1.1.0 zstd/1.5.6 libidn2/2.3.7 libssh2/1.11.0 nghttp2/1.60.0 librtmp/2.3 OpenLDAP/2.6.7
Release-Date: 2024-03-27
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz MultiSSL NTLM SPNEGO SSL threadsafe TLS-SRP UnixSockets zstd
```

MacOS、WSL2/Ubuntu のいずれも同じ結果となりました。

## postman

Postman を使って AWS Signature を指定する方法。

URL を設定します。次の例は、北米西部オレゴン (us-west-2) の Claude 3 Sonnet をしている例となります。

```
https://bedrock-runtime.us-west-2.amazonaws.com/model/anthropic.claude-3-sonnet-20240229-v1:0/invoke
```

次に、Authorization タブの Type より 'AWS Signature' を選択します。その上で次の4点を設定します。

```
aws_access_key_id: <Your AWS access key>
aws_secret_access_key: <Your AWS secret access key>

# Advanced configuration
region: us-west-2
service: bedrock
```

Body タブに次のような形でメッセージを入力します。

```json
{
        "anthropic_version": "bedrock-2023-05-31", 
        "max_tokens": 2000,
        "messages": [
          {"role": "user", "content": [
            {"type": "text", "text": "guide me how to travel LAX from SFO"}     
        ]
      }
    ]
  }
```

## awscurl

[awscurl](https://github.com/okigan/awscurl) をインストールします。以下はMacOSのインストール例ですが、OSによって読み替えてください。
```sh
brew install awscurl
```

画像を含むプロンプトをClaude 3 Sonnetにリクエストする際の注意点：

Base64エンコードされた画像データは非常に長くなるため、コマンドラインから直接渡すと`Argument list too long`エラーが発生します。この問題を回避するため、以下の手順を踏みます：

1. Base64エンコードされたデータを含むJSONリクエストをファイルに書き出します。
2. `awscurl`コマンドの`--data`オプションに`@`記号を使用して、ファイルの内容を読み込みます。

この方法により、画像データの長さに関わらず、安定してAPIリクエストを送信できます。

```sh
# Credentials
aws_access_key_id=<Your AWS access key>
aws_secret_access_key=<Your AWS secret access key>

# Endpoint
region=us-west-2
service=bedrock

# Model
modelid=anthropic.claude-3-sonnet-20240229-v1:0

# 画像をBase64 Encodeする
IMAGE_PATH="<image path>"
IMAGE_MEDIA_TYPE="image/png"
BASE64_ENCODED_IMAGE=$(base64 -i "$IMAGE_PATH")

# Prompt Message をファイルに書き出す
echo '{
        "anthropic_version": "bedrock-2023-05-31", 
        "max_tokens": 2000,
        "messages": [
          {"role": "user", "content": [
            {"type": "image", "source": {
                "type": "base64",
                "media_type": "'$IMAGE_MEDIA_TYPE'",
                "data": "'$BASE64_ENCODED_IMAGE'"
            }},
            {"type": "text", "text": "Please describe the attached image."}     
        ]
      }
    ]
  }' > request.json

  awscurl --region "$region" --service "$service" \
  --access_key "$aws_access_key_id" \
  --secret_key "$aws_secret_access_key" \
  -H "Content-Type: application/json" \
  -X POST \
  --data @request.json \
  https://bedrock-runtime."${region}".amazonaws.com/model/"${modelid}"/invoke

```

結果
```json
{
   "id":"msg_01C1CYaAD372qJFCrVVfKGbr",
   "type":"message",
   "role":"assistant",
   "content":[
      {
         "type":"text",
         "text":"The image contains statistical data and a graph related to national medical expenditure in Japan. The top section provides an overview, explaining that national medical expenditure increased by 4.8% compared to the previous year, reaching 45,359 billion yen. The expenditure per person also increased by 5.3% to 357,800 yen.\n\nThe graph shows the trend of national medical expenditure in relation to the aging population over the years. The Y-axis represents the percentage, while the X-axis represents the year. The blue line depicts the year-over-year change in national medical expenditure against the total population, which has been steadily increasing, reaching around 9.0% in recent years.\n\nThe bottom section displays a detailed data table with various statistics related to national medical expenditure, including total expenditure, expenditure per person, and its relation to the gross domestic product (GDP) and the aging population ratio. The data covers multiple years, allowing for comparisons over time."
      }
   ],
   "model":"claude-3-sonnet-28k-20240229",
   "stop_reason":"end_turn",
   "stop_sequence":null,
   "usage":{
      "input_tokens":1597,
      "output_tokens":214
   }
}
```


## 参考リンク

- [Amazon Bedrock 公式ドキュメント](https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html)
- [awscurl GitHub リポジトリ](https://github.com/okigan/awscurl)