AWSのAIモデル Amazon Nova Lite で遊んでみる

個人利用でも安く使えそうな生成AIモデルのAmazon Nova Lite と Nova Micro が登場したので遊んでみた。AWSではなく外部のKagoya 仮想サーバー（Ubuntu 22.04）で実行します。アプリはPythonコードで書きます。

## Amazon Nova モデル概要
詳しくはAWS公式サイトを見るとして、ひと言で概要と料金は下記。
| モデル | できること | 料金 |
|:---:|:---:|:---:|
| **Nova Lite** | 文書解析や質問応答などテキスト生成 | 1,000トークンあたり 入力 \\$0.00006 出力 \\$0.00024 |
| **Nova Micro** | テキスト専用 | 1,000トークンあたり 入力 \\$0.000035 出力 \\$0.00014 |
| **Nova Canvas** | 高品質な画像生成 | 1024x1024まで 画像１枚あたり \\$0.04 |
| **Nova Reel** | 短いビデオ動画生成 | 720p, 24fps 動画１秒あたり \\$0.08 |

## Amazon Nova モデルの準備
今回やった手順。あれこれあるけどがんばれー。
1. **AWSアカウントの新規開設**（個人でAWSを使うため）
2. **AWS SDK のインストール**（UbuntuでAWSコマンドを使うため）
3. **アプリ用のIAMユーザー作成**（pythonアプリが人に代わってAWSにアクセスするため）
4. **Amazon Bedrock の有効化**（生成AIを使うため）
5. **AIモデル［Nova Lite］の有効化**（AIモデルを選ぶ）
6. **Pythonコードを書いて生成AIを実行**（遊んで理解するため）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/ff19aa65-a21b-118c-1ebc-31eeb4ffe181.png)


### 1. AWSアカウントの新規開設
メールアドレスとクレジットカードを用意してサインアップ（以降、省略）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/cae22ec7-f0dc-62d8-70fa-e59a43976fdf.png)

### 2. AWS SDK のインストール
Ubuntuサーバーにログインして自分のユーザーでコマンドを実行

```
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install

インストールできたことを検査
$ aws --version
```

### 3. アプリ用のIAMユーザー作成
ここで一旦、AWSマネジメントコンソールに戻って IAMユーザー作成, アクセスキー作成, 許可ポリシーを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/d010598d-3240-fa5a-6780-3584e282794d.png)

Ubuntuサーバーに戻って aws 環境にアクセスできるように認証する

```
$ aws configure

AWS Access Key ID [None]:
# 作成したアクセスキーをコピペしてEnter

AWS Secret Access Key [None]:
# 作成したシークレットキーをコピペしてEnter

Default region name [None]: 
# 東京リージョンならap-northeast-1を入力してEnter

Default output format [None]: 未入力
# CLIの結果出力text,json,tableのいずれかを入力してEnter

登録できたか検査するには
$ cat ~/.aws/credentials
```

### 4. Amazon Bedrock , 5. AIモデル［Nova Lite］の有効化
Amazon Bedrock で使うAIモデルを選ぶ（リクエストする）
2025年1月時点では**Novaはバージニア北部リージョン(us-east-1)でのみ利用可能**です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/497becf3-ce58-ba3f-abce-b7a6915a2de0.png)

### 6. Pythonコードを書いて生成AIを実行
さあ、やっとUbuntuでpythonコードを書くよ。
その前に、正しく aws cli で redrock の Nova Lite を実行できることをCLIコマンドで検査します。生成したテキストはinvoke-model-output.txtに出力される。

```
実行するコマンド（プレイグランドのAPIをコピペしたもの）

$ aws bedrock-runtime invoke-model \
--model-id amazon.nova-lite-v1:0 \
--body "{\"messages\":[{\"role\":\"user\",\"content\":[{\"text\":\"りんご飴の材料を教えて\"}]}],\"inferenceConfig\":{\"maxTokens\":512,\"stopSequences\":[],\"temperature\":0.7,\"topP\":0.9}}" \
--cli-binary-format raw-in-base64-out \
--region us-east-1 \
invoke-model-output.txt
```

``` 
結果 $ cat invoke-model-output.txt

{"output":{"message":{"content":[{"text":"りんご飴は、主に以下の材料で作られます。以下は
～略～
なりんご飴を作ることができます。"}],"role":"assistant"}},"stopReason":"end_turn","usage":{"inputTokens":13,"outputTokens":509,"totalTokens":522}}
```


## テキストを生成して遊ぶ

生成するテキストに与えるパラメーター
- content
  - text: 会話ターンのテキスト
- inferenceConfig
  - maxTokens: 生成するトークンの最大数
  - stopSequences: リスト文字列のいずれかを生成すると生成を停止する
  - temperature: ランダム性の量(0.00001~1.0, デフォルト0.7)
  - topP: 生成するテキストのランダム性。この確率が全体の割合を占める(0.0~1.0, デフォルト0.9)

pythonコード

``` bedrock.py
import sys
import boto3
import json
from botocore.exceptions import ClientError

# Bedrock runtime client の作成, Nova Lite モデルを使う。バージニア北部リージョンで利用可能 
bedrockRuntime = boto3.client("bedrock-runtime", region_name="us-east-1")
MODEL_ID = "amazon.nova-lite-v1:0"

def runjob( prompt ):
    # モデルのネイティブ構造を使ってリクエストする
    requestPayload = {
        "messages": [
            {
                "role": "user",
                "content": [
                    {"text": prompt}
                ]
            }
        ],
        "inferenceConfig": {
            "maxTokens": 512, 
            "stopSequences": [],
            "temperature": 0.7,
            "topP": 0.9
        }
    }

    # リクエスト実行
    try:
        response = bedrockRuntime.invoke_model(
            modelId = MODEL_ID,
            body = json.dumps( requestPayload ),
            contentType = "application/json"
        )

        # generated_text の取得と表示 
        responseBody = json.loads( response['body'].read() )
        generatedText = responseBody['output']['message']['content'][0]['text']
        print( generatedText )

    except (ClientError, Exception) as e:
        print(f"ERROR: 実行できません '{MODEL_ID}', Reason: {e}")
        exit(1)

if __name__ == "__main__":
    # プロンプト入力例
    if len(sys.argv) < 2:
        print("書式$ python3 bedrock.py 'ここに質問をテキストで記載する'")
        sys.exit(1)
    else:
        prompt = sys.argv[1]
        print( prompt )
        runjob( prompt )
```

コードのアップデートはgithubに置く
https://github.com/IchiroKano/aws-nova

### 実行してみる
今日は新年2日目なので、今年の干支を確認しよう。

```
$ python3 bedrock.py 今年の干支は何？
西暦2023年は、「午年」（うまどし）です。西暦2024年は、「龍年」（たつどし）です。

$ date
Thu Jan  2 11:01:22 AM JST 2025
```
おっと、少し質問の情報が足りなかったのかな。今度は数字を加えて、もう一度質問する。

```
$ python3 bedrock.py 2025年は十二支でいうと何年？

2025年は丑（うし、う）年です。十二支の12番目で、前年は2024年が寅（とら、とろ）年、
```
いや、ちょっと待て。どこの情報だそれ。

```
$ python3 bedrock.py 2024年は辰年でした。2025年の干支は何？

2024年は辰年（みつごどし）でした。
干支は10年ごとに一巡します。つまり、辰年（2024年）から10年後には再び辰年になります。
2025年は次の干支になります。
1. 2024年：辰年
2. 2025年：巳年
したがって、2025年は巳年（みどし）です。
```
そういえばAI信頼性の注意を記載しなきゃ。
**「本記事は生成AIが生成するテキストを掲載しています。書かれている内容には虚偽が含まれている可能性がありますので、必ず根拠や裏付けを自ら確認するようにしてください」**

正確な回答を得られるであろう質問をして終わろうかな

```
$ python3 bedrock.py 日本一高い山はどの山？

日本一高い山は富士山ではなく、北海道の旭岳です。標高は2,290メートルで、
日本で最も高い山とされています。
富士山は有名な山ですが、その標高は約3,776メートルで、日本で二番目に高い山です。
富士山は日本を象徴する山として知られており、世界文化遺産にも登録されていますが、
実際には旭岳の方が高いのです。
```
おーい、ちょっと待て。パラメーター間違えているのか!?
念のためプレイングラウンドでも検査してみる「日本一高い山はどの山？」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/cbe3f01b-2da0-6c8c-8f3b-bc158214b736.png)

標高を比べればわかりそうだけど...
質問「富士山と旭岳のどちらが高い？」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/c896e249-a22a-7c1e-0d49-cde4a3124f27.png)

うーん。グローバルな質問ならどうかな。

```
$ python3 bedrock.py 世界一長い川はどこ？

世界一長い川は、ナイル川です。ナイル川はアフリカ大陸を流れ、エジプトを通って
地中海に注ぐ川で、全長約6,650キロメートルといわれています。

しかし、世界一長い川については議論があります。アマゾン川も世界最長の川として
議論されることがあります。アマゾン川の長さは約6,400キロメートルといわれていますが、
源流の位置によってはナイル川を上回る長さになることもあります。

世界一長い川については、はっきりとした定義がなく、測定方法によっても長さが異なるため、
議論があります。日本では一般的にナイル川が世界一長い川として紹介されていることが多いです。
```
大丈夫、合っている。生成したテキストの正確性は要調査だな。

## 便利だと思ったこと
AWSマネージメントコンソールにログインして Bedrock のプレイグラウンドでは、GUI画面で Novaなどのモデルを試すことができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/657cd888-ecd7-7667-a315-53bf447a9930.png)

この時、APIリクエストを表示するを選ぶと pythonコードを書く時にパラメータを指定すべき情報が表示されるので便利。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189936/874d62fb-a4c5-22eb-4644-3b35acc35abc.png)

ここら辺のコードに反映する

```
    # モデルのネイティブ構造を使ってリクエストする
    requestPayload = {
        "messages": [
            {
                "role": "user",
                "content": [
                    {"text": prompt}
                ]
            }
        ],
        "inferenceConfig": {
            "maxTokens": 512,
            "stopSequences": [],
            "temperature": 0.7,
            "topP": 0.9
        }
    }

    # リクエスト実行
    try:
        response = bedrockRuntime.invoke_model(
            modelId = MODEL_ID,
            body = json.dumps( requestPayload ),
            contentType = "application/json"
        )
```

## まとめ
AWSアカウントを新規開設してからPythonコードで生成したテキストを得るまでに6時間くらい。出力したテキストの正確性が気になるなー。今回はVPCやEC2/LambdaなどのAWSコンピュートリソースは使わず、AWS外部の仮想サーバーを使った。つまりオンプレミスのサーバーでも AWS Bedrock 生成AIを活用できることを理解した。昨年はTinyBERTなど何度も作っては壊しして生成AIの構築に時間かかってたけど、今年はBedrockを遊んで学ぶことにする。