OpenAI の Batch API を使い、複数のリクエストをまとめて非同期に送信する方法を紹介します。コストは 50% 低く、通常とは別枠の大幅に高いレート制限が適用され、24 時間以内に処理が完了します。即時のレスポンスを必要としないジョブの処理に最適です。API リファレンスを直接確認することもできます。
概要
OpenAI Platform では、用途によって同期リクエストの送信が必要ですが、即時のレスポンスを必要としないケースや、レート制限によって大量のクエリを短時間で実行できないケースも数多くあります。バッチ処理は、次のようなユースケースで役立ちます。
- 評価の実行
- 大規模なデータセットの分類
- リポジトリ内のコンテンツの埋め込み生成
- 大規模なオフライン動画レンダリングジョブのキューへの追加
Batch API は、使いやすい一連のエンドポイントを提供します。複数のリクエストを 1 つのファイルにまとめ、バッチ処理ジョブを開始して実行できます。リクエストの実行中はバッチの状態を確認でき、完了すると結果をまとめて取得できます。
標準のエンドポイントを直接使用する場合と比べ、Batch API には次の利点があります。
- 優れたコスト効率: 同期 API と比べてコストが 50% 割引
- より高いレート制限: 同期 API と比べて大幅に余裕のある上限
- 短い処理時間: 各バッチは 24 時間以内に完了し、多くの場合はさらに短時間で完了
はじめに
1. バッチファイルの準備
バッチを開始するには、API への個々のリクエストの詳細を 1 行ずつ記述した .jsonl ファイルを用意します。現在利用できるエンドポイントは次のとおりです。
/v1/responses(Responses API)/v1/chat/completions(Chat Completions API)/v1/embeddings(Embeddings API)/v1/completions(Completions API)/v1/moderations(モデレーションガイド)/v1/images/generations(Images API)/v1/images/edits(Images API)/v1/videos(動画生成ガイド)
入力ファイルの各行の body フィールドには、呼び出すエンドポイントと同じパラメーターを指定します。各リクエストには一意の custom_id 値を含める必要があります。この値は、完了後に結果を参照するために使用できます。以下は、2 つのリクエストを含む入力ファイルの例です。各入力ファイルに含められるのは、単一のモデルへのリクエストのみです。
バッチでの動画生成には、次の条件が適用されます。
- 現在、バッチでサポートされているのは
POST /v1/videosのみです。 - 動画のバッチリクエストでは、マルチパートではなく JSON を使用する必要があります。
- マルチパートアップロードを使用する代わりに、アセットを事前にアップロードし、サポートされている形式のアセット参照をリクエストボディに渡してください。
- バッチで画像を参照して生成する場合は、
input_referenceを使用します。JSON リクエストでは、file_idまたはimage_urlを含むオブジェクトとしてinput_referenceを渡してください。 - バッチでは、参照動画の入力を含め、マルチパート形式の
input_referenceアップロードはサポートされていません。 - バッチで生成された動画は、バッチの完了後、最大
24時間ダウンロードできます。
/v1/moderations を対象とする場合は、すべてのリクエストボディに input フィールドを含めてください。バッチでは、omni-moderation-latest を使ったプレーンテキスト入力と、テキストまたは画像入力を含むコンテンツ配列を受け付けます。同期モデレーションエンドポイントと同様に、バッチワーカーは stream=true が設定されたリクエストを拒否します。
{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-3.5-turbo-0125", "messages": [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": "Hello world!"}],"max_tokens": 1000}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-3.5-turbo-0125", "messages": [{"role": "system", "content": "You are an unhelpful assistant."},{"role": "user", "content": "Hello world!"}],"max_tokens": 1000}}
モデレーションの入力例
テキストのみのリクエスト:
{
"custom_id": "moderation-text-1",
"method": "POST",
"url": "/v1/moderations",
"body": {
"model": "omni-moderation-latest",
"input": "This is a harmless test sentence."
}
}
テキストと画像を入力するリクエスト:
{
"custom_id": "moderation-mm-1",
"method": "POST",
"url": "/v1/moderations",
"body": {
"model": "omni-moderation-latest",
"input": [
{
"type": "text",
"text": "Describe this image"
},
{
"type": "image_url",
"image_url": {
"url": "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg"
}
}
]
}
}
base64 のデータを埋め込む代わりに、image_url でリモートアセットを参照することをお勧めします。
これにより、.jsonl ファイルのサイズをバッチのアップロード上限である 200 MB よりも十分に小さく保てます。
特にマルチモーダルのモデレーションリクエストで有効です。
2. バッチ入力ファイルのアップロード
ファインチューニング API と同様に、バッチの開始時に入力ファイルを正しく参照できるよう、まずファイルをアップロードする必要があります。Files API を使って .jsonl ファイルをアップロードしてください。
import fs from "fs";
import OpenAI from "openai";
const openai = new OpenAI();
const file = await openai.files.create({
file: fs.createReadStream("fixtures/batchinput.jsonl"),
purpose: "batch",
});
console.log(file);3. バッチの作成
入力ファイルのアップロードが成功したら、その入力ファイルの File オブジェクトの ID を使ってバッチを作成できます。ここでは、ファイル ID を file-abc123 とします。現在、処理の完了期限に設定できるのは 24h のみです。省略可能な metadata パラメーターでカスタムメタデータを指定することもできます。
import OpenAI from "openai";
const openai = new OpenAI();
const batch = await openai.batches.create({
input_file_id: "file-abc123",
endpoint: "/v1/chat/completions",
completion_window: "24h",
});
console.log(batch);このリクエストは、バッチのメタデータを含む Batch オブジェクトを返します。
{
"id": "batch_abc123",
"object": "batch",
"endpoint": "/v1/chat/completions",
"errors": null,
"input_file_id": "file-abc123",
"completion_window": "24h",
"status": "validating",
"output_file_id": null,
"error_file_id": null,
"created_at": 1714508499,
"in_progress_at": null,
"expires_at": 1714536634,
"completed_at": null,
"failed_at": null,
"expired_at": null,
"request_counts": {
"total": 0,
"completed": 0,
"failed": 0
},
"metadata": null
}
4. バッチの状態の確認
バッチの状態はいつでも確認できます。この操作でも Batch オブジェクトが返されます。
import OpenAI from "openai";
const openai = new OpenAI();
const batch = await openai.batches.retrieve("batch_abc123");
console.log(batch);Batch オブジェクトの状態は、次のいずれかになります。
| 稼働状況 | 説明 |
|---|---|
validating | バッチを開始する前に、入力ファイルを検証しています。 |
failed | 入力ファイルの検証に失敗しました。 |
in_progress | 入力ファイルの検証が成功し、バッチを実行しています。 |
finalizing | バッチが完了し、結果を準備しています。 |
completed | バッチが完了し、結果を取得できます。 |
expired | 24 時間の制限時間内にバッチを完了できませんでした。 |
cancelling | バッチをキャンセルしています(最大 10 分かかる場合があります)。 |
cancelled | バッチはキャンセルされました。 |
5. 結果の取得
バッチが完了したら、Batch オブジェクトの output_file_id フィールドを使って Files API にリクエストを送信し、出力をダウンロードできます。取得した出力は、お使いのマシン上のファイル(この例では batch_output.jsonl)に書き込みます。
import OpenAI from "openai";
const openai = new OpenAI();
const fileResponse = await openai.files.content("file-xyz123");
const fileContents = await fileResponse.text();
console.log(fileContents);出力の .jsonl ファイルには、入力ファイル内の成功したリクエスト行ごとに、レスポンスが 1 行ずつ含まれます。バッチ内で失敗したリクエストのエラー情報は、バッチの error_file_id から取得できるエラーファイルに書き込まれます。
/v1/videos の場合、完了したバッチの結果には、completed、failed、expired などの終端状態にすでに達した動画オブジェクトが含まれます。返された動画 ID を使って、バッチ完了直後に最終的なアセットをダウンロードできます。
出力行の順序は、入力行の順序と 一致しない場合があります 。 結果を処理する際は、行の順序に頼らず、custom_id フィールドを使用してください。 このフィールドは出力ファイルの各行に含まれており、 入力のリクエストと出力の結果を対応付けることができます。
{"id": "batch_req_123", "custom_id": "request-2", "response": {"status_code": 200, "request_id": "req_123", "body": {"id": "chatcmpl-123", "object": "chat.completion", "created": 1711652795, "model": "gpt-3.5-turbo-0125", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Hello."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 22, "completion_tokens": 2, "total_tokens": 24}, "system_fingerprint": "fp_123"}}, "error": null}
{"id": "batch_req_456", "custom_id": "request-1", "response": {"status_code": 200, "request_id": "req_789", "body": {"id": "chatcmpl-abc", "object": "chat.completion", "created": 1711652789, "model": "gpt-3.5-turbo-0125", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Hello! How can I assist you today?"}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 20, "completion_tokens": 9, "total_tokens": 29}, "system_fingerprint": "fp_3ba"}}, "error": null}
出力ファイルは、バッチ完了から 30 日後に自動的に削除されます。
6. バッチのキャンセル
必要に応じて、実行中のバッチをキャンセルできます。バッチのステータスは cancelling に変わり、処理中のリクエストが完了するまで(最大 10 分間)その状態が続きます。その後、ステータスは cancelled に変わります。
import OpenAI from "openai";
const openai = new OpenAI();
const batch = await openai.batches.cancel("batch_abc123");
console.log(batch);7. すべてのバッチの一覧取得
すべてのバッチはいつでも確認できます。バッチが多数ある場合は、limit と after パラメーターを使って、結果をページに分けて取得できます。
import OpenAI from "openai";
const openai = new OpenAI();
const list = await openai.batches.list();
for await (const batch of list) {
console.log(batch);
}対応モデル
Batch API は OpenAI のほとんどのモデルで利用できますが、すべてのモデルが対応しているわけではありません。使用するモデルが Batch API に対応しているかどうかは、モデルのリファレンスドキュメントで確認してください。
レート制限
Batch API のレート制限は、既存のモデルごとのレート制限とは別に設定されています。Batch API には、次の 3 種類のレート制限があります。
- バッチごとの制限: 1 つのバッチには最大 50,000 件のリクエストを含めることができ、バッチ入力ファイルのサイズは最大 200 MB です。なお、
/v1/embeddingsのバッチでは、バッチ内の全リクエストに含まれる埋め込み入力の合計も最大 50,000 件に制限されます。 - モデルごとのキュー内プロンプトトークン数: 各モデルには、バッチ処理のキューに追加できるプロンプトトークン数の上限があります。これらの上限は、プラットフォームの設定ページで確認できます。
- バッチ作成のレート制限: 1 時間あたり最大 2,000 個のバッチを作成できます。さらに多くのリクエストを送信する必要がある場合は、バッチあたりのリクエスト数を増やしてください。
現在、Batch API には出力トークン数の制限はありません。Batch API のレート制限は新たに設けられた独立した枠のため、 Batch API を使用しても、通常のモデルごとのレート制限のトークン枠は消費されません。そのため、OpenAI の API へのリクエスト数や処理できるトークン数を手軽に増やせます。
バッチの期限切れ
制限時間内に完了しなかったバッチは、最終的に expired 状態に移行します。そのバッチ内の未完了のリクエストはキャンセルされ、完了したリクエストのレスポンスはバッチの出力ファイルから取得できます。完了したリクエストで消費されたトークンには料金が発生します。
期限切れのリクエストは、以下に示すメッセージとともにエラーファイルに書き込まれます。custom_id を使って、期限切れになったリクエストのデータを取得できます。
{"id": "batch_req_123", "custom_id": "request-3", "response": null, "error": {"code": "batch_expired", "message": "This request could not be executed before the completion window expired."}}
{"id": "batch_req_123", "custom_id": "request-7", "response": null, "error": {"code": "batch_expired", "message": "This request could not be executed before the completion window expired."}}