サブエージェントを使ったら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エージェント活用は、まだまだ発展途上の領域です。来月にはまた状況が変わっているかもしれません。
試行錯誤しながらノウハウを溜めていくのが、いちばん面白いところだと思います。
最後まで読んでいただき、ありがとうございました!