Chapter 5 · Part 2
Give Claude a tool
So far Claude can only talk. Tool use lets it act — call functions you write, to fetch live data, do math, hit other APIs, or change things in the world. This is the single idea behind every "AI agent." The mechanism is a simple back-and-forth, and you'll walk the whole loop by hand.
The four steps
- You describe a tool (name, what it does, what inputs it takes).
- Claude, if it decides the tool would help, replies with a
tool_userequest instead of a final answer. - You run the actual function and send the result back as a
tool_result. - Claude uses that result to write its real answer.
Define a tool and make the first call
We'll give Claude a pretend weather function. The input_schema is JSON Schema — it tells
Claude exactly what arguments the tool expects. Create tools.py:
from anthropic import Anthropic
client = Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name, e.g. Paris"}
},
"required": ["city"],
},
}
]
def get_weather(city): # the real function Claude can't run itself
return f"18°C and sunny in {city}."
messages = [{"role": "user", "content": "What's the weather in Tokyo? Should I take a jacket?"}]
reply = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
tools=tools,
messages=messages,
)
print(reply.stop_reason) # 'tool_use' — Claude wants to call get_weatherBecause the question needs live data, Claude doesn't answer — it stops with
stop_reason == "tool_use", and its content includes a tool_use block naming the tool and
the arguments it chose ({"city": "Tokyo"}).
Run the tool and hand back the result
Now do Claude's bidding: find the tool_use block, run the matching function, and send a
tool_result back — carrying the tool_use_id so Claude knows which call it answers:
messages.append({"role": "assistant", "content": reply.content}) # remember the tool request
tool_results = []
for block in reply.content:
if block.type == "tool_use":
result = get_weather(**block.input) # actually run it
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result,
})
messages.append({"role": "user", "content": tool_results}) # send results back
final = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
tools=tools,
messages=messages,
)
print(final.content[0].text)It's 18°C and sunny in Tokyo right now — mild and clear. You probably
won't need a jacket, though you might want a light layer for the evening.Claude asked for the tool, you ran it, and it wove the result into a natural answer. That
request → tool_use → run → tool_result → answer cycle is the entire foundation of AI
agents — real ones just loop it, with tools that search the web, run code, or query a database.
The shortcut for real apps
Doing that loop by hand is worth it once, to see the gears. In a real app, the SDK's tool
runner (client.beta.messages.tool_runner(...)) runs the whole cycle for you — you just
supply the tool functions and it handles the calls and results until Claude is done. Now that
you know what it's automating, you can reach for it freely.
Your app can talk, remember, stream, and act. Last chapter: make it robust and ship-ready.