😎

【OpenAI】Batch APIでコストを抑えて大量処理する

に公開

Batch API

OpenAIのBatch APIは、非同期で大量のリクエストをまとめて送ることができるAPIです。

処理結果がすぐに返ってこない代わりに、費用が半額ほどに抑えられるので、大量に処理したい & 急ぎではない といった場面では使用しています。

項目 内容
入力ファイルサイズ上限 200MB
リクエスト数上限 50,000件
対応エンドポイント /v1/chat/completions
/v1/embeddings
/v1/completions
/v1/responses
処理時間 最大24時間
出力保持期限 30日間
  • Batch API ユースケース例
    • 1,000件のテキストに対して「これは質問文かどうか?」を判定したい
    • 5,000件の製品説明文をembedding化してベクトルDBに登録したい
    • GPTで生成したコンテンツの品質評価タスクを大量に回したい
OpenAI クライアント セットアップ
from openai import OpenAI

OPENAI_API_KEY="sk-xxxxx"
client = OpenAI(api_key=OPENAI_API_KEY)

(今回の処理)

今回は、キャラクターの性格から「名前とセリフ」を生成する処理をBatch APIで生成します。

# キャラクターの性格
character_personalities = [
    "1: クールで冷静沈着、しかし仲間思いの戦士。普段は無口だが、いざという時に頼りになる。過去に大切な人を失った経験から、新しい絆を恐れている。",
    "2: 明るく陽気で社交的な魔法使い。好奇心旺盛で新しい魔法の研究に没頭している。失敗しても決して諦めず、ポジティブシンキングの持ち主。時々抜けているところがある。",
    "3: 高潔な精神を持つ騎士。正義と誠実さを何よりも重んじ、弱者を守ることに人生を捧げている。厳格な性格だが、内心は繊細で傷つきやすい。完璧主義な一面がある。",
    "4: 謎めいた過去を持つ盗賊。表向きは軽薄でお調子者だが、実は鋭い洞察力と計算高さを持っている。信頼を得るのに時間がかかるが、一度信頼すると命を懸けて守る。",
    "5: 古い森に住む孤独な賢者。膨大な知識と知恵を持つが、人間社会から距離を置いている。皮肉屋で辛辣な物言いをするが、本当は人々を助けたいという優しさを秘めている。自然と動物を愛する。",
]
# プロンプトを作成する関数
def prompt_character(personality: str):
    return f'''
あなたはゲームのキャラクターを作成する専門家です。
以下のキャラクターの性格から「名前」と「セリフ5つ」を生成してください。

# キャラクターの性格
{personality}

# 出力フォーマット(json)
{{
    "name": <キャラクターの名前>,
    "quotes": [
        <キャラクターのセリフ1>,
        <キャラクターのセリフ2>,
        <キャラクターのセリフ3>,
        <キャラクターのセリフ4>,
        <キャラクターのセリフ5>
    ]
}}
'''

【1】jsonlファイルを作成する

# ------------------------------------------------------------
# バッチファイルの作成(jsonl形式)
# ------------------------------------------------------------
# バッチファイルの出力先
batch_file_path = "batch_input.jsonl"
# バッチファイルの作成
with open(batch_file_path, "w", encoding="utf-8") as f:

    for index, personality in enumerate(character_personalities):
        # バッチ処理用のJSONLフォーマットで保存
        row_data = {
            "custom_id": f"request-{index}",
            "method": "POST",
            "url": "/v1/chat/completions",
            "body": {
                "model": "o4-mini",
                "messages": [{"role": "system", "content": prompt_character(personality)}],
                "temperature": 1,
                "response_format": {"type": "json_object"}
            }
        }
        f.write(json.dumps(row_data, ensure_ascii=False) + "\n")
print("✅ バッチファイル作成完了")

【2】jsonlファイルをアップロードする

# ------------------------------------------------------------
# OpenAIへファイルアップロード
# ------------------------------------------------------------
# ファイルを指定
batch_file_path = "batch_input.jsonl"
# Filesへアップロード
with open(batch_file_path, "rb") as file:
    uploaded_file = client.files.create(
        file=file,
        purpose="batch"
    )
print("✅ ファイルアップロード完了:", uploaded_file.id)

【3】ファイルバッチ処理を開始する

# ------------------------------------------------------------
# OpenAIのBatch APIを使用して、バッチ処理を実行
# ------------------------------------------------------------
batch = client.batches.create(
    input_file_id=uploaded_file.id,
    endpoint="/v1/chat/completions",
    completion_window="24h",
    metadata={
        "project": "store-judge",
        "description": "Webサイトの分類(買取専門店かどうか)"
    }
)
print("✅ バッチ作成完了:", batch.id)

【4】結果のファイルを取得する

# ------------------------------------------------------------
# バッチ処理の結果を取得
# ------------------------------------------------------------
BATCH_ID = "batch_xxxxx"
batch = client.batches.retrieve(batch_id)
status = batch.status                 # バッチ処理のステータス
output_file_id = batch.output_file_id # バッチ処理の結果のファイルID

print(f"⌛️ ステータス: {status}")
if status == "completed":
    # fileのデータを確認
    file_content = client.files.content(output_file_id)
    file_data = file_content.text

    # JSONLファイルを行ごとに処理
    records = []
    for line in file_data.strip().split('\n'):
        record = json.loads(line)
        records.append(record)

    # データフレームに変換
    df_batch = pd.DataFrame(records)
    print(df_batch)
    print("✅ バッチ処理完了")
else:
    print("バッチ処理が完了していません")

参考

Batch API - OpenAI API
Batch API Reference - OpenAI API
Files API Reference - OpenAI API

Discussion