エージェンティック・ハーネス設計ガイド — Part 3
耐久実行と再開
落ちない設計ではなく、落ちても続きから戻れる設計へ。
耐久実行(durable execution)とは、プロセスが落ちても処理の続きから再開できるように、実行の進行状況を外部に永続化しながら進める実行方式です。ステップ境界でチェックポイントを書き、完了したステップは二度と実行せず、未完了のものを検出して同じ ID で再開します。
Part 1で挙げた6つの構成要素のうち「記憶・状態」の後半、そしてPart 2で扱った「文脈をどう保つか」の外側にあるのが、この記事の主題です。
エージェント実装で最も見落とされやすいのが、ここです。デモは通るのに業務では使えない——その原因の多くは、実行が中断されたときに何が起きるかを決めていないことにあります。しかもこの領域は、AIの問題ではなく分散システムの問題です。だからこそ、すでに答えが出ている領域でもあります。
1.中断は例外ではなく、前提である
対話型AIの応答は数秒で終わります。その間に何かが起きる確率は、実質ゼロです。一方、自律型エージェントの実行は数分から数時間に及びます。
ここで重要なのは、これがAI固有の問題ではないという点です。長時間の処理を安全に完了させる方法は、分散システムの分野で長く議論され、実装のパターンが確立しています。エージェントのために新しい理論を発明する必要はなく、既存の答えを持ち込めばよい領域です。
2.4つの不変条件
文献が共通して処方する条件は、おおむね次の4つに収まります。個別の技術選定より先に、この4つが満たされているかを確認します。
3.① 流れは決定的に、ステップは冪等に
再開を成立させる土台は、2つの性質の分業です。全体の流れは決定的に、個々のステップは冪等に。この分業があって初めて、「どこまで終わったか」を照合して続きから実行できます。
よくある落とし穴
流れの分岐に「現在時刻」や乱数を使うと、再開したときに前回と違う道を辿ります。記録には「ステップB完了」とあるのに、再開後の実装はステップCへ進もうとする——このズレが、最も追いにくい不具合になります。時刻や乱数が必要なら、それ自体をステップとして実行し、結果を記録に残します。
4.二重実行を、構造的に消す
冪等性の実装は、操作に鍵を割り当て、実行前に照会するという形が基本です。
鍵は乱数ではなく、操作の中身から決まる値にします。「いつ計算しても同じ鍵になる」ことが条件で、実行のたびに新しい鍵を振ってしまうと、再試行は常に新規実行として通ってしまいます。
この仕組みの有無が、そのまま「再試行してよいか」の答えになります。冪等でない操作は、失敗しても安全に再試行できません。エージェントに「失敗したらもう一度試して」と指示する前に、その操作が二重実行に耐えるかを確認する必要があります。
5.② 待機を永続化する — 承認でプロセスを握らない
人の承認は、数時間から数日かかります。この間プロセスを保持する実装は、2つの問題を抱えます。資源を握り続けることと、再起動が入ると待機ごと消えることです。
この設計は、承認の話にとどまりません。「明日の朝まで待つ」「上流の処理が終わるまで待つ」といったあらゆる長い待機に同じ形が使えます。逆に言えば、この仕組みがないハーネスでは、長い承認フローも定時実行のような待ち合わせも安全には作れません。
あわせて設計しておきたいのが、承認待ちを実行時間の予算に算入しないことです。人を待っていた時間まで「実行時間の上限」に数えると、承認が遅れただけでタイムアウトします。
6.③ heartbeat は、生存だけでなく進捗を運ぶ
長時間の処理が生きているかを確認する仕組みが heartbeat です。多くの実装はここで打刻だけを送りますが、それでは失敗したときにゼロからやり直しになります。
運ぶ進捗は、細かい内部状態である必要はありません。次の試行が続きを判断できる最小限——処理済みの件数、最後に成功した位置、残っている対象——で十分です。
7.「応答がない」を、1種類で扱わない
運用で最も判断に迷うのが、応答がないときに待つべきか、打ち切るべきかです。同じ症状の裏には、まったく違う2つの状態があります。
この2つに加えて、リトライを横断した全体の上限を別に持ちます。1回の試行が短くても、再試行を重ねれば全体としては際限なく延びます。「1回の試行の上限」と「全体の上限」は、別の目的を持つ別の設定です。
Part 1 との対応
Part 1 で示した「タイムアウトの4分類」——キュー待ち・1回の試行・リトライ横断の総量・heartbeat の途絶——は、この判断を実装に落とすための分類です。分類そのものが目的ではなく、「待つのか、殺すのか」を機械的に決められるようにすることが目的になります。
8.④ 再開は、外から起こす
最後の条件が、回復の起点をどこに置くかです。ここに落とし穴があります。
よくある実装は、クライアントの再訪に寄生した再開です。ユーザーが画面を開いたときに「未完了があれば再開する」処理が走る。これは動いているように見えますが、誰も開かなければ永久に再開されません。夜間に落ちたバッチは、翌朝誰かが気づくまで止まったままです。
起点は、外からの定期チェックに置きます。「未完了の仕事を探して起こす」処理を独立して走らせ、クライアントの有無に依存させない。これが能動的な回復です。
もうひとつ、実運用で効いてくるのがバージョンの取り扱いです。再開の途中でコードが変わると、記録と実装が食い違います。互換のあるバージョンだけが回復を引き受けるようにしておくと、デプロイのたびに古い仕事が壊れる事態を避けられます。
9.失敗の「層」を、つぶさずに返す
耐久実行の設計と対になるのが、失敗をどう伝えるかです。ここを雑に扱うと、上のすべてが台無しになります。
最低限、次の3つは区別して返します。
- 障害 — 接続できない、落ちた。再試行の対象になる。
- 空の結果 — 正常に実行し、該当がなかった。再試行しても結果は変わらない。
- 拒否 — 権限がない、禁止されている。手段を変えるか、人に確認する。
このうち最も事故を生むのが、「障害」を「空の結果」として扱ってしまうパターンです。接続できなかっただけなのに「該当なし」として処理が進み、エージェントは何もなかったものとして次へ行く。表面上は正常に完了し、後から誰も気づけません。
10.アンチパターン早見表
ここまでの内容を、実装で見かける形にして並べます。
| よくある実装 | 何が問題か | どうするか |
|---|---|---|
| 実行状態をプロセスのメモリだけに持つ | プロセスが死ぬと、進行中の作業が丸ごと消える | ステップ境界で外部に書く |
| 冪等キーを持たずに再試行する | 送信・登録・課金が二重になる | 操作の中身から鍵を決め、実行前に照会する |
| 承認待ちの間、プロセスを保持する | 資源を握り続け、再起動で待機ごと消える | 起床条件を永続化して、いったん解放する |
| heartbeat が打刻だけ | 失敗するとゼロからやり直しになる | 進捗を一緒に運ばせる |
| タイムアウトが1種類しかない | 混雑と死亡を区別できない | キュー待ちと試行時間を分けて持つ |
| 誰かが画面を開いたときに再開する | 誰も開かなければ、永久に再開されない | 外からの定期チェックを起点にする |
| 実行環境の障害を「失敗しました」で返す | エージェントが自分の出力のせいだと解釈する | どの層で何が起きたかを保って返す |
Summary
この記事の要点
- 1中断は例外ではなく前提。「落ちない設計」ではなく「落ちても続きから戻れる設計」にする。
- 2これはAI固有の問題ではなく分散システムの問題。すでに答えが出ている領域から持ち込めばよい。
- 3全体の流れは決定的に、各ステップは冪等に。分岐に乱数や現在時刻を混ぜない。
- 4冪等キーは操作の中身から決める。乱数で振ると、再試行が常に新規実行として通ってしまう。
- 5承認待ちでプロセスを保持しない。起床条件を永続化して解放し、承認時に新しいプロセスが再開する。
- 6承認を待っていた時間を、実行時間の予算に算入しない。
- 7heartbeat には進捗を載せる。打刻だけでは、失敗するとゼロからやり直しになる。
- 8「応答がない」を1種類のタイムアウトで扱わない。混雑と死亡は、見るべき指標が違う。
- 9回復の起点は外からの定期チェックに置く。クライアントの再訪に寄生した再開は、誰も来なければ動かない。
- 10失敗は層を保って返す。とくに「障害」を「空の結果」として扱うと、誰も気づけない失敗になる。
Sources
出典・参考文献
本記事は、以下の一次資料をもとに整理しています。仕様は各出典の公開時点のものです。
FAQ
よくある質問
耐久実行とは、プロセスが落ちても処理の続きから再開できるように、実行の進行状況を外部に永続化しながら進める実行方式です。ステップ境界でチェックポイントを書き、完了したステップは二度と実行せず、未完了のものを検出して同じIDで再開します。AIエージェントの実行は数分から数時間に及ぶため、この方式が必要になります。
実行が長くなるほど、その間にデプロイ・再起動・ネットワーク断・上流の障害・人の承認待ちが起きる確率が上がるためです。数秒で終わる対話型AIでは無視できた事象が、数時間の実行では必ず起きます。「落ちない設計」を目指すのではなく「落ちても続きから戻れる設計」にするのが現実的です。
再試行を安全にするためです。同じステップを2回実行しても結果が変わらない(=冪等である)なら、失敗したときにそのまま再試行できます。冪等性がないと、再試行のたびにメールが二重送信されたり、登録が重複したりするため、そもそも安全に再試行できません。実装は、操作の中身から一意に定まる鍵を割り当て、実行前に「この鍵は実行済みか」を照会する形が基本です。
止めるべきです。承認は数時間から数日かかることがあり、その間プロセスを保持すると資源を握り続けるうえ、再起動が入ると待機ごと消えます。起床の条件を永続化してプロセスを解放し、承認が下りた時点で新しいプロセスが続きから再開する方式にします。長い承認フローは、この仕組みがないとそもそも作れません。
不十分です。打刻だけでは「動いていた」ことは分かっても「どこまで進んだか」が残らず、失敗するとゼロからやり直しになります。heartbeat に進捗を載せておけば、次の試行が中断地点の続きから始められます。長い処理ほど、やり直しのコストは大きくなります。
タイムアウトを1種類で扱わないことです。キューに積まれたまま始まっていない(混んでいるだけ)なら待つか並列度を上げる、始まったが進んでいない・落ちている(死んでいる)なら打ち切って再開する、という判断になります。この2つを区別できないと、生きている仕事を殺すか、死んだ仕事を待ち続けるかのどちらかになります。
Part 2
コンテキスト設計 — 捨てる・書き出す・畳む
有限の予算としての文脈管理。要約を最初の手段にしない設計。
Part 4 — 準備中
ツール設計とスキル — 読ませすぎない
実行可能な改善を返すエラー設計、名前空間、段階的開示の3層、決定性のスクリプト化。
実行基盤を、自社で持ちたい方へ
homulaは、AIエージェント実行基盤の要件定義から設計・構築・運用までを支援しています。耐久実行や再開の設計は、受入条件として先に定めておくべき領域です。