A basic agent that runs a loop: calls Claude, receives a tool call request, executes the tool, feeds the result back, and continues until Claude has a final answer. It handles search and math. ~50 lines of Python.
Chatbot vs Agent: the actual difference
A chatbot takes a message in, returns a message out. That's the entire lifecycle. One turn, one response, done.
An agent runs a loop. It can take multiple actions, observe the results of those actions, and decide what to do next based on those observations. The loop runs until the task is complete — or until it hits a stopping condition.
This distinction matters because most real-world tasks aren't "one message in, one answer out." They require:
- Looking something up before answering
- Doing multiple calculations and combining results
- Checking whether an action succeeded before proceeding
- Making decisions based on what's been discovered so far
Chatbots handle questions. Agents handle tasks.
Perceive → Reason → Act → Evaluate
↓
PERCEIVE — receive input, gather context
↓
REASON — Claude decides what to do next
↓
ACT — call a tool, execute a function, take an action
↓
EVALUATE — observe result, decide if task is done
↓
[if not done: loop back to REASON]
↓
Final Answer to User
The key to this loop is tool calling. Instead of generating text, Claude can output a structured "tool call" — specifying a function to run and the arguments to pass. Your code executes that function and returns the result. Claude uses the result in its next reasoning step.
This is the same pattern used by every serious AI agent system — from Claude's built-in computer use to custom enterprise pipelines. The architecture is simple. The leverage comes from what tools you give the agent access to.
Build your first agent
Install the SDK first:
pip install anthropic
export ANTHROPIC_API_KEY=your_key_here
Here's the complete first agent:
import anthropic
import json
import math
client = anthropic.Anthropic()
# ── Tool definitions ──────────────────────────────
TOOLS = [
{
"name": "search",
"description": "Search for information about a topic",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"]
}
},
{
"name": "calculate",
"description": "Evaluate a mathematical expression",
"input_schema": {
"type": "object",
"properties": {
"expression": {"type": "string", "description": "Math expression to evaluate"}
},
"required": ["expression"]
}
}
]
# ── Tool implementations ───────────────────────────
def search(query: str) -> str:
# Simulated search — replace with real API in production
results = {
"population of france": "France has a population of approximately 68 million (2024).",
"gdp of germany": "Germany's GDP is approximately $4.4 trillion (2023).",
"python release date": "Python was first released in 1991 by Guido van Rossum.",
}
for key, val in results.items():
if any(word in query.lower() for word in key.split()):
return val
return f"No results found for '{query}'"
def calculate(expression: str) -> str:
try:
# Safe eval: only math operations
allowed = {'__builtins__': {}, 'math': math}
for name in dir(math):
allowed[name] = getattr(math, name)
result = eval(expression, allowed)
return str(result)
except Exception as e:
return f"Error: {e}"
def execute_tool(tool_name: str, tool_input: dict) -> str:
if tool_name == "search":
return search(tool_input["query"])
elif tool_name == "calculate":
return calculate(tool_input["expression"])
raise ValueError(f"Unknown tool: {tool_name}")
# ── The agent loop ─────────────────────────────────
def run_agent(task: str, max_steps: int = 10) -> str:
messages = [{"role": "user", "content": task}]
for step in range(max_steps):
print(f"\n--- Step {step + 1} ---")
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=TOOLS,
messages=messages
)
# If no tool calls, Claude has a final answer
if response.stop_reason == "end_turn":
final = response.content[0].text
print(f"Final answer: {final}")
return final
# Process tool calls
tool_results = []
for block in response.content:
if block.type == "tool_use":
print(f" Tool: {block.name}({block.input})")
result = execute_tool(block.name, block.input)
print(f" Result: {result}")
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
# Add assistant response + tool results to history
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
return "Max steps reached without final answer."
# ── Test it ────────────────────────────────────────
if __name__ == "__main__":
run_agent(
"What is the population of France divided by 1000? "
"Search for the population first, then calculate."
)
Run it: python agent_day1.py. You should see Step 1 call the search tool, Step 2 call calculate with the result, and Step 3 produce the final answer. That three-step sequence is the agent loop in action.
Walk through the code
Tool definitions
Each tool is a dict with a name, description, and input_schema. The schema is JSON Schema format — it tells Claude exactly what inputs a tool accepts. Claude uses the description to decide which tool to call. Write good descriptions.
The message loop
The loop maintains a messages list. Every exchange (user → Claude → tool result → Claude) gets appended. This gives Claude the full conversation history on each API call. That history is how Claude knows what it's already done and what comes next.
stop_reason
When Claude has no more tools to call, stop_reason is "end_turn" and the response contains text. When it wants to call a tool, stop_reason is "tool_use". The loop checks this to decide whether to continue or return the final answer.
Why max_steps? Agents can loop forever if the task isn't solvable or a bug creates an infinite loop. Always set a step limit. In production, you'll also want to set a token budget. We cover that on Day 5.
Complete before Day 2
- Run the agent and verify it calls both tools in sequence
- Add a third tool:
get_current_timethat returns the current datetime - Give the agent this task: "What time is it, and what is the square root of 1764?"
- Add a
step_countto the print output so you can see the loop clearly
Tomorrow: Tools. You'll build 5 real tools (web search, file reading, API calls, database queries) and give the agent the ability to solve complex multi-step problems.