エージェント概要
Ongrid は マルチエージェント ReAct システム です。ユーザーは常に coordinator(チャット画面の最上位ペルソナ)と対話します。タスクが 専門領域に当てはまるとき(深い根本原因調査、変更を伴うアクションのレビュー、 ネットワーク深掘り)、coordinator は AgentTool 経由でサブ エージェント("worker")へ dispatch します。各 worker は同じグラフ カーネルを フィルター済み tool bag に対して走らせ、最終回答を返し、 coordinator がそれを自分の返信に編み込みます。
このページが地図です。各ペルソナの詳細は個別ページで説明します。
チャットスレッドではなくペルソナ
ペルソナ はエージェントが何をするかを記述したディスク上のファイルです。 正典のレイアウトは Claude Code のエージェントフォーマットと同じ形(snake_case キー)です:
---
name: specialist-disk
description: 文件系统 / 磁盘容量专家 — du / find / stat / inode / 挂载 / 大文件
when_to_use: |
When the task is about disk / filesystem health:
- Disk full / utilization climbing
- Hunt for large files / large directories
- inode exhaustion / mount point inspection
tools:
- query_knowledge
- host_find_large_files
- host_du_summary
- host_stat_file
- host_bash
- query_promql
- get_host_load
permission_mode: read-only
max_turns: 15
---
[markdown body — this becomes the system prompt]フロントマターの下の本文が SystemPrompt です。同じ name のペルソナ ファイルが 2 つあると衝突し、ローダーが警告をログ出力します。全フィールドは ペルソナフォーマットリファレンス を参照 してください。
ペルソナは manager イメージの ./agents/(コンテナ内では /app/agents/) にあります。Ongrid はイメージに組み込みペルソナを同梱し、マウントされた ディレクトリからユーザー作成ペルソナも読み込みます —— カスタムエージェント を参照。
Coordinator vs worker
| 観点 | Coordinator | Worker |
|---|---|---|
| ユーザーと対話 | はい(チャット画面または IM 経由) | 決してしない —— worker 出力は coordinator へ |
| Tool bag | 広い:query_*、AgentTool、redirect スタブ | 狭い:ペルソナの tools: ホワイトリスト |
| ペルソナ名 | default(または組織別オーバーライド) | specialist-*、incident-investigator、reviewer |
| spawn 元 | ランタイム(チャットセッションごとに 1) | AgentTool または review_gate デコレーター |
| spawn できる | はい(worker を) | いいえ(worker は設計上ネストしない) |
| セッション | 長命、永続化 | spawn ごとに新セッション、1 ターンにスコープ |
coordinator の仕事は dispatch + トリアージ + 合成 です。深掘りツールは worker 側にあります。coordinator は LLM がハルシネーションしやすいツール (host_bash、get_host_load、…)用の RedirectStub スロットを持ち、そのいずれかが呼ばれるとモデルに AgentTool 経由で 再発行するよう促す redirect メッセージを返します。
AgentTool
coordinator の dispatch プリミティブ。配線名は AgentTool(Claude Code の ツールカタログに合わせて PascalCase)。LLM から見えるスキーマ:
{
"type": "object",
"properties": {
"description": {"type": "string"},
"subagent_type": {"type": "string"},
"prompt": {"type": "string"}
},
"required": ["description", "subagent_type", "prompt"]
}description—— SPA タイルが使う 1 行のタスク要約。subagent_type—— ペルソナのname。coordinator のシステムプロンプトに 注入されるカタログが有効な値を列挙します(ペルソナレジストリからreviewerとdefaultを除いたもの)。prompt—— タスク要綱フル。worker は coordinator のコンテキストを 見ることができません —— 必要な詳細(incident_id、device_id、正確な 言い回し)をすべて詰め込んでください。
呼び出しは coordinator から見て同期 です。worker が completed / failed / killed に到達するまでブロックします。以前のリビジョンには 非同期の background: true フラグがありましたが、弱いモデルがそれを使い、 pending な task_id でユーザーに答えてフォローしないという挙動になりました。 今日このフラグは存在しません(事後分析コメントは agent_tool.go 参照)。非同期の唯一の経路は reviewer で、 それも LLM ではなくデコレーターが駆動します。
重複排除は組み込み
sha256(subagent_type + canonical(prompt)) でキーした 120 秒 LRU が、 2 回目の同一 AgentTool 呼び出しを短絡します。LLM は明示的な「もう dispatch 済み」ヒント付きで前回結果を見ます。coordinator ループのブローアウトを抑制 します(E2E eval D1 では重複排除なしで 240 秒間に 122 ツール呼び出しを観測)。
システムプロンプトの組み立て方
ComposeSystemPrompt は LLM が受け取るプロンプトを順に組み立てます。
basePrompt—— ランタイムの普遍的な前文。空の場合あり。agentProfile.SystemPrompt—— ペルソナの markdown 本文。coordinator も持つことがある(ほとんど持つ)、worker は常に持つ。agentProfile.CriticalReminder——<critical-reminder>...</critical-reminder>でラップ。これはペルソナ レベルの定数。graph レイヤーが長セッションの attention drift に耐える ため、さらに ターンごとに<system-reminder>として再注入します。- 各アクティブスキルごとに:
[能力: <name>]ヘッダー + スキルのPromptBody。
coordinator はスキルリストの前に追加ブロック —— エージェントカタログ (buildAgentCatalog) —— を受け取ります。これは description と when_to_use の 1 行目を含む 「利用可能な specialist」の markdown 箇条書きです。カタログは意図的に reviewer(ReviewGate デコレーターのみが spawn 可能)と default(仮想的な最上位ペルソナで、spawn 可能なサブ エージェントとして列挙すると coordinator が自身を再帰的に spawn できて しまう)を除外します。
エージェントレジストリ
AgentRegistry はパース済みペルソナをメモリに保持します。起動時に一度ロードし、Reload() は単一の sync.RWMutex スワップなので、進行中の coordinator ターンが 半分ロードされたレジストリを観測することはありません。
| メソッド | いつ |
|---|---|
Load(root) | 起動時。<root>/**/*.md を再帰的に walk。 |
Reload(root, ...) | マーケットプレースのインストール/アンインストール。アトミックスワップ。 |
ByName(name) | spawn 時のルックアップ。ミスは (nil, false)。 |
Replace(ag) | ユーザーエージェント編集。in-place upsert —— ライブレジストリ、再起動なし。 |
Remove(name) | ユーザーエージェント削除。 |
ファイルごとのパースエラーは walk を中断せず警告として記録されます (スキルレジストリと同じポリシー)。存在しないエージェントルートは エラーではなく、空のレジストリが返るだけで起動失敗にはなりません。
Reviewer とレビューゲート
reviewer は特殊です:coordinator は spawn できません。 ReviewGate デコレーターがゲートし、Class が "write" または "destructive" の どんなツールも捕捉します。デコレーターは:
- 提案ペイロード(
action、target、reason、blast_radius、operator)を構築。 reviewerワーカーを spawn(内側ツールから見て同期)。内側ツールの 15 秒タイムアウトとは独立の 60 秒タイムアウトを持つ。- reviewer が
Decision: approveを返せば、呼び出しは内側ツールへ 素通り。そうでなければデコレーターは reviewer の理由をラップしたErrReviewRejectedを返す。
これがエージェントカタログから reviewer を落とす理由です:デコレーター のみが呼び出します。カタログに置けば coordinator が何もゲートしない アドホックな「レビュー」を dispatch できてしまいます。
完全なステートマシンは Reviewer を参照して ください。
Worker ライフサイクル
Runtime.SpawnWorker のステートマシン:
pending → running → completed
↘ failed
↘ killed (StopWorker called while running)- worker が実行中でも監査と親 → worker のツリークエリが解決するように、
chat_sessions行は事前に作成されます。 - バックグラウンド spawn は長命のランタイム ctx から派生するので、終了する HTTP リクエストが worker を実行中に解体することはありません。同期 spawn は呼び出し元の ctx を継承します。
- セッション行はパニックを含むすべての終端パスで close (
closed_atが立つ)されます —— これがないと孤児行が溜まります (修正前のテスト環境で 161 件溜まりました)。
worker は worker を spawn できません。SpawnWorker は Runtime 上 のみに公開され、 disabledForWorker フィルターが worker の tool bag から AgentTool を剥がします。1 つの coordinator、N 個の並列 worker、それより深いネストなし。
次に
- Coordinator —— デフォルトペルソナ、3 つの 制御ツール、dispatch するか直接答えるかの判断。
- Incident investigator —— 0 号 病人までの根本原因、18 ツール予算、F1 eval。
- Specialists —— compute / disk / network / ops / sre、各々が所有するもの、coordinator がどう選ぶか。
- Reviewer —— 変更ツールに対する SOP ダブル サインゲート。
- カスタムエージェント —— 自前ペルソナの作成、 ホットリロード、デバッグ。