スポンサーLobeHubLobeHub詳しく見る
dshfind

第 2 課:動機となる例:VSCode プラグインと AI エージェント

一言で言うと:プラグインシステムは一般に「インストールは簡単、取り外しは困難」です——VSCode でプラグインを無効化するにはプロセス全体を再起動する必要があり、別のプラグインに依存しようとしても型の保証がありません。一方、将来の AI エージェントはまさに実行時に絶えず自己改変を行うため、「インストールでき、取り外せ、互いを破壊しない」能力が最も必要とされます。これこそが Cordis 論文が解決しようとする問題です。

1. 時間的制約:インストールは簡単、取り外しにはプロセス全体の再起動が必要

まず思考実験をしてみましょう。あなたのスマートフォンはいつでもどこでも新しいアプリをインストールできますが、もし「実行中のあるアプリだけをシステムから取り除き」、完全に停止させてメモリから退出させようとしたとき、システムがこう告げたらどうでしょう:申し訳ありません、スマートフォン全体を再起動する必要があります。他のアプリも一緒に再起動します。荒唐無稽ではありませんか?

VSCode のプラグインシステムは、まさにこの荒唐無稽な現状です。論文はこれを「プラグインシステム」の代表例として使っています:

  • VSCode はすべての拡張機能を同じ「拡張機能ホスト」(extension host)共有プロセス内で実行します;
  • 拡張機能は動的にインストール可能です——実行時にインストールするのは問題ありません;
  • しかしホストには**「実行時に個々の拡張機能のコードをアンロードする」仕組みがありません**;
  • したがって、ある拡張機能の activate 関数の実行が完了した後、それを無効化またはアンインストールしたい場合、ホストプロセス全体を再起動するしかなく、読み込み済みのすべての拡張機能が影響を受けます。

すべての拡張機能がこれほど厄介なのでしょうか?いいえ、鍵となるのはコードを含むかどうかです:

拡張機能の種類典型的な例単独で削除できるか
純粋に宣言的(コードを含まない)テーマ、キーバインド、スニペット✅ できる。自由に削除可能
実行可能なコードを含む言語サービス、デバッガー、自動補完❌ できない。削除にはホスト全体の再起動が必要

データはどれほど深刻でしょうか?インストール数上位 100 の拡張機能のうち、87 個が実行可能なコードを含んでいます。つまり、よく使われる拡張機能の大多数は「取り外す」ことすらままならないのです。

deactivate フック:「臨終コールバック」にすぎず、アンロードではない

VSCode には deactivate フックがあるのではないか?「アンロードコールバック」のように聞こえる?名前に騙されないでください:

  • それはホストプロセスがすでに終了を開始した後に呼び出される「グレースフルシャットダウンコールバック」にすぎません——遺書を書くようなもので、リアルタイムの除去ではありません;
  • さらに悪いことに、それはエフェクトの解放deactivate に書く)とエフェクトの生成activate に書く)を2 か所に分離してしまい関心の局所性(locality of concern)に違反し、「完全なクリーンアップ」の検証を困難にしています。

💡 「関心の局所性」とは何でしょうか?本の貸し借りの例で考えてみましょう:activate は「借りるときの登録」、deactivate は「返すときの登録」です。貸出登録と返却登録が完全に独立した 2 つのシステムに分かれていると、「貸し出した本がすべて返却されたか」を検証するのは困難です。deactivate が「生成」と「破棄」を分離するため、クリーンアップが完全かどうかは推測ゲームになってしまいます。

2. 空間的制約:プラグイン同士は「ほとんど相互に依存しない」

時間軸では取り外しがうまくいかない、では空間軸ではどうでしょう?プラグイン同士はうまく「協調」できるのでしょうか?論文の答えは:VSCode は「拡張機能が拡張機能に依存する」ための安全で構造化された方法をほとんど提供していません

VSCode は確かに extensionDependencies というフィールドを提供しており、拡張機能間の依存を宣言できます。しかし実際の使用状況を見てみましょう:

インストール数上位 100 の拡張機能のうち、extensionDependencies を使って組み込み以外の拡張機能への依存を宣言しているのはわずか 7 個です。

なぜこんなに少ないのでしょうか?論文は 2 つの理由を挙げています:

  1. 拡張機能 API の形態が拡張機能を「各自独立」にさせている:この API はコマンド、ビュー、言語機能などの固定された表層的な拡張ポイントしか公開しません。拡張機能は拡張ポイントを通じてホストに「機能を提供」するのであって、相互に依存するのではありません——だから拡張機能間の依存はほとんど生じません。
  2. 拡張機能間の相互作用に構造化された契約がない:VSCode は vscode.extensions.getExtension(...).exports を通じてある拡張機能の機能を他の拡張機能に公開しますが、戻り値には型がありません(デフォルトは any)——依存する側は「型チェックされたインターフェース」にまったく依存できません。

🏢 たとえ話をしましょう:マンションの住民(拡張機能)は管理人(ホスト)とだけやり取りします。隣の部屋から何かを借りたい?管理人経由でメモを渡す(exports)しかなく、しかもメモの内容の書式は誰もチェックしません(型チェックなし)。隣人の宿題を写したくても、隣人が渡してくれるのは前後の脈絡のない紙切れだけで、書式が合っていることを祈るしかありません。

まとめ:VSCode は拡張機能に対し、ホストが提供する固定された拡張ポイントの集合を使うよう導いていますが、「拡張機能同士が依存し合う」ための安全で構造化された方法は提供していません。

⚠️ ちなみに、この 2 つの制約はVSCode に固有のものではありません——さまざまなプラグインシステムで、程度の差こそあれ現れます。つまりこれはある製品の些細な欠陥ではなく、「プラグインアーキテクチャ」全体の持病であり、論文がメスを入れようとしている箇所なのです。

3. なぜ自己進化する AI エージェントにはなおさら必要なのか?

こう言う人もいるでしょう:VSCode プラグインの問題なんて、我慢すれば済むのでは?我慢できません。AI エージェントの時代はこの痛みを何倍にも増幅させるからです。

現代の AI エージェントはランタイムエージェントフレームワークに依存しています:各種ツールスイートと実行環境を組み合わせ、権限とサンドボックスを管理し、セッション状態と永続化を維持し、コンテキスト管理とメモリを提供し、サブエージェントやマルチエージェントワークフローをオーケストレーションし、ユーザーや自動化システムへのインターフェースを提供します。そして将来のエージェントフレームワークは、リクエストを継続的に処理しながら、自身のコンポーネントへの修正を生成・デプロイするかもしれません——これが「自己進化」です。モデルが合成した再利用可能なツールは、「コンポーネントレベルの自己改変」のより範囲の狭い先駆的形態です。

ここが重要です:このような自己改変のたびに、それ自体が 1 回の動的コンポジションのインスタンスになります——新しいコンポーネントをインストールするか、古いコンポーネントを取り外すかです。しかもこれらの修正は継続的に発生し、人間の監督は限定的か皆無なので、動的コンポーザビリティは「不可欠」です。これが欠けたらどうなるでしょうか?

欠けるもの結果
時間的コンポーザビリティ自己改変のたびにプロセス全体の再起動が強制され、プロセス内に蓄積されたすべての状態が失われます。この頻度で発生すると累積のダウンタイムはかなりのものになり、実行中のタスクは繰り返し中断されます。さらに悪いことに:欠陥のある自己改変は「復旧に必要なプロセス」自体を無効化する可能性があります
空間的コンポーザビリティ各モジュールは依存先モジュールの変化を自ら検出し、それらが出現、消失、または同一性を変えたときに適応しなければならず、場当たり的な手段に頼るしかありません。さらに悪いことに:素朴なコード置換戦略は依存側を音もなく破壊したり、リロード時にしか露呈しない循環依存を持ち込んだりする可能性があります

⚠️ この 2 つの「さらに悪いことに」に注目してください:時間の次元では、「システムを復旧するためのプロセス」さえ壊されかねません——命綱を燃やすようなものです。空間の次元では、破壊は「音もなく」起こり、リロード時になって初めて問題が露呈しますが、その時点ではすでに手遅れです。長期間無人で稼働するエージェントにとって、この 2 種類の「さらに悪いことに」はどちらも災難です。

4. 粗粒度の回避策:使えなくはないが、代償が大きい

こう疑問に思うかもしれません:これほど明白な問題なのに、なぜこれまで誰も解決しなかったのでしょうか?論文の答えは率直です:オペレーティングシステムとコンテナオーケストレーターがすでに「粗粒度」の代替策を提供しており、皆それで長い間しのいできたからです

  • プロセスの終了と再起動アドレス空間全体の粒度で時間的コンポーザビリティを実現できます;
  • コンテナオーケストレーションサービス全体の粒度で空間的コンポーザビリティを実現できます。

実際、ほとんどのソフトウェアは確かにこの 2 つの手段で帳尻を合わせています:モジュールの動作が異常ならプロセスを再起動し、サービス間の依存はオーケストレーターに任せるのです。

しかし、この回避策は代償が大きいのです:

  • 時間の次元:再起動のたびにプロセス内に蓄積されたすべての状態——キャッシュ、接続、部分的に完了した計算——がゼロになります。これらの状態を再構築するには数秒から数分かかります。その間の可用性を維持したい?冗長なレプリカを立てるしかなく、リソースのオーバーヘッドで「単一コンポーネントを復旧できない」問題を埋め合わせることになります。
  • 空間の次元:コンテナレベルのオーケストレーションは同じアドレス空間を共有するコンポーネント間の依存を表現できません。本来ローカル関数呼び出し 1 回で済むやり取りが、ネットワークのオーバーヘッドを負わされます。
传统做法换 1 个插件 → 重启整个宿主插件A插件B插件C插件D全部一起停 ❌Cordis 做法换 1 个插件 → 只拆它自己插件A插件B插件C插件D只停 1 个,其他继续 ✅

粒度不匹配:想换一个组件,传统做法却要推倒整个进程

これが粒度のミスマッチです:再起動とオーケストレーションはプロセスやコンテナの境界で動作しますが、現代のシステムはますますより細かいレベルでコンポーズされています。私たちに必要なのは、コンポーネント自身と同じレベルでエフェクトと依存を管理できるコンポジショナルな抽象化——コンポーネントレベルの「インストール、取り外し、互いを破壊しない」です。これこそが、論文が次に構築する形式化の基盤です。

重要ポイントの振り返り

このレッスンは情報量が少なくありませんが、次の 5 文を覚えておけば十分です:

  1. 時間的制約:VSCode のすべての拡張機能は 1 つの「拡張機能ホスト」プロセスを共有し、実行時に個々の拡張機能をアンロードする仕組みがありません。インストール数上位 100 の拡張機能のうち 87 個がコードを含み、削除にはホスト全体の再起動が必要です。
  2. deactivate はアンロードではない:それはホストプロセス終了時の「臨終コールバック」にすぎず、解放と生成を 2 か所に分離して関心の局所性に違反するため、完全なクリーンアップの検証が困難です。
  3. 空間的制約:拡張機能はホストに機能を提供するだけで、ほとんど相互に依存しません(上位 100 のうち依存を宣言しているのは 7 個のみ)。exports で機能を公開しても、戻り値は any であり、型付きの契約はありません。
  4. 自己進化するエージェント:自己改変のたびに動的コンポジションが発生します。時間的コンポーザビリティが欠けると頻繁な再起動で状態を失い、復旧プロセスさえ壊されかねません。空間的コンポーザビリティが欠けると、モジュールは各自で場当たり的に対処し、破壊は音もなく起こります。
  5. 回避策の粒度ミスマッチ:プロセスの再起動やコンテナオーケストレーションはプロセス/コンテナの境界で動作し、状態の喪失、冗長レプリカ、ネットワークオーバーヘッドという代償が伴い、コンポーネント自身のレベルでエフェクトと依存を管理できません。

🚀 次のレッスンの予告:動機は明確になりました——私たちに必要なのは「コンポーネントレベルのインストールと取り外し」です。第 3 課では、論文の 3 つの中核的貢献(取り消し可能なエフェクト、リアクティブな副作用、コンポーネントライフサイクルモデル)を概観し、全編を貫く型判断の記法に触れます。

セルフテスト · 動機となる例

回答を終えたら「解答を送信」をクリックすると、正誤と解説を確認できます。

1. なぜ VSCode で「コードを含む拡張機能」を無効化またはアンインストールするには拡張機能ホストプロセス全体を再起動しなければならないのですか?
2. VSCode の deactivate フックについて、正しい説明はどれですか?
3. なぜ VSCode の拡張機能同士はほとんど相互に依存しないのですか?(上位 100 のうち組み込み以外の拡張機能への依存を宣言しているのは 7 個のみ)
4. なぜ「プロセスの再起動やコンテナオーケストレーション」のような粗粒度の回避策は、自己進化するエージェントフレームワークの要求を満たせないのですか?