AI Agent Architecture
Design and build autonomous AI agents that can plan, reason, and take action. Covers agent loops, tool use, memory systems, multi-agent orchestration, guardrails, and the patterns that make AI agents reliable and controllable.
AI agents are LLMs that can take actions in the real world — call APIs, write code, query databases, and interact with tools. Instead of a single prompt-response, agents operate in a loop: observe, think, act, observe the result, and repeat until the task is complete.
Agent Loop
class Agent:
def __init__(self, llm, tools, memory):
self.llm = llm
self.tools = tools
self.memory = memory
def run(self, task: str, max_steps: int = 10) -> str:
"""Main agent loop: think → act → observe → repeat."""
self.memory.add("user", task)
for step in range(max_steps):
# THINK: LLM decides what to do next
response = self.llm.generate(
messages=self.memory.get_messages(),
tools=self.tools.schemas(),
)
# CHECK: Is the agent done?
if response.is_final_answer:
return response.content
# ACT: Execute the chosen tool
tool_name = response.tool_call.name
tool_args = response.tool_call.arguments
try:
result = self.tools.execute(tool_name, tool_args)
self.memory.add("tool_result", {
"tool": tool_name,
"result": result,
})
except Exception as e:
self.memory.add("tool_error", {
"tool": tool_name,
"error": str(e),
})
return "Max steps reached without completing task"
Tool Design
# Tools are the agent's interface to the world
class ToolRegistry:
def __init__(self):
self.tools = {}
def register(self, name, func, description, parameters):
self.tools[name] = Tool(
name=name,
func=func,
description=description,
parameters=parameters,
)
def schemas(self):
"""Return tool schemas for LLM function calling."""
return [
{
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters": tool.parameters,
}
}
for tool in self.tools.values()
]
# Example tools
tools = ToolRegistry()
tools.register(
name="search_database",
func=search_db,
description="Search the customer database by name, email, or ID",
parameters={
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"field": {"type": "string", "enum": ["name", "email", "id"]},
},
"required": ["query", "field"],
}
)
tools.register(
name="send_email",
func=send_email,
description="Send an email to a customer",
parameters={
"type": "object",
"properties": {
"to": {"type": "string", "description": "Recipient email"},
"subject": {"type": "string"},
"body": {"type": "string"},
},
"required": ["to", "subject", "body"],
}
)
Memory Systems
Short-Term Memory (Context Window):
What: Current conversation and recent tool results
Duration: Single session
Limit: Context window size (128K tokens)
Long-Term Memory (Vector Store):
What: Past interactions, learned facts, preferences
Duration: Persistent across sessions
Storage: Vector database (Pinecone, pgvector)
Working Memory (Scratchpad):
What: Current plan, intermediate results, notes
Duration: Current task
Storage: Structured text in context
Guardrails
class AgentGuardrails:
def pre_action_check(self, tool_name, args):
"""Validate before executing a tool."""
# Destructive action check
if tool_name in ["delete_record", "send_email", "modify_database"]:
if not self.user_approval_received:
return GuardrailResult.REQUIRE_APPROVAL
# Rate limiting
if self.action_count > self.max_actions_per_task:
return GuardrailResult.STOP
# Cost limiting
if self.estimated_cost > self.max_cost:
return GuardrailResult.STOP
# PII check
if self.contains_pii(args):
return GuardrailResult.REDACT
return GuardrailResult.ALLOW
Anti-Patterns
| Anti-Pattern | Consequence | Fix |
|---|---|---|
| No max step limit | Agent loops forever, burns tokens | Hard limit on iterations |
| No guardrails on tools | Agent takes destructive actions | Pre-action approval for dangerous tools |
| Too many tools | Agent confused, picks wrong tool | 5-10 focused tools per agent |
| No error recovery | Single tool failure stops agent | Error handling in loop, retry logic |
| No observability | Cannot debug agent behavior | Log every thought, tool call, and result |
AI agents are powerful but unpredictable. The key to production agents is not making them smarter — it is making them safer, more observable, and more controllable.