AI agents built on Claude can handle complex, multi-step tasks autonomously. This guide shows you exactly how to build one that works in production.
What Makes an Agent Different from a Chatbot
A chatbot responds. An agent acts. Agents use tools (web search, code execution, API calls), maintain state across turns, and retry on failure. Claude's tool-use API makes this straightforward.
Setting Up Tool Use
import anthropic
client = anthropic.Anthropic()
tools = [
{
"name": "search_web",
"description": "Search the web for current information",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"]
}
},
{
"name": "run_python",
"description": "Execute Python code and return the output",
"input_schema": {
"type": "object",
"properties": {
"code": {"type": "string", "description": "Python code to execute"}
},
"required": ["code"]
}
}
]
The Agent Loop
def run_agent(user_message: str, max_iterations: int = 10):
messages = [{"role": "user", "content": user_message}]
for _ in range(max_iterations):
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
tools=tools,
messages=messages
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason == "end_turn":
return extract_text(response.content)
if response.stop_reason == "tool_use":
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": str(result)
})
messages.append({"role": "user", "content": tool_results})
raise RuntimeError("Agent exceeded max iterations")
Memory Management
For long-running agents, messages grow unbounded. Use a sliding window:
def trim_messages(messages: list, max_tokens: int = 8000) -> list:
if len(messages) <= 2:
return messages
recent = messages[-10:]
if messages[0] not in recent:
recent = [messages[0]] + recent
return recent
Error Handling and Retries
import time
from anthropic import RateLimitError, APIError
def resilient_api_call(messages, tools, retries=3):
for attempt in range(retries):
try:
return client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
tools=tools,
messages=messages
)
except RateLimitError:
time.sleep(2 ** attempt)
except APIError as e:
if e.status_code >= 500:
time.sleep(1)
else:
raise
raise RuntimeError("Max retries exceeded")
System Prompt for Reliability
SYSTEM_PROMPT = """You are a precise, reliable AI agent. Follow these rules:
1. Always use tools when you need current information or need to compute something
2. Break complex tasks into smaller steps
3. Verify your work before reporting results
4. If a tool fails, try an alternative approach before giving up
5. Be explicit about uncertainty -- never guess when you can verify"""
Production Checklist
Before shipping your agent to users, verify:
- Timeouts: Every tool call has a timeout. Agents hang without them.
- Max iterations: Prevent infinite loops with a hard cap.
- Input sanitization: Never pass raw user input to code execution tools.
- Logging: Log every tool call and result for debugging.
- Cost monitoring: Agent loops can burn tokens fast -- set budget alerts.
The Claude API's tool-use feature makes agents surprisingly easy to build. The hard part is designing tools that are reliable and clear enough that Claude uses them correctly.