Chapter 2

第2章: ツール呼び出しの正体 ─ テキスト機械が関数を呼ぶ仕掛け

Claude Code を起動して「fibonacci.py を読んで」とだけ打つと、画面にこう出る。

● Read(fibonacci.py)
  ⎿  読み込み完了 (23 行)

LLM は「続きを書くだけの機械」のはずだった (第1章)。 なのにここでは、まるで関数を呼んだかのように Read(fibonacci.py) という構造化された命令が現れている。

テキストを吐くだけのモデルが、どうやって “関数呼び出し” を返しているのか。 答えは、思ったよりずっと単純で、しかし設計としてはきわめて巧い。

2.1 そもそも、なぜ “テキストのまま” ではダメなのか

ハーネス (第1章) は、LLM の出力を受け取って 本当にファイルを読みに行く プログラムだ。 LLM が「fibonacci.py を読んでください」という自然言語を返してきたら、これを解釈してファイル操作を実行する必要がある。

素直に思いつくのは「自然言語のままパースする」やり方だ。

「ファイル fibonacci.py を読んでください」 → 動詞 “読む” を検出 → 目的語 “fibonacci.py” を抽出 → read_file("fibonacci.py") を実行

ところがこれは、すぐに破綻する。

自然言語パースは、揺らぎに弱すぎる。 ハーネスが LLM の意図を確実に受け取るには、形が決まった “命令の入れ物” が要る。

ここで業界が選んだ答えが、本章のテーマ ── ツール呼び出し (tool call / function calling) だ。

2.2 ツールを “カタログ” として LLM に渡す

仕組みを最小単位から組み立てよう。 まず、ハーネスは LLM に 「あなたが使えるツール一覧」 を最初に渡す。

具体的にはこんなイメージ。

{
  "name": "Read",
  "description": "ファイルの中身を読み取って返す",
  "input_schema": {
    "type": "object",
    "properties": {
      "path": { "type": "string", "description": "読みたいファイルの絶対パス" }
    },
    "required": ["path"]
  }
}

3 つの部品だけだ。

部品意味
nameこのツールの呼び名 (Read, Write, Bash など)
descriptionこのツールが何をするかの自然言語説明。LLM が「いつ使うか」を判断する材料
input_schema引数の形を JSON Schema で厳密に定義
JSON Schema

JSON の値が満たすべき形を、別の JSON で記述するための仕様。「この値はオブジェクトで、path という文字列フィールドを必ず持つ」のような構造制約を機械可読に書ける。Web API の業界で長く使われてきた、枯れた標準。

このカタログを システムプロンプト相当の位置 (第5章で詳述) に流し込んでおくと、LLM はそれを「自分が使える道具のリスト」として認識する。

ここがコーディングエージェント設計の急所のひとつだ。 ツールの description は、LLM への一種の “求人票” になっている。 「いつ私を呼んでください」を自然言語で説得力のある形で書けるかどうかで、エージェントの賢さが大きく変わる。 description の磨き込みは、第6章 (ツール設計) でまた戻ってくる。Skills でも description という似た仕掛け (役割は違うが) が出てくる。

2.3 LLM の出力に “tool_use ブロック” が混ざる

カタログを与えられた LLM は、頼みごとを受けてこう考える。

fibonacci.py を読んで と言われた。カタログを見ると Read という道具がある。description にも合致する。これを呼べばよさそうだ」

そして LLM は、普通の文章ではなくカタログのスキーマに沿った構造化データ を出力する。 Anthropic の API ではこれが tool_use ブロック という形で返ってくる。

{
  "type": "tool_use",
  "id": "toolu_01ABC",
  "name": "Read",
  "input": { "path": "/repo/fibonacci.py" }
}

ポイントは 3 つ。

  1. type: "tool_use" という型タグで、「これは喋りではなく道具呼び出しだ」とハーネスに伝える
  2. name がカタログの name と一致する
  3. inputinput_schema の制約を満たしている (path が文字列で、必須項目が揃っている)

ハーネスは型タグを見て即座に分岐する。 普通のテキストなら画面に表示し、tool_use ブロックなら対応する関数を呼ぶ

LLM は内部では「続きを書く機械」のままだ。 ただ、出力する “続き” の中に 構造化された JSON ブロック を混ぜることを学習している。

つまり LLM がしているのは 「文章を書く」と「JSON を書く」の出し分け であり、それを ハーネスが型で見分けて分岐している だけ。 魔法ではなく、出力フォーマットの約束事の話だ。

2.4 なぜ “テキスト” ではなく “構造” なのか

ここで改めて、設計判断の意味を噛みしめておく。 LLM 側もハーネス側も、わざわざ JSON という構造化フォーマットを介する。なぜか。

理由 1: パースの安定性

JSON は文法が厳密だ。{} で囲まれ、キーと値がコロンで結ばれる。パーサーはこの形をきっちり検証できる。 「Read me first というドキュメントを開いた」のような自然文と違って、誤検出の余地がほぼない

理由 2: 引数の型保証

input_schema が「path は文字列」と宣言している。 LLM が万一おかしな値を入れようとすれば、ハーネス側でスキーマ違反として弾ける。 これは Web API のリクエストバリデーションと全く同じ思想だ。

理由 3: 複数ツールの同時呼び出し

1 回の応答で 複数の tool_use ブロックを並べて返せる (詳しくは第3章)。

[
  { "type": "tool_use", "name": "Read", "input": { "path": "a.py" } },
  { "type": "tool_use", "name": "Read", "input": { "path": "b.py" } }
]

自然言語だと「a.pyb.py を読んで」を 2 つの操作に分解するのにまた解析が要るが、構造化なら 配列の要素を順に処理するだけ

ツール呼び出しの本質は、自然言語の “意図” と機械の “実行” の間に、揺らがない契約 (JSON Schema) を一枚挟むこと。 これにより、LLM 側は「呼びたい道具と引数」を考えることだけに集中でき、ハーネス側は「契約に沿って実行する」ことだけに集中できる。

2.5 業界横断: 名前は違うが構造は同じ

この仕組みは Anthropic 固有のものではない。主要 LLM プロバイダはほぼ全員、同じ構造を提供している。呼び名だけ違う。

プロバイダ呼び名スキーマ
Anthropic (Claude)tool useJSON Schema
OpenAI (GPT)function callingJSON Schema
Google (Gemini)function callingOpenAPI スキーマ (実体は JSON Schema 系)

最初に “function calling” という名前を市場に広めたのは 2023 年の OpenAI で、業界はその語感のまま定着した。 本書では Claude Code の文脈に合わせて主に tool use / ツール呼び出し と呼ぶが、他社ドキュメントの “function calling” を見たら同じものだと思ってよい

実務メモ

モデルによって “ツールを呼ぶのが上手い・下手” の差がある。description が曖昧でも適切に呼んでくれるモデルもあれば、明示的に「次は必ず Read を使え」と書かないと自然言語で済ませてしまうモデルもある。Claude Code が Claude 系モデルに最適化されているのは、この呼び出し能力の高さに依るところが大きい。

2.6 一往復の全体像 ── 図で押さえる

ここまでの流れを一枚の図にまとめる。 LLM とハーネスの間で 1 回の道具呼び出し が完結するまでに、何が往復しているのか。

LLM続きを書く機械ハーネス外側のプログラム道具 (Read など)実際にファイルを触る① ツールのカタログ (name + description + JSON Schema)② tool_use ブロック{"type":"tool_use","name":"Read","input":{"path":"..."}}③ name で分岐 実関数を呼ぶ④ 結果を 続きとして渡すこの一往復が、エージェントの “1 ステップ” を構成する
図 2.1 — ツール呼び出しの一往復。LLM は構造化ブロックを返し、ハーネスは型を見て分岐し、結果を続きとして LLM に戻す。

ステップに分解するとこうなる。

  1. 準備: ハーネスがツールのカタログ (name + description + JSON Schema) を LLM に渡しておく
  2. 判断: LLM がユーザーの依頼を読み、tool_use ブロックを返す
  3. 分岐: ハーネスが typename を見て、対応する実関数を呼ぶ
  4. 観測: 実行結果を 続きの入力 として LLM に戻す (下記 tool_result)
tool_result

tool_use と対になるブロック。ハーネスがツールを実行した結果 (ファイルの中身、コマンド出力、エラーメッセージなど) を LLM に戻すための型タグ付き入れ物。tool_useid と紐付けて返すことで、LLM は「どの呼び出しに対する結果か」を識別できる。

ここで返した結果を見て LLM が次の手を考える ── つまり このサイクルが繰り返される ことで、第1章で見た “動ける” 状態が生まれる。 そのサイクル自体は、次の第3章 (think → act → observe) で正面から扱う。

2.7 章を貫く問いへの答え

冒頭の問いに戻ろう。

テキストを吐くだけのモデルが、どうやって “関数呼び出し” を返しているのか。

答えはこうだ。

つまり「関数呼び出し」と見えていたものは、LLM が JSON を書き、ハーネスが JSON をパースして実行する という、地に足のついた約束事の積み重ねだった。

ここまでくると、「LLM がツールを使いこなす」という言い方が、少し違って聞こえてくるはずだ。 LLM 側は 「JSON を上手に書ける」 だけ。ツールを実際に動かしているのはハーネスのほう。

この役割分担を頭に置いておくと、第6章で「ツールの良し悪し」を語るとき、なぜ description の言葉選びがそんなに大事なのかが自然に腑に落ちる。

この章の振り返り

この章で読めるようになるツイート / ブログ

次章では、ここで見た 一往復何往復も繰り返すループ に拡張する。 LLM が考え、ツールを呼び、結果を観測し、また考える ── エージェント本体の心臓部、think → act → observe サイクルの解剖に進もう。