メインコンテンツへスキップ

ツールを使わせる

  • レッスン 5
  • 10分

このレッスンで

終わる頃には、次ができるようになります

  • ツールがname・description・input_schemaの3点で定義されることを説明できる
  • tool_useブロックとtool_resultブロックの往復を、自分のコードで実装できる
  • 複数のツールを、エラー処理を含めて安全にルーティングできる

これまでのレッスンでは、Claudeは質問に答えるだけでした。ここからは「何かを調べさせる」「何かを実行させる」ところまで進みます。この仕組みをツール使用と呼びます。

ツールは契約であって実行ではない

最初に押さえておきます。Claude自身は、ツールを実行しません。Claudeがするのは「この引数で呼びたい」という要求を返すところまでです。実際にコードを動かすのは、常にあなたのアプリ側です。

通常の関数呼び出しに近い形だと考えると分かりやすくなります。関数のシグネチャを渡しておくと、Claudeは呼ぶべきだと判断したときに、引数を添えたリクエストを返します。あなたのコードがそれを受けて実行し、結果を送り返します。

ツールの定義: 3要素

ツールは次の3要素を持つJSON Schemaとして定義します。

name

ツールの識別子

description

何をするか・いつ使うか・何を返すかの説明文

input_schema

引数の形。JSON Schemaで型と必須項目を指定

ツール定義の3要素

descriptionの書き方が、ツールが正しく呼ばれるかを左右します。あいまいだと、似た場面で違うツールを選んだり、呼ぶべき場面で呼ばなかったりします。

会議室予約システムを調べるツールを例にします。

tools = [{
    "name": "check_room_availability",
    "description": "会議室の予約可否を調べる。空きの真偽値と、埋まっていれば次に空く時刻を返す。",
    "input_schema": {
        "type": "object",
        "properties": {
            "room": {"type": "string", "description": "会議室名。例: 3階A会議室"},
            "date": {"type": "string", "description": "YYYY-MM-DD形式"},
            "start_hour": {"type": "integer"},
        },
        "required": ["room", "date", "start_hour"],
    },
}]

往復の流れ: tool_useとtool_result

ツールを渡したリクエストにClaudeが応じるとき、stop_reason が "tool_use" になり、呼びたいツールの名前と引数を持つ tool_use ブロックが返ります。

01

リクエスト送信

toolsとuserメッセージを送る

02

tool_useで応答

Claudeがツール名と引数を返す。stop_reasonはtool_use

03

自分のコードで実行

実際に関数を呼び、結果を得る

04

tool_resultを送り返す

結果をtool_use_idと紐づけて次のリクエストへ

05

最終応答

Claudeが結果をもとに答える。stop_reasonはend_turn

ツール呼び出しの往復
def check_room_availability(room, date, start_hour):
    return {"available": False, "next_free_hour": 15}  # 本来は予約システムに問い合わせる

def run_tool(name, tool_input):
    if name == "check_room_availability":
        return check_room_availability(**tool_input)
    raise ValueError(name)

def call(messages):
    return client.messages.create(
        model="claude-sonnet-5", max_tokens=1024, tools=tools, messages=messages)

messages = [{"role": "user", "content": "明日の午前10時、3階A会議室は空いてる?"}]
response = call(messages)

while response.stop_reason == "tool_use":
    messages.append({"role": "assistant", "content": response.content})
    results = []
    for b in response.content:
        if b.type != "tool_use":
            continue
        try:
            r = {"type": "tool_result", "tool_use_id": b.id, "content": str(run_tool(b.name, b.input))}
        except Exception as e:
            r = {"type": "tool_result", "tool_use_id": b.id, "content": f"エラー: {e}", "is_error": True}
        results.append(r)
    messages.append({"role": "user", "content": results})
    response = call(messages)

print(next(b.text for b in response.content if b.type == "text"))

このループはstop_reasonが"tool_use"でなくなるまで続きます。「空いていなければ別の会議室も調べて」のような依頼では、呼び出しが何度か連続します。

注意

ツールの失敗はis_errorで伝える

失敗しても、結果を黙って無視してはいけません。is_error: trueを付けたtool_resultで返すと、Claudeは引数を直した再試行や利用者への説明を判断できます。握りつぶすと、見当違いの答えを出すことがあります。

複数のツールを足すとき

新しいツールを足す手順は、いつも同じです。

ツールを1つ増やす4手順

1

関数を実装

Pythonの普通の関数として書く

2

スキーマを書く

name・description・input_schemaを定義

3

toolsリストに追加

リクエストに渡すtoolsの配列に足す

4

ルーターに追加

run_toolのif/elifにツール名の分岐を足す

やってみよう

演習1: ツールを1つ定義してみる

自分の仕事でClaudeに「調べさせたい」ことを1つ選び、name・description・input_schemaの形に落とし込んでください。

演習2: 失敗したときの伝え方

そのツールが失敗する場面を1つ想定し、is_errorの中身としてClaudeに何を伝えれば、次の判断に活かせるか考えてください。

今日のまとめ

3行で振り返ります。

  • ツールを実行するのはClaudeではなく、常にあなたのコード。Claudeが返すのは「呼びたい」という構造化された要求だけ
  • 往復はstop_reason == "tool_use"のあいだ繰り返すループとして実装する。結果はtool_use_idと紐づけて返す
  • ツールの失敗はis_error: trueで伝える。黙って無視すると、Claudeは何が起きたか分からないまま答えてしまう

次のレッスンでは、社内文書や長い資料をもとにClaudeに答えさせる方法を扱います。

セルフチェック

1. ツール使用について正しい説明はどれですか。

2. ツール呼び出しのループを終える条件はどれですか。

3. ツールの実行が失敗したときの正しい対処はどれですか。

SourceDOCUMENTATION
Tool use with Claude

ツールの定義から往復の流れまでの公式ガイド。最小のコード例付き。

Webplatform.claude.com
platform.claude.com/docs/en/agents-and-tools/tool-use/overview
SourceDOCUMENTATION
How tool use works

ツールが実行される場所(クライアント実行/サーバー実行)と、エージェント的なループの仕組みの解説。

Webplatform.claude.com
platform.claude.com/docs/en/agents-and-tools/tool-use/how-tool-use-works

このレッスンは役に立ちましたか?