3行でいうと

  • AIを非同期で動かす方法は大きく3つあります。結果を取りに行く方式(バッチ、バックグラウンド実行)と、完了を知らせてもらう方式(Webhook)です。3社とも、バッチは50%割引で、24時間前後の期限や目標を書いています。
  • Webhookは「少なくとも1回」届く仕組みで、重複や遅れがありえます。OpenAIは再試行を最大72時間、Googleは24時間と書いており、配信の保証期間も違います。受け取る側は、重複を捨てる処理と、通知が来なくても状態を確認し直す処理が必要です。
  • 結果の保管期間は短く、Anthropicは作成から29日、OpenAIの出力ファイルは完了から30日、Geminiは既定で6週間です。ジョブの状態と結果は、自分のデータベースにも写しておく設計が前提になります。

この記事は、実際に使って確かめた記録ではありません。この記事は、公式の文書を読んでまとめたもので、実際に使って確かめた記録ではありません。数字と仕様は2026年10月16日に確認し、10月22日に読み直しました。変わることがあります。

先に結論

前提:同期と非同期、そしてこの記事の範囲

同期の呼び出しは、依頼を送り、そのままAIの答えが返るまで待ちます。非同期処理は、依頼を送るとすぐに受付の印(IDなど)が返り、結果は後から別の方法で受け取ります。後から受け取る方法には、こちらから聞きに行くポーリングと、相手から知らせてもらうWebhookがあります。

この記事が扱うのは、アプリの開発者向けの話です。AIの回答を画面にすぐ出す用途ではなく、大量の文書の要約や分類、夜間の一括処理、長い推論などを想定しています。バッチAPIの対象や割引そのものは別の記事で扱っているので、ここでは設計に関わる点に絞ります。

3社が用意している非同期の仕組み

公式文書を読んで、仕組みを3種類に分けて表にしました。分け方は僕らの整理です。

方式 OpenAI Anthropic Google(Gemini API)
大量・急がない処理(バッチ) Batch API(JSONLのファイルを渡す) Message Batches API Batch API(インラインかファイル)
1件の長い処理を後で受け取る Responsesのbackground: true 該当する機能は、読んだ範囲では見つかりませんでした(ストリーミングかバッチを案内) 動画生成や長時間の操作は、Webhookの対象に含まれる(後述)
完了の通知(Webhook) あり(Standard Webhooks準拠) 読んだ文書では確認できていません あり(バッチなどのイベント)

OpenAIのバックグラウンド実行は、1件の依頼を「受付だけ先に済ませる」形です。公式の説明では、queuedまたはin_progressの間は、GET /v1/responses/{id}で状態を取り直し、それ以外の状態になったら終わりです。取り消しはPOST /v1/responses/{id}/cancelで、何度呼んでも同じ結果になる(冪等)と書かれています。ストリーミングと組み合わせると、sequence_numberを目印にして、途中から再開できます。

AnthropicとGoogleのバッチは、状態の名前が違います。Anthropicはin_progress、canceling、endedの3つで、成功か失敗かは、バッチ全体ではなく1件ごとの結果の型(succeeded、errored、canceled、expired)で見ます。GoogleはJOB_STATE_PENDINGからJOB_STATE_EXPIREDまでの6つで、OpenAIはvalidatingからcancelledまでの8つです。状態の数も、「全体の状態」と「1件ごとの結果」のどちらで見るかも、会社ごとに違います。

バッチの数字を3社で並べる(2026年10月16日に確認、10月22日に読み直し)

公式のBatch系ページに書かれていた数字です。すべて、読んだページの記載をそのまま書き写しています。

項目 OpenAI Anthropic Google
割引 50% 50% 50%
完了の目安 24時間(24hのみ) 24時間で期限切れ。ほとんどは1時間以内と書かれている 目標24時間。48時間を超えると期限切れ
1回の上限 5万件、入力ファイル200MB 10万件または256MB インラインは合計20MB未満、ファイルは2GBまで
結果の保管 出力ファイルは完了の30日後に削除 作成から29日(終了からではない) 既定で6週間
期限切れの扱い 未処理分はエラーファイルにbatch_expiredで入る。完了した分のトークンが課金される expiredの1件は課金なし 48時間を超えるとJOB_STATE_EXPIRED(結果の扱いは確認できていません)
結果の順序 入力と一致しないことがある 順序は保証されない 順序の記載は読んだ範囲になし
照合のキー custom_id custom_id(1〜64文字、英数字と-と_) 入力の各行に付けるユーザー定義のキーが、応答でどの依頼の結果かを示すのに使われる
取り消し cancellingは最大10分かかる cancelingを経てended 状態にJOB_STATE_CANCELLEDがある

OpenAIには、1時間あたり2,000バッチまでの作成という上限もあります。

Anthropicのページには、バッチ内の個々の依頼の検証は非同期で、エラーはバッチ全体が終わってから返る、という注意があります。

Geminiのページには、ジョブの作成は冪等ではなく、同じ依頼を再送すると2つ目のジョブができる、と書かれています。

Webhookの仕様:3社が共通の土台を使っている

OpenAIのWebhookは、Standard Webhooksという共通仕様に沿っています。GoogleのGemini APIも、静的に登録するWebhookは同じ仕様だと書いています。つまり、受け取る側のコードは、両社で大部分を共有できます。

共通仕様(Standard Webhooks v1.0.0)が決めている主な点は、次のとおりです。

会社ごとの違いは、次のとおりです。

OpenAI Google(Gemini API)
再試行の期間 最大72時間、指数バックオフ 24時間、指数バックオフ
重複 まれにあり。webhook-idで重複を捨てる 少なくとも1回の配信。webhook-idで重複を捨てる
古い通知の拒否 時刻の許容幅は、読んだ範囲に具体値なし webhook-timestampが5分より古いものを拒否、が推奨
通知の中身 response.completedなどのイベント種別がある(例) IDと出力先のポインタだけの「薄い」中身
秘密の交換 作成直後だけ表示される 作成時の1回だけ表示。入れ替え時は旧秘密を24時間残す指定の例がある

Googleの文書は、リクエストごとに指定する「動的Webhook」も説明しています。こちらは共有の秘密ではなく、署名つきのトークン(JWT)で本物かを確かめます。静的と動的で検証の方法が違うので、両方使うなら別々の処理が必要です。なお、そのページには公開鍵を取る場所のURLが2種類あり、食い違っていました。実際に実装するときは、公式ページで直接確かめてください。

受け取る側の設計:5つの決めごと

ここからは、公式の記載を材料にした、僕らの見立てです。公式が「こう設計しなさい」と書いた部分と、僕らがそこから読み取った部分は区別して書きます。

1. ジョブの表を、自分のデータベースに持つ

状態の名前は会社ごとに違うので、自分の側で、共通の状態(受付、実行中、成功、失敗、期限切れ、取り消し)を決めて、各社の状態を対応づけるのがよいと思います。表には、各社のID(OpenAIのレスポンスID、Anthropicのバッチ、Googleのジョブ名)と、自分のジョブID、依頼の内容への参照、結果の保管場所を入れます。結果の保管期間が29日、30日、6週間と有限なので、取れたら自分の側に保存するのが前提です。これは公式の保管期間の記載から導いた見立てです。

2. 依頼を二重に出さない

Geminiは、ジョブの作成が冪等でないと書いています。冪等性は、同じ操作を何度繰り返しても、結果が1回分と同じになる性質です。作成の呼び出しがネットワークの都合で成功したのか分からないとき、慌てて再送すると、課金される処理が2つ走ります。自分のジョブIDを先に作って表に書き、各社のIDが返ってきたら表に結びつける、という順序が安全だと思います。OpenAIとAnthropicの文書では、作成の呼び出しの冪等性についての記載は、読んだ範囲では見つかりませんでした。

3. Webhookは「受けて、すぐ返し、後で処理する」

OpenAIもGoogleも、2xxを数秒以内に返すよう書いています。OpenAIは、重い処理をバックグラウンドに回すよう書いています。署名を確かめて、イベントを自分のキュー(処理待ちの列)に書き込んだら、すぐ2xxを返す、という形が考えられます。

4. 重複と順序の乱れを前提にする

公式はwebhook-idを冪等キーに使うよう書いているので、処理済みのIDを覚えておき、2回目以降は何もせず2xxを返します。共通仕様の例は5分間の保存ですが、OpenAIは再試行が72時間続くので、保存の長さは、使う会社の再試行の期間に合わせる必要がありそうです。これは僕らの見立てです。別のやり方として、状態を「進める方向にだけ」書き換える(成功のあとに実行中で上書きしない)作りにすれば、順序が入れ替わっても壊れにくくなります。

5. 通知が来なくても、状態を取り直す

Webhookの再試行には期限があります。自分の受け口が止まっていたり、URLが変わっていたり、3xxを返していたりすると、期限を過ぎた通知は戻ってきません。そこで、通知を受けるのとは別に、「一定時間、状態が動いていないジョブ」を定期的に各社のAPIで確かめ直す処理を持つのが堅いと思います。各社の文書も、ポーリングの例を載せています(Anthropicは60秒おき、Geminiは30秒おき、OpenAIのバックグラウンド実行は1〜2秒おきの例)。これらは例であって、推奨値ではありません。

Anthropicの文書には、状態がendedになるまで60秒おきに取り直す例があります(コードは、細部を確認できていないので省略します)。

部分的な失敗の扱い

バッチは、1件の失敗が他に影響しない仕組みです(Anthropicの文書)。ですから、終わったあとに「成功の分を取り込み、失敗の分だけ作り直す」処理が必要になります。

Anthropicでは、結果の型がsucceeded(課金あり)、errored、canceled、expired(いずれも課金なし)に分かれます。expiredは、24時間の期限が来た件です。OpenAIは、期限切れの件がerror_file_idのファイルにbatch_expiredで入り、custom_idから元の依頼を取り出せる、と書いています。Googleは、batchStatsのfailedRequestCountを確かめるよう案内しています。

つまり3社とも、「バッチ全体が成功した」と「全件が成功した」は別だと読めます。完了の通知を受けただけで済ませず、件数の内訳を見る必要があります。

気をつけること

出典

更新履歴