長時間AIタスクをHTTP接続に縛らない — OpenAIに学ぶ非同期運用の4原則

AIエージェントの処理が数分に伸びると、「賢いプロンプト」だけでは運用できません。ブラウザを閉じた、通信が切れた、同じ完了通知が2回来た——こうした普通の障害で、処理の二重実行や結果の取りこぼしが起きます。

OpenAIのBackground modeとWebhookの公式設計を読むと、長時間タスクで重要なのはモデルよりも状態・再開・重複排除だと分かります。今回は実装時に押さえたい4原則に絞ります。

1. HTTP接続と仕事の寿命を分ける

Background modeは、Responses APIのリクエストにbackground: trueを指定し、長時間処理を非同期で実行する仕組みです。クライアント接続が切れても仕事を継続でき、レスポンスIDから状態を取得できます。

設計上のポイントは、API呼び出しを「結果を受け取る処理」ではなく「仕事を受け付ける処理」に変えることです。受付時にレスポンスIDを自分のジョブIDと結び付けて保存し、画面や通信セッションを唯一の状態置き場にしないことが重要です。

2. 成功だけでなく、終端状態を扱う

公式ガイドでは、状態がqueuedまたはin_progressの間は処理中で、それ以外へ移れば終端状態です。つまり実装は「完了したか」だけでなく、失敗やキャンセルも含めて閉じる必要があります。

  • ポーリングには間隔と上限時間を設ける
  • キャンセル操作を用意し、ジョブ側の状態にも反映する
  • 通信エラーと処理失敗を分けて記録する

なお、実行中レスポンスのキャンセルは複数回呼んでも最終状態を返す冪等な操作として説明されています。利用者が再試行しても壊れにくいAPIは、運用時の安心材料になります。

3. Webhookは「1回だけ届く」と思わない

完了を即時に受け取りたい場合はWebhookを使えます。ただし公式ガイドは、まれに同じイベントが重複配送されると明記しています。webhook-idを冪等性キーとして保存し、処理済みなら副作用を再実行しない設計が必要です。

また、受信エンドポイントは数秒以内に2xxを返し、重い処理は別のワーカーへ渡すことが推奨されています。失敗時は指数バックオフで最大72時間再試行され、3xxリダイレクトは追跡されません。

これは生産ラインの完了信号に似ています。信号を受けた瞬間に全工程を動かすのではなく、まず受領記録を残し、同じ信号番号を二度処理しないようにしてから後工程へ流します。

4. 通知を信用する前に署名を確認する

Webhook URLは外部から到達できるため、受信したJSONだけを見て処理を開始してはいけません。OpenAIは署名シークレットと公式SDKのunwrap()を使い、送信元を検証する方法を案内しています。検証には加工前のリクエスト本文が必要です。

通知にはレスポンスIDだけを使い、最終結果はAPIから取得する構成にすると、受信処理を小さく保てます。署名エラーは拒否し、シークレットが漏れた疑いがあればローテーションします。

見落としやすいデータ保持の条件

Background modeはstore=falseでも利用できますが、非同期実行とポーリングのため、レスポンスデータは一時的にディスクへ保存されます。公式ガイドではおよそ10分と説明されています。ZDR(Zero Data Retention)を前提にするシステムでも、「保存しない」という名前だけで判断せず、処理方式ごとの例外を確認すべきです。

まとめ

長時間AIタスクを安定させる4原則は次の通りです。

  • 接続とジョブの寿命を分離する
  • 成功・失敗・キャンセルを終端状態として管理する
  • Webhookの重複を前提に冪等化する
  • 署名検証後に結果を取得する

モデルの賢さは処理内容を改善します。しかし、仕事を最後まで届けるのは状態機械と冪等性です。AIエージェントを本番へ入れるなら、まず「切れても続く、重なっても一度だけ動く」土台から設計するのが近道です。

公式資料