先に結論だけ
Claude Codeのサブエージェントでは、メインエージェントに対してプロトコルを宣言させることで、ヒューマンインザループの反復承認ワークフローが実現できます。今回実装したエージェントファイルはこちらのGistで公開しています。
本記事の内容はClaude Code 2.0.76時点の挙動に基づいています。この手法はドキュメント化されていない機能を利用しており、将来のバージョンで動作が変更される可能性が大きいことにご注意ください。
はじめに
Claude Codeのサブエージェントは、大規模なタスクを専門的なエージェントに分離する機能です。しかし、サブエージェントからAskUserQuestionツールが利用できないという制限があります。
本記事では、この制限を回避し、サブエージェントでヒューマンインザループ(Human-in-the-Loop, HITL)の反復承認ワークフローを実現する手法を解説します。サブエージェントを呼び出す側のエージェント(本記事では「メインエージェント」と呼びます)とサブエージェント間のプロトコル設計により、サブエージェントが明示的にAskUserQuestionツールの使用を宣言し、メインエージェントがそれを解釈して実行するパターンを紹介します。
本記事での用語定義
メインエージェント: サブエージェントを呼び出す側のエージェント(Claude Code本体など)を指します。公式ドキュメントでは「メイン会話」という表現が使われていますが、本記事ではエージェント間の関係性を明確にするため、この用語を使用します。
ヒューマンインザループ(HITL): 一般的なHITLはAIの誤判断を防ぐ「監視・修正」の役割ですが、本記事では反復承認型ワークフローを指します。エージェントが提案を生成し、ユーザーが承認・修正要求・却下を選択し、修正の場合は指示を与えてエージェントが再生成、承認されるまでこのサイクルを繰り返します。ペアプログラミングのように、ユーザーとエージェントが協働し、反復的なフィードバックを通じて曖昧な基準を明確化します。このプロセスを通じて成果物を作り上げるパターンです。
対象とする読者
- Claude Codeを使ったことがある
- サブエージェントを呼び出したことがある、またはドキュメントで理解している
- AskUserQuestionツールを使ったことがある、または機能を知っている
対象とする環境
- Claude Code 2.0.76
- Claude Sonnet 4.5 (claude-sonnet-4-5-20250929)
問題: サブエージェントからAskUserQuestionが使えない
AskUserQuestionツールの挙動
サブエージェントでAskUserQuestionツールを使用する場合、2つの問題があります。
サブエージェントからAskUserQuestionツールは呼び出せない
サブエージェントのコンテキストでは、AskUserQuestionツールが利用できません。
メインエージェントはサブエージェントからのAskUserQuestionツール使用要請を無視することがある
サブエージェントがメインエージェントに対してAskUserQuestionの実行を要請しても、メインエージェントがそれを無視してサブエージェントの出力をそのまま返答として採用してしまう場合があります。
なぜこの制限が存在するのか
GitHub Issue #12890によると、AskUserQuestionツールはv2.0.56からサブエージェントで利用できなくなったという報告があります(BUGラベル付き、2025年12月時点で未解決)。公式ドキュメントには設計意図の記載がなく、意図的な制限なのか、レグレッション(バグ)なのかは明らかではありません。本記事では、現時点で動作する回避策を紹介します。
この制限が問題になるケース
この制限は、プランニング、執筆、レビューなど、構造化された反復的なワークフローをサブエージェントとして分離したい場合に問題になります。これらのタスクでは、ユーザーの判断が必要なポイントが明確であり、AskUserQuestionツールを利用できれば回答がクリアに得られます。
解決策: メイン - サブエージェント間のプロトコル設計
エージェント間のプロトコル
本記事におけるプロトコルとは、サブエージェントがメインエージェントに対して「次にこのAskUserQuestionを実行してください」と明示的に宣言する仕組みです。サブエージェントの出力に特定のマーカーを含めることで、メインエージェントがそれを解釈し、適切にAskUserQuestionツールを実行します。
プロトコルが機能する理由
このプロトコルはLLMの推論能力に依存しています。サブエージェントがプロトコルを宣言すると、メインエージェントはサブエージェントの出力を単なる回答ではなく作業指示と理解し、処理を実行します。明示的なルールやシステムレベルの実装ではなく、プロンプトエンジニアリングによる協調動作です。
プロトコル設計の全体像
プロトコルの動作フローを図で示します:
実装例: 三択承認ワークフロー
実装するワークフローの概要
本記事では、承認・修正要求・却下の3つの選択肢がある反復承認型ワークフローを実装します。このワークフローでは、サブエージェントが実験結果を提案し、ユーザーが承認するまで修正を繰り返します。RequestIDベースのイテレーション管理(exp-001-r0, exp-001-r1, ...)により、修正履歴を追跡できます。
エージェントファイルの構成とGistリンク
完全な実装例はGistで公開しています。
このエージェントファイルには、以下の重要な構成要素が含まれています:
- Main Agent Instructions: メインエージェントに対する動作指示
- Approval Request Marker: 承認要求を識別するマーカー形式
- Resume Parameter Handling: イテレーション管理のためのパラメーター処理ロジック
メインエージェント向け指示セクション
プロトコルの中核となるのが「Main Agent Instructions」セクションです。サブエージェントは毎回の応答の最初にこのセクションを出力し、メインエージェントに対して具体的な動作手順を宣言します。このセクションには、AskUserQuestionツールの呼び出し方法、ユーザーの選択に応じた分岐処理、サブエージェントの再開方法が記述されています。メインエージェントはこの指示を読み取り、サブエージェントの意図した通りにAskUserQuestionを実行します。
承認要求マーカーの形式
承認要求の終了を明示するために、サブエージェントは---APPROVAL-REQUIRED---マーカーを出力します。このマーカーには、承認要求の種類、項目番号、イテレーション番号が含まれます。RequestIDはexp-001-r0のような形式で、expはマーカータイプ、001は項目番号、r0はイテレーション番号(revision 0)を表します。修正要求が発生するたびに、イテレーション番号がr1, r2と増加します。メインエージェントはこのマーカーからRequestIDを抽出し、サブエージェント再開時のパラメーターとして使用します。
マーカーの構造
マーカーは以下の形式で出力されます:
---APPROVAL-REQUIRED---
Type: EXPERIMENT_APPROVAL
Item: exp-001
Iteration: r0
RequestID: exp-001-r0
---
TypeフィールドはAskUserQuestionツールの実行内容を識別し、RequestIDフィールドはイテレーション管理に使用されます。メインエージェントはRequestIDを使って修正ループを追跡し、サブエージェントに正確なパラメーターを渡します。
ワークフローの動作例
このワークフローが実際にどのように動作するか、4つの代表的なケースを見ていきましょう。
ケース1: 即座に承認
サブエージェントが実験結果を提案(exp-001-r0)し、ユーザーが即座に承認するもっともシンプルなケースです。メインエージェントはサブエージェントの出力を受け取り、プロトコル宣言にしたがってAskUserQuestionツールで3つの選択肢(承認/修正要求/却下)を提示します。ユーザーが承認を選択すると、サブエージェントは次の実験項目(exp-002-r0)に進みます。
ケース2: 1回の修正後に承認
サブエージェントが最初の提案(exp-001-r0)を行い、ユーザーが修正要求を選択します。メインエージェントはユーザーの修正指示をresumeパラメーターに含めてサブエージェントを再開します。サブエージェントは修正指示を反映した新しい提案(exp-001-r1)を生成し、再度承認を求めます。ユーザーが承認すると、次の項目に進みます。
ケース3: 複数回の修正
修正要求が複数回発生する場合、RequestIDのイテレーション番号がr0 → r1 → r2と増加します。サブエージェントは各イテレーションで前回のフィードバックを考慮し、提案を改善します。メインエージェントは常に最新のRequestIDを追跡し、イテレーション番号をサブエージェントに渡します。これにより、サブエージェントは修正履歴を把握し、提案を生成できます。
ケース4: 却下
ユーザーが提案を却下した場合、サブエージェントは該当項目をスキップし、次の項目に進みます。却下されたRequestID(例: exp-001-r2)は記録され、サブエージェントは別のアプローチで次の項目(exp-002-r0)を提案します。
重要な実装上の注意点
プロトコル宣言は毎回必須
サブエージェントは再開されるたびに、最初の応答で必ずMain Agent Instructionsセクションを出力します。プロトコル宣言を省略すると、メインエージェントはサブエージェントの指示を理解できなくなります。これは冗長ですが、LLMベースの協調動作では不可欠な要件です。
サブエージェントの自己認識
プロトコル宣言を正しく機能させるためには、サブエージェントが自身をサブエージェントだと認識している必要があります。この自己認識がないと、サブエージェントはプロトコル宣言の必要性を理解できず、宣言を怠る場合があります。
実験過程で、サブエージェントプロンプトに「あなたはサブエージェントです」という明示的な記述がない場合、プロトコル宣言がスキップされる問題が発生しました。この問題を解決するため、プロンプトの冒頭で「あなたはサブエージェントとして呼び出されています」「メインエージェントに対してプロトコル宣言が必要です」という役割と責任を明記しました。サブエージェントが自分の立場を理解することで、プロトコル宣言を確実に実行するようになります。
RequestID
RequestIDは、イテレーション追跡に不可欠です。RequestIDがないと、サブエージェントはユーザーの回答がどの提案に対するものかを特定できなくなります。RequestIDはexp-001-r0のような形式で、項目番号(001)とイテレーション番号(r0, r1, r2...)を組み合わせます。
修正要求が発生するたびにイテレーション番号を増やし、承認または却下されたら次の項目番号に進みます。メインエージェントはこのRequestIDを使ってサブエージェントを再開し、サブエージェントは前回のフィードバックを踏まえた提案を生成できます。
パラメーターの正しい分離
サブエージェントの再開時には、resumeパラメーターとpromptパラメーターを使います。resumeパラメーターはサブエージェントのIDであり、メインエージェントが把握しています。promptパラメーターには、ユーザーの修正指示やRequestIDなど、サブエージェントが必要とする情報を含めます。
このパターンが適用可能なタスク
適用に向いているタスク
このパターンは、プランニング、執筆、レビューなど、構造化された反復的なワークフローに適しています。これらのタスクでは、ユーザーの判断が必要なポイントが明確であり(例: 段落ごとの承認、項目ごとの確認)、サブエージェントに専門性を持たせることで品質が向上します。
また、各イテレーションでの成果物が比較的小さく、ユーザーがすぐに評価できる粒度も重要です。イテレーション回数が多すぎなければ、サブエージェントのコンテキスト内で完結でき、ユーザーとの協働による高品質な成果物を生み出せます。
適用が難しいタスク
一方で、このパターンには以下の制約があります。これらの制約を考慮し、タスクの性質に応じてこのパターンの適用を判断してください。
コンテキスト制限
サブエージェントのコンテキスト制限により、イテレーション回数が多すぎるとコンテキストが溢れてしまいます。修正要求が多すぎるとサブエージェントが過去の履歴を保持できなくなり、一貫性のある提案を生成できなくなります。
リアルタイム性の要求
リアルタイム性が求められるタスクには向いていません。サブエージェント→メインエージェント→ユーザーという経路を経由するため、単純な質問に対してはオーバーヘッドが大きくなります。
プロトコル設計の複雑性
プロトコル設計が複雑になるタスクでは、メインエージェントとの協調が複雑すぎて、プロトコル自体のメンテナンスコストが高くなり、応答の信頼性が低下します。
まとめ
本記事では、以下の点を解説しました:
- Claude Codeのサブエージェントで反復承認型ワークフローを実装する手法 - AskUserQuestionツールの制限を回避し、プロトコル宣言によってヒューマンインザループパターンを実現する方法
- メイン - サブエージェント間のプロトコル設計手法 - LLMの推論能力を活用した協調動作の設計パターンと実装例
- サブエージェントの自己認識不足による失敗の回避方法 - プロトコル宣言漏れの原因と解決策、確実に動作するエージェント設計の注意点