Amazon Bedrock の Batch Inference が GA になったから試したよ！

## 二番煎じですが…
実行時間も含めた多少は独自性のある記事にしてます。

https://qiita.com/maekawataiki/items/9f5dc0d83446e7bf55a9

公式アナウンスはこちら

https://aws.amazon.com/jp/about-aws/whats-new/2024/08/amazon-bedrock-fms-batch-inference-50-price/

オンデマンドのモデル呼び出しと比べると 50% 安いですね。

## Batch Inference is 何？

詳細はこちらですが、ざっくり私の解釈は、大量のリクエストをジョブという形で処理することで、スロットリングとか気にせずやりきれるサービスで、リクエストは予め S3 にあげておいて、ジョブ実行すると結果がまた S3 に吐き出されるものです。

https://docs.aws.amazon.com/bedrock/latest/userguide/batch-inference.html

## 使えるモデルとリージョン

https://docs.aws.amazon.com/bedrock/latest/userguide/batch-inference-supported.html

こちらにあります。
Oregon が mistral small 以外全部いけるます（mistral small は全リージョンいけない）。
が、あえてここでは東京リージョンの 3.5 sonnet で試してみます。どれくらいでさばいてくれるのか知りたかったので…。

## 事前準備

### 権限周り
詳細はこちら
https://docs.aws.amazon.com/bedrock/latest/userguide/batch-inference-prereq.html
ですが、公式では珍しく
> You can attach the AmazonBedrockFullAccess policy to grant the proper permissions to the role.
> (筆者訳) AmazonBedrockFullAccessポリシーを添付することで、ロールに適切な権限を付与することができます。
という記述があります。
FullAccess が適切！

もうちょい絞る方法もガイドされているので、ぜひご確認してください。

さておき、今回必要な IAM ユーザーもしくはロールは 2 つあります。

* Batch Inference (Create Model Invocation job API) を発行するリソースのユーザーないしロール
今回は ~~AdministratorAccess を持った~~適切な権限を持った IAM User でやりました。
* Batch Inference を実行するロール
こちらの詳細は後述です。

### データ準備
ひたすら公式 DOC を貼り付けているだけな気もしますが、念の為。

https://docs.aws.amazon.com/bedrock/latest/userguide/batch-inference-data.html

私の解釈を雑に

* JSONL 形式で S3 に保存する
* 各 line は各リクエストに相当
  * 各 Line には `recordId` という11文字の alphanumeric なキーをもたせると出力とケ島できる。無い場合は出力時に勝手に付与
  * `modelInput` というキーに各モデルごとのリクエストパラメータを含める

で、特にストーリー性をもたせる必要もないのですが、漫画の各タイトルを勉強したい人向けに、事前に LLM に漫画のタイトルを 200 程度列挙させ、そのタイトルについて 6 個の視点から Batch Inference で解説させます。
→ 200 x 6 = 1200 推論させます。

ちなみになんでこんなことをしているのかというと、バッチ推論の minimum 推論単位が 1000 のため、1000 以上のデータを作る必要があるのでした。

https://docs.aws.amazon.com/bedrock/latest/userguide/quotas.html

早速データを作ってみます。まずはおまじないから。

```python:test.ipynb
# まずはおまじない
import boto3
from tools import *
from pprint import pprint
import hashlib
import json
from io import BytesIO
import uuid
from time import sleep
sts = boto3.client('sts')
account = sts.get_caller_identity()['Account']
region = 'ap-northeast-1'

bucket_name = f'sagemaker-{region}-{account}'

brt = boto3.client('bedrock-runtime',region_name=region)
br = boto3.client('bedrock',region_name=region)
s3 = boto3.client('s3',region_name=region)
```

ここからデータの作成と加工です。
まずほしいのは漫画の列挙です。
列挙ということはリスト形式で漫画のタイトルを得られると良さそうです。
Converse API の tool use を使ってリスト形式で取得しましょう。

```python:test.ipynb
# データ作成
tools = []
tools.append(
    {
        "toolSpec": {
            "name": "describe_manga",
            "description": "与えられた漫画達をそれぞれ説明するツール",
            "inputSchema": {
                "json": {
                    "type": "object",
                    "properties": {
                        "manga_list": {
                            "type": "array",
                            "description": "説明させたい漫画達の配列",
                        }
                    },
                    "required": ["manga_array"],
                }
            },
        }
    }
)

response = brt.converse(
    system=[{'text': 'あなたは漫画について博識な AI です。'}],
    modelId='anthropic.claude-3-5-sonnet-20240620-v1:0',
    messages=[
        {
            "role": "user",
            "content": [{
                "text": '''これから漫画について学びたいです。
まずどんな漫画があるかを知りたいです。漫画の内容についてはツールを用意しているので、そのツールを使うために漫画のリストをあなたが知っている限り列挙してツールを呼び出してください。
目安200個は列挙してください。
数は多ければ多いほどいいです。
'''
            }]
        }
    ],
    toolConfig={"tools": get_tools()},
    inferenceConfig={
        "maxTokens": 4096,
        'temperature': 0
    },
)

contents = response["output"]['message']['content']
for content in contents:
    if 'toolUse' in content:
        manga_list = content['toolUse']['input']['manga_list']
        pprint(manga_list)
        break
```

```text:出力
['ワンピース',
 'ドラゴンボール',
 'ナルト',
 '鬼滅の刃',
 '進撃の巨人',
 'ブリーチ',
 …
  '転生したらスライムだった件',
 '盾の勇者の成り上がり',
 '無職転生',
 'ログ・ホライズン',
 'はたらく細胞']
```

今回はぴったり 200 の漫画を入手できました（実行によって変わります）
ここからプロンプト及びリクエストデータを作っていきます。

```python:test.ipynb
model_input_1 = [{'recordId':hashlib.sha256(manga.encode()).hexdigest()[:11],'modelInput':{'anthropic_version': 'bedrock-2023-05-31','messages' : [{'role':'user','content':[{'type':'text',
    'text':f'漫画の{manga}について解説してください。'}]}],'temperature':0,'top_p':0,'max_tokens':4096}} for manga in manga_list]
model_input_2 = [{'recordId':hashlib.sha256(manga.encode()).hexdigest()[:11],'modelInput':{'anthropic_version': 'bedrock-2023-05-31','messages' : [{'role':'user','content':[{'type':'text',
    'text':f'漫画の{manga}の作者について解説してください。'}]}],'temperature':0,'top_p':0,'max_tokens':4096}} for manga in manga_list]
model_input_3 = [{'recordId':hashlib.sha256(manga.encode()).hexdigest()[:11],'modelInput':{'anthropic_version': 'bedrock-2023-05-31','messages' : [{'role':'user','content':[{'type':'text',
    'text':f'漫画の{manga}が作られたころの時代背景について解説してください。'}]}],'temperature':0,'top_p':0,'max_tokens':4096}} for manga in manga_list]
model_input_4 = [{'recordId':hashlib.sha256(manga.encode()).hexdigest()[:11],'modelInput':{'anthropic_version': 'bedrock-2023-05-31','messages' : [{'role':'user','content':[{'type':'text',
    'text':f'漫画の{manga}のストーリーについて解説してください。'}]}],'temperature':0,'top_p':0,'max_tokens':4096}} for manga in manga_list]
model_input_5 = [{'recordId':hashlib.sha256(manga.encode()).hexdigest()[:11],'modelInput':{'anthropic_version': 'bedrock-2023-05-31','messages' : [{'role':'user','content':[{'type':'text',
    'text':f'漫画の{manga}に出てくるキャラクターについて解説してください。'}]}],'temperature':0,'top_p':0,'max_tokens':4096}} for manga in manga_list]
model_input_6 = [{'recordId':hashlib.sha256(manga.encode()).hexdigest()[:11],'modelInput':{'anthropic_version': 'bedrock-2023-05-31','messages' : [{'role':'user','content':[{'type':'text',
    'text':f'漫画の{manga}を読ませるおすすめの年齢について教えて下さい。'}]}],'temperature':0,'top_p':0,'max_tokens':4096}} for manga in manga_list]
model_input = model_input_1 + model_input_2 + model_input_3 + model_input_4 + model_input_5 + model_input_6
```

かなり不自然なところでインデントしていますが、漫画のタイトル自体の解説、作者についての解説、時代背景についての解説、などオーグメンテーションしました。

これで 200 x 6 = 1200 プロンプトの完成です。

## Amazon S3 にデータを上げる

今回は sagemaker のデフォルトバケットを利用しました。

```python:test.ipynb
bucket_name = f'sagemaker-{region}-{account}'
jsonl_data = '\n'.join(json.dumps(item, ensure_ascii=False) for item in model_input)
buffer = BytesIO(jsonl_data.encode('utf-8'))
file_name = 'input/model-input.jsonl'
s3.upload_fileobj(buffer, bucket_name, file_name)
print(f"{bucket_name}/{file_name}")
```

```text:出力
sagemaker-ap-northeast-1-{your_account}/input/model-input.jsonl
```

## 実行ロールを作る
~~コードを書くのがめんどいので~~簡単なのでマネコンでつくりました。

`bedrock-create-batch-invokation` というロールで、インラインポリシーで以下のようなポリシーを与えています。

```json
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "1",
			"Effect": "Allow",
			"Action": [
				"s3:GetObject",
				"s3:PutObject",
				"s3:ListBucket"
			],
			"Resource": [
				"arn:aws:s3:::sagemaker-*-*-*-{ACCOUNT}",
				"arn:aws:s3:::sagemaker-*-*-*-{ACCOUNT}/*"
			],
			"Condition": {
				"StringEquals": {
					"s3:ResourceAccount": "{ACCOUNT}"
				}
			}
		}
	]
}
```

trust relationships は以下です。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "Service": "bedrock.amazonaws.com"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "{your_account}"
                },
                "ArnEquals": {
                    "aws:SourceArn": "arn:aws:bedrock:*:{your_account}:model-invocation-job/*"
                }
            }
        }
    ]
}
```


## Batch Inference ジョブを発行

事前に 3.5 sonnet のモデルアクセスを有効化しておいてください。でないと、
`AccessDeniedException: An error occurred (AccessDeniedException) when calling the CreateModelInvocationJob operation: You don't have access to the model with the specified model ID.`
というエラーが出て弾かれます。

ジョブ発行のコードは以下です。

```python:test.ipynb
response = br.create_model_invocation_job(
    jobName=f'my-first-invocation-job-{uuid.uuid4()}',
    roleArn='arn:aws:iam::{your_account}:role/service-role/bedrock-create-batch-invokation',
    modelId='anthropic.claude-3-5-sonnet-20240620-v1:0',
    inputDataConfig={
        's3InputDataConfig': {
            's3InputFormat': 'JSONL',
            's3Uri': f's3://{bucket_name}/{file_name}'
        }
    },
    outputDataConfig={
        's3OutputDataConfig': {
            's3Uri': f's3://{bucket_name}/output/'
        }
    },
)
job_arn = response['jobArn']
```

## ジョブの実行を確認
ジョブなので時間がかかります。以下のコードでジョブの終了を待つことができます。
`get_model_invocation_job` でジョブの詳細を取得できるので、`Completed` になるまで待ちます。

```python:test.ipynb
while True:
    response = br.get_model_invocation_job(
        jobIdentifier=job_arn
    )
    if response['status'] in ['Completed','Failed','Stopped','PartiallyCompleted','Expired']:
        print(response)
        break
    sleep(60)
```

## 結果のダウンロード
完了したらデータをダウンロードしましょう。
同じく`get_model_invocation_job` でアウトプットのパスが取れるので S3 の URI を特定してダウンロードです。

```python:test.ipynb
s3OutputDataConfig = response['outputDataConfig']['s3OutputDataConfig']['s3Uri']
_, object_key = s3OutputDataConfig.replace('s3://', '').split('/', 1)
object_key = object_key + job_arn.split('/')[-1] + '/' + file_name.split('/')[-1] + '.out'
s3.download_file(bucket_name, object_key, 'output.jsonl')
```

## 中身確認

テキストファイルで開きます。

```output.jsonl
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画のワンピースについて解説してください。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_01BPUxMTd6B4j3YiXHicfbyw","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"「ワンピース」は、尾田栄一郎によって創作された日本の人気漫画シリーズです。1997年から連載が始まり、現在も続いている長期連載作品です。以下に主な特徴をまとめます：\n\n1. ストーリー：\n   主人公モンキー・D・ルフィが海賊王になることを目指し、仲間と共に冒険する物語。\n\n2. 世界観：\n   海賊が活躍する架空の世界で、様々な島々や文化が描かれています。\n\n3. キャラクター：\n   個性豊かな登場人物が多数登場し、それぞれに独自の能力や背景があります。\n\n4. 悪魔の実：\n   食べると超人的な能力を得られる果実で、物語の重要な要素の一つです。\n\n5. テーマ：\n   友情、冒険、夢の追求、正義などが主要なテーマとして扱われています。\n\n6. 人気：\n   世界中で高い人気を誇り、累計発行部数は4億5000万部を超えています。\n\n7. メディア展開：\n   アニメ、映画、ゲームなど、様々なメディアで展開されています。\n\n8. 影響力：\n   日本のポップカルチャーを代表する作品の一つとして国際的に認知されています。\n\n「ワンピース」は、その壮大な世界観と魅力的なキャラクター、そして感動的なストーリー展開で多くのファンを魅了し続けています。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":23,"output_tokens":469}},"recordId":"532d19d45f4"}
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画のドラゴンボールについて解説してください。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_01E9oLin4s9zR12g3mEU5Wsi","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"ドラゴンボールは、鳥山明によって創作された日本の漫画シリーズで、以下のような特徴があります：\n\n1. ストーリー：主人公・孫悟空の成長と冒険を描いた物語。\n\n2. 連載期間：1984年から1995年まで週刊少年ジャンプで連載。\n\n3. 世界観：中国の西遊記をモチーフにした独特のファンタジー世界。\n\n4. ドラゴンボール：7つ集めると願いが叶う魔法の球。\n\n5. キャラクター：悟空、ベジータ、フリーザなど個性豊かなキャラクターが登場。\n\n6. バトル：激しい格闘シーンと独特の必殺技が特徴。\n\n7. 変身：超サイヤ人などのパワーアップ形態が人気。\n\n8. メディア展開：アニメ、映画、ゲームなど幅広く展開。\n\n9. 国際的人気：世界中で愛されるグローバルな作品。\n\n10. 影響力：多くの後続作品に影響を与えた。\n\n11. テーマ：友情、努力、成長などポジティブなメッセージ性。\n\nドラゴンボールは、その独創的な世界観とキャラクター、迫力あるバトルシーンで、日本のみならず世界中で大きな人気を博した作品です。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":26,"output_tokens":437}},"recordId":"2cdc4a2b688"}
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画のナルトについて解説してください。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_012iKX2D5nqreGBD8m2uE3Rd","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"「NARUTO -ナルト-」は、岸本斉史によって創作された日本の漫画シリーズです。1999年から2014年まで「週刊少年ジャンプ」で連載され、その後アニメ化されて世界中で人気を博しました。以下に主な特徴を挙げます：\n\n1. ストーリー：\n忍者の世界を舞台に、主人公うずまきナルトが火影（村のリーダー）を目指す成長物語。\n\n2. 世界観：\n忍術や chakra（チャクラ）を使う忍者たちが活躍する独特の世界。\n\n3. キャラクター：\nナルト、サスケ、サクラを中心に、多彩なキャラクターが登場。\n\n4. テーマ：\n友情、努力、成長、平和などが主要テーマ。\n\n5. 忍術システム：\n独自の忍術体系が詳細に描かれている。\n\n6. 人気：\n国内外で大ヒットし、コミックスの累計発行部数は2億5000万部を超える。\n\n7. メディアミックス：\nアニメ、映画、ゲーム、舞台など多岐にわたる展開。\n\n8. 続編：\n「BORUTO -ボルト- NARUTO NEXT GENERATIONS」として物語が継続。\n\n「NARUTO」は、アクション、ドラマ、コメディを巧みに織り交ぜた作品で、幅広い年齢層に支持されています。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":22,"output_tokens":454}},"recordId":"566b933e9cb"}
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画の鬼滅の刃について解説してください。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_0191JDzXmPBLjTiBoE4bZHFM","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"「鬼滅の刃」は、吾峠呼世晴によって創作された日本の漫画作品です。以下にこの作品の主な特徴を簡潔に説明します：\n\n1. ストーリー：主人公の竈門炭治郎が、鬼に変えられた妹を人間に戻すため、そして鬼を退治するために戦う物語です。\n\n2. 舞台設定：日本の大正時代を背景としています。\n\n3. キャラクター：個性豊かな登場人物たちが魅力的で、それぞれが独自の呼吸法や技を持っています。\n\n4. テーマ：家族愛、友情、成長、そして人間性などが主要なテーマとして描かれています。\n\n5. 人気：漫画、アニメ、映画と幅広いメディアで展開され、国内外で大きな人気を博しました。\n\n6. 戦闘シーン：独特の呼吸法を用いた迫力ある戦闘シーンが特徴的です。\n\n7. アートスタイル：鮮やかな色彩と流麗な線で描かれた美しいビジュアルが印象的です。\n\nこの作品は、その独創的なストーリー展開と魅力的なキャラクター、そして深いテーマ性により、多くの読者・視聴者の心を捉えました。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":27,"output_tokens":422}},"recordId":"2a8cf1d0573"}
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画の進撃の巨人について解説してください。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_019VTSeRFNHskftKNE3ZLoch","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"「進撃の巨人」は諫山創によって描かれた日本の漫画作品で、2009年から2021年まで連載されました。物語は、巨人と呼ばれる人食い生物に支配された世界を舞台に展開します。\n\n主な特徴：\n\n1. 複雑な物語展開と深いテーマ性\n2. 独特な世界観と設定\n3. 緻密に描かれたキャラクター\n4. アクション性の高い戦闘シーン\n\n物語は、エレン・イェーガーを中心とした若い兵士たちの成長と戦いを描きつつ、人類の起源や自由の意味など、哲学的なテーマも探求しています。\n\n作品は国内外で大きな人気を博し、アニメ化やゲーム化など、様々なメディアミックス展開がなされました。その独創的な世界観と緊迫感のある展開は、多くの読者を魅了し、現代漫画の代表作の一つとして認識されています。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":26,"output_tokens":319}},"recordId":"2de30bcb28c"}
…
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画の転生したらスライムだった件を読ませるおすすめの年齢について教えて下さい。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_01BA1GJGygfxU7ZS8dFmv96x","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"「転生したらスライムだった件」は、一般的に10代後半から20代の読者層をターゲットにしていますが、内容によっては年齢制限が異なる場合があります。以下に、年齢別の推奨事項をまとめました：\n\n1. 12歳以上：\n軽めのファンタジー要素や冒険を楽しむことができます。ただし、一部の暴力描写や複雑な政治的要素は理解が難しい可能性があります。\n\n2. 15歳以上（推奨）：\nストーリーの大部分を理解し、楽しむことができる年齢です。キャラクター間の関係性や世界観をより深く理解できます。\n\n3. 18歳以上：\n作品に含まれる一部の成人向け要素（軽度の性的描写や暴力シーン）を適切に処理できる年齢です。\n\n注意点：\n- 個人の成熟度や経験によって、適切な年齢は異なる場合があります。\n- 保護者の方は、事前に内容を確認し、お子様に適しているかどうかを判断することをおすすめします。\n- 出版社や販売元が定める年齢制限がある場合は、それに従うことが重要です。\n\n最終的には、読者個人や保護者の判断に委ねられますが、一般的には15歳以上が適切な年齢だと考えられています。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":43,"output_tokens":435}},"recordId":"0e8adb9465c"}
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画の盾の勇者の成り上がりを読ませるおすすめの年齢について教えて下さい。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_017n9WKjVt2Abz4Tv8wUwbq2","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"「盾の勇者の成り上がり」は、その内容や主題から考えると、主に以下の年齢層におすすめできます：\n\n1. 中学生以上（13歳〜）：\n基本的には、中学生以上の読者向けと考えられます。ストーリーの複雑さや登場人物の心理描写を理解するには、ある程度の読解力が必要です。\n\n2. 高校生以上（15歳〜）がより適切：\n物語には暴力的な描写や、複雑な人間関係、社会的な問題などが含まれているため、高校生以上の読者の方がより深く作品を理解し、楽しむことができるでしょう。\n\n3. 保護者の判断：\n個々の子どもの成熟度や理解力によっては、中学生未満でも楽しめる可能性があります。ただし、その場合は保護者が内容を確認し、適切かどうか判断することをおすすめします。\n\n4. 成人向け要素：\n一部の巻では、より成人向けの要素（性的な描写など）が含まれることがあるため、18歳以上の読者向けとされる場合もあります。\n\n結論として、15歳以上（高校生以上）が最も適切な年齢層と言えますが、個々の成熟度や家庭の方針によって判断が必要です。また、出版社や販売元の年齢制限がある場合は、それに従うことが重要です。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":45,"output_tokens":450}},"recordId":"f8ce00180c1"}
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画の無職転生を読ませるおすすめの年齢について教えて下さい。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_01DEdGDjSsp4UWHjKZrNTW2k","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"「無職転生」は、その内容や主題の複雑さから、一般的に10代後半から大人向けの作品と考えられています。以下に、年齢別の考慮事項をまとめました：\n\n1. 15歳未満：\n- 性的な描写や暴力的なシーンがあるため、推奨されません。\n- 主人公の前世での行動や考え方が理解しづらい可能性があります。\n\n2. 15-17歳：\n- 親や保護者の判断によります。\n- 作品のテーマや内容を理解できる年齢ですが、一部の描写に注意が必要です。\n\n3. 18歳以上：\n- 作品の主題や複雑な人間関係、社会的な問題を十分に理解できる年齢です。\n- 性的な描写や暴力的なシーンにも対応できると考えられます。\n\n4. 20代以上：\n- 人生経験を積んでいるため、主人公の成長や葛藤により共感できる可能性があります。\n- 作品の深い意味や社会的な批評を十分に理解できます。\n\n結論として、「無職転生」は18歳以上の読者に最も適していると言えますが、個人の成熟度や価値観によっても異なる場合があります。親や保護者は、younger readers向けに内容を事前に確認することをお勧めします。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":37,"output_tokens":423}},"recordId":"da082570d91"}
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画のログ・ホライズンを読ませるおすすめの年齢について教えて下さい。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_01UubT5PtE3B8N8LSDXzJ1L8","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"ログ・ホライズンは、主に10代後半から20代前半の読者層をターゲットにしていますが、内容によっては年齢の低い読者にも適している部分があります。以下に、年齢別の推奨事項をまとめました：\n\n1. 12歳以上：\n- 基本的なストーリーラインを理解できる\n- ゲームの概念に親しみがある\n- 軽度の暴力描写を処理できる\n\n2. 15歳以上：\n- より複雑な政治的、社会的テーマを理解できる\n- キャラクター間の関係性をより深く理解できる\n- 中程度の暴力描写や軽度の性的な暗示を処理できる\n\n3. 18歳以上：\n- すべての内容を十分に理解し、楽しむことができる\n- より成熟したテーマや複雑な人間関係を深く考察できる\n\nただし、これはあくまで一般的なガイドラインです。個々の子供の成熟度や理解力によって、適切な年齢は異なる場合があります。保護者の方が内容を確認し、お子様の発達段階に合わせて判断することをお勧めします。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":41,"output_tokens":370}},"recordId":"ecce2bd8634"}
{"modelInput":{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":[{"type":"text","text":"漫画のはたらく細胞を読ませるおすすめの年齢について教えて下さい。"}]}],"temperature":0,"top_p":0,"max_tokens":4096},"modelOutput":{"id":"msg_bdrk_01RAGVEkvuTi4xZt2h41eugi","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"「はたらく細胞」は、幅広い年齢層に人気がある漫画ですが、おすすめの年齢は以下のように考えられます：\n\n1. 小学校高学年（10-12歳）以上：\n   - 基本的な生物学の概念を理解できる年齢\n   - 物語の展開を追うことができる\n\n2. 中学生（13-15歳）：\n   - より複雑な生物学的概念を理解できる\n   - キャラクター間の関係性や比喩表現を理解できる\n\n3. 高校生以上（16歳以上）：\n   - より深い生物学的知識を持っている\n   - 作品の科学的な側面をより深く理解できる\n\nただし、以下の点に注意が必要です：\n\n- 個人の成熟度や興味によって適切な年齢は変わる\n- 一部の医療や生物学的描写が若い読者には刺激が強い可能性がある\n- 保護者や教育者が内容を確認し、適切かどうか判断することが望ましい\n\n結論として、10歳以上であれば楽しめる作品ですが、読者の成熟度や興味に応じて判断することが重要です。また、教育的な観点からは、中学生以上がより深く作品を理解し、学習効果を得られる可能性が高いでしょう。"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":40,"output_tokens":420}},"recordId":"d974d25f462"}
```

しっかりと 1200 行の結果が取れました。
ちなみに、ap-northeast-1 で 3.5 sonnet で 1200 件処理するのに 3時間22分かかりました。
とすると、1分あたり6件程度処理したことがわかりました。リソースが空いているときにまわしているはずなのでこのくらいのスピード感なんでしょうね。
もう少しプロンプトを長くしたらもうちょっとかかるとは思います。

また、ジョブ実行中にS3のファイルを確認していたのですが、おそらく２０件ごとに S3 に結果をダンプしていたようでした。処理途中でも処理結果をできたところまで確認できるのは地味に嬉しいですね。

## おわりに

プロンプトを作って、実行して時間をはかる、というところまで行いました。東京リージョンでもできるのがとてもうれしかったですね（小並感