サブエージェントを使ったら30秒の作業が11分になった話 〜マルチエージェント沼からの生還記〜

「生成AIって、人間より速いはずなのに、なんかモタモタしてない……?」

そんな小さな違和感から、今回の検証は始まりました。 「なんとなく遅い気がする」で終わらせず、ちゃんと計測してみたところ、結果はこうでした。

オーケストレーターが単体でやれば30秒で終わる作業が、ワーカー(サブエージェント)に投げた途端に11分かかっていた

約20倍です。しかもモデルは Opus 5.5 / Sonnet 5.5 という、それなりに優秀な子たちを揃えていました。 なぜこうなったのか。この記事は、その沼にハマった失敗談と、そこから見えてきた「サブエージェントとの付き合い方」のまとめです。

xychart-beta title "同じ作業の所要時間(分)" x-axis ["オーケストレーター単体", "ワーカーに委任"] y-axis "分" 0 --> 12 bar [0.5, 11]

😱 事件の現場:理想の「最強開発チーム」を作ったつもりだった

当時組んでいたのは、こんな「完璧なエージェント組織」でした。

  • オーケストレーター:全体の指揮
  • ワーカー:設計・実装
  • CTO:設計レビュー
  • レッドチーム:攻撃的な検証
graph TD User([👤 ユーザー]) --> Orch[🎯 オーケストレーター] subgraph pipeline["重厚長大なパイプライン"] Orch -->|"① 指示"| Worker[🛠 ワーカー<br/>設計・実装] Worker -->|"② 結果"| Orch Orch -->|"③ レビュー依頼"| CTO[🧑‍💼 CTO<br/>設計確認] CTO -->|"④ OK / NG"| Orch Orch -->|"⑤ 設計書を渡す"| Red[🥷 レッドチーム<br/>攻撃的検証] Red -->|"⑥ OK / NG"| Orch end Orch -->|"⑦ 合格!"| Next[✅ 次のゲート処理] classDef agent fill:#fde2ff,stroke:#333,stroke-width:2px; class Orch,Worker,CTO,Red agent;

「これだけレビューを重ねてるんだから、品質はバッチリでしょ!」 ……と本気で信じていました。当時の自分、ちょっと正座してほしい。

実際に動かしてみると、まる二日かけても、一つの機能すら実装できないという大惨事に。


🐢 なぜ20倍も遅くなったのか?

1. そもそも「持っている情報」が違う

オーケストレーターは、対象のコードも、ここまでの経緯も、判断基準も、すべて自分の頭(コンテキスト)の中に持っています。 だから30秒は、ほぼ「思い出して答える」だけの時間。

一方ワーカーは 毎回、白紙からスタート です。

sequenceDiagram autonumber participant O as 🎯 オーケストレーター participant W as 🛠 ワーカー participant F as 📁 ファイル群 Note over O: すでに全部知っている<br/>推論1〜2回で完了 O->>O: 思い出して回答(約30秒) Note over O,W: ここからワーカーに委任すると… O->>W: 指示を送る(背景や制約を全部詰め込む) W->>F: ファイル探索 F-->>W: 一覧 W->>F: 読む F-->>W: 中身 W->>F: grepで関連箇所を探す F-->>W: 結果 W->>W: 理解・確認・また読む… W->>F: 念のため再確認 F-->>W: 結果 W-->>O: 結果を要約して報告(約11分)

ツール呼び出し1往復ごとに推論が1回走るので、これが数十回続くと、あっという間に分単位になります。

2. パイプラインが「直列」で全員が白紙スタート

しかもワーカーだけではありません。CTO も、レッドチームも、それぞれ白紙から始まって、前段の成果物を読み直していました。

gantt title 重厚パイプラインの時間の積み上がりイメージ dateFormat mm:ss axisFormat %M:%S section ワーカー 白紙から探索・読み込み :a1, 00:00, 3m 実装・実行 :a2, after a1, 1m section CTO 成果物を読み直す :b1, after a2, 2m 解析・報告 :b2, after b1, 1m section レッドチーム 成果物とCTO解析を読み直す :c1, after b2, 2m 攻撃検証・実行 :c2, after c1, 1m section オーケストレーター 総合評価 :d1, after c2, 1m

※ 上記は構造を示すためのイメージです(実測値ではありません)。

各段で「起動 → 文脈の再構築 → 作業 → 要約して返す」を繰り返すので、段数が増えるほど時間が足されていきます。 さらに要約を挟むたびに情報が落ち、後段が元ファイルを読みに戻る、という手戻りも発生します。

3. 「同じ出力」でも「同じ作業量」ではない

最終的な答えが同じでも、そこに至る道のりは違います。

flowchart LR subgraph O["🎯 オーケストレーター"] direction LR o1["文脈を持っている"] --> o2["そのまま回答"] end subgraph W["🛠 ワーカー"] direction LR w1["白紙"] --> w2["探索"] --> w3["読む"] --> w4["仮説を立てる"] --> w5["確認する"] --> w6["回答"] end O ~~~ W

さらにモデルの違い(短い方が Opus、長い方が Sonnet)も、文脈が薄い状態では「探索の的確さ」「止まるタイミングの判断」の差になって、往復回数を増やす要因になったかもしれません。


🔍 敗因をまとめると、こうでした

mindmap root((遅さの原因)) スコープが広すぎ 「いい感じにやって」で丸投げ AIが迷子になる 脱線と無限ループ 自由度を持たせすぎた 人間が軌道修正し続ける コンテキストの押し出し やり取りが長引く 最初の大事な指示が消える ワーカーが無言でフリーズ 育成マインドの勘違い AIは育てる部下ではない 手順の明示が必要だった

① スコープが広すぎた(丸投げの弊害)

「この機能を、いい感じに設計・実装・テストして!」

人間の部下なら空気を読んでくれますが、AIにやると 迷子の大行進 になります。

② 脱線と無限ループ

プロンプトをガチガチに縛ると窮屈になりそうだと思い、あえて自由度を持たせました。 結果、議論はどんどん脱線し、そのたびに人間が軌道修正するハメに。本末転倒です。

③ コンテキストウィンドウのところてん現象

やり取りが長引くとコンテキストが溢れ、最初に渡した大事な指示が、ところてん式に押し出されて忘れ去られます。 ワーカーが突然「無言でフリーズ」する現象も、これが一因っぽいです。

flowchart LR subgraph t0["最初"] direction TB a1["★大事な指示"] a2["指示の詳細"] a3["やり取り1"] end subgraph t1["少し経つと"] direction TB b1["★大事な指示"] b2["やり取り1〜5"] b3["読んだファイル"] end subgraph t2["だいぶ経つと"] direction TB c1["💨 大事な指示が押し出される"] c2["やり取り1〜30"] c3["読んだファイル大量"] end t0 --> t1 --> t2 style c1 fill:#ffd6d6,stroke:#c00

④ 山本五十六方式の勘違い

「やってみせ、言って聞かせて、させてみせ……」の精神で、自走して育ってくれることを期待していました。 でもAIは「育てる部下」ではなく 超高速なプログラム です。 最初から、手順やデータの観点まで、手取り足取り細かく指示する必要がありました。


💡 分かった!サブエージェントとの付き合い方

結論はシンプルでした。

サブエージェントは「会議のメンバー」ではなく、「関数」として使え!

flowchart LR subgraph bad["❌ 会議のメンバー扱い"] direction TB m1["広いスコープ"] --> m2["都度推論・分岐"] --> m3["長い議論"] --> m4["脱線・フリーズ"] end subgraph good["✅ 関数扱い"] direction TB f1["狭く固めたスコープ"] --> f2["大量処理をバーッと実行"] --> f3["結果だけ返す"] end

使う・使わないの判断フロー

flowchart TD Start([この作業、サブエージェントに出す?]) --> Q1{短時間で終わる作業?} Q1 -->|はい| Main1[🎯 メインに直接やらせる] Q1 -->|いいえ| Q2{条件・スコープは<br/>カッチリ固まっている?} Q2 -->|いいえ| Fix[📝 まず条件を固める] --> Q2 Q2 -->|はい| Q3{大量の処理で<br/>メインの文脈を汚したくない?} Q3 -->|いいえ| Main2[🎯 メインに直接やらせる] Q3 -->|はい| Sub[🛠 サブエージェントを関数として召喚] classDef good fill:#d6f5d6,stroke:#2a7; classDef warn fill:#fff3cd,stroke:#c90; class Main1,Main2,Sub good; class Fix warn;

具体的なコツ

  • 基本はメイン(オーケストレーター)にやらせる メインの方が、キャッシュも効くしトークンも節約できて、圧倒的に速いです。
  • 回答文はとことん抑制する サブエージェントが長々と親切に語ると、それだけで遅くなりトークンも食います。「端的にまとめて出力せよ」と徹底しましょう。
  • コンテキストが埋まる前にバトンタッチする パンパンになったら、新しいサブエージェントに引き継いで、古い方は終了させます。
  • 生存確認(ハートビート)を仕込む 黙って落ちるワーカーを定期的に監視する「お守り監視」があると安心です。
sequenceDiagram participant O as 🎯 オーケストレーター participant W1 as 🛠 ワーカー(旧) participant W2 as 🛠 ワーカー(新) O->>W1: 狭く固めた指示 loop 定期的なハートビート O->>W1: 生きてる? W1-->>O: 生きてます(進捗%) end Note over W1: コンテキストがパンパンに近づく W1-->>O: 途中経過をファイルに保存して報告 O->>W1: 終了 O->>W2: 保存した途中経過を渡して続きを依頼 W2-->>O: 結果(端的に)

✨ まとめ

flowchart LR Before["😵 Before<br/>重厚パイプライン<br/>まる二日で1機能も未完成"] Learn["💡 学び<br/>サブエージェントは関数<br/>メインが速い"] After["😎 After<br/>短い作業はメイン<br/>大量処理だけ委任"] Before --> Learn --> After
  • 短くサクッと終わる作業にサブエージェントを使うのは、ぶっちゃけ 逆効果 でした。
  • 条件がカッチリ固まった大量の処理を任せる時だけ、サブエージェントを召喚する。
  • それ以外は、メインのエージェントに走らせる。

「最強のチームを作ったつもりが、会議ばかりして何も進まない組織になっていた」というのは、人間の世界でもありがちな失敗ですよね。AIエージェントでも、同じことが起きます。

AIエージェント活用は、まだまだ発展途上の領域です。来月にはまた状況が変わっているかもしれません。 試行錯誤しながらノウハウを溜めていくのが、いちばん面白いところだと思います。

最後まで読んでいただき、ありがとうございました!