What Is an AI Agent?
(Not the Hype Version)
Every week there's a new headline about "autonomous AI agents" doing something incredible — or something terrifying. The word "agent" has been stretched to mean everything from a glorified chatbot to a fully self-directed digital entity. Here's the actual definition, stripped of marketing:
An AI agent is a system that perceives its environment, decides what to do, takes action, and observes the results — and repeats this loop until the task is done.
That's it. The loop is what makes it an agent. Without the loop — without the ability to take action and then observe what happened — you just have a text generator.
What an agent is NOT:
- ✗ Just a chatbot with a long system prompt
- ✗ A thin wrapper around an LLM API call
- ✗ "Autonomous" in any science fiction sense — it operates within the tools and permissions you give it
- ✗ Something that works without human-designed constraints and guardrails
The key difference — tools:
The most important thing that separates an agent from a chatbot is the ability to use tools to affect the world and retrieve information. A chatbot receives text and returns text. An agent can:
- ✓ Search the web and read the results
- ✓ Read and write files to disk
- ✓ Call external APIs (Slack, GitHub, Stripe, your database)
- ✓ Execute code and observe the output
- ✓ Send emails, create calendar events, post messages
- ✓ Query a database and incorporate results into its reasoning
And critically — after using a tool, it observes the result and decides what to do next. That feedback loop is the engine of agent behavior.
Chatbot vs Agent vs
Simple API Call
One of the most expensive mistakes developers make is using the wrong tool for the job. Not everything needs an agent. Agents are slower and more expensive than simple LLM calls. Knowing when to reach for each approach will save you time, money, and debugging pain.
| Dimension | Simple API Call | Chatbot | Agent |
|---|---|---|---|
| Goal | Single transformation | Conversational exchange | Complete a multi-step task |
| LLM Calls | 1 | 1 per turn | N (until done) |
| Tools | None | None (usually) | Web, files, APIs, DB, etc. |
| State | Stateless | Per-conversation | Persistent across steps |
| Cost | Lowest | Low | Higher (variable) |
| Speed | Fast (<2s) | Fast (<3s) | Slower (seconds to minutes) |
| Reliability | Very high | High | Requires careful design |
| Use When | Summarize, translate, extract, classify | Q&A, customer support, copilot | Research, automation, complex workflows |
- → If a single prompt + completion solves your problem, just use the API. No loops, no tools, no overhead.
- → If you need back-and-forth conversation but no external data access, a chatbot (with a good system prompt) is the right call.
- → If the task takes more than one LLM call to complete, you need an agent.
- → If you need to fetch or write data from an external source during the task, you need an agent with tools.
- → If the task is unpredictable in length — you don't know upfront how many steps it needs — you need an agent.
Real examples:
Anatomy of an Agent
Every agent — regardless of framework, provider, or complexity — is built from four core components. Understand these and you can reason about any agent architecture you encounter or design.
Memory types — which one to use:
Everything the agent has seen and done in the current session, stored directly in the conversation. Fast to access, but limited by context window size. Best for single-session tasks up to ~50 steps. Once you hit the context limit, you need to summarize or externalize.
Store facts, documents, and previous results outside the context window. Use semantic search to retrieve only what's relevant for the current step. Best for long-running agents, knowledge bases, and agents that need to remember across sessions.
Compress previous conversations into structured summaries and inject them at the start of new sessions. Best for personal assistants and support agents that need to "remember" users across multiple separate conversations without blowing up the context window.
The Agent Loop in Python
Enough theory. Here's the core agent loop implemented with the Anthropic Python SDK. This is production-ready code you can copy, extend, and deploy. Study every line — this pattern underpins every agent in this kit.
pip install anthropic and set your API key as the environment variable ANTHROPIC_API_KEY.
import anthropic import json client = anthropic.Anthropic() # Define tools the agent can use tools = [ { "name": "search_web", "description": "Search the web for current information on a topic", "input_schema": { "type": "object", "properties": { "query": {"type": "string", "description": "The search query"} }, "required": ["query"] } }, { "name": "write_file", "description": "Write content to a file", "input_schema": { "type": "object", "properties": { "filename": {"type": "string"}, "content": {"type": "string"} }, "required": ["filename", "content"] } } ] def execute_tool(name, inputs): """Route tool calls to actual implementations""" if name == "search_web": return search_the_web(inputs["query"]) # your impl elif name == "write_file": return write_to_file(inputs["filename"], inputs["content"]) return "Tool not found" def run_agent(task: str, max_iterations: int = 10) -> str: """Core agent loop""" messages = [{"role": "user", "content": task}] for iteration in range(max_iterations): response = client.messages.create( model="claude-opus-4-6", max_tokens=4096, system="You are a helpful research agent. Use tools to complete tasks thoroughly.", tools=tools, messages=messages ) # Agent decided it's done if response.stop_reason == "end_turn": for block in response.content: if hasattr(block, 'text'): return block.text return "Task complete" # Agent wants to use tools if response.stop_reason == "tool_use": # Add assistant response to history messages.append({"role": "assistant", "content": response.content}) # Execute each tool call tool_results = [] for block in response.content: if block.type == "tool_use": print(f" → Calling tool: {block.name}({block.input})") result = execute_tool(block.name, block.input) tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": str(result) }) # Feed results back to agent messages.append({"role": "user", "content": tool_results}) return "Max iterations reached — check your task complexity" # Run it result = run_agent("Research the top 5 open-source LLMs in 2024 and write a summary to research.md") print(result)
Line-by-line breakdown — what actually matters:
The messages array is the agent's entire working memory. Every tool call and every result gets appended here. The agent's context window IS the messages array.
This is the agent saying "I'm done." It has decided not to use any more tools and is returning its final answer. Always check this first.
The agent has decided to call a tool. You must execute the tool, capture the result, and feed it back as a user message. If you don't do this, the API will return an error — it's waiting for the tool result.
Your safety net against infinite loops. Always set this. 10 is a good default for most tasks. Complex research agents may need 20-30. If an agent needs more than 50 iterations, you have an architecture problem.
Critical: When returning tool results, you must include the tool_use_id that matches the original tool call. The API uses this to correlate results with calls. Get this wrong and your agent loop will break.
Production error handling pattern:
def execute_tool(name: str, inputs: dict) -> str: """Execute a tool call with error handling.""" try: if name == "search_web": result = search_the_web(inputs["query"]) return str(result) if result else "No results found for this query" elif name == "write_file": with open(inputs["filename"], "w") as f: f.write(inputs["content"]) return f"File '{inputs['filename']}' written successfully ({len(inputs['content'])} chars)" else: return f"Unknown tool: {name}. Available tools: search_web, write_file" except FileNotFoundError as e: return f"File error: {str(e)}. Check that the directory exists." except ConnectionError as e: return f"Network error calling {name}: {str(e)}. Try again or use cached data." except Exception as e: return f"Tool {name} failed: {str(e)}"
Common Agent Architectures
Once you understand the basic agent loop, you can compose multiple agents into more powerful systems. Here are the five patterns you'll use most often, when to use each, and what each looks like structurally.
The 5 Most Common
Agent Mistakes
These are the failure modes that trip up developers at every level — from first-time agent builders to teams deploying at scale. Knowing them in advance will save you hours of debugging.
Developers see multi-agent systems in blog posts and assume that's the professional approach. It's not — it's a complexity multiplier. A well-designed single agent with good tools can handle most tasks. Multi-agent adds orchestration overhead, harder debugging, more failure points, and higher latency.
The agent keeps searching, re-reading, or re-processing without making progress toward the goal. This happens when: the task is too vague, the tools return low-quality results, or the system prompt doesn't guide toward a stopping condition.
Injecting 50K tokens of context on every LLM call. This inflates cost quadratically (you pay for input tokens on every iteration), increases latency, and often hurts quality because the model is overwhelmed with irrelevant information.
A web search returns a 503. A database query times out. A file path doesn't exist. Without error handling, the exception propagates up and the entire agent run fails — even if it was 90% done.
The agent writes a database query and you run it directly. The agent drafts an email and you send it immediately. The agent decides to delete files and your code deletes them. LLMs make mistakes, misread instructions, and can be manipulated through prompt injection in tool results.
Where to Go Next
You now have the mental model. You understand what agents are, when to use them, how the loop works, and what the common failure modes look like. The rest of the kit builds directly on this foundation.