Building Agents

Tools and Function Calling

Build and integrate tools that agents can use to interact with the world.

Tools Give Agents Superpowers

Tools extend what an agent can do beyond text generation:

  • Web search: Find current information
  • Code execution: Run Python, JavaScript
  • Database queries: Read/write structured data
  • API calls: Interact with external services
  • File operations: Read, write, process files

Tool Design Principles

  • Clear descriptions: The LLM uses your description to decide when to call a tool
  • Specific schemas: Well-typed inputs reduce errors
  • Return useful output: Return enough context for the LLM to continue
  • Handle errors gracefully: Return error messages, not exceptions

Tool Schema Format

Different providers use slightly different formats, but the pattern is the same:

  • Name and description
  • Input schema (JSON Schema)
  • Required vs optional parameters

Example

python
import requests
from anthropic import Anthropic
import json
from typing import Any

client = Anthropic()

# Real-world tool: web search simulation
def search_web(query: str, max_results: int = 3) -> list[dict]:
    """Simulate web search (replace with real API like Serper, Tavily, etc.)"""
    return [
        {"title": f"Result for: {query}", "url": "https://example.com", "snippet": f"Information about {query}..."},
    ]

# Real-world tool: execute Python code
def execute_python(code: str) -> str:
    """Execute Python code in a sandbox (use restricted exec in production)"""
    import io
    import sys
    stdout_capture = io.StringIO()
    sys.stdout = stdout_capture
    try:
        exec(code, {"__builtins__": {"print": print, "range": range, "len": len}})
        output = stdout_capture.getvalue()
        return output or "Code executed successfully (no output)"
    except Exception as e:
        return f"Error: {e}"
    finally:
        sys.stdout = sys.__stdout__

# Real-world tool: fetch URL content
def fetch_url(url: str) -> str:
    """Fetch content from a URL"""
    try:
        response = requests.get(url, timeout=10)
        return response.text[:2000]  # truncate for context window
    except Exception as e:
        return f"Error fetching URL: {e}"

tools = [
    {
        "name": "search_web",
        "description": "Search the web for current information",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Search query"},
                "max_results": {"type": "integer", "description": "Maximum results (1-10)", "default": 3}
            },
            "required": ["query"]
        }
    },
    {
        "name": "execute_python",
        "description": "Execute Python code and return output",
        "input_schema": {
            "type": "object",
            "properties": {
                "code": {"type": "string", "description": "Python code to execute"}
            },
            "required": ["code"]
        }
    },
]

def dispatch_tool(name: str, inputs: dict) -> Any:
    match name:
        case "search_web":
            return json.dumps(search_web(**inputs))
        case "execute_python":
            return execute_python(**inputs)
        case _:
            return f"Unknown tool: {name}"

def agent(task: str):
    messages = [{"role": "user", "content": task}]

    while True:
        response = client.messages.create(
            model="claude-3-5-haiku-20241022",
            max_tokens=2048,
            tools=tools,
            messages=messages
        )

        messages.append({"role": "assistant", "content": response.content})

        if response.stop_reason == "end_turn":
            return next(b.text for b in response.content if hasattr(b, "text"))

        results = [
            {"type": "tool_result", "tool_use_id": b.id, "content": dispatch_tool(b.name, b.input)}
            for b in response.content if b.type == "tool_use"
        ]
        messages.append({"role": "user", "content": results})

print(agent("Write and execute Python code to generate the first 10 Fibonacci numbers"))
Try it yourself — PYTHON