第9章: 計画とサブエージェント ── 骨組みと分岐
小さな頼みごとは、もう驚くほど器用にこなす。
「fibonacci.py のバグを直して」── 3 ステップで的確に直ってくる。
ところが、こう頼んだとたんに様子がおかしくなる。
「認証まわりをまるごとリファクタして、テストも通しておいて」
最初の 1 ファイルは丁寧に直す。 ところが途中から、関係ないファイルを開き始める。 気づくと「修正完了しました」と言い切って戻ってくるが、テストは赤いまま。
小さな仕事はできる。大きな仕事になると、急に迷子になる。
同じ LLM、同じ道具、同じハーネス。何が足りないのか。
9.1 そもそも、ループだけだと「次の一手」しか考えない
第3章で見た think → act → observe の三拍子は、エージェントの強みの源泉だった。 やりながら考える。ためしてから直す。──「先に完璧な計画を立てる」よりも、現代のコーディングエージェントは やりながら考える ほうが向いている、と書いた。
ただし、ここには 見落とされがちな性質 がひとつある。
ループは、毎ターン “目の前の一手” を生成しているだけだ。
ループ自体には、「全体としてどこを目指していて、いま何合目にいるか」を見渡す機構が組み込まれていない。
小さなタスクならこれで十分だ。次の一手がそのままゴールに直結する からだ。 ところが大きなタスクではこうはいかない。
「認証まわりをリファクタ」 = ① モデル層を直す → ② リポジトリ層を直す → ③ サービス層を直す → ④ ルーター層を直す → ⑤ テストを直す → ⑥ 動作確認
各ステップが終わらないと次に進めない。6 個の手を、順序を守って、しかも全体像を見失わずに 打つ必要がある。 ここで「次の一手」しか見ていないループは、よくこんな失敗をする。
- ① を終えた直後、文脈の中で目に入った別の関数が気になり、無関係なリファクタを始める
- ⑤ のテスト修正で、テストが参照する無関係なモジュールまで書き換える
- ④ までやって満足し、テストを動かさずに 「完了しました」と返してくる
これは 全体俯瞰の不在 から来る病だ。
人間のエンジニアは、複雑なタスクに着手するとき、手を動かす前にメモを書く。 TODO リストでも、ホワイトボードでも、付箋でも構わない。
「① → ② → ③ の順でやる、いま①」と 外に書き出すからこそ 、途中で脇道に逸れても戻ってこられる。 エージェントにも、同じ仕掛けが要る。
9.2 解決策 ── 計画と実行を分離する
ここでぶっきらぼうな解決策が出てくる。
そもそも、考えるフェーズと、動くフェーズを分けてしまえばいい。
エージェントに、まず 計画だけ立てさせる。手は出させない。 その計画を人間(あるいはエージェント自身)が眺めて、納得できたら 実行フェーズに切り替える。実行中は計画を参照して、脇道に逸れたら計画に戻る。
これは要するに、ループの上にもう一段「計画」というレイヤーを差し込む ことだ。 ハーネスは、計画フェーズの間は Write / Edit / Bash のような副作用ツールを通さない。LLM は「Read で調べて、自然言語で計画書を出す」ことしかできなくなる。 承認されてはじめて、実行モードに切り替わる。
「先に骨組みを書く」が効くのは、脱線防止・進捗の見える化・停止判断の明確化 ── 三つを同時に手に入れられるからだ。
- 脱線防止: 計画と外れたことをやり始めても、計画を読み直せば戻れる
- 進捗の見える化: 残りの作業が外に書き出されているので、人間も LLM 自身も俯瞰できる
- 停止判断の明確化: 「計画の全項目が終わったか?」で止めどきを決められる
9.3 プロダクトでの実装 ── Plan モードと TodoWrite
「計画と実行を分ける」という同じ発想は、各プロダクトで少しずつ違う形で現れる。
Claude Code は二段構えだ。
- Plan モード ── ファイル編集・シェル実行系のツールを モード全体で封じる。
Shift+Tabを 2 回押すと入る。計画を提示してユーザーが承認すると、通常モードに戻って実行する - TodoWrite ── 実行中に、サブタスクのリストを 外部に書き出す 専用ツール。各サブタスクには「未着手 / 進行中 / 完了」のステータスがあり、進捗に応じて Claude 自身が更新する
計画ツール (TodoWrite 系)LLM が複雑なタスクに取りかかるとき、やることリストを明示的なテキストとして書き出す ための専用ツール。書いた瞬間に、そのリストは LLM 自身のコンテキストに残り、次のターン以降の判断材料になる。Claude Code の
TodoWrite、Cursor のチェックリスト表示、Aider の TODO 注釈などが同じ系譜。
Cursor や Codex CLI にも、似た仕掛けがある。明示的な「モード切り替え」を持たないものもあるが、システムプロンプトの中で「複雑なタスクではまずプランを書き出してから着手しろ」と指示することで、同じ動きを誘導している。 Devin のように、ジョブを受け取った直後に Plan を Slack に投稿してから実行に入る タイプもある。
実装の表面は違うが、骨は同じだ。「ループの上に、計画というもう一段のレイヤーを置く」 こと。
ここで重要な気づきがある。 計画フェーズで生成される計画書は、ハーネス側が解釈する特殊な構造ではなく、ただの自然言語のテキスト であることが多い。
なのに、なぜ書かせるだけで挙動が改善するのか?
それはテキストとして書かれた瞬間、その計画は LLM 自身の以降のコンテキストに乗る からだ (第7章のコンテキストウィンドウの話)。書かれていないものは、次のターンには思い出せない。 「考えたら書く」だけで、自己レビュー・記憶・俯瞰が一度に手に入る ── これが計画ツールの不思議な威力の正体だ。
9.4 計画は書き換える前提で運用する
「計画を立てるなら最初に完璧に立てるべき」── そう思いたくなる。 だが現代のエージェントの設計は、その逆を行く。
計画は実行中に書き換えてよい。むしろ書き換える前提で設計されている。
実装に入ってから「あ、このファイル構造、想定と違った」「思ったよりリポジトリ層が密結合だった」と気づくことは普通にある。 そのとき LLM は、TodoWrite を呼んで サブタスクのリストを書き換える。途中までの進捗はそのままに、残りのステップを現実に合わせて差し替える。
これは ── ループだけのエージェントが脇道に逸れていく挙動とは、似ているようでまったく違う。
| 計画なしで脇道に逸れる | 計画を更新して進む |
|---|---|
| 無関係なファイルを触り始める | 関連ファイルが想定外に多いと気づき、リストに足す |
| 何をやっていたか忘れる | 残りのサブタスクを参照して戻ってくる |
| 「完了しました」で打ち切る | 残ったサブタスクを意識して、次に進む |
両者の差は 「外部にメモがあるかどうか」 だけ。メモがあれば現実とのズレを反映して進める。なければ、ズレに呑まれて脇道に消える。
ここまでが、ループに 骨組み を入れる話だ。続いて、ループに 分岐 を入れる話に移る。
9.5 ループの中にループを呼ぶ ── サブエージェント
もう一度、最初のシーンに戻ってみる。
「認証まわりをまるごとリファクタして」── 計画を立てて 6 段のサブタスクに切ったとしても、まだ問題が残ることがある。 たとえばこんなとき。
「12 個のパッケージを順に調べて、依存関係の地図を作って」
計画を立てて順に処理すること自体はできる。だが調査が後半に進むにつれて、最初の方のパッケージの調査結果がコンテキストに居座り続け、机の上が散らかっていく (第7章で扱った文脈の物理)。 気づくと、12 個目の調査は最初の方に比べて記述がやせ細っている。
ここで誰かが思いつく。
「調査は 別の Claude に任せて、結論だけ受け取れば、こっちの机は散らからない」
これが サブエージェント の動機だ。
サブエージェント (sub-agent)親エージェントから起動される、別コンテキストで動く別の LLM セッション。親の会話履歴を引き継がず、ゼロから始まる新しいコンテキストを持ち、タスクを終えると 結論のテキストだけ を親に返す。親はサブの内部で起きたことを直接見ない。
仕掛けは拍子抜けするほどシンプルだ。
Claude Code でいえば、サブエージェントの正体は Task という名前のツールを呼んだだけ ── つまり第5章の function calling と何も変わらない。
- 親が「
Taskツールを呼びたい (引数: 調査タスクの説明)」と出力する - ハーネスがそれを受け取り、内部で新しい LLM セッション を起動する
- その新しいセッションが、独立に think → act → observe を回す
- 結果テキストがハーネス経由で親に 「ツール実行結果」として 戻る
- 親はそれを観測して、続きを考える
サブエージェントは「魔法の並列処理エンジン」ではない。親のループにおける一つのツール呼び出し に過ぎない。 特殊なのは、そのツールの中身が「ファイルを読む」ではなく 「別のループを一回まるごと走らせる」 ことだけ。
ループの中にループを呼ぶ ── 再帰的な発想だが、構造は単純だ。
9.6 親子ループの絵 ── 三つのご利益
親と子のループを並べて描くと、こう見える。
ここから、サブエージェントの 三つのご利益 が見える。
ご利益 1: コンテキストの隔離 子の中で 30 回ツールを呼ぼうが、20 ファイル読もうが、親の机には何も増えない。返るのは結論のテキスト 1 本だけ。 長いタスクで品質が落ちる主因は、第7章で見たコンテキストウィンドウの圧迫だった。サブエージェントは、その圧迫を 構造で回避 する道具だ。
ご利益 2: 並列分岐 第5章で見たとおり、LLM は 1 回の応答で複数のツール呼び出しを並べる ことができる。これをサブエージェント起動に応用すると、こうなる。
親の 1 メッセージに
Task(packages/a 調査)、Task(packages/b 調査)、Task(packages/c 調査)の三つを並べる → ハーネスは三つの LLM セッションを 本当に並行起動 する → 結果が揃ったら、まとめて親に返す
シーケンシャルに「a → b → c」と回すより、所要時間が ほぼ 1/N になる (API レート制限の範囲で)。
ご利益 3: 専門化 ここまでは「同じ Claude を分身させる」話だった。もう一歩進むと、役割ごとに違うシステムプロンプトと違う道具セット を渡したくなる。
| 専門エージェント | 役割 | 道具セット (例) |
|---|---|---|
| code-reviewer | コード変更の品質と安全性をレビュー | Read、Grep、Glob (書き込み禁止) |
| explorer | コードベースを地図化 | Read、Grep、Glob、Bash (読み取りのみ) |
| researcher | Web や社内文書から情報収集 | WebFetch、WebSearch |
| test-runner | テストを書いて走らせる | Read、Write、Edit、Bash |
Claude Code の /agents コマンドや、プロジェクトの .claude/agents/ 配下に専門エージェントを定義しておけば、親は「code-reviewer でこの変更を見て」と一言指示するだけでよくなる。
実務メモよくある誤解として、「サブエージェントは別モデルが走っている」と思っている人がいる。 プロダクトによる が、Claude Code の現状の挙動を見るかぎり、親と同じ LLM を別のループで回しているだけ であることが多い。賢さの源泉は別モデルではなく、「別コンテキスト・別システムプロンプト・別道具セット」という 環境の違い にある。
9.7 サブエージェントの代償 ── 親はサブの中を直接見ない
サブエージェントは万能ではない。最大の代償は 透明性の喪失 だ。
子の中で:
- どんな仮説を立てて捨てたか
- 何回失敗してリトライしたか
- どのファイルをどんな順で読んだか
- 途中で道具の使い方を間違えたか
これらは、親には 基本的に見えない。返ってくるのは結論テキスト 1 本だけだから。
落とし穴サブエージェントは「親のデバッグ性を犠牲にして、コンテキストの節約と並列性を買う」トレードオフだ。
うまく仕事した時は嬉しい。だが結果が変だった時、原因究明は格段に難しくなる。 特に「サブが幻覚を含む結論を返し、親がそれを信じて次の手を打つ」と、エラーは 見えない場所で連鎖する。これは次章 (三大病) で正面から扱う。
実務上の対策はいくつかある。
- タスクの境界を明確に渡す ── 曖昧な指示はサブの中で迷子になる
- 戻り値のフォーマットを指定する ── 「JSON で
{found: [...], missing: [...]}を返せ」のように - 重要な書き換えはサブに任せない ── 「探索・調査・レビュー」はサブ向き、「最終的な書き込み」は親で
- 結論だけでなく、根拠の引用も求める
つまりサブエージェントは「便利な万能分身」ではなく、「親の机を散らかさずに済む代わりに、中で何が起きたかは諦める」 という設計上の取引きとして使う道具だ。
9.8 計画とサブエージェントは、同じ系譜の発明
最後にもう一度、本章の二つの仕掛けを並べておく。
| 仕掛け | 何を入れた? | 効くしくみ |
|---|---|---|
| 計画 (Plan / TodoWrite) | ループの 上 に「考える層」を入れた | 全体像を外部メモにしてループに参照させる |
| サブエージェント (Task) | ループの 中 に「別ループ」を入れた | 重い文脈を別の机に逃がして、親を軽く保つ |
向きは違うが、どちらもループに対して「もう一段の構造」を導入する という点で兄弟だ。 平坦なループのままでは、文系・他分野エンジニアの読者が最初に驚いた「動く」体験はできても、大きな仕事に挑むと必ず破綻する。
計画とサブエージェント ── この二つは、ループに 骨と分岐 を入れて、大きな仕事に耐えうる形へ進化させる発明だった。
私は最初、Plan モードは「面倒な確認ステップ」だと思っていた。早く動かしたいのに、なぜわざわざ計画を読まされるのかと。 ところが何度も使っているうちに、計画フェーズで提示された TodoWrite のリストを眺める数十秒が、実行中に発覚する大事故を防ぐ最大の保険 だと分かってきた。
サブエージェントも同じだ。最初は「並列で速い」が嬉しいが、本当のご利益は 親の机が散らからない こと。長い仕事を任せたエージェントが、最後まで集中力を保ってくれる ── この体感は、コンテキスト圧迫の苦しみを一度味わった人にしか分からない。
二つとも地味な機構なのに、体感を一段引き上げる 不思議な発明だ。
9.9 この章の振り返り
- ループは「次の一手」しか考えない。大きな仕事では 全体俯瞰の不在 で迷子になる
- 解決策は 計画と実行を分離 すること ── ループの上に「考える層」を入れる
- Plan モードは 道具を物理的に封じて 考えさせるモード。TodoWrite は外部メモを書く道具
- 計画は完璧でなくてよい。書き換える前提 で運用する
- サブエージェントは ループの中にループを呼ぶ 仕掛け。中身は function calling と同じ
- ご利益は三つ ── コンテキストの隔離・並列分岐・専門化
- 代償は 透明性の喪失。中で何が起きたかは親には見えない
- 計画とサブエージェントは、ループに 骨と分岐 を入れる兄弟の発明
この章で読めるツイート / ブログ
- 「大きなタスクは Plan モードで一回挟まないと、絶対に途中で逸れる」 → 計画と実行を分離する設計判断が、大規模タスクで効く理由が構造として読める
- 「
code-reviewerをサブで常駐させて、本体はコード書きに集中させてる」 → 専門化と道具セット分離。親の机を圧迫しない設計、と読める - 「並列ワークツリーで 4 本同時に走らせたら一気に終わった」 → 1 メッセージで複数のサブを並べる並列分岐が、所要時間を 1/4 に削ったケース
次章ではいよいよ本書のクライマックスに入る。 ここまで積み上げてきたループ・道具・文脈・計画・サブエージェント ── 全部を組み上げてもなお残る、三大病 と、それを抑える最後の砦としての HITL の話だ。