Tech カテゴリのイメージ

LLMのバッチ処理と非同期処理とは?待てる仕事を安く安全に流す

LLMを使う処理のすべてに、その場で回答を返す必要があるとは限らない。過去データの分類、商品説明の付与、埋め込みの再作成、評価データの採点などは、数時間後に終わればよい場合がある。

このような仕事を対話用のAPIへ一件ずつ同期的に送り続けると、混雑時の失敗、再試行、費用、運用負荷が増える。待てる仕事は非同期のキューや提供者のBatch APIへ分けると、利用者向けの応答経路を守りながら処理できる。

並列処理・非同期処理・Batch APIを分ける

似た言葉だが、役割は異なる。

  • 並列処理は、複数の要求を同時に実行して全体の所要時間を短くする方法である
  • 非同期処理は、要求を受け付けた時点で処理完了を待たず、後から状態や結果を取得する設計である
  • Batch APIは、多数の要求をひとまとまりのジョブとして提供者へ渡し、一定の完了枠で処理してもらう機能である

並列数を増やすだけでは、レート制限や下流障害の影響も大きくなる。非同期化しても、裏側で一件ずつ通常APIを呼ぶなら料金体系は変わらない。Batch APIは価格や処理枠に利点がある場合があるが、即時応答は期待できない。

まず、利用者が待てる時間と結果が必要になる期限を決め、その条件に合う方式を選ぶ。

待てる仕事だけをバッチへ移す

バッチ処理に向くのは、入力が先にそろい、結果をすぐ画面へ返さなくてよい仕事である。

  • 評価データセットへの一括推論
  • 文書や商品の分類、要約、属性付与
  • 埋め込みの作成や再作成
  • 過去データの補完
  • 夜間の品質検査やレポート生成

対話チャット、利用者の操作を確定する判断、時刻に強く依存する案内、数秒以内の応答が必要な処理は通常のオンライン経路に残す。バッチが安いという理由だけで、利用者が結果を待つ画面へ適用してはいけない。

オンラインとバッチで同じプロンプトを使う場合も、実行条件は同一とは限らない。モデル、提供者の処理枠、タイムアウト、利用できる道具を含めて別の構成として評価する。

受付と完了を別の状態として扱う

非同期処理では、APIがジョブを受け付けたことと、各項目の推論が成功したことを分ける。受付に成功した直後は、利用者や後続処理へ「完了」と返さない。

少なくとも次の状態を持つ。

  1. 受付済み
  2. 検証中または待機中
  3. 実行中
  4. 一部成功
  5. 完了
  6. 失敗、期限切れ、取消済み

提供者側のジョブ状態だけでなく、自分のアプリで結果を取り込み、検証し、保存できたかも記録する。提供者側で完了していても、結果ファイルの取得やデータベース反映に失敗すれば、業務としては終わっていない。

行番号ではなく安定したIDで対応付ける

バッチの出力は、入力と同じ順序で返るとは限らない。入力項目ごとに一意なIDを付け、結果もそのIDで原本へ結び付ける。

IDには、単なる連番より、処理対象と版を追える内部IDを対応させる。入力本文をそのままIDへ入れると個人情報や機密情報がログに広がるため、意味のない識別子と内部の対応表を使う。

同じ項目を再送するときは、新しい試行IDと元の作業IDを分ける。これにより、二重登録を避けながら、何回目の試行で成功したかを調べられる。

ジョブ成功と全件成功は同じではない

一つのジョブが完了しても、内部の一部要求だけが失敗することがある。OpenAIのBatch APIも、完了件数と失敗件数、成功結果とエラー結果を分けて返す。

処理後は次を確認する。

  • 入力件数、成功件数、失敗件数が一致するか
  • すべての入力IDに結果かエラーが一つだけあるか
  • 応答のJSON Schemaや必須項目を満たすか
  • 空文字、打ち切り、不適切な拒否などを成功扱いしていないか
  • 期限切れや取消後に残った部分結果をどう扱うか

失敗分だけを再送できるようにする。ジョブ全体を無条件に再送すると、成功済み項目の重複処理と費用が増える。

再試行しても二重更新しない

LLMの分類結果を保存するだけなら上書きしやすいが、メール送信、注文変更、外部サービスへの登録を結果に続ける場合は注意が必要である。結果の取得や通知は重複する前提で、同じ作業IDを二度適用しない仕組みを用意する。

モデルへの再試行と、モデル結果を外部へ反映する再試行も分ける。推論は成功済みなのに保存だけ失敗した場合、モデルを再実行せず同じ結果を安全に保存し直す。

再試行回数には上限を設ける。形式エラー、権限エラー、入力が長すぎる場合など、同じ条件で繰り返しても直らない失敗は人の確認へ送る。

入力と設定を送信時点で固定する

長時間のジョブでは、処理中に原本、プロンプト、モデル設定が更新されることがある。結果を後から説明できるように、送信時点の構成を記録する。

  • 入力データの版または安全なハッシュ
  • モデルと設定
  • プロンプトと出力Schemaの版
  • 参照資料や検索索引の版
  • 送信時刻、期限、ジョブID
  • 実行した組織、プロジェクト、地域

結果を反映する前に、原本の版が変わっていないか確認する。古い入力から作った要約や分類で、新しい原本を上書きしない。

キューの古い仕事を捨てる判断も必要になる

非同期化すると、障害中も仕事がキューへ積み上がる。復旧後に古い要求をすべて実行すると、不要な費用が発生し、現在の状態へ古い結果を反映する危険がある。

仕事ごとに最終期限を持ち、期限を過ぎたら失敗として終了する。利用者向けの重要処理、日次集計、低優先度の再計算を同じ列へ入れず、優先度やキューを分ける。

流入量が処理量を継続して上回る場合は、並列数だけを増やさない。入力をまとめる、重複を除く、低価値な仕事を止める、利用者へ遅延を知らせる順で負荷を下げる。

入出力ファイルもデータ保持の対象である

Batch APIでは、要求をまとめた入力ファイルと結果ファイルが追加のデータコピーになる。通常APIのログだけを見ていると、この保存先を見落とす。

送信前に不要な個人情報を除き、ファイル、ジョブ、アプリ側の対応表それぞれに保持期限と削除手順を決める。提供者によって、既定の保存期間、手動削除、出力の有効期限、Zero Data Retentionとの互換性は異なる。

例えばOpenAIの現行資料では、Batch APIの入力はJSONLファイルとしてアップロードし、入力項目の識別に custom_id を使う。保持条件や上限は更新され得るため、実装時に公式のAPI ReferenceとData controlsを確認する。

小さい同期実行で確かめてから大量に流す

数万件を送ってから形式や品質の問題に気付くと、やり直しの費用と時間が大きい。まず代表例と境界例を少数だけ通常APIで実行し、出力Schema、品質、拒否、文字コード、長い入力を確認する。

次に小さなバッチで、IDの対応付け、部分失敗、取消、期限切れ、結果の再取得を試す。問題がなければ段階的に件数を増やす。

完了後も平均だけを見ず、入力の種類ごとの成功率と品質を調べる。大量処理では、少数の異常が全体率に隠れやすい。

成功一件当たりの総費用で比べる

バッチ処理の評価では、API単価だけでなく、再試行と運用を含めて測る。

  • 受付から利用可能になるまでの待ち時間
  • キューに残る最古の仕事の年齢
  • 成功、失敗、期限切れ、取消の件数
  • 一件当たりの再試行回数
  • 成功一件当たりのトークンと総費用
  • 結果取り込みまで含む完了時間
  • オンライン経路の遅延とエラー率への影響

バッチ単価が低くても、失敗の再送や古い結果の手修正が多ければ改善とは限らない。期限内に正しい結果を反映できた件数を分母にして比較する。

バッチ処理の目的は、単に大量の要求を送ることではない。待てる仕事をオンライン経路から分離し、受付、部分失敗、再試行、反映、削除までを一つの非同期ワークフローとして管理することである。安定したID、版、期限、保持方針を先に決めれば、費用を下げながら安全に規模を広げられる。

参照資料

生成AI・機械学習講座の一覧へ