プログラミング
Prime AgentをRustで書き直し
Rewriting Prime Agent in Rust (primeintellect.ai)
要約
Prime Agentは、30万回以上ダウンロードされ、8兆トークン以上を処理したツールですが、この度Rustでゼロから書き直されました。Rustへの移行により、パフォーマンスの向上、リソース使用量の削減、コードの保守性・開発性の向上が実現しました。この書き直しは、2,000以上のエージェントが自己書き換えを行うという自律的なプロセスを経て行われました。
全文翻訳
Prime AgentをRustで書き直し
Prime Agent [1] を8月にローンチして以来、30万回以上ダウンロードされ、8兆トークン以上を処理してきました。本日、Rustでゼロから書き直された、より高速でクリーン、そして信頼性の高いPrime Agentを出荷します。2週間かけて、Prime Agentは2,000以上のエージェントの群れをオーケストレーションし、エンドツーエンドで自己書き換えを行いました。これは10,000以上のPrime Sandbox上で、Prime InferenceのGLM-5.3エンドポイントからの2,000億トークン以上を使用して実行されました。
Rustへの書き直しは、Prime Agentのマルチエージェント機能、特に大規模なエージェント群、自律的なリサーチ、強化学習を可能にするために構築してきたサンドボックスおよび推論インフラストラクチャをストレステストしました。TypeScriptバージョンとの機能同等性を確保するため、Prime Agentはサブエージェントをオーケストレーションして依存関係をトポロジカルソートさせ、有限状態機械がループ計算と正しさのチェックを構造化しました。並行して、メンテナンスと開発を容易にするためにコードアーキテクチャを書き直しました。その後、ランタイムベンチマークと実際のPrime Agentトレースを使用してパフォーマンスメトリクスをヒルクライムし、バグをトリアージしました。現在、Prime Agentはほとんどのコーディングエージェントハーネスよりも高速に実行され、リソース使用量も少なくなっています。
サブエージェントの深さ
| Depth | ParentDepth | Depth 1 | Depth 2 | Depth 3 |
|---|---|---|---|---|
| Rust Implementation | 19 | 2.99B tokens | 1,981 agents | |
| Performance Hillclimb | 35.70B tokens | 228 agents | Oct 01, 15:59 | 2,209 agents · 16,758 agent-to-agent messages · 228.70B total tokens |
なぜRustか
TypeScriptはPrime Agentを迅速にリリースするのに役立ちましたが、その型はオプションであり実行時には消滅し、エラーはチェックされない例外として伝播します。レンダリングや大規模セッションの解析のようなCPU負荷の高い作業は、単一のイベントループ上でキーボード入力と競合し、各プロセスはJavaScriptランタイムとガベージコレクタのコストを負担します。私たちは、これまで通りの速さでリリースを続けたいと考えていますが、コードが成長するにつれてより高い基準を維持したいと考えており、Rustはその目的に適しています。
パフォーマンス: Prime Agentは長時間稼働するデーモンであり、セッションごとにワーカープロセスを使用します。ガベージコレクタのないネイティブコードは、メモリと起動時間のほとんどの改善の大部分を占めています。
並行性: 1つのデーモンがモデル出力をストリーミングし、ツール呼び出しを実行し、エージェント間のメッセージを中継し、接続されているすべてのクライアントに同時にサービスを提供します。RustのSendおよびSyncトレイトは、コンパイラがどのデータがスレッド間で移動可能で、どのデータが共有可能かをチェックできるようにします。
コンパイル時の保証:網羅的な列挙型、所有権、ライフタイムは、コードが実行される前にクラス全体のバグを排除します。Clippyの厳格なリンティングは、さらに数百のチェックを追加します。これは、エージェントがコードのほとんどを書く場合には重要です。
これらの明確なパフォーマンス上の利点に加えて、書き直しは設計上の選択を再考する機会を与えてくれました。コードベースを大幅にモジュール化し、Windowsサポート、セッションクラッシュの分離、より一貫したデーモンプロトコルなど、この書き直しから得られるメリットを享受しています。
Prime Agentはいかにして自己書き換えを行ったか
私たちの目標は、人間の介入を可能な限り少なくして、エージェントが自律的に書き換えを行うことでした。したがって、必要な人間の作業は、大規模な自律展開を可能にするための適切な検証を設定することでした。以前のRustへの自動翻訳 [2] の作業と同様のセットアップに従いました。各仕様は、異なる種類のパリティをカバーしていました。
TUIパリティ: 差分テストスイートは、TypeScriptとRustのバイナリを並べて同じスクリプト化されたモデルに対して比較し、それぞれがレンダリングするターミナルフレームを差分表示します。起動、スラッシュメニュー、ツール呼び出し、圧縮、エージェントビュー、セッション再開、サブエージェント、クラッシュリカバリを含むユーザーフローをカバーします。
ハーネスパリティ: 同じ実行でセッショントランスクリプトとバイナリがモデルプロバイダーに送信するリクエストを差分表示するため、両方とも同じ入力から同じセッションを生成します。
プロトコルパリティ: デーモンプロトコルのすべてのメッセージタイプは、TypeScript実装に対してチェックされ、ACPおよびデーモンプロトコルAPIの一貫性が保証されます。
機能パリティ: スクリプト化されたフローはインターフェース全体をカバーできないため、エージェントはTypeScript製品をコンポーネントごとに監査し、それぞれを一致、部分一致、または欠落として分類しました。
各種類のパリティに対して客観的なチェックがあるため、エージェントは自身の進捗を測定し、変更がマージされる前にリグレッションを検出でき、人間のレビューを削減できました。残りのバグと動作の違いは、主に内部使用を通じて発見され、欠落している機能、信頼性、インターフェースの洗練に関するフォローアップ作業を導きました。
すべてのオーケストレーターとそのエージェントを、それぞれ100以上の同時サブエージェントとそのCpythonカーネルをサポートする2つの8コアオンデマンドCPUノードで実行しました。さらに、多数のエージェントが同時に実行されている場合、コンパイル、型チェック、差分表示は単一のマシンを飽和させるため、エージェントが重い作業をPrime Sandboxにオフロードするためのユーティリティを構築し、ポートを大幅に並列化できるようにしました。
客観的なTUIパリティ検証ツールは、TypeScriptバージョンとRustバージョンのターミナルフレームを比較し、違いを強調表示します。
有限状態機械のオーケストレーション
単一のルートエージェントが書き換えをオーケストレーションし、作業をタスクのトポロジカル順序に分割しました。ルートエージェントは製品コードを一切書かず、すべてのタスクを監視し、完了した作業をマージし、優先順位や決定事項について私たちと協力しながら書き換えの全体像を維持することに専念しました。また、コードを書くエージェントは評価において偏りがあるため、生成と検証を別々のエージェントに分けました。したがって、オーケストレーターによって割り当てられた各タスクは、4つのエージェントを経由しました。
プランナー: 機能設計、グラウンドトゥルースのTypeScriptの動作、および検証ツール(パリティチェック)を含む、全体のマシン仕様を作成します。
実装者: 機能を並列開発できるように、専用のワークツリーにRustコードを記述します。
レビュー担当者: 実装者とは異なるモデルと別のコンテキストを使用して、変更が間違っている理由を探し、敵対的にプルリクエストを検査します。
検証者: 新しいPrime Sandboxで機能のパリティチェックとテストをコンパイルして実行します。
レビューまたは検証が失敗すると、機能は調査結果とともに実装者に送り返され、両方がパスするとPRはマージされます。
私たちはこのパターンをPrime Agentに組み込み、有限状態機械のファクトリをオーケストレーションしており、このようなワークフローは一度定義され、再利用され、更新される可能性があります。
アーキテクチャの再設計
Rustへのポートは、コードベースを再構築する機会も与えてくれました。これが長期的なメリットの多くをもたらす部分です。
モジュール性: コードは9つのクレートに分割され、Cargoが強制する一方向の依存関係グラフを持ち、TUIの唯一の内部依存関係は共有型クレートです。最大のソースファイルは現在約2,500行で、TypeScriptの約15,000行から削減され、TypeScriptの4ファイルに対して、5,000行を超えるファイルはありません。
分離: 各セッションは、小さなスーパーバイザーの下で独自のワーカープロセスで実行されるため、1つのセッションの障害が他のセッションの実行を妨げず、セッションはディスクに永続化されるため、クライアントは再起動後に再接続できます。
プラットフォーム抽象化: トランスポート、プロセス制御、ファイルロックはプラットフォーム固有のインターフェースの後ろに配置されているため、Windowsサポートのようなものは、デーモンを配線し直すのではなく、それらのトレイトを実装することによって実現されました。
1つのプロトコル定義: クライアント、デーモン、およびすべてのワーカーは、共有型クレートの同じメッセージタイプに対してコンパイルされるため、プロトコルの変更は使用されているすべての場所でチェックされます。
カタログ駆動型モデル: モデルとMCPリストを、実行時に取得される別のカタログにポートしたため、Prime Agentのリリースなしで新しいモデルとプラグインをリリースできます。
作業の洗練
自律ワークフローは予想以上に進みましたが、パリティチェックは実行された動作しか検証しませんでした。メインのRLMループでパリティが達成された後、すべての書き換えエージェントをRustに移行し、Rustバージョンを大規模にドッグフードできるようにしました(そして今やPrime Agent Rustは再帰的に自己改善していました!)。その後、内部チームをRustビルドに移行して日常使用できるようにしたところ、差分テストのカバレッジ外のバグや欠落している動作が露呈しました。私たちのすべての書き換えエージェントをRustに移行し、Rustバージョンを大規模にドッグフードできるようにしました(そして今やPrime Agent Rustは再帰的に自己改善していました!)。その後、内部チームをRustビルドに移行して日常使用できるようにしたところ、差分テストのカバレッジ外のバグや欠落している動作が露呈しました。私たちのすべての書き換えエージェントをRustに移行し、Rustバージョンを大規模にドッグフードできるようにしました(そして今やPrime Agent Rustは再帰的に自己改善していました!)。その後、内部チームをRustビルドに移行して日常使用できるようにしたところ、差分テストのカバレッジ外のバグや欠落している動作が露呈しました。