Anthropic APIのベータ機能をお試し（キャッシュ、バッチ）

Anthropicが提供するAPIに10/18時点で２つのベータ機能があります

* Prompt Caching

https://www.anthropic.com/news/prompt-caching

* Message Batches

https://www.anthropic.com/news/message-batches-api

この２つを試してみました。

## Prompt Caching

ドキュメント： https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching

プロンプトをキャッシュしてくれる機能です。キャッシュから読み取ることで、通常の入力トークンより安く使える仕組みです。

:::note
常に同じ内容で送信するシステムプロンプトや、ツール定義に使用すると効果がありそうです。
:::

SDKを使うと簡単に実行できます。

通常のメッセージ送信とはこれらの点が異なります。

* HTTPヘッダーに`"anthropic-beta": "prompt-caching-2024-07-31"`が必要
* `client.beta.messages.create`を使用
* キャッシュさせたいプロンプトに`"cache_control": {"type": "ephemeral"}`を付与

```python
from anthropic import Anthropic

client = Anthropic(
    api_key=api_key,
    default_headers={"anthropic-beta": "prompt-caching-2024-07-31"},
)

model = "claude-3-haiku-20240307"

message = client.beta.messages.create(
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "キャッシュさせるプロンプト",
                    "cache_control": {"type": "ephemeral"},
                },
                {
                    "type": "text",
                    "text": "キャッシュさせないプロンプト",
                },
            ],
        }
    ],
    model=model,
)
print(message.usage)
print(message.content)
```


「キャッシュさせる」「キャッシュから読み取る」は、別々の操作があるわけではありません。キャッシュにあればキャッシュから読み取り、キャッシュになければキャッシュさせる動作になるようです。

そのため、上記リクエストの1回目は「キャッシュさせる」動作となり、全く同じリクエストを２回目に送信すると「キャッシュから読み取る」動作になります。

## Message Batches

ドキュメント： https://docs.anthropic.com/en/docs/build-with-claude/message-batches

複数のメッセージをバッチでまとめて処理を行う仕組みです。リアルタイムでの返答は得られませんが、料金が50%オフになります。

:::note
RAG用のドキュメント整形などに使えそうです。
:::

:::note
バッチ処理はBedrockでも提供されています。
https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/batch-inference.html
:::

こちらもSDKが対応済みです。

* `client.beta.messages.batches`を使用
* requestsのなかに複数メッセージを格納して送信
* custom_idは後で入力と出力の紐づけに使用


```python
from anthropic import Anthropic

client = Anthropic(
    api_key=api_key,
)

batches_response = client.beta.messages.batches.create(
    requests=[
        {
            "custom_id": f"id_{n}",
            "params": {
                "model": model,
                "max_tokens": 1024,
                "messages": [
                    {
                        "role": "user",
                        "content": [
                            {
                                "type": "text",
                                "text": doc,
                            },
                        ],
                    }
                ],
            },
        }
        for n, doc in enumerate(batch_doc)
    ]
)
```

バッチ処理のステータスを`retrieve`APIを使ってチェックします。
ステータスが変わるまで定期的に実行します。

```python
message_batch = client.beta.messages.batches.retrieve(
    batches_response.id,
)

while message_batch.processing_status == "in_progress":
    import time

    time.sleep(5)

    message_batch = client.beta.messages.batches.retrieve(
        batches_response.id,
    )
```

処理が完了したら、結果を取得します。

```python
batch_results = client.beta.messages.batches.results(batches_response.id)

for result in batch_results:
    print(result.to_dict())
```

## Prompt CachingとMessage Batchesを同時に使う

同時に使う場合はこのようになります

* `client.beta.messages.batches`をつかう
* `betas=["prompt-caching-2024-07-31"]`パラメーターを指定する
* メッセージの中でキャッシュさせたいものに`"cache_control": {"type": "ephemeral"}`を付与する

```diff_python
  client.beta.messages.batches.create(
+     betas=["prompt-caching-2024-07-31"], 
      requests=[
          {
              "custom_id": f"id_{n}",
              "params": {
                  "model": model,
                  "max_tokens": 1024,
                  "messages": [
                      {
                          "role": "user",
                          "content": [
                              {
                                  "type": "text",
                                  "text": doc,
+                                 "cache_control": {"type": "ephemeral"}
                              },
                          ],
                      }
                  ],
              },
          }
          for n, doc in enumerate(batch_doc)
      ]
  )
```

## まとめ

Bedrockでもキャッシュがほしい