エージェントシステム
デュアルエージェントアーキテクチャ
OpenCodeは3種類のエージェントを使い分ける設計を採用している。
| エージェント | 役割 | 使用場面 |
|---|---|---|
| General Agent | デフォルトの会話エージェント | 質問応答、簡単なタスク |
| Plan Agent | 要件分析とタスク分解 | 複雑なタスクの計画立案 |
| Build Agent | 実装の実行 | コード生成、ファイル編集 |
Plan Agentが「何をすべきか」を決定し、Build Agentが「どう実装するか」を担当する。 この分離により、計画と実装のフィードバックループが明確になる。
SessionPrompt.prompt() ループ
エージェントの中核は SessionPrompt.prompt() メソッドである。
以下の7ステップを繰り返すことでタスクを遂行する。
1. ユーザー入力の受信
|
v
2. システムプロンプトの構築
|
v
3. コンテキストの組み立て (会話履歴 + ツール結果)
|
v
4. LLMへのリクエスト送信
|
v
5. レスポンスの解析 (テキスト or ツール呼び出し)
|
v
6. ツール実行 & 結果の収集
|
v
7. 完了判定 → 未完了ならステップ3へ戻る
ステップの詳細
ステップ2: システムプロンプトの構築では、エージェントの種類に応じたプロンプトが 動的に生成される。Plan Agentには分析・計画用の指示が、Build Agentには 実装に特化した指示が含まれる。
ステップ5: レスポンスの解析では、LLMの出力がテキスト応答かツール呼び出しかを判定する。 ツール呼び出しの場合、Permission.check()による権限チェックを経て実行される。
ステップ7: 完了判定では、LLMがツール呼び出しを行わずテキストのみを返した場合に ループを終了する。
サブエージェント(task ツール)
task ツールを使用すると、メインエージェントからサブエージェントを生成できる。
サブエージェントは独立したコンテキストで動作し、結果をメインエージェントに返す。
{/* task ツールの概念的な使用例 */}
// メインエージェント: "テストを書いて"
// → task ツール起動
// → サブエージェント: テストファイルを分析し、テストを生成
// → 結果をメインエージェントに返却
// メインエージェント: サブエージェントの結果を確認して次のステップへ
サブエージェントの利点は以下の通りである。
- コンテキストの分離: メインの会話履歴を汚さずにタスクを委譲できる
- 並列性: 複数のサブタスクを独立して実行可能
- スコープの限定: サブエージェントに特定の目的を持たせることで精度が向上する
コンテキスト圧縮
長時間のセッションではコンテキストウィンドウが圧迫される。
OpenCodeは SessionCompaction.compact() により、古いメッセージを要約して
コンテキストサイズを削減する。
[メッセージ1] [メッセージ2] ... [メッセージN] [最新のメッセージ群]
| | |
+---- compact() で要約 --------+ |
| |
v v
[要約メッセージ] [最新のメッセージ群(そのまま)]
圧縮のプロセスは以下の通りである。
- 古いメッセージを一定の閾値で選別する
- LLMを使って会話の要点を要約する
- 要約を単一の「サマリーメッセージ」として保存する
- 元のメッセージをサマリーで置換する
これにより、トークン消費を抑えつつ過去の文脈を保持できる。
エージェント設定
エージェントの振る舞いは opencode.json で構成できる。
{
"agent": {
"default": "general",
"plan": {
"model": "anthropic:claude-sonnet-4-20250514",
"systemPrompt": "あなたは計画立案の専門家です..."
},
"build": {
"model": "anthropic:claude-sonnet-4-20250514",
"systemPrompt": "あなたは実装の専門家です..."
}
}
}
Plan AgentとBuild Agentにそれぞれ異なるモデルやシステムプロンプトを設定でき、 タスクの特性に応じた最適なエージェント構成が可能である。