15 KiB
Nia 構想
llm-workerをベースとして、カスタマイズ可能なToolや、pluginによってワークフローを設計可能にする。
目標は、エージェントを動かすためのエンジンとなり、Dockerのようなエコシステムを構築すること。
-
エージェントの活動単位
- プロセス:(MORE SPEC REQUIRED)1プロセス1セッション?サブエージェントの扱い方
- ディレクトリ:基本は下位ディレクトリ全体をワーキングディレクトリとして扱う。
サブエージェントに移譲する際は、ディレクトリのexclude又は権限の移譲を必要とし、同時に書き込むことを防ぐ。
- これは単に、ディレクトリツリーの管轄を切り分け、ツールの制限として弾き、また、他のpodが存在するディレクトリは削除・移動出来ないということ
- ネットワーク越し:通常のメッセージパッシングだが、
niad(デーモンプロセス)を用いる必要がある。 後述のworkspace単位で公開鍵認証あたりが必要だと考えている
-
workspaceとして、複数エージェント間のコミュニケーションや知識を取りまとめる区分を作成する- 複数のワーカーが存在する以上、可視範囲を作らなければならない
- が、これをローカルマシンに閉じる必要がないという考え
- モジュール・マイクロサービスを総括するためのもの
- (PLAN)スケーラビリティの考え方、大規模にスケールできる必要性(将来的には)
- 複数のワーカーが存在する以上、可視範囲を作らなければならない
-
永続化
- セッションの履歴を完全に保持する必要はないと考えている。
- ドキュメントとして残し、参照可能にする。
- 直近のセッションは復元可能である必要性がある
- Gitとの相性:ドキュメントでのある時点での参照は後々壊れる可能性がある。
- そもそもworkspaceは複数gitレポジトリに跨ることがあるし、workspace自体をgitで管理するべきとするか否か。
- コミットハッシュ+ファイル名みたいな挙動が必要かも。
- ビルトイン・モジュールで詳細化している。
- セッションの履歴を完全に保持する必要はないと考えている。
エコシステム設計
前提
以下の既存の仕組みについて考察する。
既存の仕組みとの折り合い
AIのツールを拡張する仕組みに、MCPがある。ツール、データソースの供給、プロンプトのテンプレートを標準化している。
MCPツールをniaのツール定義につなぐ仕組みは既存資源の活用の観点から必須であると考えている。 リソースアクセスは解釈の余地があるが、結局get_resourceみたいなツールとしてAIに渡されるので、Niaが持つResource管理の仕組みに組み込めたら良いかもしれない。
テンプレートはSkillsと合わせて一つの仕組みにするべきだと考えている。 Skillsは任意のタイミングで読める、知らない知識や壊れやすい手順を補助する説明書で、AIにはそれを読むことでタスクの行い方を理解することが期待される。
よって、MCPのPromptsはシステムプロンプトを含めたコンテキストの初期状態から組み立てる必要のあるSkillsと解釈できる。 しかしながら、システムプロンプト含めて構築するのは、サブエージェントでは有効だが、長期間のタスクでは適さないと考えている。
ACPは、エージェントとエディタの通信を定義する仕組み。ACPはセッションの開始要求や操作・能力の通知などを行う仕組みであるから、このシステムには適さない。 また、権限や処理等をエディタに任せる仕組みである為、立場としてはacp対応エージェントをpodでwrapし、niaシステムで利用できるようにするような組み込み方が適していると考えている。
AGENTS.mdは、プロジェクトの全容や知っておくべき内容を記載するドキュメントだが、これはAIに更新させるには原始的すぎで、人が更新するには自由すぎる仕組みだと考えている。 ユーザーの指示はAIが理解して記憶するべきだし、プロジェクトの知識やユーザーの指示を蓄積するよりよい仕組みに代替されるだろうという考え。
拡張性に求められる仕組み
llm-workerで目指した、抽象化はするが、より深い制御も可能にする設計は、niaでも必要だと考えている。 MCPからToolsやResourcesを作る仕組みは必要だが、このデフォルト機能をオプトアウトし、ユーザーが自身で仕組みを作れなければ、エコシステムとしては十分でない。
llm-workerとの境界がまさにこれで、エンジンとしてのllm-workerの自由度を利用しつつ、ビルトインの仕組みにプラグインできると良い。 CURDやShellツール、subagentを呼び出すツール等のビルトインツールは提供しつつ、ユーザーが自身で定義するフォーマットも受け入れられる必要がある。
ワーカーの設計を行う仕組み
なにが出来るかを定義する仕組みがSkillsで、説明と追加のリソースとツールをセットで提供する。 どう動く必要があるかを定義する仕組みがWorkflowsで、出来ること(Skills)に加え、Hooksとロジックを合わせて定義できる。
Workflowはセッション固有で、Skillsは幾つでも定義可能。
Toolsは、KVキャッシュ・コンテキストエンジニアリングの考えに基づき、一度コンテキストに載せたら削除は出来ない。 なぜなら、実行したことのあるツールが存在しない状況はLLMにとって混乱を招く為。
- Tools: ツールを定義する、((比較的)低レイヤな)llm-workerの仕組み
- Hooks: イベントに基づいてWorkerを制御する、(同上)llm-workerの仕組み
- Resources: ReadOnlyな情報源を定義する仕組みで、Toolsを生成する。
- (TODO) 結局はツールなので、そのツールの設計は考える必要がある。
- Skills: LLMに対する動的な指示文を定義する仕組み。ClaudeのSkillsと類似する。
- Workflows:
LLMが行うべき作業の流れを定義する仕組み。Tools/Hooks/Skillsを持てる。
- システムプロンプトを定義し、セッション全体の流れを制約するものであるため、動的にロードできない。ある地点から、今から作業完了モードに入るというよりは、 全体の流れを定義するものにしたい。
- Skillsを内包するが、システマチックに行動を制約する仕組みを提供する。
コーディング->lintを通す->レビューをパスする->記録を書く->完了みたいな流れを定義可能にしたい。任意の言語でロジックを書けるようにするか、あるいはDSL的に定義するか。
- Profiles:
利用可能なツール、登録されたHooks、最初から与えられるSkills/Workflow、利用可能なSkillsなどをまとめて定義する。
- 利用するプロバイダとモデルや、ビルトインのシステムに対するコンフィグ、サードパーティのプラグインに対するコンフィグなどを纏めて良いかも。
LSP/Toolchainについて:言語機能やツールチェーンを呼び出す仕組みは、Hookを用いて編集検知->自動lintフィードバックと、Workflowで編集したらbashでcheckを実行する指示を出せば良い。
また、他のエコシステムとの統合を目指して、LLM/Workerの抽象化層を提供する仕組みを考える必要があるが、 現在のllm-workerでは、llm_clientとして抽象化しているが、拡張機能としてプロバイダをロードする仕組みを提供する必要がある。
as Plugin/Extension
Workflowを書くことができればそれでハーネスになると考えている。
具体的には、Tool/Hookからデータを収集し、Workflowを進める仕組みなど。
Rhai等のスクリプトを用いて書けると良いと思うが、RustのWasmコンパイルを用いて安全で深い制御ができれば、より良い選択肢になるだろう。
ビルトイン・モジュール
エコシステムの上に成り立つ、組み込みのモジュールで構成されるシステム。
デフォルトの挙動を形成し、最も重要と言える。
File Tools
CURDと権限をセットで提供する。AIが何を読み、何を編集したのかを記録できる。
また、先述の管轄ディレクトリ内に権限を制限したり、差分を取得するAPIを提供したりする。
Companion
ユーザーが主に対話するプロファイルで、直接的にタスクには取り組まず、秘書のように振る舞う。
この役割自体は、Profileとして定義されており、ユーザーの指示を広く受け取るため、Workflowは使われない。
ドキュメントやメモリーを参照したり、ファイルを検索したりして、ユーザーの質問に答えたり、タスクを設計したりする。
常にプロジェクトを把握している役割として振舞うことが期待される。
Document Resources
ドキュメントを記録する仕組み。
- specドキュメント
- 作業記録
Readable-Index を組み込みたい。
workspace
同じプロジェクトに属するpodをまとめる仕組みで、プロジェクトに応じてpodを分離するための論理的な空間である。
ファイルシステム的な制約は無く、ディレクトリを持つ必要はない。
先述のドキュメントシステムをworkspace単位で構築する仕組みを提供する。
システムの必要なコンポーネント
pod:実際にファイルを読み書きするプロセスniad:デーモンプロセス:niaのコミュニケーションや監視・リストを行うnia-cli:コマンドラインインターフェース:niaの操作を行うconsole:フロントエンド:niaの操作を行う
ワークスペースの作成、ダッシュボード、ログ監視、Inboxシステムなど。
当面はWebフロントエンドで作成する。 将来的にはネイティブアプリケーションの方がいいと思う。
離散的なアイデア
Podスポーンとサブエージェント
Podが別のPodをスポーンさせるしくみを持つ。複数のエージェントに非同期的にタスクを行わせる為の仕組みである。
同じworkspaceを共有するpodとしてスポーンし、親podは子podのターン完了Hookでループの合間に通知として受け、子podのレスポンスをpollingし、指示を出せる。
この際、編集がコンフリクトしないように、最低限ローカルの書き込み権限を移譲する仕組みが求められる。
これは、1 pod = 1 sessionの仕組みを用いるべきで、 親ディレクトリに居るpodが、子ディレクトリで権限を渡してpodをスポーンさせることで解決できるのではないか。
サブエージェントは、コンテキストを引き継がず、親セッションが必要な情報のみを渡し、より良い指示追従性能を求めるもので、Skillsの、コンテキストを持ったまま新しい技能を仕入れる仕組みよりもより明確に役割を分けることになる。
レビューの結果を再度返して修正し、またサブエージェントに投げるなどで、コンテキストを引き継いでほしいという用途も考えられる。 しかし、互いのアウトプットをプロンプトとする関係上、相互に悪い方向に向かってしまい、元々の要件である指示追従性を損なう可能性がある。 設計思想としては、サブエージェントの単位で相互コミュニケーションはさせるべきではないと考えている。
(TODO) Skillsとサブエージェントの関係性を考える・サブエージェントの要件を詳細化する
readable index
ドキュメントや作業記録、プロジェクトの知識などを、AIが読める形でインデックス化する仕組み。
すべてのドキュメントのname-descriptionを列挙する仕組みでは、コンテキストを浪費してしまう。 なので、作業記録を書いた際に、サブエージェントをHookから呼び、過去作業との連続性を把握させ、既存のRIをアップデートさせる。
加えて、機械的なlinterを導入してRIの構成や内容をチェックし、品質を保証しないと破綻しそう。
これを作り、AGENTS.mdとして配置する仕組みがあるべきだよなと過去に考えていた。 niaにネイティブに組み込むべきだと思う。
(TODO)ドキュメント化してリンクを張る
ランタイムAPI
RustそのままでExtensionやPluginを作るのは難しそう。
Rustで書いた拡張をWasmとしてコンパイルしてもらい、それをロードできる仕組みが良い(Zedの拡張機能の仕組みを参考にする)
アーカイブをロード可能にし、スクリプトをロードするので全然良いかも。
コンテキスト
コンテキスト圧縮のタイミングで、Skillsはアンロード・Workflowは維持し、ここから利用可能なToolsを再構築する仕組みにする。
プロジェクトの存在意義
既存のプロジェクトとの比較
ClaudeCode/CodexのようなCLIエージェントと比べて、"エージェントの統括"にフォーカスする。 正直、細部のコーディング能力などはそれらの製品の焼き直しのようになると思うが、オープンソースなエンジンとして、より大きな価値を提供できるものと考えている。
OpenHandsは、ソフトウェアエンジニアリングのタスクを自動化するツールとしての価値を提供する一方、niaは対話的にプロジェクトを統括するツールとしての価値を提供する。