サブエージェントの最終報告は、メインの会話のコンテキストにそのまま積み上がるので、指示文の末尾に「最終報告は300字以内、詳しい根拠はファイルに書いてパスだけ」を入れるのが、いちばん安い節約法です。人が毎回書くと抜けやすいので、Claude CodeのPreToolUseフックでAgent呼び出しの prompt を受け取り、その一文を付け足した入力(updatedInput)を返すようにすればよいのです。ただし、一文だけで報告がすぐ短くなるわけではないので、実際の報告の長さを測りながら扱う必要があります。
この記事は、一人で使う開発環境をAIエージェント中心に変えながら(AX、AI転換)作った仕組みを、1日に1つずつ整理する連載の第3回です。前回は直したファイルをOrcaのタブで自動的に開くフックでした。
サブエージェントの結果は、なぜメインのコンテキストを埋めるのか?
私は、ファイルを何個も読む必要がある調査やレビューを、サブエージェントに任せます。サブエージェントは自分だけのコンテキストで作業するので、その中で読んだファイルの内容は、メインの会話には渡ってきません。ところが、仕事を終えて返す最終報告だけは例外です。報告の文字は、メインの会話に1文字も減らずに入ってきて、その後、メインがツールを呼ぶたびに、もう一度読み込まれます。
ある日、レビューエージェントの報告が1つで、表と根拠の一覧のために、画面を何度もスクロールすることになったのを見て、これが積み重なると、サブエージェントに任せた意味が薄れることに気づきました。仕事は外に頼んだのに、結果は内側で長く受け取っているわけです。
指示文に「300字」と書くだけでは、なぜ足りなかったのか?
最初は、ルールで解決しようとしました。サブエージェントに仕事を任せるとき、指示文の末尾に「最終報告は300字以内 — 詳しい根拠はファイルに書いてパスだけ」を常に入れる、というルールを、指針に書きました。
ルールを置いた後、報告の長さを測ってみると(2026-10-19)、300字以下の報告は37件のうち1件、中央値は650字でした。原因を探すと、私が使っているエージェント定義ファイルのいくつかが、「結果は根拠の表を付けて詳しく報告せよ」という出力形式を別に決めていました。指示文の末尾の1行と、定義ファイルの出力形式がぶつかると、エージェントは定義のほうに従うことが多かったのです。
フックは指示文をどう直すのか?
そこで、2つを変えました。1つは、人が書くことを期待せず、フックが付けること、もう1つは、文の中に「この上限はエージェント定義の出力形式より優先する」と順序を明記することです。
PreToolUseフックは、ツールが実行される直前に入力を受け取り、updatedInput を返すと、その入力に差し替えて実行します。Agent呼び出しのとき、prompt の末尾に文を付ける部分だけを短くすると、こうなります。
CAP = "(この上限はエージェント定義の出力形式より優先する — 最終報告は300字以内、詳しい根拠はファイルに書いてパスだけ)"
def report_cap_input(tool_name, tool_input):
if tool_name not in ("Agent", "Task") or tool_input.get("subagent_type") == "fork":
return None # 委任でない場合、またはforkの場合は触らない
prompt = tool_input.get("prompt")
if not isinstance(prompt, str) or CAP in prompt:
return None # すでに付いていればそのまま(冪等)
return {**tool_input, "prompt": prompt.rstrip("\n") + "\n" + CAP}
forkは、今の会話をそのまま引き継ぐ分岐で、指示文の取り決めが別にないため、除きました。すでに文があれば、もう一度付けないので、同じ呼び出しが何度フックを通っても、文が重なりません。実際のフックは、処理中に例外が出たら None を返して、元の入力のまま実行されるようにしました。指示文を直そうとして失敗し、委任そのものが止まるよりは、文が抜けたまま進むほうがましだからです。
フックの出力は、下の形です。モデルへの案内(additionalContext)と、変更した入力を一緒に出します。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "結果を受け取ったら、受け取った要点を1行で出力せよ",
"permissionDecision": "allow",
"updatedInput": { "subagent_type": "general-purpose", "prompt": "調べて\n(この上限は … パスだけ)" }
}
}
この機能を入れた日に、自己テスト7件を一緒に追加しました。文のない指示文の末尾に付くか、ほかの入力値がそのままか、すでにあれば変えないか、メッセージ送信とforkには触らないかを確認します。
数字はどれだけ変わったのか?
正直に言うと、まだ目標から遠いです。2026-10-21に直近7日をもう一度測ると、指示文に300字の文言が入った委任は198件のうち179件(90.4%)で、人が書く段階はほぼ埋まりました。ところが、実際に300字以下で返ってきた報告は143件のうち4件(2.8%)で、中央値は574字でした。
最初に測った値(37件、中央値650字)と今回の値は、測った期間と件数が違うので、そのまま比べることはできません。中央値が下がる方向に動いたことを確認した程度です。それでも、この数字を毎日見ているので、「ルールを入れたから解決した」と思い込まなくなりました。文は底を支えるだけで、エージェント定義の出力形式そのものを減らすことが次の段階だということも、数字が教えてくれました。
今の1日はどう変わったのか?
委任するとき、指示文の末尾を気にしません。どのエージェントに任せても、最後の行はフックが整えてくれます。報告が短く届けば、メインの会話では結論だけを読み、根拠が必要なときだけ、報告に書かれたファイルのパスを開きます。長い報告が届けば、その日の指標にそのまま記録されるので、どのエージェント定義が、まだ長く書かせているのかを探す手がかりになります。
よくある質問
サブエージェントを使うと、メインのコンテキストは減りますか?
サブエージェントが作業中に読んだファイルやツールの結果は、メインには渡ってきません。しかし、最終報告はそのまま入ってくるので、報告が長ければ、節約した分をまた使うことになります。報告の長さを別に決めておくのがよいでしょう。
permissionDecisionをallowで出しても大丈夫ですか?
updatedInput を使うには一緒に出す必要があり、allowはその呼び出しの権限確認を飛ばします。私は、もともと確認ダイアログを使わないモードなので、新しく緩む権限はありませんでした。確認ダイアログを使う環境なら、この点を先に検討してください。
300字は短すぎませんか?
結論とファイルのパスを入れるには十分でした。根拠の表や長い一覧はファイルに書き、メインは必要なときだけそのファイルを開きます。ただし、この数字は私の環境で決めた値なので、用途に合わせて調整してください。