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