Designing Simple Tool Interfaces › Implementing the Framework

Michael BrenndoerferJune 25, 20252 min read
AI Agent HandbookAll chapters
Part 5 of 15Tool Use - Extending the Agent's Abilities
Chapter 13Designing Simple Tool Interfaces › Implementing the Framework
Reading section 5 of 12 · Implementing the Framework · 2 minSection 5 of 12 · 2 min

Book contents

Section 5 of 12 · 2 min read

Designing Simple Tool Interfaces › Implementing the FrameworkOne section · Sections in this chapter5 / 12 ↓

Let's put this all together into a simple implementation. We'll build a basic framework that handles the entire tool use workflow:

In[6]:
Code
import os
from anthropic import Anthropic

## Using Claude Sonnet 4.5 for its superior agent reasoning and tool use capabilities
client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

## Define our tools
def get_weather(city: str) -> dict:
    """Get current weather for a city."""
    # Mock implementation
    return {
        "city": city,
        "temperature": 72,
        "conditions": "partly cloudy"
    }

## Tool descriptions for the agent
tools = [
    {
        "name": "get_weather",
        "description": "Get current weather conditions for a specified city",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "City name (e.g., 'Tokyo', 'New York')"
                }
            },
            "required": ["city"]
        }
    }
]

## Tool registry
tool_registry = {
    "get_weather": get_weather
}

def run_agent(user_message: str) -> str:
    """Run the agent with tool support."""
    messages = [{"role": "user", "content": user_message}]
    
    # Initial agent call
    response = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=1024,
        tools=tools,
        messages=messages
    )
    
    # Check if agent wants to use a tool
    if response.stop_reason == "tool_use":
        tool_use = response.content[-1]
        tool_name = tool_use.name
        tool_input = tool_use.input
        
        # Call the tool
        tool_result = tool_registry[tool_name](**tool_input)
        
        # Send result back to agent
        messages.append({"role": "assistant", "content": response.content})
        messages.append({
            "role": "user",
            "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use.id,
                "content": str(tool_result)
            }]
        })
        
        # Get final response
        final_response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=1024,
            tools=tools,
            messages=messages
        )
        
        return final_response.content[0].text
    
    # No tool needed, return direct response
    return response.content[0].text

This implementation handles the complete workflow:

  1. Sends the user's message to the agent
  2. Checks if the agent wants to use a tool
  3. If yes, calls the tool and sends the result back
  4. Gets the agent's final response incorporating the tool result

Let's see it in action:

In[7]:
Code
response = run_agent("What's the weather in Tokyo?")
print(response)
Out[7]:
Console
The current weather in Tokyo is 72°F (approximately 22°C) with partly cloudy conditions.
In Tokyo right now, it's 72°F and partly cloudy.

The agent recognized it needed weather information, called the get_weather tool with "Tokyo" as the parameter, received the result, and formulated a natural response.