1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

本番環境のAI画像生成で非同期処理が必要になる理由

1
Posted at

AI画像生成は、一見すると単純なリクエスト・レスポンスの機能に見えます。

ユーザーがプロンプトを入力し、生成ボタンを押し、画像が返ってくるのを待つ。

プロトタイプであれば、この形でも十分に動きます。ただし、本番環境のプロダクトとして扱うと、この設計はすぐに脆くなります。

画像生成には数秒から数分かかることがあります。プロバイダーによっては、最初にジョブIDだけを返し、最終結果は後で返します。結果がWebhookで届く場合もあれば、こちらからポーリングする必要がある場合もあります。リクエストは失敗したり、タイムアウトしたり、ユーザーがページを離れた後に完了したりします。

そのため、AI画像生成は非同期ワークフローとして設計した方が扱いやすくなります。

この記事では、Image 2 を開発する中で整理した、AI画像生成を非同期化する理由と基本的な設計をまとめます。

単純な実装

もっとも直接的な実装は、次のような形です。

User -> API route -> AI provider -> result -> user

理解しやすい構成ですが、いくつか問題があります。

  • HTTPリクエストがタイムアウトする可能性がある
  • リトライによって重複ジョブが作られる可能性がある
  • フロントエンド体験がプロバイダーの応答時間に依存する
  • 課金やクレジット消費の保護が難しくなる
  • 生成された画像が一時的なプロバイダーURLに依存する
  • リクエスト終了後に失敗状態を修復しにくい

この形はデモには向いています。しかし、実ユーザー、決済、ストレージ、リトライが関わると、安定して運用するのが難しくなります。

より扱いやすい形

より堅牢にするには、ユーザーからのリクエストと実際の生成処理を分離します。

User request
  |
  v
Create generation record
  |
  v
Push message to queue
  |
  v
Background worker submits job
  |
  v
Webhook or polling gets result
  |
  v
Store asset and update status

ユーザー向けのAPIは、生成タスクを作成してすぐに返します。UI側では queuedprocessingcompletedfailed のような状態を表示します。

時間のかかる処理はバックグラウンドで進めます。

非同期化で何が良くなるか

非同期ワークフローにすると、システムが失敗から回復しやすくなります。

プロバイダーの応答が遅い場合、タスクは processing のまま維持できます。

プロバイダー側で失敗した場合、タスクを failed に更新し、必要であればクレジットを戻せます。

Webhookを受け取れなかった場合でも、後からスケジュールジョブでポーリングできます。

Webhookとポーリングの両方が同じ最終結果を見た場合でも、重複した確定処理を無視できます。

最後の点は本番環境では重要です。同じ生成結果が複数回観測されることはあります。completedfailed のような終端状態への更新は、冪等にしておく必要があります。

小さな状態モデル

最初から複雑なステートマシンを作る必要はありません。小さなモデルでも十分に始められます。

created -> queued -> processing -> completed
                         |
                         -> failed

それぞれの状態は、明確な意味を持たせます。

  • created: リクエストを受け付けた
  • queued: バックグラウンド処理を予約した
  • processing: プロバイダー側のジョブが開始された
  • completed: 最終的な画像アセットが利用可能になった
  • failed: タスクを完了できない

重要なのは、終端状態を保護することです。一度 completed または failed になったタスクに対して、リトライや重複コールバックが同じ結果を再適用しないようにします。

生成結果は自分たちのストレージに保存する

多くのAIプロバイダーは、生成画像のURLを返します。ただし、そのURLは一時的なものだったり、プロバイダー側の管理下にあったりします。

本番プロダクトでは、最終結果を自分たちのストレージにコピーした方が扱いやすくなります。

Provider result URL -> app storage -> stable asset URL

Cloudflareを使う場合であれば、最終画像をR2に保存し、自分たちのCDNドメインから配信する構成が考えられます。

これにより、次のような処理を管理しやすくなります。

  • ユーザー所有権の確認
  • ダウンロード
  • クリーンアップ
  • モデレーション
  • 安定したプレビューURL
  • 課金履歴との紐付け

AIプロバイダーは画像を生成します。一方で、画像をプロダクト内でどう扱うかはアプリケーション側が責任を持つべき領域です。

複数モデル対応ではさらに効いてくる

複数のモデルや生成方式を扱うアプリでは、非同期ワークフローの価値がさらに大きくなります。

テキストから画像を作るモデル、画像編集モデル、参照画像を使うワークフローでは、それぞれ挙動が異なります。すぐに結果を返すものもあれば、プロバイダー側のジョブIDが必要なものもあります。高解像度出力に対応しているものもあれば、入力制限が異なるものもあります。

このような差分をフロントエンドに直接漏らすと、UIと状態管理が複雑になります。

一方で、バックエンド側に共通のタスクライフサイクルを持たせておけば、ユーザーにはシンプルな生成体験を提供しつつ、プロバイダーごとの差分を内部に閉じ込められます。

これは、特定のプロバイダーAPIを中心に設計するのではなく、プロダクトのワークフローを中心に設計するという考え方です。

まとめ

AI画像生成は、単なるモデル呼び出しではありません。プロダクトとしては、時間のかかるジョブ、重複コールバック、リトライ、ストレージ、モデレーション、クレジット処理まで含んだワークフローです。

実験であれば同期的なAPIルートでも十分です。本番環境では、非同期アーキテクチャにしておくことで、遅い処理や失敗をより安定して扱えます。

モデルは画像を作ります。ワークフローはプロダクトを信頼できるものにします。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?