背景:深夜2時、Claude Codeが「混乱」し始めた
あの日、かなり大規模なPythonコードベースをリファクタリングしていた。40ファイル程度で、FastAPI、Celeryワーカー、そして大量のビジネスロジックが混在している構成だ。Claude Codeに複合タスクを依頼した。スキーマ全体の読み込み、ユニットテストの作成、ドキュメントの更新、循環インポートのチェック、これらをすべて同時にやらせようとした。
結果は散々だった。Claude Codeが関数名をハルシネーションし始めた。存在しない関数のテストを提案し、別ファイルから間違ったドキュメントをコピペしてきた。コンテキストウィンドウが満杯になり、モデルが以前に読んだ内容を「忘れ」始めていたのだ。
それがsub-agentsについて調べるきっかけになった。この機能により、Claude Codeはタスクを専門的なサブエージェントに委譲できる。各エージェントは独自のコンテキストで特定のタスクを処理するため、他のタスクの情報に干渉されることがない。
単一エージェントではなくsub-agentsが必要な理由
LLMには非常に現実的な制約がある。コンテキストウィンドウだ。一つのエージェントに詰め込みすぎると——40ファイルの読み込み、テスト作成、ドキュメント更新、インポートチェック——どこかで混乱が生じる。モデルの性能が低いのではなく、使い方が間違っているのだ。
Sub-agentsはこの問題を非常に実用的な方法で解決する:
- 隔離性:各サブエージェントは独自のコンテキストを持ち、他のタスクに汚染されない
- 並列化:複数のサブエージェントが同時に動作し、全体の処理時間を短縮する
- 専門化:エージェントAはコードの読み込みだけ、エージェントBはテスト作成だけ、エージェントCはドキュメント作成だけ——各エージェントが一つのことに集中し、より高い精度で実行できる
- 障害隔離:一つのサブエージェントが失敗しても、パイプライン全体が崩れない
実際に約40ファイルのコードベースでこのパターンを使ったところ、ハルシネーションの発生率が明らかに減少した。毎回3〜4個のエラーを修正していたのが、ほぼゼロになった。並列実行のおかげで、全体の処理時間も30〜40%ほど短縮された。
Claude Codeのセットアップとsub-agents使用の前提条件
Sub-agentsはClaude Codeの組み込み機能であり、追加インストールは不要だ。いくつかの条件を満たせばよい:
最低要件
- 最新バージョンのClaude Code(npm経由でインストール)
- ProまたはMaxプランのClaudeアカウント(sub-agentsはより多くのトークンを消費する)
- Node.js 18以上
# Claude Codeのインストールまたはアップデート
npm install -g @anthropic-ai/claude-code
# バージョン確認
claude --version
# プロジェクトディレクトリで起動
cd /path/to/your/project
claude
CLAUDE.mdの構造——サブエージェント同士が理解し合うための基盤
ここは多くの人が見落としがちな点だ。親エージェントがサブエージェントを生成すると、そのサブエージェントもプロジェクト内のCLAUDE.mdファイルを読み込む。新しいメンバーが入社して何かをする前にオンボーディングドキュメントを読むのと同じだ。このファイルは、エージェントがプロジェクトを即座に理解できるほど明確に書かれている必要がある。追加の質問が発生しないようにすることが重要だ。
# CLAUDE.md
## Project structure
- src/api/ — FastAPI routers
- src/workers/ — Celery tasks
- src/models/ — SQLAlchemy models
- tests/ — pytest test suite
## Rules
- Always use absolute imports
- Test files mirror src/ structure: src/api/users.py → tests/api/test_users.py
- Never modify migration files directly
明確であればあるほど、サブエージェントの問い返しやミスが減る。複雑なタスクを実行する前に、CLAUDE.mdをしっかり書くために15分かけることにしている。
詳細設定:サブエージェントへのタスク割り当て方法
方法1:Claude Codeが自動でサブエージェントを生成する
十分に複雑なタスクであれば、Claude Codeは追加の指示なしに自動でサブエージェントを生成・起動する。ターミナルの出力はこのようになる:
# Claude Codeが自動的にタスクを分割する
> Refactor authentication module and write tests for all edge cases
# ターミナル出力:
[Agent] Spawning sub-agent: code-explorer (reading auth module)
[Agent] Spawning sub-agent: test-writer (writing unit tests)
[Agent] Running in parallel...
[code-explorer] Read src/auth/jwt.py, src/auth/oauth.py
[test-writer] Writing tests/auth/test_jwt.py
方法2:カスタムワークフローでAgent toolを使う(SDK)
Claude Agent SDKで自動ワークフローを構築している場合、以下のようにプログラム的にサブエージェントを呼び出せる:
import anthropic
client = anthropic.Anthropic()
# 親エージェントが大きなタスクを受け取る
def run_parent_agent(task: str):
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
tools=[
{
"name": "spawn_subagent",
"description": "特定のサブタスクに特化したサブエージェントを生成する",
"input_schema": {
"type": "object",
"properties": {
"task": {"type": "string"},
"context": {"type": "string"}
},
"required": ["task"]
}
}
],
messages=[{"role": "user", "content": task}]
)
return response
方法3:CLIから複数の独立したエージェントを並列実行する
複数のファイルを並列処理する際によく使うパターンだ。考え方はシンプルで、複数のプロセスをforkしてシェルに並列管理させ、最後にwaitする:
#!/bin/bash
# エージェント1:セキュリティ問題のレビュー
claude --print "Review src/api/ for SQL injection and XSS vulnerabilities. Output findings as JSON." \
> security_report.json &
PID1=$!
# エージェント2:APIドキュメントの生成
claude --print "Read all FastAPI routers in src/api/ and generate OpenAPI-compatible docs." \
> api_docs.md &
PID2=$!
# エージェント3:デッドコードの検出
claude --print "Find unused functions and imports in src/. List file:line for each." \
> dead_code.txt &
PID3=$!
# すべての完了を待機
wait $PID1 $PID2 $PID3
echo "All agents done. Check security_report.json, api_docs.md, dead_code.txt"
親エージェントとサブエージェント間のコンテキスト受け渡し
実際によく遭遇する問題:サブエージェントが次のステップを実行するために、前のエージェントの出力を知る必要がある場合だ。最もシンプルな解決策は中間ファイルへの書き出しだ。後続のエージェントはコードベース全体を再クロールする代わりに、サマリーファイルを読み込む:
# ステップ1:スキーマ分析エージェント
claude --print "Read all SQLAlchemy models in src/models/, output a JSON summary of each table: name, columns, relationships." \
> schema_summary.json
# ステップ2:サマリーを元にマイグレーションを作成するエージェント
claude --print "$(cat schema_summary.json)
Based on the schema above, write an Alembic migration to add 'updated_at' timestamp to all tables that don't have it. Output only the Python migration file content." \
> migrations/add_updated_at.py
echo "Migration file ready: migrations/add_updated_at.py"
ここでのschema_summary.jsonは「共有メモリ」の役割を果たす。コンパクトで明確なため、後続のエージェントは元の40ファイルを読み直す必要がない。
検証とモニタリング:サブエージェントが正しく動作しているかを把握する
各サブエージェントのログを確認する
Claude Codeはすべてのツール呼び出しの詳細ログを記録する。verboseモードを有効にして各ステップを追跡しよう:
# すべてのツール呼び出しを確認するためにverboseで実行
claude --verbose
# または環境変数で設定
export CLAUDE_LOG_LEVEL=debug
claude "refactor auth module"
verboseの出力では、各サブエージェントが読み込んだファイル、呼び出したツール、返した結果が明確に確認できる。サブエージェントが誤動作した際は、ここを最初に確認すべき場所だ。
最後に独立したレビューエージェントを追加する
このステップは見落とされがちだが、非常に重要だ。すべてのサブエージェントの実行が完了したら、レビュー専用のエージェントを追加で起動する。このエージェントは前の処理経緯を知らず、出力だけを読んで評価する:
claude --print "
Review the following files that were just auto-generated:
- tests/auth/test_jwt.py
- tests/auth/test_oauth.py
Check:
1. Do tests actually cover edge cases or just happy paths?
2. Are there any tests that test implementation details instead of behavior?
3. Will these tests break if we refactor internals?
Output a score 1-10 and specific issues found."
サブエージェントに問題が発生しているサイン
- 関数名のハルシネーション:存在しない関数のテストを書く → プロンプトのスキーマをより明確に提供する必要がある
- タイムアウトまたは長時間の処理:タスクのスコープが広すぎる、さらに細かく分割する必要がある
- 空の出力または「I cannot」:ファイル読み込みのパーミッションが不十分 → 作業ディレクトリを確認する
- エージェント間で矛盾した結果:並列に動作する2つのエージェントが、別のエージェントが変更中のファイルを読んでいる → 読み取り専用ロックを使用するか、順次実行に切り替える
失敗から学んだ4つのルール
- サブエージェント一つにつき、目的は一つ:読み込み・書き込み・バリデーションを一つのエージェントに担わせない——三つの独立したエージェントに分割する
- 出力フォーマットを明確に定義する:自由形式のテキストではなく、特定のJSONまたはmarkdown形式での返答を要求する
- パスでスコープを制限する:
"Only look at files in src/api/, do not touch other directories"とすることで、エージェントの集中度と速度が向上する - べき等な操作にする:何度実行しても問題が生じないようにタスクを設計する——自動実行のサブエージェントに「一時ファイルをすべて削除する」ようなタスクは避ける
Sub-agentsはすべての問題を解決できるわけではない。シンプルなタスクであれば、一つのエージェントで十分だ。サブエージェントを追加しても、トークンを余分に消費するだけで得るものはない。しかし、コードベースが大きくなり、複数の独立したステップを必要とするタスクが増え、エージェントがコンテキストの末尾で情報を「忘れ」始めたとき——それが分割のサインだ。一つの万能エージェントが圧倒される代わりに、それぞれが一つのことに特化した小さなチームを構成し、その仕事を確実にこなせるようになる。

