未来を形作るテクノロジーの深掘り記事。

LLMエージェントは結局、分散システムだ

マルチエージェントLLMは分散システムと同じ課題を抱える。調整コスト、合意形成、障害モード、そして形を変えたCAP定理まで解説する。

テーブルを囲んでメッセージチューブでやり取りする発光ロボットたち。1体は故障して暗くなっている。

AIコミュニティでは今、マルチエージェントシステムの開発が進んでいる。単一のモデルでは扱いきれない問題を解くために、LLMのチームが作業を分担し、互いに連携する仕組みだ。「リサーチャー」エージェントが情報を集め、「コーダー」エージェントが実装を書き、「レビュアー」エージェントが品質を確認し、「コーディネーター」エージェントがワークフロー全体を管理する。専門化されたエージェントが、うまく回っているエンジニアリングチームのように協働するという発想は、確かに魅力的だ。

どこかで聞いた話だと思うかもしれない。実際その通りで、分散システムの研究者たちは独立したプロセスを協調させる問題を40年にわたって研究してきた。マルチエージェントLLMシステムは、分散システムのコミュニティが何十年も前に解決した(あるいは解けないと証明した)問題を、ゼロから再発見しているようなものだ。こうした類似点を理解しておけば、解決策を一から作り直す手間が省けるし、予測可能で既によく知られた形で壊れるシステムを作らずに済む。

調整のコスト

分散システムの最初の教訓は、協調にはオーバーヘッドがかかるということだ。独立した別々のタスクを2つのプロセスで並行に処理すれば、確かに速度は2倍になる。しかし同じタスクを2つのプロセスで分担し、しかも互いに調整が必要になると、通信と同期のオーバーヘッドが並列化の利益を上回り、1つのプロセスより遅くなることがよくある。

マルチエージェントLLMシステムでも、これはすぐに起きる。「リサーチャー」エージェントがレポートを作る。「コーダー」エージェントはコードを書くためにそのレポートを理解する必要がある。「レビュアー」エージェントは有益なフィードバックを返すために、レポートとコードの両方を把握しなければならない。エージェント間の受け渡しのたびに、文脈をプロンプトへ直列化し、受け取った側のエージェントがそれを解析して理解する必要がある。これはまさに共有状態という分散システムの問題であり、エージェントを増やすほど悪化していく。

Single agent vs. multi-agent for a coding task:
Single agent:
1. Understand the problem         (1 LLM call)
2. Research relevant APIs          (2 LLM calls)
3. Write implementation            (1 LLM call)
4. Review and fix                  (1 LLM call)
Total: 5 LLM calls, full context throughout
Multi-agent (researcher + coder + reviewer):
1. Coordinator describes task      (1 LLM call)
2. Researcher reads and plans      (1 LLM call)
3. Researcher does research        (3 LLM calls)
4. Researcher summarizes findings  (1 LLM call)
5. Coder reads summary             (1 LLM call)  ← context lost here
6. Coder writes implementation     (1 LLM call)
7. Reviewer reads code + summary   (1 LLM call)  ← context lost here
8. Reviewer provides feedback      (1 LLM call)
9. Coordinator synthesizes         (1 LLM call)
Total: 11 LLM calls, context degraded at each handoff
More agents = more communication = more cost = worse context.

分散システムの言葉で言えば、これは通信に適用されたアムダールの法則だ。並列化による高速化は、並列化できない逐次的な通信によって頭打ちになる。密な調整が必要なタスクにエージェントを追加すると、システムは速くなるどころか遅くなる。

合意形成の問題

複数のエージェントが同じタスクに取り組むと、いくつかの点で合意する必要が出てくる。要件は何か。どのアプローチを取るべきか。この実装は正しいのか。分散システムではこれが合意問題(コンセンサス問題)であり、原理的に難しいことが知られている。FLP不可能性定理が示すとおり、非同期システムでは障害のあるプロセスが1つでもいると、決定的な合意は不可能になる。

LLMエージェントは、非決定的であるという理由で、従来の分散プロセスよりも合意形成が厄介だ。同じエージェントに同じ質問を2回すれば、違う答えが返ってくることがある。同じコードをレビューした2つのエージェントが、そのコードが正しいかどうかで意見を違える可能性もある。意見の対立を解決するよう求められた「コーディネーター」エージェントが、コイン投げのような判断を下すこともありうる。

マルチエージェントのフレームワークは、通常この問題を2通りの方法で扱う。最終的な決定権を持つコーディネーターエージェントを置くか(中央集権型の合意モデルで、単純だが単一障害点を生む)、多数決を取るか(コストが高く、1回の決定に最低3つのエージェントが必要になる)だ。どちらも機能はするが、そもそも作業を複数のエージェントに分割したことで生じた問題を解いているにすぎない。

見覚えのある障害モード

マルチエージェントシステムは、分散システムのエンジニアならすぐに気づくような形で壊れる。

  • 連鎖的な障害。 エージェントAが不適切な出力を生成する。Aの出力を前提に作業するBは、さらに悪い出力を作る。Bの成果をレビューするCは、元の誤りに気づかない。誤った前提を引き継いでしまうからだ。これは分散システムにおけるエラーの伝播にあたり、いわゆるGIGO(ゴミを入れればゴミが出る)が各段階で増幅される。
  • デッドロック。 エージェントAは先に進むためにBの出力を待つ。Bは先に進むためにAのフィードバックを待つ。どちらも前に進めない。実際には、エージェント同士が作業を行ったり来たりさせ、いつまでも収束しない無限ループとして現れることが多い。
  • スプリットブレイン。 関連するタスクを担当する2つのエージェントが、問題に対して食い違った認識を持つ。一方はAPIがJSONを返すと想定し、もう一方はXMLを想定している。それぞれの出力は単独では正しいが、互いに噛み合わない。
  • サンダリングハード(雷鳴の群れ)。 コーディネーターエージェントが複数のエージェントに同時に作業を振る。全員が同じAPIを叩いてレート制限に達したり、同じファイルを同時に変更しようとしたりする。単一のエージェントなら決して遭遇しないリソースの競合だ。

マルチエージェントが本当に役立つとき

分散システムとの類似は、両刃の剣でもある。分散システムには特定の問題に対する実際の利点があり、マルチエージェントシステムにも、分解すると本当に恩恵のある問題では同じことが言える。

並列化が容易なタスク。 50個のコードベースから同じパターンを探すなら、50個のエージェントが独立して作業すれば、文字通り50倍速い。調整は一切不要で、各エージェントが別々の入力を扱い、独立した出力を生成する。これはMapReduceのパターンであり、分散データ処理と同じくLLMエージェントにもそのまま効く。

多様な視点。 異なるシステムプロンプトを与えた3つのエージェントに同じコードをレビューさせると、1回のレビューでは見落とすような問題が見つかることがある。これは冗長化のパターンであり、PRに複数のレビュアーを付けるのに近い。コストは計算資源の3倍だが、カバレッジは広がる。

明確なインターフェースを持つ専門化。 テキストを受け取って翻訳済みテキストを返す翻訳エージェントは、きれいなインターフェースを持つ。文書を受け取って要約を返す要約エージェントも同様だ。これらを組み合わせ、翻訳してから要約するという流れは、間のインターフェースが単純なのでうまく機能する。分散システムに置き換えれば、明確に定義されたAPIを持つマイクロサービスは、やり取りが多く複雑なインターフェースのマイクロサービスより良く機能する、ということになる。

分散システムから学べること

マルチエージェントLLMシステムを作るなら、数十年分の分散システムの知見がそのまま当てはまる。

  1. 多数の専門エージェントより、少数で能力の高いエージェントを優先する。 うまく設計されたモノリスが、雑に作られたマイクロサービス構成より優れた結果を出すのと同じで、多くのタスクでは、適切なプロンプトを与えた1つの有能なエージェントが、狭い役割のエージェントチームより優れる。単一のエージェントでは処理しきれないと実証できた場合にだけ、エージェントを追加する。
  2. エージェント間のインターフェースを明確に定義する。 各エージェントの入力と出力は明確に定義すべきだ。「リサーチャーが見つけたものを把握して実装して」といった曖昧な受け渡しは、文脈の欠落と誤解釈を招く。エージェント間では、自由形式のテキストよりも構造化されたデータ契約のほうが機能しやすい。
  3. エージェントを冪等にする。 エージェントが途中で失敗したら、同じ入力で再起動して正しい結果が得られるべきだ。そのためには、隠れた状態を持たず、出力の正しさを確認するまで副作用を起こさないエージェントが必要になる。
  4. オブザーバビリティを確保する。 エージェント間のメッセージ、すべての判断、すべての失敗を記録する。マルチエージェントシステムが誤った出力を出したとき、どのエージェントがどの理由で誤った判断をしたのかを追跡できなければならない。オブザーバビリティがなければ、デバッグは当てずっぽうになる。
  5. 部分的な障害を前提に設計する。 どのエージェントも失敗したり、ゴミを出力したり、タイムアウトしたりしうる。システムはそれを穏当に処理すべきで、リトライする、より単純な方法にフォールバックする、あるいは人間に尋ねるといった対応を取る。すべてのエージェントが成功すると決して仮定してはならない。

耳の痛い真実

単一のモデルで処理できるタスクであれば、ほとんどのマルチエージェントLLMシステムは、良いプロンプトを持つ1つのエージェントで作ったほうがうまくいく。マルチエージェント構成の調整コスト、文脈の欠落、障害モードは、多くの場合その利点を上回ってしまう。AIツールが進化するにつれて、精巧なマルチエージェントシステムを作りたくなる誘惑は強まるが、分散システムの教訓は明快だ。分散させる必要のないものは分散させるな。

例外は確かに存在する。並列化が容易なタスク、明確なインターフェースを伴う本当の専門化、そして単一モデルのコンテキストウィンドウを超える問題がそれにあたる。それ以外の場合は、よく構造化されたプロンプト、良いツール、そして思慮深いリトライ戦略を備えた単一のエージェントが、エージェントのチームより良い結果を出す。建築としての派手さには欠けるが、そのほうが確実に動く。最良の分散システムとは、そもそも構築する必要がなかったシステムである。