7月28日、Salesforce Engineeringが「Building Reliable Production AI with Durable Workflows」と題した記事を公開した。本番環境のAIシステムを信頼できるものにするために、Durable Workflows(耐久性のあるワークフロー)をどう設計するかを、Agentforce Grid構築の実例をもとに解説した内容だ。
プロトタイプが本番で壊れる理由
AIのプロトタイプを作るのは簡単だ。プロンプトを送り、レスポンスを受け取り、結果をユーザーに返す。リクエストが独立している限り、動作は単純で、テストもデバッグもしやすい。
問題は、本番環境に出た瞬間に始まる。
たとえば、1万件のレコードに対してAI出力を生成するケースを考える。数千のモデル呼び出しが同時に走り始め、あるものはすぐ完了し、あるものはレートリミット、一時的な障害、バリデーションエラー、ツール呼び出しの遅延に遭遇する。そこにワーカーの再起動やデプロイが重なったとき、問題はもはや「モデルが正しい回答を生成したか」ではなくなる。「何が完了していて、何がまだ動いていて、何を重複なく安全にリトライできるか」という分散実行のデバッグに変わる。
この記事は、SalesforceがAgentforce Gridの構築を通じて得た知見をまとめたものだ。
「失敗した行」は本当の問題ではない
記事が最も鋭い指摘をしているのが、この節だ。
ワーカーが8,432行目の処理中にクラッシュし、8,431行は成功している状況を考える。一見、「8,432行目が失敗した」のが問題に見える。だが実際に問いかけるべきは別のことだ。
- モデルはレスポンスを生成できていたが、ワーカーがDBへの書き込み前にクラッシュしたのではないか?
- 出力はDBに届いたが、ステータス更新だけが失敗したのではないか?
- この行を安全にリトライできるのか、それとも完了済みの処理を重複実行してしまうのか?
これらは「行」の問題ではなく、実行そのものに明示的な状態表現がないことの問題だ。失敗した行は、不確実性が表面化した場所に過ぎない。
回復の単位をどう決めるか
Gridが採用したアプローチは、実行を階層構造としてモデル化することだ。
- カラム実行:ユーザーの全体リクエストを表す親ワークフロー
- 行またはバッチ:意味のある実行単位(子ワークフロー)
- アクティビティ:入力の解決、プロンプト構築、モデル呼び出し、バリデーション、出力書き込み
この構造により、無関係な処理を再実行せずに失敗を隔離できる。全体をひとつのジョブとして扱えば、リトライが数千件の成功済みモデル呼び出しを繰り返す。逆に細かすぎる粒度で管理すれば、オーケストレーションのオーバーヘッドが跳ね上がる。適切なリトライ境界は、回復可能な最小の意味ある作業単位というのが、ここで導かれる原則だ。
実行状態をどこに置くか:Temporalの採用
GridはDurable Workflowsの基盤としてTemporalを採用した。Temporalは、長時間実行するワークフローを、永続化された履歴・リトライポリシー・回復境界を持つワークフローとアクティビティとしてモデル化できるワークフローエンジンだ(※元記事でOSSとの明示はないため、ライセンス形態についてはTemporal公式サイトを参照されたい)。
従来の多くのシステムは、ログやDBの状態、タイムスタンプから進捗を「再構築」しようとする。この方法は障害が少ない間は機能するが、実行が長く複雑になるほど脆くなる。
Temporalを使うと、実行履歴がワーカーのライフサイクルの外側に永続化される。ワーカーが消えても、別のワーカーがその履歴から処理を再開できる。ワーカーは交換可能だが、実行は失われない。
内部パフォーマンステストの結果
記事内で公開されている数字は明確だ。10ユーザー同時アクセス・1ワークシートあたり200行という条件での内部テストにおいて:
- 移行前(同期実行パス):負荷下で約90%の失敗率。リトライストームが10分以上続き、その間システムはどこまで処理が終わったか把握できなかった
- Temporal移行後:失敗率0%。Prompt Templateの移行では、P95完了時間が約60%改善
なお、これらは内部パフォーマンス環境の数字であると記事内で明記されている。
リトライ設計の具体策
リトライもDurable Workflowsの境界に合わせて設計されている。
- 各バッチは行ごとにチェックポイントを記録
- 指数バックオフで最大10回リトライ
- リトライ時は、まだ完了していない最初の行から再開
- すでに有効な出力を生成した行は再実行しない(モデルクォータの無駄遣いを防ぐ)
- アクティビティレベルで、リトライ不可のエラータイプを定義可能
一時的なモデルのタイムアウトは該当アクティビティのみをリトライし、バリデーション失敗は失敗した行だけに隔離される。
ユーザーへの進捗の見せ方
正しく回復できることと、ユーザーが信頼できることは別の話だ。「実行中…」という単一のステータスでは、処理が進んでいるのか、リトライしているのか、止まっているのかが分からない。特にAIワークフローは実行時間が長くなりやすく、ユーザーが途中で処理を中断したり誤った操作をしたりするリスクが高い。そのため、進捗の可視性は単なるUXの問題ではなく、システムの信頼性を構成する要素のひとつだ。
Gridは実行を複数レベルで公開している:
- セル:個別の生成値のステータス
- 行:1レコードの処理状況
- カラム:ユーザーが要求した実行全体
- ワークシート:全体の進捗サマリー
回復の境界と進捗表示の境界を一致させることで、エンジニアもユーザーも状態を手動で再構築せずに把握できる。内部的なリトライが発生していても、どの粒度で何が完了・失敗・処理中なのかをリアルタイムに把握できる構造は、障害発生時のデバッグコストを大きく下げると記事は述べている。
モデルを選ぶ前に設計すべきこと
記事の結論として強調されているのは、アーキテクチャの優先順位だ。AIが本番ワークフローに組み込まれた瞬間、それは他の大規模プラットフォームと同じ分散システムの課題を引き継ぐ:状態管理、並行性、リトライ、観測可能性、デプロイ、冪等性、回復。
「どのモデルを使うか」「どうプロンプトを書くか」より先に問うべきことがある:
- 回復可能な最小の意味ある作業単位は何か?
- ワーカーの再起動を超えて生き残るべき状態は何か?
- どの操作を安全にリトライできるか?
記事はこう締めている。「実行が8,432行目に到達したところで何か予期せぬことが起きたと想像してほしい。最初の直感が『全部やり直す』なら、まだモデル実行を中心に設計している。『どの状態が残ったか』と問うなら、本番向けの設計が始まっている。」
詳細はBuilding Reliable Production AI with Durable Workflowsを参照していただきたい。