maestro/docs/tools/spawnsubtask.md
oss-sync a6d1879d63
Some checks failed
CI / build-and-test (push) Has been cancelled
sync: update from private repo (c764df2f)
2026-06-29 01:32:25 +00:00

122 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SpawnSubTask
タスクを並列サブタスクに分解して実行する。各サブタスクは独立した workerジョブで動き、完了後に親タスクが結果を集約する。
> **デフォルト無効opt-in**。SpawnSubTask は Bash などと同じセンシティブ扱いのツールで、初期状態ではエージェントに提示されない。使うにはワークスペースの **設定 → ツール** タブで明示的に有効化する。有効化していない場合、SpawnSubTask は呼べず、分解は [`Delegate`](./delegate.md)(直列・インプロセス)で行う。
>
> タスク分解の既定手段は Delegate直列。research / general / brainstorming などのピースは Delegate でサブ調査を 1 件ずつこなす。SpawnSubTask は「壁時計時間の短縮のために独立テーマを本当に並列で走らせたい」ワークスペースだけが有効化する。
## 基本
```js
SpawnSubTask({
title: "ローカル LLM 比較調査",
instruction: "Ollama, vLLM, llama.cpp の最新性能ベンチマークを比較する。各ツールについて: 1) 直近6ヶ月の主要ベンチマーク, 2) ハードウェア要件, 3) 対応モデル一覧 を output/report.md にまとめる。",
piece: "research" // 任意。指定しないと自動分類
})
```
呼び出すと `subtasks/{index}/` にサブタスクのワークスペースが作られ、結果はそこに集約される。
## いつ使うか
まず Delegate直列で足りるかを検討する。SpawnSubTask は opt-in で有効化したうえで、**並列の別ジョブで壁時計時間を縮めたい**場合に限って使う。
### 並列分解が効果的なケース
- 2 つ以上の **独立したテーマ**(互いに参照しない)
- 各テーマが軽くなく、調査・処理に時間がかかる
- 分解後の各タスクが単独でも意味を持つ成果物になる
- 壁時計時間の短縮が GPU・実行枠の追加消費に見合う
例:
- 「3 つの製品比較レポート」→ 製品ごとに 3 サブタスク
- 「複数 PDF の OCR 処理」→ ファイルごとに分解
- 「複数 SNS の情報収集」→ プラットフォーム別に分解
### 分解しないほうがよいケース
- 単一テーマで論理的に連続する処理A→B→C のように依存)
- サブタスクが極端に小さい(オーバーヘッドの方が大きい)
- 全体像を見ながら判断する必要がある作業(対話的タスク等)
## instruction の書き方
- **完結した依頼文**で書く(親タスクの文脈を持たないので、サブタスクは instruction だけで判断する)
- 期待する成果物(出力ファイル名・場所)を明示
- 必要な前提情報があれば文中に展開
❌ 「これと同じ調査を別キーワードでやって」
✅ 「キーワード『A』『B』『C』について、各々のメリット・デメリットを比較する独立した調査を行い、output/A-vs-B.md にまとめる」
## piece の指定
- 省略時: 親と同じ classifier ロジックで自動選択
- 明示する場合: `research`, `general`, `office-process` 等の piece 名を指定
## WaitSubTask完了待ち
`SpawnSubTask` でサブタスクを起動したあとは、**`WaitSubTask`(引数なし)を 1 回呼んで全サブタスクの完了を待つ**。
```js
SpawnSubTask({ title: "A の調査", instruction: "..." })
SpawnSubTask({ title: "B の調査", instruction: "..." })
SpawnSubTask({ title: "C の調査", instruction: "..." })
WaitSubTask() // ここで全部の完了を待つ
// 再開後、subtasks/*/result.md を Read して集約 → complete
```
- `WaitSubTask`**同期的にブロックしない**。呼ぶとジョブはいったん停止parkして worker を解放し、全サブタスクが終わると **同じ movement のまま再開** する
- 再開時、各サブタスクの結果は `subtasks/{index}/result.md` に書き出されている。Read で読んで集約レポートを作る
- 起動した分の成果物は `subtasks/{index}/output/` 以下にも残る
### ワークフロー
1. `SpawnSubTask` を必要な数だけ呼ぶ(並列に起動される)
2. `WaitSubTask()` を 1 回呼ぶ
3. 再開後、`subtasks/*/result.md` を読んで集約する
4. `complete` で終了する
### auto-park取りこぼし防止
サブタスクがまだ走っている最中に `complete`successを呼んでも、エンジンが**偽の完了を返さず、自動で park して完了を待つ**。`WaitSubTask` を呼び忘れても結果を取りこぼさない安全網。とはいえ意図を明示するため、原則 `WaitSubTask` を明示的に呼ぶこと。
### orphan の自動キャンセル
親ジョブが**失敗・キャンセル・リトライ**したとき、まだ走っているサブタスクは**自動でキャンセル**される。親が消えたのに子だけ GPU を使い続ける「ゾンビサブタスク」は発生しない。
ただし **ASKユーザー回答待ちで停止した場合は子を残す**。親があとで再開して結果を使うため。
### delegate との違い
| | delegate | SpawnSubTask + WaitSubTask |
|---|---|---|
| 既定 | **デフォルト有効**(分解の既定手段) | **デフォルト無効**(要 opt-in 有効化) |
| 実行 | 直列・インプロセス | 並列・別ジョブ |
| 待機 | 自動1 ツール呼び出しで完結) | `WaitSubTask` で待つ |
| 負荷 | GPU・実行枠が軽い | 並列ぶん多く消費する |
| 向く用途 | 逐次の分解・重い委譲全般 | 独立テーマを並列で短時間化したいとき |
## 起動の間隔spawn_stagger_ms
短時間に大量の `SpawnSubTask` を呼ぶと、その一団が GPU スロットの優先順位を一気に奪ってしまう。これを避けるため、`SpawnSubTask` のキュー投入の間に既定で 1 秒の間隔を入れる。
```yaml
subtasks:
spawn_stagger_ms: 1000 # SpawnSubTask 投入間の間隔(ミリ秒、デフォルト 1000、0 で無効)
```
- `0` にすると間隔を入れず即時に投入する
- エージェントから見た呼び出し方は変わらない(透過的に間隔が入るだけ)
## 結果の参照
サブタスク完了後、親タスクは:
- `subtasks/{index}/result.md` にサブタスクの要約結果があるRead で読む)
- `subtasks/{index}/output/` 以下にサブタスクの成果物がある
## 制限
- ネスト深さは `subtasks.maxDepth`(デフォルト 2まで
- サブタスクが waiting_human 等で停止すると親もブロックされる