Tool Use Intro

Su Suriya Ravichandran Updated 10 Nov 2026
8 min read ·Lesson 81 of 200

What Tool Use Is

On its own, Claude can only work with what is in the conversation and what it learned during training. It cannot look up today's weather, query your database, check an order's status, or send an email.

Tool use (also called function calling) changes that. You describe tools, functions your application can run, and Claude can decide to call them when it needs information or wants to take an action. Your code runs the tool and sends the result back, and Claude uses the result to continue.

User: "Is it a good day for a walk in Chennai?"

Claude: (needs current weather) → calls get_weather({"city": "Chennai"})
Your code: runs get_weather → returns "31°C, humid, light rain expected at 5 PM"
Claude: "It's warm and humid, with rain expected around 5 PM, so a morning walk is best."

Claude never runs your code itself. It produces a structured request: the tool's name and its input. Your application decides whether and how to execute it. That separation keeps you in control of what actually happens.


Why Tool Use Matters

CapabilityExample tools
Access current or private dataWeather, stock prices, your product catalog, a user's orders
Take actionsCreate a support ticket, send a notification, update a record
Calculate preciselyExact arithmetic, date calculations, unit conversions
Connect to other systemsSearch engines, internal APIs, databases
Build agentsMulti-step workflows where Claude chooses which tools to use, in which order

Tool use turns Claude from a system that only answers into one that can act on your behalf, within the limits you define.


Client Tools and Server Tools

Client toolsServer tools
Who runs themYour applicationAnthropic's servers
ExamplesAny function you define: get_weather, lookup_orderWeb search, web fetch, code execution
What you doDefine the tool, run it, send back the resultEnable the tool in the request; results appear in the response
Covered inLessons 81–100Lesson 155

This section focuses on client tools: tools you define and run yourself.


How Tool Use Works: The Loop

Tool use is a conversation with extra steps:

┌─────────────────────────────────────────────────────────────────┐
│ 1. You send: messages + tool definitions                        │
│ 2. Claude replies with stop_reason = "tool_use" and tool_use    │
│    blocks: [{id, name, input}, ...]                             │
│ 3. Your code runs each requested tool                           │
│ 4. You send back: Claude's reply + a user message containing    │
│    tool_result blocks [{tool_use_id, content}, ...]             │
│ 5. Claude continues: another tool call (back to step 2),        │
│    or a final answer with stop_reason = "end_turn"              │
└─────────────────────────────────────────────────────────────────┘
StepLesson
Define tools and their input schemas82, 83
Send tools with a request84
Read tool_use blocks85
Run the matching Python function86
Return tool_result blocks87
Loop until Claude finishes88
Control whether and how tools are used89
Handle failures90

The SDK also offers a tool runner that automates this loop (Lessons 91–92). Learning the manual loop first makes clear what the runner does for you.


The Building Blocks

A Tool Definition

weather_tool = {
    "name": "get_weather",
    "description": "Get the current weather for a city. Use it when the user asks about "
                   "current conditions or whether the weather suits an activity. "
                   "Returns temperature in Celsius and a short description.",
    "input_schema": {
        "type": "object",
        "properties": {
            "city": {"type": "string", "description": "City name, e.g. Chennai"},
        },
        "required": ["city"],
    },
}

A Tool Call (in Claude's Response)

{"type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather",
 "input": {"city": "Chennai"}}

A Tool Result (in Your Next Message)

{"type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
 "content": "31°C, humid, light rain expected at 5 PM"}

The tool_use_id links each result to the call that requested it.


Practical Example: Your First Tool Call

This complete example defines one tool, lets Claude call it, runs a simple local implementation, sends the result back, and prints Claude's final answer.

"""first_tool.py: a complete tool use round trip."""

from anthropic import Anthropic

client = Anthropic()
MODEL = "claude-opus-5-5"

WEATHER = {
    "chennai": "31°C, humid, light rain expected at 5 PM",
    "bengaluru": "24°C, partly cloudy, no rain expected",
}

TOOLS = [{
    "name": "get_weather",
    "description": (
        "Get the current weather for a city. Use it whenever the user asks about current "
        "conditions, or whether the weather suits an activity. Returns the temperature in "
        "Celsius and a short description. It does not provide forecasts beyond today."
    ),
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string", "description": "City name, e.g. Chennai"}},
        "required": ["city"],
    },
}]


def get_weather(city: str) -> str:
    return WEATHER.get(city.strip().lower(), f"No weather data available for {city}.")


messages = [{"role": "user", "content": "Is it a good day for an evening walk in Chennai?"}]

# Step 1–2: send the question with the tool; Claude decides to call it
response = client.messages.create(model=MODEL, max_tokens=2048, tools=TOOLS, messages=messages)
print("stop_reason:", response.stop_reason)

# Step 3: run every requested tool
tool_results = []
for block in response.content:
    if block.type == "tool_use":
        print(f"Claude called {block.name}({block.input})")
        result = get_weather(**block.input)
        tool_results.append({"type": "tool_result", "tool_use_id": block.id, "content": result})

# Step 4: send Claude's reply and the results back
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})

# Step 5: Claude continues with the tool's information
final = client.messages.create(model=MODEL, max_tokens=2048, tools=TOOLS, messages=messages)
print("stop_reason:", final.stop_reason)
print("".join(b.text for b in final.content if b.type == "text"))

Example output:

stop_reason: tool_use
Claude called get_weather({'city': 'Chennai'})
stop_reason: end_turn
It's warm and humid in Chennai (31°C), and light rain is expected around 5 PM, so an evening walk may get wet. If you can, go earlier in the afternoon, or take an umbrella.

How It Works

  1. TOOLS describes one tool: its name, a detailed description of what it does and when to use it, and an input_schema (a JSON Schema) for its input. Claude only sees this description, not your Python code.
  2. The first request includes tools=TOOLS. Claude reads the question, decides it needs current weather, and responds with a tool_use block. stop_reason is "tool_use", which means Claude is waiting for your code.
  3. The loop over response.content finds every tool_use block. For each one, get_weather(**block.input) runs the local function, using the input dictionary as keyword arguments.
  4. Each result becomes a tool_result block, with tool_use_id set to the call's id.
  5. The conversation continues: Claude's response is appended unchanged as an assistant message (it may include thinking blocks, Lesson 16), followed by a user message containing the tool results.
  6. The second request includes the same tools. Claude reads the result and writes its final answer, with stop_reason "end_turn".

This example handles one round of tool calls. Lesson 88 builds a loop that handles any number of rounds.


Tool Use and Costs

Tools add input tokens to every request that includes them:

  • Tool definitions (names, descriptions, schemas) are sent with each request.
  • When tools are present, the API also adds a tool-use system prompt that explains how to call them.
  • Tool calls are output tokens, and tool results are input tokens in the next request.

Use count_tokens() with your tools to measure the overhead (Lesson 44), and send only the tools a request needs.


Common Mistakes

Expecting Claude to Run the Code

What happens: developers wait for Claude to "execute" a function, but nothing happens.

Fix: your application runs tools. Claude only requests them.

Treating stop_reason == "tool_use" as a Final Answer

What happens: the user sees a short preamble, such as "I'll check the weather", instead of an answer.

Fix: when the stop reason is tool_use, run the tools and continue the conversation.

Mismatched tool_use_id Values

What happens: a 400 error, because results do not correspond to the calls.

Fix: set each result's tool_use_id to the id of the call it answers.

Modifying Claude's Tool-Use Response

What happens: 400 errors in tool-use conversations, because thinking blocks from the latest assistant turn must be returned unchanged.

Fix: append response.content exactly as received.

Vague Tool Descriptions

What happens: Claude calls the tool at the wrong times, or not at all.

Fix: describe what the tool does, when to use it, and what it returns (Lesson 82).


Best Practices

  • Write detailed tool descriptions. They are the most important factor in tool performance.
  • Keep your application in control: validate inputs and decide what tools may do.
  • Return all tool results together in one user message.
  • Pass Claude's responses back unchanged.
  • Include the same tools in every request of a tool-use conversation.
  • Measure token overhead, and send only relevant tools.
  • Use the SDK's tool runner once you understand the manual loop (Lessons 91–92).

Exercise

  1. Ask first_tool.py about Bengaluru instead of Chennai. How does the answer change?
  2. Ask about a city that is not in WEATHER. What does Claude say?
  3. Ask a question that does not need weather, such as "What is a Python list?". Does Claude call the tool?
  4. Ask "Compare the weather in Chennai and Bengaluru." How many tool_use blocks are in the first response?
Show answers for steps 3 and 4

Step 3: Claude answers directly, without calling the tool. The first response has stop_reason == "end_turn" and no tool_use blocks, so the loop finds nothing to run. Your code should check for this case: in first_tool.py, the second request would be unnecessary. Lesson 88 handles it properly.

Step 4: typically two tool_use blocks in the same response, one for each city. Claude makes parallel tool calls by default when a request benefits from several. The example's loop already handles this: it runs every call and returns all the results together in a single user message, which is the required format.

0 Comments

Reviewed before they appear

No comments yet.

Anthropic SDK Using Python
Anthropic SDK Intro Claude API Intro SDK Requirements Install Anthropic SDK Upgrade the SDK Create an API Key Set API Keys Use Environment Variables Import Anthropic Create a Client Send Your First Message Choose a Claude Model Set Max Tokens Read a Response Print Response Text Understand Message Blocks Use System Prompts Send User Messages Set Temperature Handle Stop Reasons Messages API Intro Create Messages Use Message Roles Send Conversation History Continue a Conversation Build a Chat Loop Reset Chat History Use Multiple Turns Inspect Message IDs Read Usage Data Write Clear Prompts Set a System Prompt Add Context to Prompts Use Prompt Templates Add Examples to Prompts Request JSON Output Use XML Tags Control Response Length Improve Prompt Quality Avoid Prompt Injection Read Text Blocks Read Content Blocks Check Stop Reasons Count Input Tokens Count Output Tokens Count Tokens Before Sending Limit Output Tokens Use Stop Sequences Read Request IDs Parse API Responses Streaming Intro Stream Text Output Use Stream Events Use Stream Helpers Get Final Messages Stream Async Responses Handle Stream Errors Build a Live Chat Stream Long Responses Close Streams Safely Build a Chatbot Keep Chat History Manage Chat Sessions Add Chat Memory Build a CLI Chatbot Build a Web Chatbot Use Flask with Claude Use FastAPI with Claude Return JSON from an API Add Chat Error Messages Async SDK Intro Create an Async Client Send Async Messages Use asyncio Run Parallel Requests Stream Async Text Handle Async Errors Set Async Timeouts Close Async Clients Choose Sync or Async Tool Use Intro Define a Tool Create Tool Schemas Send Tools to Claude Read Tool Calls Run Python Tools Return Tool Results Continue After Tool Use Control Tool Choice Handle Tool Errors Use the beta_tool Decorator Create a Tool Runner Add Tool Docstrings Validate Tool Inputs Use Multiple Tools Limit Tool Calls Log Tool Activity Build a Weather Tool Build a Search Tool Build a Calculator Tool Structured Output Intro Request JSON Data Validate JSON Output Use Pydantic Models Handle Invalid JSON Extract Fields from Text Generate Typed Data Use Image URLs Send Base64 Images Read PDFs with Claude Use Output Schemas Build Data Extraction Test Structured Responses Send Image Inputs Upload Files Use File IDs Process Text Files Summarize Documents Extract Table Data Handle File Errors Read Cache Usage Reduce Repeated Input Costs Debug Cache Misses Prompt Caching Intro Enable Prompt Caching Cache System Prompts Cache Long Context Test Cache Performance Use Cache Breakpoints Cache Best Practices Message Batches Intro Create a Message Batch Set Batch IDs Check Batch Status List Message Batches Get Batch Results Process Batch Outputs Handle Failed Batch Items Use Batches for Bulk Tasks Compare Batches and Requests Handle API Errors Handle Rate Limits Retry Failed Requests Set Request Timeouts Handle Network Errors Use Exponential Backoff Build Reliable API Calls Use Extended Thinking Log API Errors Track Request IDs Paginate API Results Set Thinking Budgets Read Thinking Blocks Use Tool Search Use Web Search Tools Use Computer Tools Use Citations Use Token Counting Read Raw Responses Set Custom Headers Use Claude on AWS Bedrock Use Claude on Vertex AI Use Claude on Microsoft Foundry Configure Cloud Credentials Choose a Cloud Provider Compare API Integrations Configure Provider Clients Handle Cloud Errors Use Cloud SDK Extras Deploy Cloud Apps Protect API Keys Use a .env File Ignore Secrets in Git Validate User Input Reduce Prompt Injection Limit Tool Permissions Avoid Unsafe Tool Calls Sanitize Tool Results Set Usage Limits Review Security Logs Test SDK Functions Mock API Responses Test Error Handling Test Streaming Code Measure Token Usage Track API Costs Configure Logging Deploy with Docker Deploy a FastAPI App Monitor Production Apps Build a Claude Chatbot Build a Text Summarizer Build a Code Explainer Build a JSON Extractor Build a PDF Assistant Build a Streaming Chat App Build a Tool-Calling Agent Build a Batch Processor Build a Research Assistant Build a Claude API Dashboard
Ask about this post
AI Ask about this post

Ask questions about Tool Use Intro and get answers drawn from it.

Signed-in readers only.