Tool use connects Claude to the rest of your stack. Write the schemas carefully and the agent books flights, queries databases and drives a browser. Write them carelessly and the model will confidently call get_weather with location: "the place the user mentioned". In 2026 Sonnet 4.6 and Opus 4.8 handle parallel calls and computer use, and they stick to JSON more tightly than before. So the distance between a demo and production now comes down almost entirely to the quality of your tool definitions.
What follows is the practical guide we wished we had when we built our first agents on Claude.
What a tool definition is made of
Three fields matter, and only three:
{
"name": "get_weather",
"description": "Get the current weather and 24h forecast for a specific city. Use this when the user asks about temperature, rain, snow, or weather conditions. Do not use for historical weather (before today) — use get_historical_weather instead.",
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name in English, e.g. 'San Francisco', 'Tokyo'. Do not include country."
},
"units": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature units. Default to celsius unless the user is in the US."
}
},
"required": ["city"]
}
}
In order of priority:
description. Nothing else affects tool selection as much. Claude reads this field to decide whether to call your tool at all and whether it fits the request. Write it the way you would write a docstring for a junior engineer who has never opened your codebase.input_schema. A JSON Schema for the arguments. Useenumfreely, give every property adescription, and put only the truly mandatory fields inrequired.name. Lowercase, snake_case, verb first:get_,create_,search_.
Most people get one thing wrong on day one: they treat description as a label. It is a mini-prompt. Say when Claude should use the tool, when it should not, what side effects the call has and what each input means.
Parallel tool calls in Sonnet 4.6+
Older Claude releases produced one tool_use block per assistant turn. Sonnet 4.6 and Opus 4.8 can return several tool_use blocks in a single response when the calls are independent. That matters because round-trip latency dominates the experience of using an agent.
Say a user asks, "what's the weather in Tokyo and Paris, and what's on my calendar tomorrow?" A 2025 integration runs three sequential turns. A 2026 integration gets three tool_use blocks in one response, runs them in parallel on your side and sends back three tool_result blocks in the next user message. One round trip instead of three.
There is nothing to switch on. Just be ready to receive an array of calls and dispatch them concurrently.
A working example: weather and an orders database
A minimal but realistic agent loop. It goes through the codexkey gateway, which accepts the Anthropic Messages API format directly:
import anthropic
import json
client = anthropic.Anthropic(
base_url="https://api.codexkey.online/v1",
api_key="cxa-..."
)
tools = [
{
"name": "get_weather",
"description": "Current weather for a city. Use for 'what's the weather' questions.",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name in English"},
"units": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
},
{
"name": "query_orders",
"description": "Search the orders database by customer email or order ID. Returns up to 20 most recent orders.",
"input_schema": {
"type": "object",
"properties": {
"email": {"type": "string", "format": "email"},
"order_id": {"type": "string", "description": "Order ID like 'ORD-12345'"}
}
}
}
]
def execute_tool(name, args):
if name == "get_weather":
return {"city": args["city"], "temp_c": 14, "condition": "cloudy"}
if name == "query_orders":
return {"orders": [{"id": "ORD-12345", "total": 89.50, "status": "shipped"}]}
return {"error": f"unknown tool: {name}"}
messages = [{"role": "user", "content": "Weather in Tokyo, and find orders for jane@example.com"}]
while True:
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=2048,
tools=tools,
messages=messages
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
break
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})
print(response.content[-1].text)
Look at the loop. While stop_reason == "tool_use", run every tool block, put all the results into a single user message and call the model again. That is the whole orchestration pattern.
Tool errors: tell Claude what went wrong
One habit buys the most reliability: a tool error is data, not an exception. When a tool fails (bad input, API down, rate limit), return the error inside tool_result and let Claude respond to it:
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"is_error": True,
"content": "Database timeout after 5s. Try again with a narrower filter or fewer fields."
})
Claude reads the message and often retries with adjusted arguments, or explains the problem to the user. This single pattern replaces a pile of brittle try/except code you would otherwise wrap around the model.
tool_choice: auto, any, tool, none
The tool_choice parameter sets how eagerly Claude reaches for tools:
{"type": "auto"}is the default. Claude decides whether to call a tool or answer in text.{"type": "any"}requires Claude to call some tool. Which one is up to it.{"type": "tool", "name": "get_weather"}forces one specific tool. This suits structured extraction: define arecord_user_intenttool with exactly the schema you need, force the call and you get guaranteed JSON back.{"type": "none"}blocks tool calls for this turn even though tools are defined.
A forced tool_choice is still the cleanest way to get reliable structured output from Claude in 2026. Skip the JSON-mode gymnastics: define a tool, force it, parse block.input.
Computer use: when text tools are not enough
Sonnet 4.6+ supports computer use. The model takes screenshots, moves the mouse, types and clicks on a virtual desktop. You enable it with a special computer_20250124 tool plus bash and text_editor. Claude returns actions such as {"action": "screenshot"} or {"action": "click", "coordinate": [512, 384]}, your harness executes them and sends back the fresh screenshot.
Reach for computer use when:
- the system you need to drive has no API (legacy admin panels, vendor portals);
- the task is visual by nature (checking a layout, reading a chart inside a PDF);
- you need end-to-end QA of your own product.
If a real API exists, use it. Computer use is slower, less reliable and more expensive per task than function calling against a proper backend.
Anthropic format versus OpenAI-compatible format
codexkey exposes both endpoints. The two shapes differ visibly: Anthropic uses tool_use and tool_result content blocks, while OpenAI uses tool_calls with function.name and function.arguments as a JSON string.
Starting from scratch, pick the Anthropic shape. It is structured, parallel calls are easier to handle, and arguments do not arrive as strings. If you are porting an existing OpenAI-shaped codebase, the compatible endpoint https://api.codexkey.online/v1/chat/completions lets you change the model without rewriting your tool layer. Move to the native shape later.
Debugging tool calls
When an agent goes off the rails, three things give you 90% of the signal.
- Log every
tool_use_idtogether with the input and the result. Mismatched IDs are the most common cause of silent breakage. - Log
stop_reasonon every turn. Seeingend_turnwhere you expectedtool_usemeans the description is unclear ortool_choiceis set wrong. - After a failure, replay the whole message array through the API. At low temperature Claude is deterministic enough that the bad call usually reproduces.
A small dashboard that shows the message timeline, the tool calls and the results side by side pays for itself within a week.
Bottom line
Reliable Claude agents in 2026 rest on two habits, repeated every time.
- A rich description on every tool and every parameter. Treat the description field as a prompt. Say when the tool should not be used, what the inputs mean and what comes back.
- Small tools that each do one thing. Five single-purpose tools beat one mega-tool with twelve optional parameters, every time. Claude chooses more accurately, the schemas stay simple and errors are easier to trace.
Parallel calls, computer use and a forced tool_choice are powerful, but they only amplify what your tool design already contains. Spend an hour on the descriptions. In the whole agent stack, no other hour pays back as much.
For the cost side of tool-heavy workloads, see our Claude API pricing breakdown.