AI News HubLIVE
站内改写4 分で読了

すべてのAIエージェント機能はキャッシュ無効化面である

OpenClacky(Rubyで書かれたオープンソースAIエージェント)の創業者Yafei Lee氏は、スキル、メモリ、サブエージェント、ブラウザ自動化、動的モデル切り替え、長時間実行セッションなどの機能を構築する際に、プロンプトキャッシュが深刻な問題を引き起こすことを共有しています。2年間と3世代のアーキテクチャ(最初の2世代は失敗)を経て、90%以上のキャッシュヒット率を達成する7つのエンジニアリング上の決定に収束しました。この記事では、RAGとマルチエージェントオーケストレーションの失敗と、最初の3つの決定(ダブルキャッシュマーカー、固定システムプロンプト、単一メタツール)について詳しく説明しています。

ソースHacker News AI著者: gemHunter

著者のYafei Lee氏は、Rubyで書かれたオープンソースAIエージェント「OpenClacky」の創業者です。彼らは、スキル、メモリ、サブエージェント、ブラウザ自動化、動的モデル切り替え、長時間実行セッションなどの機能を備えたAIエージェントを構築しようとしたところ、これらの機能がそれぞれ異なる方法でプロンプトキャッシュを悪化させることを発見しました。真のアーキテクチャ上の問題は、LLMの呼び出し方やツールの追加方法、エージェントの調整方法ではなく、製品が変化し続ける中でキャッシュのプレフィックスを安定させることでした。すべてのエージェント機能はキャッシュ無効化面です。スキルは新しいシステムコンテキストをロードし、ピアエージェントのワークフローはプレフィックスをフォークし、ブラウザ自動化は変動しやすいツール出力を追加し、圧縮は履歴を書き換え、モデル切り替えはキャッシュ名前空間を断片化します。強力なエージェントを構築しているのにキャッシュヒット率が予想よりはるかに低い場合、これが原因でしょう。

2年間と3世代のアーキテクチャ(最初の2世代は失敗)を経て、彼らは7つのエンジニアリング上の決定に収束し、それらの機能をすべて維持しながら実際のタスクで90%以上のキャッシュ率を達成しました。この記事では、何が壊れたか、何を試したか、そして実際に何が機能したかについて完全なストーリーを提供しています。

第一世代:RAGですべてをカバー(2024年初頭~2025年初頭)。最初のエージェントは教科書的なRAGシステムでした。ユーザーのコードベース、ドキュメント、会話履歴をベクトルストアに埋め込み、すべてのクエリはハイブリッド検索、再ランキング、クエリ書き換えを経てからLLMに渡されました。理にかなっているように聞こえますが、実際は違いました。コストは上昇し続け、データは常に古くなっていました。コードベースの更新のたびに再埋め込みが必要で、リアルタイム同期は信頼性が低く、ベクトルストアは実際のコードに遅れをとっていました。彼らはますます間違ったインデックスに対して高いコストを支払っていました。90%の再現率では十分ではありません。誤ったコンテキストが返される確率が10%あり、エージェントが複数のステップを連鎖させる場合、その誤差は急速に累積します。97%の再現率がエージェントが正味プラスになるための最低限の要件であると推定しましたが、それにはほど遠い状態でした。さらに、ベクトルデータベースはクラッシュ、遅延、またはガベージを返す可能性のあるもう一つのコンポーネントでした。ローカルリポジトリで動作するコーディングエージェントの場合、彼らはRAGを完全に排除しました。埋め込みもベクトルストアも検索パイプラインもありません。エージェントがコンテキストを必要とする場合は、ファイルを直接読むかgrepで検索します。

第二世代:マルチエージェントオーケストレーション(2025年中期)。次のアイデアはSWEBenchリーダーボードのプレイブックからそのまま引用したものでした。プランナーエージェント、コーダーエージェント、レビューアーエージェント、テスターエージェントがメッセージバスを通じて調整され、それぞれに役割固有のプロンプトが与えられます。SWEBenchのスコアは良かったものの、製品はひどいものでした。エージェントのハンドオフのたびにキャッシュミスが発生し、各サブエージェントが独自のシステムプロンプトとキャッシュ名前空間を持っていました。エージェント間のコンテキストの受け渡しには状態のシリアル化が必要で、ハンドオフのたびに受信エージェントのキャッシュプレフィックスが消去されました。1つのエージェントで4分で完了するタスクが、4つでは14分かかりました。コストは6倍、デバッグは悪夢でした。彼らは役割ベースのマルチエージェントオーケストレーションを廃止し、1つのメインエージェント、1つの会話、1つのキャッシュ名前空間に戻しました。サブエージェントは、単一の安定したツールを通じて呼び出される、隔離されたスキル実行コンテキストとしてのみ存続しました。

第三世代:7つの決定。第三世代は、すべてを単一のエージェントのキャッシュヒット率を中心に最適化したらどうなるかという疑問から始まりました。コスト削減のハックとしてではなく、アーキテクチャの原則としてです。キャッシュヒット率が高いということは、モデルが一貫したコンテキストを確認し、応答が速く、コストが低いことを意味します。以下に最初の3つの決定を紹介します。

決定1:履歴の増大がプレフィックスマッチングを壊す → ダブルキャッシュマーカー。プロンプトキャッシュはプレフィックスマッチングによって機能しますが、履歴の単調な増加、ツールコールのリトライ、セッション中のモデル切り替えによってシングルマーカーキャッシュが壊れます。彼らはダブルマーカーを使用します。毎ターン、連続する2つのメッセージにマークを付け、ローリングダブルバッファを形成します。これにより、ツールコールのリトライ時でも2番目のマーカーが残ることがよくあります。マーカー選択ロジックは、システムインジェクションされたメッセージ(セッションコンテキストブロックなど)をハードルールでスキップします。

決定2:動的セッション状態がシステムプロンプトを壊す → 固定システムプロンプト。システムプロンプトはセッション開始時に一度構築され、その後バイト単位で固定されます。動的な情報(現在の日付、作業ディレクトリ、モデルID、新しくインストールされたスキル、更新されたユーザー設定など)をシステムプロンプトに含めることはできません。代わりに、システムインジェクション・マークされたユーザーメッセージとして履歴に注入されます。これにより、これらの情報が変わっても、後続のすべてのキャッシュエントリが無効化されることはありません。注入のタイミングは重要で、システムプロンプトの構築後に行う必要があります。そうしないと、システムプロンプトの構築がスキップされてしまいます。

決定3:スキルとサブエージェントが履歴を肥大化させる → 単一メタツール。invoke_skillは16のツールのうち最も多くの作業を行い、検索可能なスキルワークスペースからスキルファイルを読み取り、ツール定義を動的に入力します。重要な設計は、スキルの説明がツール定義に事前に入力されるのではなく、呼び出し時にSKILL.mdから読み取られることです。これにより、新しいスキルをインストールしてもツール定義が変わらず、キャッシュプレフィックスが安定します。スキル名はセッション開始時にシステムプロンプトにレンダリングされて固定されるため、新しいスキルは次のセッションまで自動的に検出されませんが、ユーザーが明示的に要求した場合はinvoke_skillを通じて実行できます。

記事はここで終わっていますが、著者は各決定を実装したコードへのリンクを記事の最後に提供すると約束しています。