はじめに
最近、Claude Codeをとにかく週の利用枠を使い切ることを目標に動かしていました。
ただ、闇雲に使っているとToken limitに達しやすくなります。
Claude Codeには、通常の単一セッション(1つのセッションで全部やる)以外に、subagent(サブタスクを別コンテキストに委譲する)とagent teams(複数のClaude Codeインスタンスがチームで協調する)という実行パターンがあります。公式ドキュメントにはagent teamsについて「significantly more tokens than a single session(単一セッションよりも大幅に多くのトークンを消費する)」と書かれていますが、実際にどれくらい違うのかの肌感覚がありませんでした。
そこで、同じタスク(FizzBuzz実装)を3つの実行パターンで実行し、トークン消費を詳細にみていきました。
本記事では、3パターンの構成を説明したうえで、2つの実験結果を順に見ていきます。
検証環境
- macOS(Apple Silicon)
- Claude Code(Haiku 4.5)
- Claude Code CLI(2.1.104)
- プラン: Team plan
- agent teamsは実験的機能のため
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMSを有効化
3つの実行パターン
Claude Codeの公式ドキュメントに基づいて、今回比較する3パターンを整理します。
| Subagent | Agent teams | |
|---|---|---|
| コンテキスト | 独自のコンテキスト長。結果はメインに返る | 独自のコンテキスト長。完全に独立 |
| 通信 | メインへの報告のみ | teammate同士で直接メッセージ |
| 適性 | 結果だけが重要な集中タスク | 議論や協調が必要な複雑な作業 |
| トークンコスト | 低め:結果がメインに要約される | 高め:各teammateが独立したインスタンス |
※ 公式ドキュメントのCompare with subagentsより引用
単一セッション
通常のClaude Codeセッションです。subagentもagent teamsも使わず、1つのセッションがすべてのファイル作成・テスト実行・修正を行います。
ユーザー → Claude Code(単一セッション)
├── Write(ファイル作成)
├── Bash(テスト実行)
├── Edit(修正)
└── Bash(再テスト)
Subagent
メインセッションがAgentツールでsubagentを起動します。各subagentは独立したコンテキスト長で作業し、結果だけがメインに返ります。subagent同士は通信できません。
ユーザー → メインセッション
├── Agent(実装担当) → 独立コンテキストで作業 → 結果を返す
├── Agent(テスト担当) → 独立コンテキストで作業 → 結果を返す
└── メインが結果を統合・最終確認
Agent teams
leadセッションがTeamCreateでチームを作成し、TaskCreateでタスクを定義します。teammateがそれぞれ独立したClaude Codeインスタンスとして起動し、shared task listからタスクを取得して作業します。teammate同士はSendMessageで直接通信できます。
ユーザー → Lead(チーム管理)
├── TeamCreate → TaskCreate ×N
├── Agent(teammate A) → 独立インスタンスで作業
├── Agent(teammate B) → 独立インスタンスで作業
├── teammate間で SendMessage(理論上)
└── leadが進捗追跡(TaskUpdate)・統合確認
トークン消費の仕組み
Prompt Cachingとキャッシュ機構
Claude CodeはMessages APIを通じてClaudeと通信します。このAPIはステートレスであるため、毎回のAPI呼び出しでコンテキスト全体を送り直す必要があります。会話が長くなるほど、送信するコンテキストが膨張していきます。
ここで効いてくるのがprompt cachingです。2回目以降のAPI呼び出しでは、前回と同じ部分はサーバーサイドのキャッシュから読まれ、料金が大幅に割引されます。
セッションログには、トークンが4種に分けて記録されます。
| フィールド | 内容 | 料金(Haiku 4.5) |
|---|---|---|
input_tokens |
キャッシュにも乗らなかった部分 | $1 / MTok |
cache_creation_input_tokens |
初めて送った部分(キャッシュに書き込み) | $2 / MTok (1hキャッシュの場合) |
cache_read_input_tokens |
前回と同じ部分(キャッシュから読み出し) | $0.10 / MTok |
output_tokens |
モデルが生成した応答 | $5 / MTok |
cache readは通常入力の10分の1の料金。API呼び出しが重ねるたびに、既存のコンテキスト(ファイル内容、ツール呼び出し履歴、前回の応答など)がキャッシュから読み出されます。結果として、送信トークンの大部分がcache readで占められ、raw token数の印象ほどにはコスト増加は膨らみません。
実験設計
2つの実験を実施しました。
| 実験 | タスク | 狙い |
|---|---|---|
| 実験1:単一タスク | FizzBuzz の実装+テスト | 最小タスクでの基本特性を確認する |
| 実験2:段階タスク | FizzBuzzを3段階に分けて要件追加 | コンテキスト膨張の違いを見る |
すべてほぼ同じプロンプトを3パターン(単一セッション、Subagent、Agent Teams)に与え、Haiku 4.5で実行しました。パターンごとの違いはClaude Codeの実行方式だけです。
実験1: FizzBuzz
最もシンプルなタスクです。FizzBuzzの実装とテスト作成を1プロンプトで依頼しました。
各パターンの動き
| パターン | 構成 | 方法 |
|---|---|---|
| 単一セッション | 1セッション | Write → Bash pytest → Edit修正 → Bash再テスト。一直線に完遂 |
| Subagent | メイン + 2 subagent | Agent(実装) + Agent(テスト)を起動。メインが結果を読んで統合 |
| Agent teams | lead + 2 teammate | TeamCreate → TaskCreate×2。実装teammate + テストteammateが並列作業 |
トークン消費の内訳
| 内訳 | 単一セッション | Subagent | Agent teams(lead+teammate合算) |
|---|---|---|---|
| input_tokens | 172 | 191 | 1,344 |
| cache_creation | 42,699 | 197,307 | 997,166 |
| cache_read | 918,782 | 732,379 | 6,720,771 |
| output_tokens | 7,167 | 9,518 | 52,784 |
| コスト換算 | $0.21 | $0.52 | $2.93 |
| vs 単一セッション | 1.0x | 2.4x | 13.9x |
| 指標 | 単一セッション | Subagent | Agent teams |
|---|---|---|---|
| 実行時間 | 33.1秒 | 83.4秒 | 151.9秒 |
実験1:3パターンのキャッシュ構造詳細比較
FizzBuzz実装タスクで、なぜキャッシュトークン消費が 1倍 → 2.4倍 → 13.9倍 に分かれるのかを、各パターンの実測データから詳しく説明します。
A. 単一セッション
セッション構成:
- ターン数: 16回(実測)
- プレフィックス: ~46,000トークン(system prompt + CLAUDE.md + tools)
cache_creation:42,699 トークン
T1: system + CLAUDE.md + tools 初期化
→ 11,122 トークン作成
T2-3: Write結果を追加
→ コンテキスト蓄積 × 2 = 11,122 × 2 = 22,244 トークン
T4-16: テスト失敗→修正ループ
→ 442~895 ずつ × 13ターン = 9,333 トークン
合計: 42,699 トークン
理由: 単一セッションは同じコンテキストウィンドウ内で逐次実行。毎ターン「会話履歴が1つ追加される」→ 新しいキャッシュバージョン作成という最小限のオーバーヘッド。
cache_read:918,782 トークン
T1-3(Write×2フェーズ)
→ 46,863 token/ターン × 3 = 140,589
T4-10(テスト実行・修正)
→ 57,000~60,000 token/ターン × 7 = 410,200
(Write・テスト作成が蓄積、コンテキスト増加)
T11-16(最終テスト)
→ 60,000~61,169 token/ターン × 6 = 367,014
(修正内容・テスト失敗ログが積み重なる)
合計: ≈ 918,782 トークン
理由: 毎ターン「前のターンのすべての履歴」がキャッシュから読み出される。ターン数(16)が少なく、コンテキストも ~46K で抑えられるため、合計トークンも最小限。
B. Subagent
セッション構成:
- Main session: 1
- Subagent(実装): 独立セッション
- Subagent(テスト): 独立セッション
- 合計3セッション
cache_creation:197,307 トークン
Main起動時:
→ system + CLAUDE.md 初期化 = 42,699
Agent(SubAgent-impl) spawn時:
→ 独立インスタンス起動
→ system + CLAUDE.md 独立作成 ≈ 77,000
Agent(SubAgent-test) spawn時:
→ 別の独立インスタンス起動
→ system + CLAUDE.md 独立作成 ≈ 77,600
合計: 197,307 トークン
理由: 各subagentは親のキャッシュを引き継がない → 3つの独立prefixが存在。Main(42K)+ SubAgent-impl(77K)+ SubAgent-test(77K)= 約196K。単一セッションの 4.6倍。
cache_read:732,379 トークン
Main(約10ターン):
→ ~15K/ターン × 10 = ~150,000
SubAgent-impl(実装、約3ターン):
→ ~50K/ターン × 3 = ~150,000
SubAgent-test(テスト、約15ターン):
→ ~28K/ターン × 15 = ~432,000
合計: 732,379 トークン
理由: ターン数が分散されるため、単一セッション(916K)より 25%削減される。
C. Agent Teams
セッション構成:
- Lead session: 1
- Teammate(実装): 完全独立インスタンス
- Teammate(テスト): 完全独立インスタンス
- 合計3インスタンス、全く独立した3つのClaude Codeプロセス
cache_creation:997,166 トークン(23.4倍)
| セッション | cache_creation | 内訳 |
|---|---|---|
| Lead | 389,119 | 初期化(62,549×5) + 進捗管理(943~5,066×56ターン) |
| Teammate A(実装) | 255,358 | 初期化(32,772 + 62,592×3) + 完了(666+353) |
| Teammate B(テスト) | 352,689 | 初期化(32,878×3 + 62,814×3) + テスト修正ループ(281~9,107×41ターン) |
| 合計 | 997,166 | - |
理由:
-
インスタンス数による重複: 同じ system + CLAUDE.md が3回独立に作成
- Lead: 62,549
- Teammate A: 32,772
- Teammate B: 32,878
- = 単一セッション(42K)の 2.4倍以上
-
ターン数の増加: 16ターン → 121ターン(7.5倍)
- Lead: 61ターン(管理オーバーヘッド)
- Teammate A: 5ターン
- Teammate B: 55ターン
-
毎ターン「新バージョン」の作成: Lead自身が 60K の prefix を保持したまま毎ターン新バージョンを作成
- T6: 62,549 + 1行 = 新バージョン作成 → 943トークン記録
- T7-T61: 同じパターンが56回繰り返される
-
⚠️ 余計なcache_creation発生の可能性: ログ分析から以下を観察
- Lead T1-5:cache_creation 毎ターン62,549 発生 → cache_read は T6 までゼロ
- Teammate A T1-5:同様に cache_creation のみ → cache_read は T6 以降
- Teammate B T7-9:cache_read が一部停滞
要因が不明確:
- TeamCreate/TaskCreate/TaskGet/Agent spawn といった制御系ツール呼び出しが、新しいコンテキストを要求するため、キャッシュが効かない可能性
- または、初期化フェーズが意図的に新規コンテキストで構築される仕様
- いずれにせよ、本来読み出せるはずのキャッシュが読まれず、新規作成されている可能性がある
結論: 997,166 / 42,699 ≈ 23.4倍
cache_read:6,720,771 トークン(7.3倍)
| セッション | cache_read | 内訳 | 計算式 |
|---|---|---|---|
| Lead | 3,752,395 | ~61K/ターン × 61ターン | 61 × 61,514 |
| Teammate A(実装) | 251,700 | ~50K/ターン × 5ターン | 5 × 50,340 |
| Teammate B(テスト) | 2,716,676 | ~49K/ターン × 55ターン | 55 × 49,394 |
| 合計 | 6,720,771 | - | - |
理由:
-
Lead が全体をを持つ: 単一セッション同様に、3段階分の履歴をすべて保持
- 61K × 61ターン = 3,752,395 トークン
-
Teammate の read も積算: 各teammates が独立して prefix を読み出し
- A: 5ターン(50K)= 251,700
- B: 55ターン(49K)= 2,716,676
- 計算式:
単一セッション: 61.25K × 16 = 918,782
Agent Teams: Lead(61K×61) + A(50K×5) + B(49K×55)
= 3,752,395 + 251,700 + 2,716,676
= 6,720,771
倍率: 6,720,771 / 918,782 ≈ 7.3倍
観察できたこと:
- Lead T1-5 で cache_creation は毎ターン 62,549 発生、しかし cache_read は T6 までゼロ
- Teammate A T1-5 で同様に cache_creation のみ、cache_read は T6 まで発生しない
- Teammate B でも T7-9 で cache_read が増えないまま停滞
このパターンは GitHub Issue #29966: Agent SDK subagents have prompt caching disabled by defaultと同様の可能性がありそうでresults。ただし Agent Teams での prompt caching 仕様は公式ドキュメントに明記されていないため、確定ではありません。
実験2: FizzBuzz 3段階タスク
FizzBuzzを3段階に分けて要件を追加していくタスクです。
- 段階1: fizzbuzz(n)の基本実装 + テスト(3→Fizz, 5→Buzz, 15→FizzBuzz)
- 段階2: 7→Bazz, 21→FizzBazz, 35→BuzzBazz, 105→FizzBuzzBazzを追加
- 段階3: 1,000,000件を1秒以内のパフォーマンス要件 + ベンチマーク
各パターンの動き
| パターン | 構成 | 方法 |
|---|---|---|
| 単一セッション | 1セッション(3段階を同一コンテキストで処理) | 段階ごとにEdit + Bash pytest。全contextが蓄積し続ける |
| Subagent | メイン + 6 subagent(各段階でimpl + test) | 段階ごとに2 subagentを起動。subagentは独立contextなので既存実装をReadで渡す必要あり |
| Agent teams | lead + 6 teammate(各段階でimpl + test) | 段階ごとにteamを作り直す結果となった(TeamCreate×3, TeamDelete×5)。テンプレートのプロンプト生成時に「同じteamで継続」と明示しなかったため |
トークン消費の内訳
| 内訳 | 単一セッション | Subagent | Agent teams(lead+teammate合算) |
|---|---|---|---|
| input_tokens | 665 | 196 | 3,529 |
| cache_creation | 103,971 | 57,750 | 762,610 |
| cache_read | 4,195,738 | 1,071,008 | 18,741,880 |
| output_tokens | 35,159 | 19,284 | 136,134 |
| コスト換算 | $0.80 | $0.32 | $4.08 |
| vs 単一セッション | 1.0x | 0.40x | 5.1x |
| 指標 | 単一セッション | Subagent | Agent teams |
|---|---|---|---|
| 実行時間 | 346.3秒 | 427.7秒 | 405.8秒 |
実験2のコスト差の要因
subagentが単一セッションの40%のコストで完遂しました。
単一セッション の cache_read が 419万に膨張する理由:
- 3段階(基本実装 → 7→Bazz追加 → パフォーマンス最適化)の全履歴をセッション内で保持
- 各段階のEdit、Bash実行のたびに、過去のすべてのコード変更・テスト結果・実装履歴がコンテキストに含まれる
- 段階が進むほどコンテキストが膨張し、最終段階では数十KBのファイルと膨大な実行ログが全部送信される
subagent の cache_read が 107万に抑えられる理由:
- 各段階で新しいsubagentを起動し、独立した小さなコンテキストで作業
- subagentは「前段階の実装を入力として受け取る」だけ(メインがReadで渡す)
- メイン自体も「各subagentの結果を統合」するだけの軽いコンテキスト
- 結果として、全体のコンテキスト膨張を防ぎ、cache_read が約4分の1に抑える
おわりに
本記事では、Claude Codeの3つの実行パターン(単一セッション・subagent・agent teams)について、FizzBuzz実装を例に詳しく検証しました。
主な学び:
- 短期間で完結するタスク(1往復で終わる作業)では単一セッションで十分です。一方、複数段階にわたるタスクではsubagentを使った方がトークン消費を効率的に抑えられることがわかりました。
- Agent Teams では Lead と各 Teammate が独立して system prompt + CLAUDE.md をキャッシュするため、トークン消費(金銭換算)は単一セッションの5〜15倍程度になりました。prompt caching の仕様が不明確なため、今後の公式ドキュメント更新に期待したいところです。
- Agent Teams については、このレベルのコード実装タスクではまだ最適な活用方法が見えていません。設計議論やコードレビューなど、エージェント間の議論がより本質的に必要なタスクでの検証を続けていきたいと思っています。