2024年4月にOpenAIの新機能として、Batch APIがリリースされました。本記事では、Batch APIの概要・実際の操作方法・レート制限について説明します。
Batch APIについて
概要
OpenAIのBatch APIでは、リクエストを24時間以内で非同期処理する代わりに、通常の50%の価格でOpenAIの各種エンドポイントを利用することができます。
また、通常の同期処理のAPIの場合には、時間当たりのリクエスト数やトークン数に対してレート制限が設けられていますが、Batch APIではレート制限が大きく緩和されています。レート制限の詳細ついては、本記事の最後に紹介します。
※2024/05/20時点でBatch APIはOpenAIのみで提供されている機能で、Azure OpenAI Serviceでは提供されていません。
Batch APIを使用すべき場面
即時応答(同期処理)が不要な多くの場面では、コストとレート制限の観点からBatch APIを利用した方が良いことになります。
具体的には以下のシーンでは、即時の応答が不要であり、レート制限の制約を受けずに大量のリクエストを処理したいため、Batch APIの使用が適しています。
- テキストや画像形式の大量のデータセットを、GPTを使用して分類する
- RAGアーキテクチャ等で、手持ちのドキュメントをベクトル検索できるように、ベクトル(埋め込み)に変換する
- チャットシステムの回答精度を多くのテストデータで評価する
Batch APIに対応しているエンドポイント
Batch APIで処理を指定できるのは、現状では以下のエンドポイントのみになります。
/v1/chat/completions
/v1/embeddings
/v1/completions
つまり、Batch APIはOpenAIのAssistant API・画像生成系AI・音声系AI等には対応していません。
Batch APIを実際に使ってみる
全体の流れ
Batch APIの使用の流れを簡単にまとめると、以下のようになります。
- 複数のリクエストを1つにまとめたバッチファイルを作成する。
- バッチファイルをOpenAIにアップロードする。
- アップロードしたバッチファイルを指定して、バッチジョブを開始する。
- バッチジョブの実行状況を確認して、完了を待つ。
- バッチジョブが完了した後、結果を取り出す。
以降では、PythonでBatch APIを利用する手順を説明します。
使用方法や仕様に関して、以下のドキュメントを参考にしました。
- https://platform.openai.com/docs/guides/batch/getting-started
- https://platform.openai.com/docs/api-reference/batch
- https://cookbook.openai.com/examples/batch_processing
操作方法
jsonl形式のバッチファイルを作成する
まずは、バッチジョブとしてBatch APIに渡す.jsonl
形式のバッチファイルを作成します。
今回は/v1/chat/completions
エンドポイントを使用する想定で、以下のバッチファイルを作成しました。
{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-3.5-turbo-0125", "messages": [{"role": "system", "content": "あなたはレストランのユーザーレビューがポジティブかネガティブかを判断するAIです。ユーザー入力の内容がポジティブな場合は'positive', ネガティブな場合は'negative'とだけ返答してください。"},{"role": "user", "content": "料理がとても美味しかったです。"}]}} {"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-3.5-turbo-0125", "messages": [{"role": "system", "content": "あなたはレストランのユーザーレビューがポジティブかネガティブかを判断するAIです。ユーザー入力の内容がポジティブな場合は'positive', ネガティブな場合は'negative'とだけ返答してください。"},{"role": "user", "content": "店内BGMの音量が大きく、声が聞こえにくかったです。"}]}}
バッチファイル内のそれぞれの行が、対象のエンドポイントに渡すリクエストになります。つまり、上記のバッチファイルには2つのリクエストが含まれていることになります。
リクエスト内容としては、あるレストランに対するユーザーレビューが高評価か低評価かをGPTに判断させるものです。実際に分類や精度評価を行う場合には、Fucntion calling機能を用いて出力フォーマットを調整すると思いますが、今回はサンプルなのでそこまで凝ったことはしていません。
バッチファイル内の各リクエストのパラメータは、以下のような設定をする必要があります。
パラメータ | 説明 |
---|---|
custom_id |
バッチファイル内のそれぞれリクエストに一意のIDを振る必要があります。 |
method |
処理を投げるエンドポイントへのHTTPリクエストメソッドです。現在対応している3つのエンドポイントではPOST を指定します。 |
url |
前述のBatch APIに対応しているエンドポイントのいずれかを指定します。後続のBatch APIへのリクエストの際にも全体で使用するエンドポイントを1つ指定します。それと一致させるように、1つのバッチ内ではすべて同一のエンドポイントを指定する必要があるようです。 |
body |
url で指定したエンドポイントに通常の同期処理のリクエストを投げる場合と同じパラメータを指定します。 |
実際にはバッチジョブで大量のリクエストを送る前に、同期処理のAPIでいくつかリクエストを投げて、概ね期待する結果が返ってくることを確認してからBatch APIは利用しましょう。
OpenAI CookbookではpandasのDataFrameからバッチファイルを作成し、Batch APIにリクエストを投げるサンプルコードが紹介されていますので、実際の運用でBatch APIを利用する際の参考になります。
バッチファイルをFiles APIでアップロードする
Assistants APIやFine-tuning APIでファイルをアップロードする場合と同様に、Files APIを使用して先ほど作成したバッチファイルをアップロードします。この際、purpose
パラメータをbatch
にする必要があります。
batch_input_file = client.files.create( file=open("batch_tasks.jsonl", "rb"), purpose="batch" )
バッチジョブを送信する
実際にバッチジョブを作成するには、アップロードしたバッチファイルのIDを指定する形でBatch APIに対してリクエストを投げます。
batch_job = client.batches.create( input_file_id=batch_input_file.id, endpoint="/v1/chat/completions", completion_window="24h", metadata={ "description": "レストランレビュー分析ジョブ" } )
指定するパラメータは以下の通りです。
パラメータ | 説明 |
---|---|
input_file_id |
Files APIでファイルをアップロードした際に返されるファイルIDを指定します。 |
endpoint |
Batch APIに対応しているエンドポイントのいずれかを一つ指定します。バッチファイル内のリクエストのurl パラメータと一致させます。 |
completion_window |
現状24h のみが指定できます。 |
metadata (任意) |
任意でメタデータを設定できます。 |
バッチジョブのステータスを確認する
バッチジョブの作成後は、その実行状況を確認することができます。以下のようにバッチジョブのIDを渡すことで、最新のステータスを取得できます。
batch_job = client.batches.retrieve(batch_job.id)
レスポンスのstatus
パラメータが実行状況を表しています。
statusの値 | 意味 |
---|---|
validating | バッチ開始前で、入力バッチファイルを検証中です。 |
failed | 入力バッチファイルの検証で失敗しました。 |
in_progress | 入力バッチファイルが正常に検証され、バッチが現在実行中です。 |
finalizing | バッチが完了し、結果が準備されています。 |
completed | バッチが完了し、結果が準備完了しています。 |
expired | バッチが24時間以内に完了できませんでした。 |
cancelling | バッチのキャンセルが開始されました。 |
cancelled | バッチがキャンセルされました。 |
結果を受け取る
バッチジョブのステータスがcompleted
になっていることを確認できたら、実行結果を取得します。
以下のコードで、結果を取得して、jsonlファイルとして出力します。
# 実行結果の取得 content = client.files.content(batch_job.output_file_id).content # jsonlファイルとして保存 with open('output.jsonl', 'wb') as file: file.write(content)
今回の実行結果は以下のようになっていました。*
で一部情報はマスクしています。
{"id": "batch_req_*************************", "custom_id": "request-1", "response": {"status_code": 200, "request_id": "******************************", "body": {"id": "chatcmpl-****************************", "object": "chat.completion", "created": 1716188983, "model": "gpt-3.5-turbo-0125", "choices": [{"index": 0, "message": {"role": "assistant", "content": "positive"}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 110, "completion_tokens": 1, "total_tokens": 111}, "system_fingerprint": null}}, "error": null} {"id": "batch_req_*************************", "custom_id": "request-2", "response": {"status_code": 200, "request_id": "******************************", "body": {"id": "chatcmpl-****************************", "object": "chat.completion", "created": 1716188983, "model": "gpt-3.5-turbo-0125", "choices": [{"index": 0, "message": {"role": "assistant", "content": "negative"}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 121, "completion_tokens": 1, "total_tokens": 122}, "system_fingerprint": null}}, "error": null}
同期処理のAPIの場合と同じスキーマで、body
パラメータにレスポンスが含まれています。
Batch APIのレート制限の詳細
最後にBatch APIのレート制限について説明します。
Batch APIのレート制限は、OpenAIの他のAPIとは異なるルールになっています。以下2つの制限があります。
Per-batch limits(バッチごとの制限)
1つのバッチに含まれる最大リクエスト数は50,000であり、入力バッチファイルのサイズは最大で100MBになります。
つまり、複数のバッチに分割すれば、リクエスト数に上限は存在しません。
Enqueued prompt tokens per model(モデルごとの待機状態のプロンプトトークン数)
バッチ処理待ちのキューに待機できる入力トークン数の合計には、モデルごとに上限値(Batch Queue Limit)があります。処理が完了したバッチジョブの入力トークン数は、カウントから除外されます。
各モデルの上限値(Batch Queue Limit)は、Usage tiersによって異なります。例えば、Tier1では各モデルの上限値は以下のようになっています。
モデル | Batch Queue Limit |
---|---|
gpt-4o | 90,000 |
gpt-4-turbo | 90,000 |
gpt-4 | 100,000 |
gpt-3.5-turbo | 200,000 |
text-embedding-3-large | 3,000,000 |
text-embedding-3-small | 3,000,000 |
text-embedding-ada-002 | 3,000,000 |
詳細は以下の参考ドキュメントをご確認ください。
- https://platform.openai.com/docs/guides/batch/rate-limits
- https://platform.openai.com/docs/guides/rate-limits/rate-limits
最後に
テキストの分析やチャットシステムの回答精度評価を実施する際に、連続でリクエストを送信することでトークン数の制限を受けることや、コストの増大を今までは心配していました。
特に前者の問題は、実装工夫したり、レート制限の上限値を引き上げることで解決していたと思います。Batch APIの登場によって、これらの問題は大きく軽減されました。
今後は、Batch APIを前提としたデータパイプラインの設計が求められると考えていますので、その方向性で検証を進めていきたいです。