C.W.K.
Stream
Lesson 03 of 05 · published

The Tool-Calling Breakthrough

~22 min · tool-calling, function-calling, structured-output

Level 0Curious Reader
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

The breakthrough is so quiet that it is easy to miss. Around 2023, providers added a new piece to their inference APIs: when you call the model, you can hand it a list of tool definitions alongside the conversation. If the model decides a tool is needed, the response no longer mixes English and JSON. Instead, the response carries a separate, structured tool-call object — name, arguments — that the SDK exposes as a typed field.

This is a small change in shape and an enormous change in trust. The tool call is not text the model wrote; it is a decision the inference engine emitted in a place reserved for machine-readable instructions. The serializer guarantees the shape. The schema you provided guarantees the fields. The agentic loop becomes:

  1. You call the model with a user message and a tool list.
  2. The model returns either a normal text answer or a tool-call object — never both jammed into prose.
  3. If a tool was called, you execute it and feed the result back as a new message.
  4. You call the model again. It either calls another tool or finishes with text.

That is the entire loop. Every modern agent — Claude Code, Cursor, ChatGPT with browsing, your custom MCP-backed assistant — is some version of those four steps. Tool calling did not make the model smarter. It gave the model a clean, structured door to act through, and it gave you a clean, structured handle to attach your code to.

From here on the quest gets concrete: the schema you write, the loops you run, the way different providers shape their tool dialects, and how MCP scales the same idea so that a single server can be reused across every tool-calling client on earth.

Code

Tool calling, the modern shape (Anthropic)·python
# The model's tool call comes back as a structured 'tool_use' content
# block — not as text the model wrote.
import anthropic, json

client = anthropic.Anthropic()
tools = [{
    "name": "get_weather",
    "description": "Look up the current weather for a city.",
    "input_schema": {
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"],
    },
}]

resp = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "Weather in Seoul?"}],
)

for block in resp.content:
    if block.type == "tool_use":
        print(block.name, block.input)
        # 'get_weather' {'location': 'Seoul'}
The four-step agentic loop·python
# Pseudocode for the loop that powers every modern agent.
def agent_loop(user_msg, tools, executors):
    messages = [{"role": "user", "content": user_msg}]
    while True:
        resp = call_model(messages, tools=tools)
        if resp.stop_reason == "end_turn":
            return resp.text
        for tc in resp.tool_calls:
            result = executors[tc.name](**tc.args)
            messages.append({"role": "assistant", "tool_calls": [tc]})
            messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})

External links

Exercise

Pick any provider SDK and write a 30-line script that defines one tool, hands it to the model, executes the tool when called, and feeds the result back. Stop after one round-trip. The point is to feel how short the loop is now compared to the prompt-and-parse era.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.