Loading lesson…
Underneath every agent framework is the same primitive — the model returns a structured tool call, you execute it, you feed the result back. Master this loop and every framework looks familiar.
All three major API providers — Anthropic, OpenAI, Google — implement tool use the same way. You send a request that includes tool definitions. The model either replies with text OR returns a 'tool_use' block with a name and arguments. Your code runs the tool and sends the result back in a 'tool_result' block. Repeat until the model returns a final text answer.
import anthropic client = anthropic.Anthropic() tools = [ { "name": "get_weather", "description": "Get current weather for a city.", "input_schema": { "type": "object", "properties": { "city": {"type": "string", "description": "City name"}, "unit": {"type": "string", "enum": ["C", "F"]} }, "required": ["city"] } } ] messages = [{"role": "user", "content": "What's the weather in Tokyo?"}] while True: resp = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, tools=tools, messages=messages, ) if resp.stop_reason == "end_turn": print(resp.content[0].text) break if resp.stop_reason == "tool_use": tool_use = next(b for b in resp.content if b.type == "tool_use") result = run_tool(tool_use.name, tool_use.input) # your code messages.append({"role": "assistant", "content": resp.content}) messages.append({ "role": "user", "content": [{ "type": "tool_result", "tool_use_id": tool_use.id, "content": str(result) }] })The agent loop, from scratch, in ~25 lines. Everything else is sugar on top.| Aspect | Anthropic | OpenAI | |
|---|---|---|---|
| Field name | tools + tool_use + tool_result | tools + function_call + tool response | tools + functionCall + functionResponse |
| Schema style | JSON Schema under input_schema. | JSON Schema under parameters. | JSON Schema under parameters. |
| Parallel calls | Yes (multiple tool_use blocks). | Yes (tool_calls array). | Yes (functionCalls array). |
| Forced tool | tool_choice: {type: 'tool', name: X}. | tool_choice: {type: 'function', function: {name: X}}. | function_calling_config: {mode: 'ANY'}. |
| Streaming tool calls | Yes, with delta events. | Yes. | Yes. |
All three providers emit multiple tool calls per turn when independent. If the model needs to look up weather in Tokyo, London, and Paris, it returns three tool_use blocks at once. You execute them in parallel and return all three tool_result blocks in the next user message. This is 3x faster than sequential.
# Parallel execution pattern import asyncio async def handle_tools(tool_uses): results = await asyncio.gather(*[ run_tool_async(t.name, t.input) for t in tool_uses ]) return [ {"type": "tool_result", "tool_use_id": t.id, "content": str(r)} for t, r in zip(tool_uses, results) ]Run parallel tool calls in parallel. Don't serialize by accident.Claude's extended thinking (Opus 4.7, Opus 4.6, Sonnet 4.6) enables interleaved thinking between tool calls. The model can reason about a tool result before deciding the next action. Anthropic recommends adaptive thinking (default 'high' effort) for any agentic workload. Pass thinking: {type: 'enabled', budget_tokens: 8000} to turn it on.
8 questions · take it digitally for instant feedback at tendril.neural-forge.io/learn/quiz/end-agentic-tool-use-api-creators
What is the main idea of "Tool Use at the API Level: The Primitive"?
Which concept is most central to "Tool Use at the API Level: The Primitive"?
Which use of AI fits this topic best?
What should a careful learner remember about "Tool-use hallucinations happen"?
You want to use AI after this lesson. What is the safest next step?
How should AI output about tool use be treated?
Name one way to verify an AI answer about tool use.
Which action would help you apply "Tool Use at the API Level: The Primitive" responsibly?