Claude Tool Use Tutorial

Claude Tool Use and Function Calling Tutorial

Tool use (also called function calling) lets Claude interact with external systems by calling functions you define. Instead of just generating text, Claude can decide to call a calculator, search a database, fetch weather data, or perform any action you expose as a tool. This tutorial covers implementation from basics to advanced patterns.

How Tool Use Works

The tool use flow follows three steps:

  1. Define tools — You describe available functions with names, descriptions, and parameter schemas in your API request.
  2. Claude decides — Based on the conversation, Claude decides whether and which tool to call, providing structured arguments.
  3. Return results — You execute the function, then send the result back to Claude in a follow-up message so it can formulate its final response.

Basic Python Example

import anthropic
import json

client = anthropic.Anthropic()

# Define a tool
tools = [
    {
        "name": "get_weather",
        "description": "Get the current weather for a given city. Use this when the user asks about weather conditions.",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "The city name, e.g. 'San Francisco'"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "Temperature unit"
                }
            },
            "required": ["city"]
        }
    }
]

# First API call — Claude decides to use the tool
response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "What's the weather in Tokyo?"}]
)

# Check if Claude wants to use a tool
if response.stop_reason == "tool_use":
    tool_block = next(b for b in response.content if b.type == "tool_use")
    print(f"Claude wants to call: {tool_block.name}")
    print(f"With arguments: {json.dumps(tool_block.input, indent=2)}")

    # Execute your function (simulated here)
    weather_result = {"temperature": 22, "condition": "Partly cloudy", "unit": "celsius"}

    # Second API call — send the tool result back
    final_response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        tools=tools,
        messages=[
            {"role": "user", "content": "What's the weather in Tokyo?"},
            {"role": "assistant", "content": response.content},
            {
                "role": "user",
                "content": [{
                    "type": "tool_result",
                    "tool_use_id": tool_block.id,
                    "content": json.dumps(weather_result)
                }]
            }
        ]
    )
    print(final_response.content[0].text)

Node.js Example

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();

const tools = [
  {
    name: 'search_database',
    description: 'Search the product database by query string',
    input_schema: {
      type: 'object',
      properties: {
        query: { type: 'string', description: 'Search query' },
        limit: { type: 'number', description: 'Max results to return' },
      },
      required: ['query'],
    },
  },
];

async function runWithTools() {
  const response = await client.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 1024,
    tools,
    messages: [{ role: 'user', content: 'Find laptops under $1000' }],
  });

  if (response.stop_reason === 'tool_use') {
    const toolUse = response.content.find((b) => b.type === 'tool_use');
    console.log(`Calling ${toolUse.name} with:`, toolUse.input);

    // Execute your function and return results
    const results = [
      { name: 'ThinkPad T14', price: 899 },
      { name: 'MacBook Air M3', price: 999 },
    ];

    const finalResponse = await client.messages.create({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 1024,
      tools,
      messages: [
        { role: 'user', content: 'Find laptops under $1000' },
        { role: 'assistant', content: response.content },
        {
          role: 'user',
          content: [
            {
              type: 'tool_result',
              tool_use_id: toolUse.id,
              content: JSON.stringify(results),
            },
          ],
        },
      ],
    });
    console.log(finalResponse.content[0].text);
  }
}

runWithTools();
Tip: Write detailed tool descriptions. Claude uses these descriptions to decide when and how to call each tool. Vague descriptions lead to incorrect tool selection or missed tool calls.

Multiple Tools in One Request

You can define multiple tools and Claude will choose the most appropriate one. Claude can even call multiple tools in a single response when needed:

tools = [
    {"name": "get_weather", "description": "Get weather for a city", ...},
    {"name": "search_flights", "description": "Search for flights between cities", ...},
    {"name": "book_hotel", "description": "Book a hotel in a city", ...},
]

# Claude will call the appropriate tool based on the user's request

Agentic Tool Use Loop

For complex tasks, implement an agentic loop where Claude can call tools multiple times:

def run_agent(user_message):
    messages = [{"role": "user", "content": user_message}]

    while True:
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=4096,
            tools=tools,
            messages=messages
        )

        # If Claude is done (no more tool calls), return
        if response.stop_reason == "end_turn":
            return response.content[0].text

        # Process tool calls
        messages.append({"role": "assistant", "content": response.content})
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                result = execute_tool(block.name, block.input)
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": json.dumps(result)
                })
        messages.append({"role": "user", "content": tool_results})
Warning: Set a maximum iteration limit on agentic loops to prevent runaway tool calls. A limit of 10-20 iterations is typical. Also validate and sanitize all tool inputs before execution, as Claude generates the arguments.

Best Practices

  1. Use descriptive names — Tool names like search_products are better than query.
  2. Validate inputs — Always validate tool arguments before executing functions.
  3. Handle errors gracefully — Return error messages as tool results so Claude can inform the user.
  4. Use enums for constrained values — Enums in the schema prevent invalid inputs.
  5. Keep tools focused — Each tool should do one thing well rather than being a multi-purpose function.

Tool use through a relay service like claude4u.com works identically to the direct API. Simply set your ANTHROPIC_BASE_URL and the relay transparently handles the tool use request-response cycle.

Get Started with 轻舟 AI

Stable, fast AI API relay — supports Claude, OpenAI, Gemini and more

Sign Up Free