エージェントシステムを出荷するすべてのチームが、だいたい3か月目に同じ質問にたどり着きます。「Temporal / Inngest / Restate が必要なのか、それともリトライを足すだけでいいのか?」
答えはほぼ必ず「durable オーケストレータが必要だが、その理由は『リトライ』ではない」です。
リトライが本当に解決するもの
リトライは、呼び出しを発行した同じプロセス が一時的な失敗を観測したときの正しい道具です。ネットワークの瞬断、レート制限のレスポンス、不安定なダウンストリーム。呼び出し元は失敗結果を手元に持っており、何をやろうとしていたかを把握しており、単にもう一度試せばよいわけです。
このために必要なものは、exponential backoff を持つリトライポリシー、最大試行回数の上限、受信側の冪等性です。これはシステムではなくライブラリの話です。p-retry、tenacity、tokio-retry のどれかを選んで次に進みましょう。
Durable 実行が本当に解決するもの
Durable 実行は、プロセス自体 がステップ間で死ぬ可能性があるときの正しい道具です。クラッシュ、デプロイ、k8s による Pod 退避、リクエストタイムアウトを超える30分の LLM 呼び出し。問うべきは「もう一度試せるか」ではなく、「電気が切れたときどこにいて、すでに成功した部分をやり直さずにどう再開するか」です。
これは根本的に別の問題です。必要なものは:
- 永続化されたステップ状態 — どのステップが完了したか、その結果は何かのログ。
- 再生可能なヒストリ — プロセスが再開するときログを辿り、完了済みステップをスキップし、最初の未完了ステップから続行する。
- 決定論的なステップ境界 — 再生をまたいでオーケストレータがステップを一意に識別できるようにコードを構造化する。
これをゼロから書くこともできます。実際に書く人もいます。レースコンディションを6か月デバッグした末に、Temporal の劣化版を作っていることに気づきます。
実際の判断
エージェントシステムに以下があるなら:
- 個別に数秒以上かかるツール呼び出し、
- 約3ステップ以上の逐次ワークフロー、
- 途中のどこかでハンドオフや human-in-the-loop が入る、
- デプロイ再起動でユーザー可視の失敗が起きるのを許容できない SLA、
…durable オーケストレータが必要です。「あれば便利」ではありません。必要です。後から導入するのは、最初から導入するより遥かに高くつきます。
システムが短く、同期的で、ステートレスなら(プロンプト1つ、レスポンス1つ、5秒で完了)、リトライで十分です。オーバーエンジニアリングしないでください。
我々が出荷するもの
実務では、デフォルトは言語スタックに応じて Temporal か Restate です。各 LLM 呼び出し、ツール呼び出し、承認が別ステップになるようワークフローコードを構造化します。コストは学習曲線と運用すべきランタイムです。便益は、「このプロセスがワークフローの途中でクラッシュしたらどうなるか」が新機能ごとに答えなければならない問いではなくなることです。オーケストレータが一度答えてくれます。
リトライは「この呼び出しが失敗した」を解決します。Durable 実行は「この ワークフロー が、それを実行している何かの障害をまたいで生き延びる必要がある」を解決します。これらは代替ではありません。本番システムのほとんどは両方を必要とし、人々が過小評価しているのは2つ目です。