7月24日、Inside AIが「Why Adding More AI Agents Made Our System Slower, Not Faster」と題した記事を公開した。AIエージェントを増やすほどシステムが遅くなるという逆説的な現象の原因と、その設計上の解決策について、Planckチームの実例をもとに詳しく論じている。
エージェントを増やしたら遅くなった
Planckのチームが本番環境でAIエージェントを少数運用していたころ、パフォーマンスは許容範囲内だった。しかし、エージェントを数百規模に拡張し、それぞれが数十のサブエージェント呼び出しを行うようになると、レイテンシが非線形的に増加し始めた。タイムアウトや原因不明のレイテンシスパイクも発生した。
最初に疑われたのは外部のLLMプロバイダーだった。しかしログを調べると、プロバイダー側のリクエスト処理は速い。問題は自分たちのシステム内にあった。
真の犯人は「小さなCPU処理の積み重ね」
PlanckのサービスはPythonのasyncioとaiohttpを使って並列リクエストをさばいていた。I/Oバウンドな処理が主体であれば、理論上レイテンシは最も遅いLLM呼び出しに支配されるはずだ。ところがプロファイリングの結果は異なる様相を示した。
「LLMのレスポンスが届くたびに、イベントループは次のコルーチンに移る前に少量のCPU処理を実行しなければならない。個々の処理はほぼコストゼロだ。しかし数百、数千の並列呼び出しにわたって集積すると、それがボトルネックになる」——Planckチーム
原因として挙げられたのは、JSONのシリアライズ・デシリアライズのオーバーヘッド、コネクションプールの上限、そしてPython特有のGIL(グローバルインタープリタロック)だ。GILはPythonのバイトコード実行を直列化するため、並列に見える処理でも実際にはコアを奪い合う形になる。
orjsonでJSONパースを高速化し、aiohttpのコネクション上限を引き上げても、エージェント数が増えるとレイテンシは上昇し続けた。asyncio.sleep(I/O模擬)とtime.sleep(CPU処理模擬)を組み合わせたベンチマークでも同じパターンが確認された。純粋なI/O処理はスケールするが、わずかなCPU処理が混入するだけでレイテンシが線形増加する。
「ボトルネックをなくす」のではなく「分散させる」
マイクロ最適化の限界を悟ったPlanckは、アーキテクチャ自体を再設計した。単一プロセスで全エージェントをさばく構造から、ルーターが複数のワーカーに仕事を分配する構造へ移行した。各ワーカーは独自のイベントループとコネクションプールを持つ独立したプロセスとして動作する。
具体的には、受信リクエストをルータープロセスが受け取り、タスクキューを介して複数のワーカープロセスへ振り分ける構成だ。各ワーカーは担当するエージェント群のみを管理するため、あるワーカーでCPU負荷が高まっても他のワーカーの処理には波及しない。ワーカー数はエージェントの増加に合わせて水平方向に追加でき、既存ワーカーのイベントループを圧迫しない。
「ボトルネックをなくしたわけではない。水平スケールできる小さな単位に分割した」——Planckチーム
この設計変更により、新しいエージェントを追加しても既存のパフォーマンスを劣化させずに済むようになった。エンジニアが継続的なマイクロ最適化に追われる状況からも解放された。
これはPythonだけの問題ではない
Planckが直面したのは、いわゆるファンアウトパターンの古典的な落とし穴だ。単一リクエストが多数の並列タスクを生成し、それぞれがI/O完了後にわずかなCPUを要求する構造は、言語を問わず限界を露わにする。GILはPythonでその影響を増幅させるが、GoやJavaであってもコア数の上限という現実は同じだ。ファンアウトパターンでは、大量リクエストの殺到による過負荷(サンダリングハード問題)を避けるための慎重なリソース管理が必要とされる点も、広く知られた設計上の課題だ。
また、Planckはこれと並行して、RAGパイプラインのストレージをインメモリから共有ストレージへ切り替える必要にも迫られた。エージェントのスケールはデータ基盤全体の見直しを要求することも多い。ベクターデータベースの使いどころについては、元記事内でも別記事として言及されているが、そのURLは本稿執筆時点では確認できなかったため、リンクは割愛する。
教訓:効率的なコードより設計が先
Planckの経験が示す教訓は明快だ。
「優れたエンジニアリングとは効率的なコードを書くことだけではない。システムが成長し続けてもスケールできる設計をすることだ。よく書かれたコードは、設計の悪いシステムを補うことはできない」——Planckチーム
非同期I/Oの初期の単純さは、高負荷時にのみ顕在化する隠れたCPUコストを覆い隠す。プロファイリングと段階的な最適化は有効だが、最終的な解答は水平スケールを前提とした設計にある、というのがPlanckの結論だ。
詳細はWhy Adding More AI Agents Made Our System Slower, Not Fasterを参照していただきたい。