
Give Claude a Function to Call: The Tool-Use Round Trip Every Agent Runs
Chris Harper
3 min read
Aug 30, 2026 · 04:03 UTC
What you will be able to do after this: wire any Python function — a database lookup, a search API, an internal retrieval call — into Claude as a callable tool, handle the result correctly, and understand the token overhead so costs don't surprise you.
Three things to take away:
- Claude never executes your function — it returns a
tool_useblock with structured arguments; your code runs the function and sends atool_resultback so Claude can continue stop_reason: "tool_use"is the signal to handle a call;stop_reason: "end_turn"means Claude is done with tools and has its final answerstrict: truein a tool definition guarantees Claude's output always matches your JSON schema — catch argument type errors before they reach your function
The loop, step by step:
import anthropic, json
client = anthropic.Anthropic()
# 1. Define the tool — Claude gets the name, description, and schema
tools = [{
"name": "get_order_status",
"description": "Look up the current status of a customer order by order ID.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "The order ID, e.g. A42"}
},
"required": ["order_id"]
},
"strict": True # output always matches this schema exactly
}]
messages = [{"role": "user", "content": "What is the status of order A42?"}]
# 2. First turn: Claude decides to call the tool, returns stop_reason="tool_use"
response = client.messages.create(
model="claude-opus-5", max_tokens=1024,
tools=tools, messages=messages,
)
tool_call = next(b for b in response.content if b.type == "tool_use")
# 3. Your code runs the actual function
result = lookup_order(tool_call.input["order_id"]) # your DB / API call
# 4. Send the result back — Claude continues and gives the final answer
messages += [
{"role": "assistant", "content": response.content},
{"role": "user", "content": [{
"type": "tool_result",
"tool_use_id": tool_call.id,
"content": json.dumps(result)
}]}
]
final = client.messages.create(
model="claude-opus-5", max_tokens=1024,
tools=tools, messages=messages,
)
print(next(b.text for b in final.content if b.type == "text"))
The cost reality: Every tool schema adds tokens to every request. On Claude Opus 5, the tool-use system prompt overhead alone is 286 tokens for tool_choice: auto and 406 tokens when using any or tool. Add ~50–150 tokens per tool definition. Ten detailed tool schemas on a short conversation can easily add 2–3k tokens per turn — size your descriptions to what Claude needs to choose correctly, not to what a human reader would want.
To skip the round-trip loop: use Tool Runner — the Anthropic SDK can execute your tools automatically and send results back without explicit handling code. Useful for simple loops; keep the manual loop when you need to log, gate, or transform results.
Sources: Tool use overview — platform.claude.com · Build a tool-using agent tutorial — Anthropic · Claude API Function Calling: Complete Guide (2026) — DEV Community