マルチエージェントオーケストレーションと分散システム
分散システムの古典的な課題
一部が失敗し、他は動き続ける
逆に言えば、部分的な障害が全体に大きな障害をもたらしてはならない 共有状態がない
各プロセスは他プロセスの内部状態を直接参照できない 観測できるのは、通信と外部化された状態だけ
複数プロセスが同じ資源を同時に扱うため、競合しうる
通信の信頼性がない
マルチエージェントシステムでも同様の課題がある
あるエージェントがタイムアウトしても、他のエージェントは動き続ける
各エージェントは他のエージェントの内部状態を直接は知らない
基本的には独立している
あるいは持っていたとしても局所的な観測のみ
複数エージェントが同じコードベースやファイルに対して同時に変更を試みる
worktreeを分離して作業していても、マージ時にコンフリクトが発生する可能性がある
LLMのAPIコールや外部ツール呼び出しは不安定
失敗、遅延、途中で断絶、不完全な結果を返すことがある
ハーネス設計で前提とすべきこと
ハーネスは、独立に失敗しうる複数のプロセスを調停し、再試行し、統合しなければならない
LLMエージェントの実行は(仕組みからして当然)非決定論的
同じ入力でも出力は一意でない
APIコールが失敗する
出力が途中で止まる
想定外の変更を行い、他のプロセスの担当範囲を侵すことがある
一切の失敗なく一方向に進行できることを前提にしてはならない
途中失敗、再試行、中断、再開、差し戻しを前提とした設計が必要
設計原則
決定論的(deterministic)処理と非決定論的(non-deterministic)処理の分離
非決定論的な操作(LLM呼び出し、外部I/O等)はステップとして隔離し、結果を永続化する
ステップ間の制御フローはできる限り決定論的に保つ
これにより、障害発生後のreplayで同じ履歴から同じ制御経路を再現しやすくなる
完了済みステップの結果(cache)を安全に再利用できる
両者を混在させるとreplay時に異なる経路をたどりやすくなり、再実行の安全性が崩れる(冪等性が保証されなくなる)
状態の外部化
オーケストレーターのプロセス自身はできるだけステートレスに保つ
インメモリでステートを持たない
こうすることでオーケストレーターが故障しても、復帰後に状態を読み取り、タスクを安全に再開できる
各プロセスは隔離された環境で並列に作業を進め、コンフリクトは統合時に検出する
原則としては事前にロックで排他しない(悲観的並列性制御はしない)
コンフリクトが検出された場合は、そのコンフリクト情報を元に再試行で解消する
LLM呼び出し自体は非冪等だが、ステップの結果を永続化することでステップレベルの冪等性を実現する
再実行時はキャッシュされた結果を返し、実際の操作は行わない
冪等性は操作の性質ではなく、フレームワークが保証する
リトライ時に前回の試行を上書きしない
新しい試行を作成し、古い試行は凍結された履歴として残す
これにより、失敗した試行の不完全なクリーンアップによる状態の不整合を防ぐ
監査・デバッグ・observabilityの観点でもメリットがある
失敗は例外ではなく通常系
timeout、retry、部分的失敗/成功が起こることを前提とする
逆に言えば全てが一発で完全に成功することを前提としてはならない
可観測性
各ステップの入力、出力、ログ、再試行履歴、マージ履歴などは追跡可能であるべき
ハーネスは単に実行するだけでなく、何が起きたかを説明できなければならない
非決定論的システムでは、可観測性は補助機能ではなく制御機構の一部
関連実装
決定論的/非決定論的処理の分離
Temporal Workflows must be deterministic.
"For a given Workflow Type, its Workflow Definition (implementation) must produce the same sequence of Commands given the same History"
状態の外部化
楽観的並行性制御
Git: 並列で作業して、merge時にコンフリクトを検出したらそのときに解消する