Day 01 Foundations

What Agents Are and Why They Matter

The difference between a chatbot and an agent. The agent loop. Your first working agent in ~50 lines of Python.

~1 hour Hands-on Precision AI Academy

Today’s Objective

The difference between a chatbot and an agent. The agent loop. Your first working agent in ~50 lines of Python.

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:

Chatbots handle questions. Agents handle tasks.

Perceive → Reason → Act → Evaluate

User Task

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. Here's what that means in plain English: instead of just writing a text answer, Claude can say "I need to run a calculation — here's the math expression" and your code actually runs that calculation, then hands the result back to Claude. Claude reads the result and continues from there.

Think of it like a research analyst who can pick up the phone and call an expert, wait for the answer, and then incorporate it into their work. The analyst (Claude) decides when to call and what to ask. The expert (your tool) just answers the question. The analyst writes the final report.

This pattern — Claude decides, your code acts, Claude reads the result, repeat — is the foundation of every serious AI agent system. The architecture is simple. The leverage comes from what tools you give the agent access to.

Build your first agent

Install the SDK first:

Terminal
TERMINAL
pip install anthropic
export ANTHROPIC_API_KEY=your_key_here

Here's the complete first agent:

agent_day1.py
PYTHON
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 Python dictionary (a key-value data structure) with three fields:

In plain English: the description is the job posting, and the schema is the required fields on the application form. Write clear descriptions — they directly affect whether Claude picks the right tool.

The message loop

The code maintains a running list called messages. Every turn of the conversation gets added to this list — your original task, Claude's responses, the results of tool calls. On each API call, you send the entire list so Claude can see everything that happened so far. That's how it knows what it has already done and what still needs to happen.

How the loop knows when to stop

Every response from Claude includes a stop_reason field that says why Claude stopped generating. Two values matter here:

Why max_steps? Agents can loop forever if the task isn't solvable or a bug creates a cycle. The max_steps parameter is a safety limit — after this many steps, the loop stops regardless. Always set one. In production, you'll also want to set a token budget (a limit on how much text is processed in total). We cover that on Day 5.

Complete before Day 2

  1. Run the agent and verify it calls both tools in sequence
  2. Add a third tool: get_current_time that returns the current datetime
  3. Give the agent this task: "What time is it, and what is the square root of 1764?"
  4. Add a step_count to 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.

Supporting Resources

Go deeper with these references.

Day 1 Checkpoint

Before moving on, make sure you can answer these without looking:

Continue To Day 2
Tools — Giving Your Agent Superpowers