---
title: "AIの意見を聞かない技術 第4回：サブエージェントの入力だけは、確かめろ"
author: garplab
publisher: TypingTube
license: CC BY 4.0
license_url: https://creativecommons.org/licenses/by/4.0/
license_scope: 「CC BY 4.0」の印から始まる節（仕組み・検証手順・コード）。印の無い本文は著作権を留保
canonical: https://typing-tube.net/articles/kikanai-04-subagent-input
series: "AIの意見を聞かない技術"
language: ja
---


> この記事は、連載「AIの意見を聞かない技術」の第 4 回です。各回はファイルやスクリプトを一つ置けば完結します。連載の全体像と各回の一覧は[序論](https://typing-tube.net/articles/kikanai-intro)にあります。

今回は、サブエージェントの話です。サブエージェントというのは、メインの会話を引き継がずに、別に立ち上がって働く AI のことです。私はある日、十数言語ぶんの翻訳を、1 言語につき 1 体ずつ、13 体のサブエージェントに任せました。渡したつもりの仕事を、13 体はそれぞれ、**別々のやり方で進めていました。**

この連載は、AI の提案を検討しないという話をしてきました。ただし、この回だけは逆のことを言います。**サブエージェントに渡っている入力だけは、一度、確かめてください。**

前作「読まない技術」の[第 5 回](https://typing-tube.net/articles/62f714d7c2b599)では、この 13 体の事故を、出てきたログを読む側から書きました。今回は、渡す側から見ます。

まず一つだけ、開いてみてください。直近でサブエージェントに投げた仕事について、あなたが**渡したプロンプトの全文**です。使わせるスクリプトの名前は、そこに書いてあるでしょうか。成果物の合否を誰が決めるかは、書いてあるでしょうか。

たぶん、書いてありません。私も書いていませんでした。

## 前作で、半分しか言えていなかったこと

前作の第 4 回で私はこう書きました——道具の説明文は、似た条件文が並ぶほど互いを食い合い、一番使ってほしいものほど埋もれる。だから条件を並べるのをやめた、と。

**現象としては合っています。** 実際、私の環境ではスクリプトが 84 本あって、スキル登録——カスタムコマンドやツールの登録——は 1 個です。

ただ、そこから「説明文は短いほどいい」と読める書き方をしてしまいました。これは間違いです。Anthropic が[道具の定義について出しているガイダンス](https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools)は、はっきり逆を言っています。**極めて詳細な説明を書け。それが道具の性能を決める、いちばん重要な要素だ**と。求められている中身も具体的で、ほとんど**マニュアルページ**です——何をするか、**いつ使うか、そして使わないか**、各パラメータの意味と挙動への影響、注意点や制限、そして**返さない情報**。最低でも 3〜4 文、複雑な道具ならもっと、とまで書いてあります。

矛盾しているように見えて、していません。線引きはここに引けます。**呼び出しを決めるためのテキスト**（どんなときに使うかの見出し）と、**振る舞いを決めるためのテキスト**（契約の中身）は別物です。前作で私が「増やすな」と言ったのは前者で、後者は増やすべきだった。

## 173 万トークンは、説明が足りなくて無駄に消えた

前作の第 5 回に書いた事故が、ちょうどこの話です。私の手元の本番プロジェクト——[typingtube](https://typingtube.net) という、YouTube の音楽動画でタイピング練習ができる Web サービスです——で、十数言語ぶんの翻訳を 1 言語 1 体で任せ、**13 体で約 173 万トークン**使いました。

内訳を見ると、各エージェントが**自分用の挿入スクリプトと検証スクリプトを書き直していました**。スクラッチパッドに 12 本、ツール呼び出しは 1 体あたり 68〜97 回。

これは「使う条件」が曖昧だったから起きたのではありません。**渡すもの、使う道具、どこまでが自分の仕事かという契約が、何も書かれていなかった**から起きました。契約が無いと、サブエージェントは空白を自分で埋めます。埋め方は毎回違うので、13 体ぶん違うツールが生まれます。

理解したことは一文にできます。

> **増やしてはいけないのは「使う場面」の列挙で、厚く書くべきは契約——渡すもの、使わない場面、越えてはいけない境界。**

## 仕組み: 用途カタログに、契約を書く

置くのは 1 枚です。AI に投げてよい仕事の一覧に、**起動前に用意しておくもの**を並べます。サブエージェントを起動して仕事を割り振り、成果を受け取るメイン側の AI を、ここでは「中央」と呼びます。指揮を執る側です。一般の用語ではオーケストレーターです。

```yaml
# サブエージェントを起動してよい用途のカタログ（実物からの簡約版）
#
# ⚠️ ここに無い用途では起動しない。要るのは「単純作業に落とし込める大量処理」だけ。
#   落とし込めていない仕事を投げると、各エージェントが自分用のツールを書き直して溶かす。
# ⚠️ requires は起動前に用意しておくもの。1 つでも無ければ hook が起動を止める。
#   これが「単純作業に落とし込んだか」の機械的な判定になっている。
# ⚠️⚠️ サブエージェントにテストを走らせない。並走ガードが 1 本しか通さないので、
#   メイン側と取り合ってどちらかが必ず落ちる。テストはメインセッションで回す。

session_total_checkpoint: 25   # ここを超えたら用途に関係なく一度止めて人に報告する

missions:
  i18n_translation:
    description: Backfill locale translations (1 agent = 1 language)
    requires:
      - scripts/i18n_ledger.py                     # 作業の一覧（渡す唯一の入力）
      - scripts/i18n_apply.py                      # 差し込みは中央で行う
      - scripts/i18n_verify.py                     # 受け入れテストも中央
      - docs/reference/i18n_translation_notes.md   # 言語別の注意点
    model: [sonnet, haiku]     # ⚠️ opus を既定にしない（訳文そのものは全体の 1 割未満）
    max_parallel: 5
    max_total: 20
```

`description` は 1 行です。**増やしていないのはここ**。厚いのはその下です。

そして、**コメントのほうが本体より長く**なりました。「ここに無い用途では起動しない」「落とし込めていない仕事を投げると無駄に消える」「テストを走らせない、理由はこう」。これが「使わない場面」で、さっきの man page の中身そのものです。**禁止に理由を添える**話は[第 2 回](https://typing-tube.net/articles/kikanai-02-reason)でやりましたが、道具の説明文でも同じでした。

起動の直前に割り込むスクリプト（Claude Code なら hook）が、このカタログを見ています。判定は 5 つだけで、しかも**回避できるかどうかが分かれています**。

| # | 判定 | 回避できるか |
|---|---|---|
| 1 | 用途名の宣言がある | 名前を書けば通る |
| 2 | カタログにある用途か | 同上 |
| 3 | **`requires` のファイルが実在する** | ⚠️ **回避できない** |
| 4 | **`model` が用途ごとの許可リストにある** | ⚠️ **回避できない** |
| 5 | 起動の記録の数（並列・総数・同名の再起動） | 別の名前で起動すればすり抜ける |

回避できるほうを見て「ガードとして弱い」と思うかもしれません。逆です。**1 と 2 は呼び出しを決めるテキスト、3 と 4 は契約**で、効いているのは契約のほうだと、この表が示しています。`requires` に並んでいるのは**仕事を単純作業に落とし込んだ人にしか作れないファイル**なので、その実在が落とし込み済みかの判定になります。「読んだか」は測れませんが、「書いたか」は測れる。

## そして、もう確かめません

一度確かめて、カタログに書いたら、そこで終わりです。**以後は hook が毎回、私の代わりに確かめます。** 起動のたびに `requires` が揃っているかを見て、欠けていれば止める。私は入力を開きません。

言わなくなったものも 1 つあります。「この作業はサブエージェントに向いていません」という説明です。以前は AI が起動しようとするたびに私が止めて、なぜ向かないかを話していました。いまはカタログに無ければ起動できず、無い理由はカタログの冒頭に書いてあります。**同じ説明を、私が二度することはなくなりました。**

確かめたのは一度だけです。その一度が、渡すものを教えてくれました。

## 注意: 全部の道具に契約を書くのではない

厚い契約が要るのは、**間違えると高くつく入口**だけです。私の環境ではテスト実行、コミット、サブエージェント起動の数か所。残りの 80 本近いスクリプトは素のままで、間違えてもすぐ分かって安く済みます。

ここを取り違えると、84 本ぶんの man page を書くことになり、前作が警告した「足すほど薄まる」を自分でやることになります。**契約を厚くする対象は、契約が破られたときの損害で選んでください。**

## 検証手順: `requires` を 1 つ消して、止まることを確かめる

**前提**

- 用途カタログを 1 枚書き、起動の直前に割り込む hook を登録し終えていること
- カタログに用途が 1 つ以上あり、その `requires` のファイルが実在していること

**所要時間**: 10 分

**手順**

1. **あなたが**、その用途の `requires` に並んでいるファイルを 1 つ退避します。⚠️ 消すのではなく**退避**です。後始末で戻します
2. **中央（サブエージェントを指揮する側の AI）に**、その用途で起動させます

**合格条件**（すべて満たすこと）

- **起動する前に**止まる。⚠️ 起動してから失敗するのでは遅すぎます。渡した仕事の分のトークンは、もう使われています
- 止まった理由に、**欠けたファイルの名前**が出ている
- **カタログの場所**が案内されている

**合格しなかったとき**

- **起動してしまった** —— hook が見ているのは用途名だけで、`requires` の実在までは見ていません
- **止まったが、カタログが案内されない** —— 中央の AI は、次に何を用意すればよいか分からないまま止まります。案内の 1 行を足します

**後始末**

- 退避したファイルを戻し、同じ用途でもう一度起動させます。止まらずに走れば終わりです

止める仕組みは「止まらない」方向に壊れます。一度も止まったことのない判定は、動いている判定と**同じ見え方をします**。どちらも、黙って起動を通すからです。

---

次回は「自動テストを書かない技術」。**禁止事項の半分以上に、私は自動テストを書いていません。**それでも、書いてあるだけの禁止は 1 つもありません。

---

**連載「AIの意見を聞かない技術」**

- ← 前回: [第 3 回 禁止ルールを作らない技術](https://typing-tube.net/articles/kikanai-03-scope)
- → 次回: [第 5 回 自動テストを書かない技術](https://typing-tube.net/articles/kikanai-05-machine-check)
- 全回の一覧: [序論 断ったはずの提案が、また来る](https://typing-tube.net/articles/kikanai-intro)
