約450行。+1ツール。分割統治。
v2で計画を追加。しかし「コードベースを探索してから認証をリファクタリング」のような大きなタスクでは、単一のエージェントはコンテキスト制限に達する。探索で20ファイルが履歴にダンプされる。リファクタリングで集中を失う。
v3はTaskツールを追加:分離されたコンテキストで子エージェントを生成。
単一エージェントのコンテキスト汚染:
メインエージェント履歴:
[探索中...] cat file1.py -> 500行
[探索中...] cat file2.py -> 300行
... さらに15ファイル ...
[リファクタリング中...] 「あれ、file1の内容は?」
解決策:探索をサブエージェントに委任:
メインエージェント履歴:
[Task: コードベースを探索]
-> サブエージェントが20ファイルを探索
-> 返却: "認証はsrc/auth/、DBはsrc/models/"
[クリーンなコンテキストでリファクタリング]
各エージェントタイプが能力を定義:
AGENT_TYPES = {
"explore": {
"description": "検索と分析のための読み取り専用",
"tools": ["bash", "read_file"], # 書き込みなし
"prompt": "検索と分析。変更しない。簡潔な要約を返す。"
},
"code": {
"description": "実装のためのフルエージェント",
"tools": "*", # すべてのツール
"prompt": "効率的に変更を実装。"
},
"plan": {
"description": "計画と分析",
"tools": ["bash", "read_file"], # 読み取り専用
"prompt": "分析して番号付き計画を出力。ファイルを変更しない。"
}
}{
"name": "Task",
"description": "集中したサブタスクのためにサブエージェントを生成",
"input_schema": {
"description": "短いタスク名(3-5語)",
"prompt": "詳細な指示",
"agent_type": "explore | code | plan"
}
}メインエージェントがTaskを呼び出す → 子エージェントが実行 → 要約を返す。
Taskツールの心臓部:
def run_task(description, prompt, agent_type):
config = AGENT_TYPES[agent_type]
# 1. エージェント固有のシステムプロンプト
sub_system = f"You are a {agent_type} subagent.\n{config['prompt']}"
# 2. フィルタリングされたツール
sub_tools = get_tools_for_agent(agent_type)
# 3. 分離された履歴(重要: 親コンテキストなし)
sub_messages = [{"role": "user", "content": prompt}]
# 4. 同じクエリループ
while True:
response = client.messages.create(
model=MODEL, system=sub_system,
messages=sub_messages, tools=sub_tools
)
if response.stop_reason != "tool_use":
break
# ツールを実行、結果を追加...
# 5. 最終テキストのみを返す
return extract_final_text(response)重要な概念:
| 概念 | 実装 |
|---|---|
| コンテキスト分離 | 新しいsub_messages = [] |
| ツールフィルタリング | get_tools_for_agent() |
| 専門化された振る舞い | エージェント固有のシステムプロンプト |
| 結果の抽象化 | 最終テキストのみ返却 |
def get_tools_for_agent(agent_type):
allowed = AGENT_TYPES[agent_type]["tools"]
if allowed == "*":
return BASE_TOOLS # Taskなし(デモでは再帰なし)
return [t for t in BASE_TOOLS if t["name"] in allowed]explore: bashとread_fileのみcode: すべてのツールplan: bashとread_fileのみ
サブエージェントはTaskツールを取得しない(このデモでは無限再帰を防ぐ)。
サブエージェント出力はメインチャットを汚染しない:
あなた: コードベースを探索して
> Task: コードベースを探索
[explore] コードベースを探索 ... 5ツール, 3.2秒
[explore] コードベースを探索 - 完了 (8ツール, 5.1秒)
見つかったものはこちら: ...
リアルタイム進捗、クリーンな最終出力。
ユーザー: "認証をJWTを使うようにリファクタリング"
メインエージェント:
1. Task(explore): "認証関連のすべてのファイルを見つける"
-> サブエージェントが10ファイルを読む
-> 返却: "認証はsrc/auth/login.py、セッションは..."
2. Task(plan): "JWT移行を設計"
-> サブエージェントが構造を分析
-> 返却: "1. jwtライブラリを追加 2. トークンユーティリティを作成..."
3. Task(code): "JWTトークンを実装"
-> サブエージェントがコードを書く
-> 返却: "jwt_utils.pyを作成、login.pyを更新"
4. 変更を要約
各サブエージェントはクリーンなコンテキストを持つ。メインエージェントは集中を保つ。
| 側面 | v2 | v3 |
|---|---|---|
| コンテキスト | 単一、増大 | タスクごとに分離 |
| 探索 | 履歴を汚染 | サブエージェントに含まれる |
| 並列性 | なし | 可能(デモにはなし) |
| 追加コード | 約300行 | 約450行 |
複雑なタスク
└─ メインエージェント(コーディネーター)
├─ サブエージェントA (explore) -> 要約
├─ サブエージェントB (plan) -> 計画
└─ サブエージェントC (code) -> 結果
同じエージェントループ、異なるコンテキスト。これがすべてのトリック。
分割統治。コンテキスト分離。