Agent Mentor Learn
エージェントツール呼び出し: エージェントに実際に行動させる · 第 3 回 / 全 6 回

レッスン3: 5つの一般的なツールタイプ: 読む、書く、実行する、検索する、呼び出す

学習目標:

  • 一般的なツールを、どれだけのダメージを与えられるかによって5つのカテゴリに分類し、それぞれの典型的なシグネチャの名前を言える
  • コマンド実行ツールが他の4つとは異なるリスククラスにある理由を説明できる
  • 検索ツールがファイル全体ではなく一致するスニペットを返す理由を説明できる

前提: レッスン2を終え、ツール呼び出しのラウンドトリップの形を理解している | 前: レッスン2 << | 次: レッスン4 >>

テーブルから始める

ツール典型的な入力返すもの間違ったときの最悪のケース
ファイルを読むpathファイルの内容(文字列)読むべきではないファイルを読み、情報が漏洩する
ファイルを書くpath, content成功/失敗ステータス誰かがまだ保存していない作業を上書きする
コマンドを実行するcommandstdout/stderr/終了コードデータベースを消去し、リクエストを送信し、汚染されたパッケージをインストールする — 不可逆的
検索query, pathマッチ場所のリスト + スニペットコンテキストを吹き飛ばすほど大量に返すか、重要な結果を見逃す
外部APIを呼び出す構造化されたパラメータ(サービスによって異なる)JSON/エラーオブジェクト誰かのお金を使い、間違ったメッセージを送信し、古いデータを取得する

このテーブルを何で並べているのでしょうか? アルファベット順ではありません。それは「1回の呼び出しがどれだけ広い範囲の害を引き起こせるか」 — その呼び出しの爆発半径です。読み取り専用ツールの爆発半径はほぼゼロです: 間違ったファイルを読むことは、この会話の1ターンを脱線させるだけです。ファイルを書くことは既存の内容を上書きできます。コマンドを実行することはシステム全体に対して何でもできます。各カテゴリを見ていくと、「それが何をできるか」を超えて、そのカテゴリだけがつまずく落とし穴があることがわかります。

読む: 最も安全だが、リスクはゼロではない

ファイル読み取りツールは通常このようなシグネチャを持ちます:

戻り値はファイルの内容そのもので、通常は行番号付きなのでモデルが後で参照できます:

1  export function add(a, b) {2    return a + b;3  }

ファイルを読むことは状態を変更しません。モデルが間違ったものを読んだり、読みすぎたりしても、最悪の結果はこの1ターンに無関係な内容が入ることです — そしてモデルは間違ったものを読んだことに気づいて再度読む傾向があります。これが「最も安全な」カテゴリと呼ばれる理由です: リスクがないということではなく、リスクがこの会話の範囲を超えられないということです。

本当のリスクは決して触れるべきではなかったファイルを読むことです。エージェントが~/.ssh/id_rsaやプロジェクトの.envを読む権限を持っている場合、無邪気に見える「このディレクトリに何があるか見せて」が秘密鍵を逐語的に会話コンテキストに持ち上げることができます。そこから、そのコンテキストがモデルによって発行され、ログに書かれ、または後の「外部APIを呼び出す」ツールによって運び出された瞬間、漏洩はすでに起こっています。だからこそファイル読み取りツールは、「読み取り専用だから、鍵を渡せばいい」ではなく、ほぼ常にパス許可リストやサンドボックスと一緒に使われます。レッスン5でこの種の境界を設定する方法を詳しくカバーします。

書く: 結果が対称でなくなる場所

ファイル書き込みツールは読み取りよりパラメータが1つ多く、安全性が少し低いです:

戻り値は通常シンプルで、ステータスだけです:

問題は戻り値ではなく、呼び出しそのものです。読み取りが間違っても、再度読めば何も変わっていません。書き込みが間違った場合 — たとえばモデルが間違ったpathを埋めたり、contentが本来あるべきものの半分しかなかったりすると — 元のファイルの内容はすでに上書きされていて復旧できません。バージョン管理やバックアップがない限り。これが「読み取りツールと書き込みツールの非対称性」です: 2つの呼び出しの形はほぼ同一に見えます(pathといくつかのパラメータ)が、一方は自由にリトライでき、もう一方は毎回賭けになります。

だから責任ある書き込みツールは保護層を追加します — たとえば、編集する前にファイルが読まれていることを要求する(モデルが記憶から編集するのを防ぐ)、または単なる「成功」ではなく古い内容と新しい内容のdiffを返すことで、呼び出し側(ホストアプリケーション)が実際にディスクに当たる前に変更を表示する機会を持ちます。これらはここでの焦点ではありません; レッスン4でインターフェース設計をカバーするときに開きます。

実行する: 独自のリスククラス

コマンド実行ツールは5つの中で最も素朴に見えるシグネチャを持ちます:

1つの文字列が入り; stdout、stderr、終了コードが出ます:

問題はこのcommandフィールドが本質的にオープンエンドのエントリポイントだということです — 「このファイルを削除」や「この行を読む」のような特定のスキーマで制約された操作ではなく、任意のシェルスクリプトです。rm -rf、外部サーバーにデータを送るcurl、汚染されたパッケージを引き込むnpm install — すべてがその1つの文字列に収まります。他の4つのカテゴリ(読む、書く、検索する、APIを呼び出す)は、どのようにシグネチャを設計しても、できることはパラメータ構造によって制限されています。コマンド実行ツールの能力境界はオペレーティングシステム全体の能力境界です。だからこそそれは独自のクラスにあります: 「少しリスクが高い」ではなく、リスクの桁が違うのです。

まさにその理由で、公式ドキュメントはこのカテゴリ専用にオペレーティングシステムレベルの隔離を設計しています: ファイルシステムアクセスとネットワークアクセスは2つの別々のサンドボックス層であり、たとえモデルがプロンプトインジェクションによって操られて危険なコマンドを実行することを主張しても、OS境界は関係なく保持されます — モデルが協力することを「望む」かどうかに依存しません1。述べられた動機は率直です: 目標はプロンプトインジェクションが成功したとしても完全に封じ込められ、サンドボックスから逃げられないことです2。レッスン5でその隔離を設定する方法をカバーします; 今のところ、1つのことを覚えておいてください: 「コマンドを実行する」シグネチャが現れる場所では、デフォルトで5つの中で最も追加の制約を必要とするカテゴリとして扱ってください。

検索: 場所を返し、世界全体ではない

検索ツール(たとえば、コードベース全体でキーワードや正規表現を見つけるもの)は、そのシグネチャに「どれだけ返すかを制限する」パラメータを持つことが多いです:

戻り値はファイル自体ではなく、「マッチがどこにあり、周囲のコンテキストがどのように見えるか」です:

このツールがマッチしたすべてのファイルの完全な内容を詰め込んで返すだけなら、2つの問題が現れます。1つ目はトークンの問題です: 1回の検索が50個のファイルにヒットし、それぞれ数百行で、すべてがコンテキストに注ぎ込まれます — そしてこの単一のツール呼び出しがこのターンの入力予算全体を食い尽くし、モデルが作業を続けるためのものが何も残りません3。ツールの説明を書き、入力と出力の境界を制御すること自体が、ツールを使えるようにするための基本要件です4。2番目の問題はもっと重要です: 検索のポイントは「関連するかもしれないすべてを読み通す」ではなく、「次にどこを見るべきかモデルが把握するのを助ける」ことです。マッチ場所と短いコンテキストのスニペットを返し、モデルはそれらのスニペットを読んで自分で判断します — 「これらの結果のうち、2番目が求めているもののようだ、そのファイルの完全な内容を単独で読もう。」これが検索ツールと読み取りツールが一緒に機能する方法です: 検索が範囲を狭め、読み取りが詳細を取得します。「マッチ場所」を返すことは「ファイル全体」ではなく、モデルが必要とするフォローアップのリードであり、役に立つかもしれないすべてを一度にダンプするのではありません。

外部APIを呼び出す: 失敗は例外ではなく標準

最初の4つのカテゴリは主にローカルシステム内に留まります。外部APIを呼び出すことは異なります — ネットワークを越えて、あなたがコントロールしないサービスに行きます:

通常の戻り値はこのようになります:

しかし外部サービスはあなたをレート制限し、タイムアウトし、権限不足でリクエストを拒否し、呼び出しの間に自分のインターフェースを変更します。これらは「予期しない状況」ではなく、このカテゴリの通常の実行条件です。ツールが良いかどうかを実際に決めるのは「うまくいっているときに何を返すか」ではなく、「失敗したときに何を返すか」です:

このエラーメッセージはあなたのためではなく、モデルのためです — 次にリトライすべきか戦略を切り替えるべきかは、そのerrorフィールドを読めるかどうかに依存します。MCP仕様はこれを直接プロトコルに書き込んでいます: クライアントはツール実行エラーを言語モデルに提供すべきであり、モデルが自己修正して再試行する機会を持つようにすべきです5。言い換えれば、429を静かに飲み込んで「呼び出し失敗」以外何も返さないツールは、モデルが自己修正する機会を奪っています; retry_afterのような具体的な詳細を運び返すツールは、「失敗」をワークフローの通常の一部として設計しているツールです。

外部APIを呼び出すカテゴリはもう1つのリスク層も引きずり込みます: このエージェントがプライベートデータを読むことができると同時に、信頼できないコンテンツ(たとえばユーザーが貼り付けたウェブテキストの塊)にさらされ、さらに外向きにメッセージやリクエストを送信することもできる場合、これら3つが一緒になることをセキュリティ研究では「致命的な三要素」と呼びます — 攻撃者はあなたのシステムに侵入する必要はなく、エージェントが読むコンテンツに命令を隠し、エージェントにプライベートデータを自分で運び出させるだけです6。レッスン5でこのトピックを単独で開きます; 今のところ、これを知っておいてください: 外部APIを呼び出すことはそのチェーンの最後で最も重要なリンクです。なぜならそれがデータが実際にシステムから離れる出口だからです。

まとめ

  • 5つのカテゴリ全体でリスクは均等に分散していません: ファイルを読むが最も軽い結果を持ち、ファイルを書くことは物事が不可逆的になり始める場所であり、コマンドを実行する爆発半径はオペレーティングシステム全体と等しく、検索と外部APIを呼び出すはそれぞれ独自の別々の落とし穴を持っています
  • 読み取りツールと書き込みツールの核心的な違いは安全にリトライできるかどうかです — 間違って読んでも再度読むだけですが、間違って書くと元の内容が永遠に失われるかもしれません
  • コマンド実行ツールはOSレベルのサンドボックスに頼る必要があります。なぜならそのcommandパラメータはオープンな文字列で、他の4つのようにスキーマ構造によって制約されていないからです1 2
  • 検索ツールはファイル全体ではなくマッチ場所とスニペットを返します。第一にトークンを節約するため、第二に「場所を特定する」と「詳細を読む」を分割し、モデルにフォローアップできるリードを渡すためです3
  • 外部APIを呼び出すツールは失敗情報(エラータイプ、リトライ可能かどうか)をそのままモデルに運び返すべきで、飲み込むべきではありません — このカテゴリでは、失敗は例外ではなく標準です5

次のレッスンでは、これら5つのカテゴリの「シグネチャ」を分解します: 良いツール名、説明、パラメータスキーマ、戻り値の書き方を学び、モデルが最初から正しく呼び出すようにします。

>> レッスン4: ツールインターフェースの設計: 名前、説明、パラメータ、戻り値

Footnotes

  1. Configure the sandboxed Bash tool - Claude Code Docs — https://code.claude.com/docs/en/sandboxing 2

  2. Making Claude Code more secure and autonomous with sandboxing - Anthropic Engineering — https://www.anthropic.com/engineering/claude-code-sandboxing 2

  3. Introducing advanced tool use on the Claude Developer Platform | Anthropic Engineering — https://www.anthropic.com/engineering/advanced-tool-use 2

  4. Writing effective tools for AI agents—using AI agents | Anthropic Engineering — https://www.anthropic.com/engineering/writing-tools-for-agents

  5. Tools - Model Context Protocol — https://modelcontextprotocol.io/docs/concepts/tools 2

  6. The lethal trifecta for AI agents - Simon Willison's Weblog — https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/

練習

01

以下はツール呼び出しからの3つのドラフト結果で、それぞれ問題があります。問題が属するツールのカテゴリ(読む/書く/実行する/検索する/外部APIを呼び出す)を言い、設計がなぜ不適切なのかを説明し、あなたが行う変更を示してください。

レベル1: ツールの戻り値を選ぶ
  1. search_codeが返す: { "content": "<50個のファイルの完全なソースを繋ぎ合わせたもの、合計8000行>" }
  2. write_fileが返す: { "success": true }(diff、旧内容情報なし)
  3. send_emailが失敗時に返す: { "error": "failed" }
完了基準 · ローカルでチェック
02

エージェントのためにツールを接続する必要があります: 定期的にサードパーティ物流APIの出荷ステータスをチェックし、ステータスが「異常」になった場合、追跡番号と理由をローカルのalerts.logファイルに書き込みます。

レベル2: 新しいシナリオのツールタイプを選び、シグネチャを設計する

このタスクは実際には複数のカテゴリのツールを含みます。以下を書き出してください:

  1. このレッスンの5つのカテゴリのうちどれが必要ですか? それぞれ何を担当しますか?
  2. 「外部APIを呼び出して出荷ステータスをクエリする」ツールのJSON input_schemaを書いてください。少なくとも追跡番号パラメータを含めてください(インターフェース設計の体系的なアプローチは次のレッスンです; ここではこのレッスンに現れたシグネチャフォーマットを真似てください)
  3. このツールのクエリが失敗したとき(追跡番号が存在しない、リクエストがタイムアウトする)、戻り値はどのように見えるべきですか?
完了基準 · ローカルでチェック