blog postFeb 19, 2026

Building AI Agents That Actually Work: 5 Architecture Patterns with Code Examples

Learn five practical AI agent architecture patterns - from simple reactive agents to sophisticated multi-agent systems. Includes Python examples and real-world use cases for each pattern.

AI-generated

Building AI Agents That Actually Work: 5 Architecture Patterns with Code Examples

AI agents are everywhere, but most implementations fall into predictable patterns. Understanding these patterns helps you choose the right architecture for your specific use case and avoid common pitfalls.

Here are five proven patterns, each with strengths, weaknesses, and practical examples.

1. Reactive Agent Pattern

The simplest pattern: respond to inputs without internal state or memory.

class ReactiveAgent:
    def __init__(self, llm_client):
        self.llm = llm_client
    
    def respond(self, user_input):
        prompt = f"User says: {user_input}\nRespond helpfully:"
        return self.llm.generate(prompt)

Best for: Chatbots, content generation, simple Q&A Pros: Fast, stateless, easy to scale Cons: No memory, can't handle complex multi-step tasks

2. State Machine Agent Pattern

Agents that move through defined states based on inputs and conditions.

class OrderAgent:
    def __init__(self):
        self.state = "greeting"
        self.order_data = {}
    
    def process(self, user_input):
        if self.state == "greeting":
            return self._handle_greeting(user_input)
        elif self.state == "taking_order":
            return self._handle_order(user_input)
        elif self.state == "confirming":
            return self._handle_confirmation(user_input)
    
    def _handle_greeting(self, input_text):
        self.state = "taking_order"
        return "What would you like to order?"
    
    def _handle_order(self, input_text):
        # Extract items from input_text
        self.order_data['items'] = self._extract_items(input_text)
        self.state = "confirming"
        return f"Got it: {self.order_data['items']}. Confirm?"

Best for: Structured workflows, customer service, form filling Pros: Predictable behavior, easy to debug Cons: Rigid, requires predefined states

3. Planning Agent Pattern

Agents that break down complex goals into actionable steps.

class PlanningAgent:
    def __init__(self, llm_client, tools):
        self.llm = llm_client
        self.tools = tools
    
    def execute_goal(self, goal):
        # Step 1: Generate plan
        plan = self._create_plan(goal)
        
        # Step 2: Execute each step
        results = []
        for step in plan:
            result = self._execute_step(step)
            results.append(result)
            
            # Re-plan if needed
            if result.get('failed'):
                plan = self._replan(goal, results)
        
        return results
    
    def _create_plan(self, goal):
        prompt = f"""
        Goal: {goal}
        Available tools: {list(self.tools.keys())}
        Create a step-by-step plan:
        """
        response = self.llm.generate(prompt)
        return self._parse_plan(response)

Best for: Research tasks, data analysis, complex automation Pros: Handles complex goals, adapts to failures Cons: Slower, can get stuck in planning loops

4. Tool-Using Agent Pattern

Agents that can call external functions and APIs to accomplish tasks.

class ToolAgent:
    def __init__(self, llm_client):
        self.llm = llm_client
        self.tools = {
            "search_web": self._search_web,
            "send_email": self._send_email,
            "get_weather": self._get_weather
        }
    
    def respond(self, user_input):
        # Decide which tool to use
        tool_choice = self._choose_tool(user_input)
        
        if tool_choice == "none":
            return self._generate_response(user_input)
        
        # Execute tool
        tool_result = self.tools[tool_choice](user_input)
        
        # Generate response using tool result
        return self._generate_response_with_context(user_input, tool_result)
    
    def _choose_tool(self, user_input):
        prompt = f"""
        User input: {user_input}
        Available tools: {list(self.tools.keys())}
        Which tool should be used? Return tool name or 'none'.
        """
        return self.llm.generate(prompt).strip()
    
    def _search_web(self, query):
        # Implementation for web search
        pass

Best for: Personal assistants, customer support, information retrieval Pros: Very capable, can interact with external systems Cons: Security concerns, tool selection can be unreliable

5. Multi-Agent System Pattern

Multiple specialized agents working together on complex tasks.

class MultiAgentSystem:
    def __init__(self):
        self.researcher = ResearchAgent()
        self.writer = WriterAgent()
        self.reviewer = ReviewAgent()
        self.coordinator = CoordinatorAgent()
    
    def create_report(self, topic):
        # Coordinator decides task flow
        plan = self.coordinator.plan_report_creation(topic)
        
        # Research phase
        research_data = self.researcher.gather_information(topic)
        
        # Writing phase
        draft = self.writer.create_draft(topic, research_data)
        
        # Review phase
        feedback = self.reviewer.review_draft(draft)
        
        # Revision if needed
        if feedback.get('needs_revision'):
            final_draft = self.writer.revise(draft, feedback)
        else:
            final_draft = draft
        
        return final_draft

class ResearchAgent:
    def gather_information(self, topic):
        # Specialized research logic
        return {"sources": [...], "key_facts": [...]}

Best for: Content creation, complex analysis, software development Pros: Specialized expertise, can handle very complex tasks Cons: Complex coordination, potential conflicts between agents

Choosing the Right Pattern

Pattern Complexity Speed Memory Best Use Case Reactive Low Fast None Simple chat, content generation State Machine Medium Fast Session Structured workflows Planning High Slow Task context Complex goal achievement Tool-Using Medium Medium Tool context Interactive assistants Multi-Agent Very High Slow System-wide Enterprise automation

Real-World Example: Customer Support Agent

Here's how you might combine patterns for a customer support system:

class CustomerSupportAgent:
    def __init__(self):
        # State machine for conversation flow
        self.conversation_state = "greeting"
        
        # Tools for external operations
        self.tools = {
            "lookup_order": OrderLookupTool(),
            "create_ticket": TicketTool(),
            "escalate": EscalationTool()
        }
        
        # Planning for complex issues
        self.planner = PlanningAgent()
    
    def handle_customer_message(self, message, customer_id):
        # Simple reactive response for greetings
        if self.conversation_state == "greeting":
            self.conversation_state = "helping"
            return "Hi! How can I help you today?"
        
        # Tool usage for specific requests
        if "order" in message.lower():
            order_info = self.tools["lookup_order"].execute(customer_id)
            return f"Here's your order status: {order_info}"
        
        # Planning for complex issues
        if "problem" in message.lower():
            resolution_plan = self.planner.create_resolution_plan(message)
            return self._execute_resolution(resolution_plan)
        
        # Default reactive response
        return self._generate_helpful_response(message)

This hybrid approach gives you the speed of reactive responses, the structure of state machines, the power of tools, and the sophistication of planning when needed.

Key Takeaways

  1. Start simple - Begin with reactive agents and add complexity only when needed
  2. Match patterns to use cases - Don't use planning agents for simple Q&A
  3. Combine patterns - Real systems often use multiple patterns together
  4. Focus on reliability - Complex agents fail in complex ways
  5. Test thoroughly - Agent behavior can be unpredictable

The goal isn't to build the most sophisticated agent possible, but to build one that reliably solves your specific problem. Choose patterns that match your requirements, not your ambitions.