レッスン1: 「ただ話す」から「行動する」へ: エージェントにツールが必要な理由
学習目標:
- エージェント内部における「ツール」とは実際に何か、そして通常の応答テキストとどう違うのかを説明できる
- ツール定義に最低限含まれなければならない3つの要素を認識できる
- 与えられたタスクが実際にツールを必要とするかどうかを判断できる
前提: 基本的なプロンプトを書くことができ、Claude Codeのようなものを使ったことがある | 次: レッスン2 >>
同じ文、2回尋ねられる
数十個のファイルがあるプロジェクトで、あなたはエージェントにこう言います:
"プロジェクト内のすべてのconsole.logを見つけて。"
1回目、このエージェントはツールが接続されていない、APIに接続されたチャットボックスに過ぎません。 その応答はこんな感じです:
ファイルシステムに直接アクセスすることはできませんが、ターミナルで次のコマンドを実行すればそれらを見つけることができます:
これはsrc/下のすべてのファイルを再帰的に検索し、console.logを含む行とファイル名・行番号を出力します。プロジェクトがTypeScriptを使用している場合は、検索範囲に.ts/.tsxを含めることを忘れないでください。
悪くありません — むしろ親切です。しかしあなたは検索方法の説明を求めたのではなく、結果を求めたのです。このターンが終わっても、プロジェクト内のどのファイルに実際にconsole.logが含まれているかはまだ分かりません。ターミナルを開いて自分でそのコマンドを入力する必要があります。
2回目、同じ文を、検索ツールが接続されたエージェントに渡します。 その応答はこんな感じです:
プロジェクトを検索したところ、console.logが7箇所見つかりました:
src/api/client.ts:42
src/api/client.ts:88
src/utils/logger.ts:12
src/components/Cart.tsx:156
src/components/Checkout.tsx:23
src/hooks/useAuth.ts:67
scripts/seed-db.js:5
src/utils/logger.ts:12にあるものは意図的なロギングラッパーのようですが、他の6つはデバッグ時の残骸のようです。これらをクリーンアップしましょうか?
両方とも質問は一字一句同じでした。同じモデル、同じプロンプト。1つだけ違ったものがあります: 2回目には、このエージェントは1つの追加要素を手にしていました — ツールです。1回目にはトレーニングで見た知識から「おそらくこれで動くだろう」というコマンドを推測してあなたに説明することしかできませんでした。2回目には実際に検索を実行し、今のあなたのプロジェクトに何があるかを見て、それから話しました。
このレッスンで明らかにするのはまさにそれです: ツールとは何か、何によってエージェントが「アプローチについて話す」から「実際に検索を実行する」に変わるのか、そしてどのタスクがツールを全く必要としないのか。
ツールはホストがモデルに渡すメニュー
まず、ある直感を修正しましょう: あの7つのファイルを見つけたのはモデルではありません。モデルにはファイルシステムがありません; ディレクトリを開いたり正規表現マッチを自力で実行したりすることはできません。実際にその検索を実行したのは、エージェントを実行しているホストプログラムです — Claude Codeかもしれませんし、あなたが書いたClaude APIを呼び出す数十行のスクリプトかもしれません。
ツールとは、ホストプログラムがモデルに「あなたのためにできることはこれです」と伝えるリストです。 各項目は3つのことを明示します: その機能が何と呼ばれるか、いつ使うべきか、そしてどのパラメータを渡すべきか。1
その検索を例にとりましょう。ホストがリクエストに詰め込むツールリストは大体このような感じです:
3つのフィールドにはそれぞれ役割があります: nameはモデルがこのツールを選ぶときに書く識別子です; descriptionはそのツールが何をするか、いつ使うべきか、どのように動作するかをモデルに伝えるテキストブロックです; input_schemaは呼び出し時にどのパラメータを渡すべきか、それぞれの型は何かを明示するJSON Schemaです。1
モデルはあなたのファイルシステムを見たことはありませんが、このリストは見ています。descriptionにこのツールが「プロジェクトのソースディレクトリを検索... ファイルパスと行番号を返す」と書いてあるのを読み、あなたのリクエスト「プロジェクト内のすべてのconsole.logを見つけて」を見て、2つを照らし合わせ、このツールを選んでpatternにconsole\.logを渡すことを決めます。このステップはモデルの仕事です — ツールを選び、パラメータを埋める — これこそ言語モデルが最も得意とすることです: 意図を読み取り、正しい選択肢にマッチさせることです。
しかし選んだ後は? 実際にファイルを読みに行くのは誰でしょうか?
モデルは提案するだけ; ホストが作業を行う
このレッスンで最も重要な一文がこれです: モデルは何も自分自身では実行しません。「どのツールを呼びたいか、どのパラメータを渡すか」を構造化データの塊にパッケージ化してホストプログラムに返すだけです; 実際にファイルを開き、コマンドを実行し、リクエストを送信するコードはホストプログラム自身のものです。2
その検索について、完全なシーケンスはこうなります:
- モデルはあなたの質問と
search_filesツールリストを見て、{"pattern": "console\\.log"}でそれを呼び出すことを決めます。その決定をこのターンの応答の内容としてラップします — 応答には検索結果がないことに注意してください。なぜならモデルには検索結果がないからです; リクエストをしただけです。
- ホストプログラム(Claude Code、またはあなたが書いたスクリプト)がそのデータを受け取り、「これはツール呼び出しだ」と認識し、自分で実行しに行きます — 実際にディスク上で検索を実行し、その7つのマッチを取得します。
- ホストプログラムは検索結果を会話履歴に戻し、もう一度モデルに尋ねます:「この呼び出しの結果はこれです、続けてください。」
- ここで初めてモデルは本物の検索結果を見て、それから見たあの応答を書きます。
OpenAIのドキュメントはこれを「アプリケーションとモデルの間の複数ステップの会話」と呼んでいます: モデルが関数を呼び出すとき、それを実行して結果を返す責任はモデル側ではなくアプリケーション側にあります。3 Anthropicはもっと端的に述べています:
"The model never executes anything on its own. It emits a structured request, your code (or Anthropic's servers) runs the operation, and the result flows back into the conversation."
(モデルは何も自分では実行しません。構造化されたリクエストを発行し、あなたのコード(またはAnthropicのサーバー)が操作を実行し、結果が会話に流れ戻ります。)2
付け加えると:「誰が実行するか」はもう一段階分かれます。ドキュメントでは、あなたのプログラムが自分で実行しなければならないツールを「クライアントツール」と呼び、Anthropic自身のサーバーがあなたのために実行するもの(例えばウェブ検索)を「サーバーツール」と呼んでいます。4 いずれにせよ、モデル側の動作は変わりません — 依然として提案するだけで、決して行動しません; 唯一の違いは誰がその提案を実際の行動に変えるかです。
あなたが使っているClaude Codeは、まさにこの種のホストプログラムです。ファイルを読む、ファイルを書く、ターミナルコマンドを実行する、コードを検索するなど、組み込みのツールセットを持っています。モデルがどれを使うかを決めるたびに、この固定リストから選んでいるのであって、何もないところから新しい機能を発明しているわけではありません。5 このリストがどこから来て、各項目がどのように見えるかは、レッスン3で一つずつ見ていきます。
すべてのタスクがツールを必要とするわけではない
このプロセスを見た後、逆の極端に走りがちです: ツールがこれほど便利なら、なぜすべてにツールを与えないのか? そうしてはいけません。テストはシンプルです — 自分に1つの質問をしてください: このタスクに必要な情報や行動は、モデルがすでに手にしているか?
モデルが自力で処理できるタスクもあり、外部世界との接触は不要です:
- 文章をより簡潔に書き直す
- 会議メモをまとめる
- Pythonのコードを同じロジックでJavaScriptに翻訳する
- 説明した要件から新しいコードを書く(プロジェクトの既存ファイルに触れる前)
これらが引き出す知識について、モデルはトレーニング中に同様の例をたくさん見ました; 言語能力だけで完了します。この種のタスクに無理やりツールを押し付けても、モデルは毎回「今回呼び出すべきか否か」を決めなければなりません — 決定が1つ増えることは選択を誤る機会が1つ増えることです。まったくの無駄です。
モデルがどんなに賢くてもできないタスクもあります。なぜなら欠けているのは能力ではなく情報だからです:
- 「今のプロジェクトにconsole.logがいくつあるか」 — モデルの知識はトレーニング時点で止まっています; この瞬間のディスク上のファイル内容については何も知りません
- 「そのコマンドが今出力したもの」 — コマンドはまだ実行されておらず、出力はまだ存在せず、モデルはそれを事前に知ることはできません
- 「このエンドポイントが今返すもの」 — それはこの瞬間にサーバーが返すレスポンスであり、モデルがトレーニングで見た例とは無関係です
この種のタスクについては、プロンプトをどれほど詳細に、または誘導的にしても、モデルは本当の答えを生み出すことはできません。なぜなら単にデータを手にしていないからです。唯一の方法は、ホストプログラムがそれを取得しに行けるようチャネルを与えることです — そしてそれがツールが存在する理由です。
それらの5種類のツール — 読む、書く、コマンドを実行する、検索する、外部サービスを呼び出す — がどのように見えるかは、レッスン3で一つずつ分解します; このレッスンで覚えておくべきことは、「これはツールが必要か」という質問の仕方だけです。
まとめ
- ツールはホストプログラムがモデルに公開する呼び出し可能な機能のリストです。各機能は少なくとも
name、description、input_schemaを明示し、モデルはこれを使ってそれを呼び出すべきかどうか、何を渡すべきかを判断します。1
- モデルは提案するだけで、自分では決して実行しません。 「どのツールを呼び出すか、どのパラメータを渡すか」を構造化データにパッケージ化してホストプログラムに返します; 実際にファイルを開き、コマンドを実行し、リクエストを送信するコードはホストプログラム自身のものです。3 2
- 結果は往復します: ホストが実行を終えた後、結果を会話に戻し、そこで初めてモデルは本当の結果を見て最終応答を書きます — そのステップの完全なラウンドトリップが次のレッスンのトピックです。
- タスクがツールを必要とするかどうかを判断するには、1つの質問で十分です: このタスクに必要な情報や行動を、モデルはすでに手にしているか? なければツールが必要です; あれば、追加は無駄です。
- 同じ質問でも、ツールの有無で大きく異なる結果が生まれます — ツールなしではエージェントはトレーニングからの一般的な知識に頼ってアプローチを説明することしかできません; ツールがあれば、今のプロジェクトが実際にどうなっているかに触れることができます。
レッスン2: ツール呼び出しの完全なラウンドトリップ >>