ガイドと洞察

AI API ゲートウェイを介した統合バッチ ジョブ: 耐久性のあるキュー、プロバイダー アダプター、テナント レベルの課金

耐久性のあるジョブ レコード、プロバイダー バッチ アダプター、冪等な結果の取り込み、予算の予約、テナント レベルの分析など、1 つのマルチモデル API を通じてレイテンシーに強い AI ワークロードを実行するための実用的なアーキテクチャ。

バッチ処理を AI API ゲートウェイの脇道として扱うべきではありません。評価、ドキュメント エンリッチメント、抽出、モデレーション スイープ、または埋め込みジョブが同期リクエスト パスから外れる場合でも、テナント制御、コスト アトリビューション、再試行、監査可能性、および使用状況分析が必要です。

実装パターンは、バッチ実行をファーストクラスのゲートウェイ サブシステムにすることです。ゲートウェイは、OpenAI、Anthropic、Gemini、および将来のプロバイダー バッチ API に舞台裏で適応しながら、プロバイダーに依存しない 1 つのジョブ コントラクトを公開する必要があります。

読者の問題: バッチ API は、目的は似ていますが、操作は異なります。

レイテンシーに耐性のあるワークロードは、バッチ実行に自然に適合します。難しいのは、ジョブを待ってもよいかどうかを判断することではありません。難しいのは、プロバイダ間でバッチ作業を一貫して実行することです。

検証済みの事実: OpenAI の Batch API は非同期で、アップロードされたファイルからリクエストを読み取り、出力ファイルにレスポンスを書き込み、現在 24 時間の処理ウィンドウを使用しています。 OpenAI には、検証中失敗進行中ファイナライズ中完了期限切れキャンセル中キャンセルなどのステータスがリストされます。 Anthropic のメッセージ バッチ API は、多くのメッセージ リクエストを非同期で処理し、各リクエストを個別に処理し、ポーリングを必要とし、処理終了後に結果を返します。 Anthropic では、結果の順序が保証されていないため、意味のある custom_id 値も推奨しています。 Gemini の Batch API は、リスト、キャンセル、削除、更新メソッドなどの長時間実行の操作スタイルのメソッドを公開しており、そのキャンセル操作はベストエフォートとして説明されています。

実際のビジネス要件を追加すると、これらの違いが重要になります。

  • どのテナント、顧客、プロジェクト、または API キーが各アイテムを所有していますか?
  • ジョブがゲートウェイを離れる前に予算が予約されていましたか?
  • バッチの有効期限が切れるか、キャンセルされますか?
  • 成功した作業を複製せずに、部分的な失敗はどのように再試行されますか?
  • 結果ファイルはどのくらいの期間取得できますか?また、ゲートウェイは何を保存する必要がありますか?
  • パートナーは、上流のプロバイダーの認証情報を公開せずに、顧客を対象としたバッチ処理を構築できますか?

答えは、プロバイダーの違いをすべて隠すことではありません。答えは、デバッグ、調整、サポート用にプロバイダー固有のメタデータを保持しながら、運用コントラクトを正規化することです。

推奨パブリック API: バッチ ジョブを同期完了から分離する

推奨: チャット完了の特別なフラグとしてではなく、独自の API サーフェスとしてバッチ ジョブを公開します。同期リクエストと非同期バッチ ジョブには、ライフサイクル、請求、再試行、結果取得セマンティクスが異なります。

実際のゲートウェイ コントラクトには、次の操作が含まれます。

  • create_job: テナント、プロジェクト、キー、またはパートナー顧客が所有するドラフト ジョブを作成します。
  • append_items またはupload_manifest: 安定したアイテム識別子を持つ個々のリクエストを追加します。
  • submit: 検証、予算の予約、プロバイダーの選択、ディスパッチ、送信されたマニフェストのロックを行います。
  • get_status: 正規化されたジョブとアイテムの数を返します。
  • list_results: 正規化されたアイテムの結果、エラー、および
  • cancel: 即時終了を約束せずにキャンセルをリクエストします。
  • export_usage: 分析または請求システム用にジョブレベルおよびアイテムレベルのコストレコードをエクスポートします。

パブリックジョブオブジェクトの例:

{
  "job_id": "job_01j7...",
  "テナントID": "テナント_acme",
  "customer_id": "cust_123",
  "エンドポイント": "chat.completions",
  "モデル": "分析-大",
  "ステータス": "実行中",
  「カウント」: {
    「送信済み」: 50000、
    「完了」: 31240、
    「失敗」: 180、
    「期限切れ」: 0
  }、
  「コスト」: {
    "推定": "184.20",
    "予約済み": "205.00",
    "決済済み": "117.43",
    "通貨": "米ドル"
  }、
  "created_at": "2026-08-19T10:00:00Z",
  "submitted_at": "2026-08-19T10:05:00Z",
  "取得_期限": "2026-09-17T10:00:00Z"
}

パブリック オブジェクトは、デフォルトでプロバイダー ファイル ID、操作名、または生のアップストリーム エラーを公開すべきではありません。これらはオペレータ向けのメタデータに属します。

信頼できる情報源として永続的なジョブ レコードを使用する

ゲートウェイ所有のバッチ レイヤーは、上流に何かが送信される前に永続的な状態を必要とします。唯一の状態ストアとしてプロバイダーのバッチ レコードに依存しないでください。プロバイダーのレコードは必要ですが、テナント階層、予算予約、内部モデルのエイリアス、パートナー顧客、分析要件は知りません。

最小データベース モデル

有用なスキーマには 3 つのレベルがあります。

1.バッチ ジョブ

batch_jobs
- ジョブID
- テナント ID
- プロジェクトID
- customer_id は null 可能- api_key_id
- エンドポイント
- 要求されたモデル
- 解決済みプロバイダー
- 解決済みプロバイダーモデル
- ステータス
- アイテム数
- 推定入力トークン
- 推定出力トークン
- 予約済み金額
- 決済金額
- 作成された場所
- 送信済み_at
- 完了_at
- 有効期限切れ
- 取得_期限
- cancel_requested_at

2.バッチアイテム

batch_items
- ジョブID
- アイテムID
- カスタムID
- 冪等性キー
- リクエストハッシュ
- ステータス
- Provider_request_index NULL 可能
- 推定トークン
-actual_input_tokens は null 可能です
-actual_output_tokens は null 可能です
- Setted_amount NULL 可能
- result_pointer は null 可能
- error_code は null 可能
- retry_of_item_id は null 可能
- 作成された場所
- 解決済み_at

3.プロバイダーのメタデータ

batch_provider_metadata
- ジョブID
- プロバイダー
- Provider_batch_id は null 可能
- input_file_id は null 可能
- Output_file_id は null 可能
- error_file_id は null 可能
- 操作名はnull可能です
- エンドポイント
- 領域がヌル可能
- ネイティブステータス
-native_request_counts jsonb
- last_polled_at
- raw_error_pointer nullable

プロバイダーのメタデータをパブリック ジョブ コントラクトから分離しておくと、ゲートウェイはテナント側の API を壊すことなくプロバイダー アダプターを進化させることができます。

ディスパッチ前に安定したアイテム識別子を要求する

推奨事項: ゲートウェイの job_id を生成し、ディスパッチ前にアイテムごとの custom_id または冪等キーを要求します。順序によって結果を調整しないでください。

Anthropic は、結果の順序が保証されていないことを明示的に警告し、意味のある custom_id 値を推奨します。プロバイダーが秩序を保っているように見えても、ゲートウェイはそれに依存すべきではありません。ジョブはチャンク化され、再試行され、キャンセルされ、部分的に完了し、再取り込まれます。注文の仮定は最終的には失敗します。

安全なアイテム識別子の形式は記述的ですが機密ではありません:

tenantA.invoice_extraction.2026-08-19.row_000381

生の電子メール、名前、ドキュメントのタイトル、または顧客の秘密を識別子に含めることは避けてください。機密の相関データは、プロバイダーに表示される ID 内ではなく、独自のテナント データベース内に保存します。

プロバイダーの詳細を消去せずにステータスを正規化します。

プロバイダーのバッチ API は、さまざまなライフサイクルを公開します。ゲートウェイは、ダッシュボード、請求、自動化が理解できる小さな内部ステート マシンにそれらを正規化する必要があります。

推奨される正規化されたライフサイクル:

  • ドラフト: ジョブは存在しますが、まだ編集可能です。
  • 検証中: ゲートウェイまたはプロバイダーの検証が実行中です。
  • queued: 受け入れられましたが、まだ未承認です。
  • running: プロバイダーはアイテムを処理しています。
  • finalizing: プロバイダーは計算を終了し、結果アーティファクトを準備しています。
  • completed: 受け入れられたすべてのアイテムが最終成功に達しました。
  • completed_with_errors: 一部のアイテムは成功し、一部は失敗しました。
  • expired: プロバイダー ウィンドウすべての作業が完了する前に終了しました。
  • cancel_requested: テナントがキャンセルを要求しましたが、最終的な請求可能な作業が解決されていません。
  • canceled: キャンセルが解決されました。
  • failed: ジョブレベルの障害により有効な実行が妨げられました。

ネイティブ プロバイダーのエラーを汎用ラベルにまとめるのが早すぎないでください。オペレーターは、デバッグ時にネイティブ ステータス、検証エラー、リクエスト数、ファイル ID、およびオペレーション名にアクセスする必要があります。

送信前に機能マトリックスに対して検証する

推奨事項: 予算の予約とプロバイダーのディスパッチの前に、プリフライト検証を実行します。バッチ モードは、遅延のある同期モードだけではありません。一部のモデル、エンドポイント、リクエスト機能、リージョン、ツール構成は、プロバイダーのバッチ API でサポートされていない場合があります。

内部機能マトリックスで次のことを確認する必要があります。

  • サポートされるエンドポイント: チャット、メッセージ、埋め込み、モデレーション、または生成。
  • バッチ モードのモデルの適格性。
  • 最大ジョブ サイズ、アイテム数、リクエスト サイズ、アップロードされたファイル サイズ。
  • ストリーミングが有効かどうか。
  • ツールの使用と関数呼び出しのサポート。
  • 構造化出力または JSON スキーマのサポート。
  • 画像、音声、またはマルチモーダル入力のサポート。
  • 地域と居住地の制約。
  • プロバイダーの保持期間と結果取得ウィンドウ。
  • バッチ固有のレート制限とキュー制限。
  • キャンセルセマンティクス。

適切なプリフライト応答は具体的です。

{
  "エラー": "バッチ機能がサポートされていません",
  "message": "選択されたプロバイダー バッチ アダプターはストリーミング応答をサポートしていません。stream=true を削除するか、同期エンドポイントを選択してください。",
  "フィールド": "items[*].request.stream"}

これは、ジョブを受け入れて上流の検証パス後に失敗するよりも便利です。

テナントの予算を予約してから実際の使用量を決済する

バッチ実行では、結果ファイルが利用可能になるまでゲートウェイが正確な使用量への同期アクセスを失う可能性があるため、請求が複雑になります。安全なパターンは、見積もり、予約、送信、取り込み、決済、調整です。

確認された事実: OpenAI は、バッチ API の価格は同期 API と比較して割引価格で提供されており、期限切れまたはキャンセルされたバッチでも、請求対象となる完了した作業が返される可能性があると述べています。 Anthropic 氏は、高スループットのバッチ処理ではワークスペースの使用制限をわずかに超える可能性があるため、ゲートウェイ側の予約と決済後の処理が重要になると指摘しています。

推奨事項: 見積もられたトークン、選択されたプロバイダーの価格ルール、および安全マージンを使用して、送信前にテナントの予算を予約します。結果が取り込まれた後、実際の使用量をアイテムレベルで決済します。見積もりが高すぎる場合は、未使用の予約を解放します。低すぎる場合は、テナントの設定された超過ポリシーを適用します。

実用的な台帳イベント:

batch.estimated
バッチ.予約済み
バッチ.送信済み
バッチ.アイテム.決済済み
バッチ.アイテム.返金済み
バッチ.キャンセル_リクエスト済み
バッチ.期限切れbatch.reconciled

項目レベルの台帳は不可欠です。 45,000 項目が完了し、5,000 項目が期限切れになった場合、テナントは、単一の未分化 BLOB としての元のマニフェストではなく、完了したプロバイダーの作業に対して請求される必要があります。

ビジネス ロジックの所有者ではなく、トランスレーターとしてプロバイダー アダプターを構築する

各プロバイダー アダプターは、ゲートウェイ ジョブをプロバイダーのバッチ形式に変換し、送信し、ステータスをポーリングまたは取得し、結果をダウンロードし、ネイティブの結果を正規化されたものにマッピングする方法を知っている必要があります。

テナント ポリシーをアダプタの外部に保持します。アダプターは、顧客に十分な予算があるかどうか、パートナー顧客が一時停止されているかどうか、またはプロンプトを保存できるかどうかを決定すべきではありません。これらはゲートウェイの決定です。

アダプターの責任

  • プロバイダー固有のリクエスト マニフェストをレンダリングします。
  • 入力ファイルをアップロードするか、プロバイダー オペレーションを作成します。
  • プロバイダー識別子をメタデータに保存します。
  • ネイティブ ステータスを正規化されたステータスにマッピングします。
  • 出力およびエラー アーティファクトを取得します。
  • 項目レベルで解析します。
  • 利用可能な場合はネイティブの使用状況レコードを返します。
  • 再試行可能なサーフェスとターミナル エラー。

ゲートウェイの責任

  • テナントと API キーを認証します。
  • チーム、プロジェクト、および顧客の制御を適用します。
  • モデルのエイリアスとプロバイダーのルーティング ポリシーを解決します。
  • バッチを検証します。
  • 予算の予約と決済。
  • ジョブとアイテムの状態の保持。
  • 保持ポリシーの強制。
  • 分析とエクスポートの公開。

この分離により、請求、分析、テナント ガバナンスを書き換えることなく、新しいプロバイダーを簡単に追加できるようになります。

結果を冪等に取り込む

結果の取り込みは、多くの場合に行われます。バッチ システムでは、誤って請求が重複したり、部分的な作業が失われたりします。摂取を反復可能なプロセスとして扱います。同じ出力ファイルを 2 回ダウンロードしたり、同じプロバイダーの操作を 2 回処理したり、同じ Webhook イベントを 2 回再生したりしても安全です。

推奨事項: 項目レベルの冪等性キーと台帳の一意性制約を使用します。 job_id +custom_id の結果は、取り込みが再試行された場合でも、一度だけ確定する必要があります。

堅牢な取り込みフロー:

  1. ジョブまたは結果アーティファクトに対して有効期間の短いロックを取得します。
  2. プロバイダーの出力とエラー アーティファクトを取得します。
  3. レコードを正規化された項目結果イベントに解析します。
  4. 各レコードを次のように照合します。 custom_id またはゲートウェイ アイテム ID。
  5. 結果のメタデータとトランザクションでの使用法を書き込みます。
  6. 台帳決済イベントがまだ存在しない場合にのみ作成します。
  7. 仮定ではなくアイテムの状態からジョブ数を更新します。
  8. すべての最終状態がわかったら、未使用の予算予約を解放します。

Webhook が使用可能な場合は、署名を検証し、リプレイから保護します。ポーリングが必要な場合は、アダプティブ ポーリングを使用します。完了が予想される近くで頻繁にポーリングし、長時間実行中にバックオフし、最終決済後に停止します。

ジョブ全体ではなくアイテムを再試行します

推奨事項: 可能な限りアイテム レベルで再試行します。ジョブ全体の再試行は簡単ですが、重複作業のリスクが高まり、請求が難しくなります。

再試行前に失敗を分類する:

  • 検証エラー: 通常、リクエストが修正されるまで終了します。
  • プロバイダ 5xx エラー: 多くの場合、バックオフで再試行できます。
  • クォータまたはレート制限のエラー:容量が利用可能になってからのみ再試行してください。
  • 安全ブロック: やみくもに再試行しないでください。
  • 期限切れアイテム: テナントがまだ作業を希望し、予算が許せば、新しいジョブで再試行できます。

再試行すると、元のアイテムにリンクされた新しいアイテムが作成されます:

{
  "item_id": "item_retry_002",
  "retry_of_item_id": "item_001",
  "custom_id": "tenantA.eval.row_901.retry_1"
}

完了したアイテムが、completed_with_errors または expired として終了したジョブの一部だったという理由だけで、完了したアイテムを再送信しないでください。

保存するものを決定します: 生の結果、ポインタ、またはハッシュ

バッチ システムは、プロンプトと出力を蓄積する場所として魅力的です。 これはエクスポートやデバッグには便利ですが、データ保持の責任が増大します。

推奨: ストレージ ポリシーをテナントが構成できるようにします。 機密性の高いワークロードの場合は、生のプロンプトや出力ではなく、メタデータ、ハッシュ、使用法、および結果ポインターを保存します。機密性の低いワークロードの場合、保持期間、アクセス制御、および削除ワークフローが明確であれば、正規化された結果ストレージが許容される可能性があります。

少なくとも以下を追跡します。

  • 生の入力が保存されたかどうか。
  • 生の出力が保存されたかどうか。
  • プロバイダーの結果アーティファクトが存在する場所。
  • プロバイダーの取得期限。
  • ゲートウェイの削除
  • コンテンツの露出を伴わない監査のリクエストとレスポンスのハッシュ。

検証された事実: Anthropic States のバッチ結果は、作成後 29 日間利用可能であり、ワークスペース内で隔離されます。 この種のプロバイダー固有の取得ウィンドウは、ゲートウェイのメタデータとテナント側のエクスポートに反映される必要があります。

チームの運用方法に一致する分析を公開する

バッチ分析は、ジョブ レベルとアイテム レベルの両方に存在する必要があります。 製品所有者は、夜間のエンリッチメントが完了したかどうかを知りたいと考えています。 財務管理者は、テナント、モデル、顧客ごとのコストを知りたいと考えています。 エンジニアは、どの失敗クラスを再試行すべきかを知りたいと考えています。

有用な指標には次のものが含まれます。

  • 送信済み、完了済み、失敗した、期限切れ、およびキャンセルされた項目数。
  • 推定コストと確定コスト。
  • まだ保留されている予約予算。
  • プロバイダーおよびモデル別の入出力トークン。
  • プロバイダーが公開するキャッシュ ヒット インジケーター
  • 再試行回数と再試行成功率。
  • キュー状態、実行中、終了処理状態の平均時間。
  • エンドポイントおよびモデル別の上位の検証エラー。
  • パートナー顧客の属性。

パートナー API ユーザーの場合、バッチ ジョブを顧客スコープのリソースとして公開します。 これにより、代理店や SaaS ビルダーは、上流のプロバイダーの認証情報、請求調整、ゲートウェイ内でのレート制限の処理を維持しながら、オフライン AI 処理を提供できるようになります。

明確にするためのトレードオフ

ゲートウェイの抽象化とプロバイダー固有の機能: 統一された契約は統合を簡素化しますが、すべてのプロバイダーの機能を同一にすることはできません。 機能エラーを明示的に保ちます。

予算の予約と見積もりの​​精度: 予約はテナントを暴走したジョブから保護しますが、見積もりが間違っている可能性があります。 台帳は、調整、払い戻し、超過料金の処理をサポートする必要があります。

ポーリングと Webhook: ポーリングはシンプルで信頼性がありますが、API 呼び出しが無駄になり、完了が遅れる可能性があります。 Webhook は高速ですが、署名の検証、リプレイ保護、監視が必要です。

生の結果の保存と保持の最小化: 正規化された結果を保存すると、エクスポートと分析が向上しますが、コンプライアンスの負担が増加します。 敏感なテナントはポインタとハッシュを好む場合があります。

大規模なバッチとチャンク化されたバッチ: 巨大なバッチはプロバイダ側の効率を向上させる可能性がありますが、チャンクが小さいほど爆発半径が減少し、再試行が容易になります。

実装チェックリスト

  • 別個のバッチ ジョブ API サーフェスを作成します。
  • プロバイダの前にジョブとアイテムのレコードを永続化します。
  • ゲートウェイ ジョブ ID とアイテムごとのカスタム ID を要求します。
  • ネイティブ プロバイダーのメタデータを保存するときにステータスを正規化します。
  • 各プロバイダーのバッチ アダプターの機能マトリックスを構築します。
  • 予算を予約する前にマニフェストを検証します。
  • ディスパッチ前にテナントの予算を予約します。
  • 取り込み後にアイテム レベルで実際の使用量を確定します。
  • 結果の取り込みを行う冪等。
  • ジョブ全体を盲目的に再試行するのではなく、失敗したアイテムを選択して再試行します。
  • プロバイダーの取得期限とゲートウェイ保持ポリシーを追跡します。
  • ジョブとアイテムの分析をテナントとパートナー顧客に公開します。

予測: このパターンの方向性

予測: バッチ実行は、単なる割引メカニズムではなく、AI 自動化インフラストラクチャの通常の一部になるでしょう。 チームがより多くの評価、データ クリーンアップ タスク、安全性レビュー、エンリッチメント パイプラインを実行するにつれて、非同期ワークロードにも同期 API 呼び出しと同じガバナンスが適用されることが期待されます。

予測: プロバイダー バッチ API は、有用な方法で分岐し続けるでしょう。 ファイル用に最適化するもの、長時間実行操作用に最適化するもの、管理されたデータセットまたはイベント コールバック用に最適化するものもあります。 アダプター上の運用コントラクトが安定した状態を維持できるため、ゲートウェイ アダプター レイヤーの価値は下がるどころか、さらに高まります。

実行可能な結論

プロバイダー固有の避難口としてバッチ処理を AI API ゲートウェイにボルトで固定しないでください。 独自のジョブ レコード、アイテム ID、ステータス モデル、プロバイダー アダプター、予算予約、べき等取り込み、分析を備えた耐久性のあるサブシステムとして構築します。

最も重要な設計上の選択は、アイテム レベルの会計です。 バッチ内のすべてのリクエストが安定した ID を持つと、ゲートウェイは順序付けされていない結果を調整し、失敗した作業のみを再試行し、完了したプロバイダーの作業のみを請求し、何が起こったかをテナントに表示できます。これが、プロバイダーにファイルを送信することと、非同期ワークロード用の信頼できるマルチモデル API を操作することの違いです。

関連資料

FAQ

よくある質問

ゲートウェイはプロバイダーネイティブのバッチ API を直接公開する必要がありますか?
通常はいいえ。ネイティブ API を公開すると、開発者はプロバイダー機能に直接アクセスできるようになりますが、テナント レベルの課金、分析、再試行、ガバナンスが弱体化します。より良いパターンは、オペレーターが利用できるプロバイダー固有のメタデータを備えた、プロバイダーに依存しないジョブ契約です。
アイテムごとにcustom_idが必要なのはなぜですか?
バッチ結果は、送信された順序で返されない場合があります。安定したアイテムごとの識別子により、ゲートウェイは結果を調整し、使用量を解決し、失敗したアイテムを再試行し、重複請求を回避できます。
キャンセルされたバッチまたは期限切れのバッチはどのように請求されるべきですか?
結果が取り込まれて調整された後、完了したプロバイダーの作業に対してのみ請求されます。キャンセルされたジョブや期限切れのジョブには完了したアイテムが含まれている可能性があるため、ジョブ レベルのステータスだけでは正確な請求を行うには十分ではありません。
ゲートウェイはバッチ ジョブからの生のプロンプトと出力を保存する必要がありますか?
デフォルトでは機密性の高いテナントには適用されません。テナントが明確な保持ポリシーを使用して生の結果のストレージを明示的に有効にしない限り、メタデータ、ハッシュ、使用法、および結果ポインターを保存します。