Overview of Agent Types

Different agent architectures excel at different tasks. Understanding each type's strengths and weaknesses is crucial for building effective AI systems. This guide covers the major agent patterns and when to use each one.

πŸ”„
ReAct Agent
Reasoning + Acting in Synergy

ReAct agents interleave reasoning and action-taking, creating a dynamic problem-solving approach. They think about what to do, take action, observe results, and adjust their approach based on feedback.

How ReAct Works

Thought
β†’
Action
β†’
Observation
β†’
Thought
β†’
...
# ReAct Agent Implementation
class ReActAgent:
    def solve(self, question):
        max_iterations = 5
        
        for i in range(max_iterations):
            # Thought: Reason about what to do
            thought = self.think(question, self.history)
            print(f"Thought {i+1}: {thought}")
            
            # Action: Decide and execute action
            action = self.decide_action(thought)
            print(f"Action {i+1}: {action}")
            
            # Observation: Get results
            observation = self.execute_action(action)
            print(f"Observation {i+1}: {observation}")
            
            # Check if task is complete
            if self.is_complete(observation):
                return self.format_answer(observation)
            
            # Update history for next iteration
            self.history.append({
                "thought": thought,
                "action": action,
                "observation": observation
            })
        
        return "Max iterations reached"

# Example execution:
"""
Question: What is the population of Tokyo's largest district?

Thought 1: I need to find information about Tokyo's districts
Action 1: search("Tokyo largest district by area")
Observation 1: Ōta is Tokyo's largest district by area (60.83 km²)

Thought 2: Now I need to find the population of Ōta district
Action 2: search("Ōta district Tokyo population")
Observation 2: Ōta has a population of approximately 734,000 (2023)

Thought 3: I have the answer - Ōta district has 734,000 people
Action 3: return_answer("734,000")
"""
                

βœ… Strengths

  • Transparent reasoning process
  • Self-correcting through observations
  • Excellent for multi-step problems
  • Can recover from errors

❌ Limitations

  • Can be verbose and slow
  • May get stuck in loops
  • Requires careful prompt engineering
  • Higher token consumption
Best Use Cases: Research tasks, debugging, complex problem-solving, tasks requiring external tool use, situations where transparency is important.
🧠
Chain of Thought (CoT) Agent
Step-by-Step Reasoning

Chain of Thought agents break down complex problems into a series of intermediate reasoning steps, making their thought process explicit and verifiable. They excel at mathematical problems, logical reasoning, and analytical tasks.

# Chain of Thought Agent
class CoTAgent:
    def __init__(self, model):
        self.model = model
        self.cot_prompt = """
        Let's approach this step-by-step:
        1. First, identify what we're asked to find
        2. Break down the problem into components
        3. Solve each component
        4. Combine results for the final answer
        """
    
    def solve_with_cot(self, problem):
        prompt = f"""
        Problem: {problem}
        
        {self.cot_prompt}
        
        Step-by-step solution:
        """
        
        response = self.model.generate(prompt)
        return response

# Example: Math Word Problem
"""
Problem: A bakery sells cupcakes for $3 each and cookies for $2 each. 
Sarah buys 5 cupcakes and 8 cookies. If she pays with a $50 bill, 
how much change does she get?

Step-by-step solution:
1. Calculate cost of cupcakes: 5 Γ— $3 = $15
2. Calculate cost of cookies: 8 Γ— $2 = $16
3. Calculate total cost: $15 + $16 = $31
4. Calculate change: $50 - $31 = $19

Answer: Sarah gets $19 in change.
"""

# Zero-Shot CoT
zero_shot_prompt = "Let's think step by step."

# Few-Shot CoT with examples
few_shot_prompt = """
Example 1: [Problem] β†’ [Step-by-step solution]
Example 2: [Problem] β†’ [Step-by-step solution]
Now solve: [New Problem]
"""
                

βœ… Strengths

  • Improves accuracy on complex tasks
  • Interpretable reasoning process
  • Works well with few-shot learning
  • Reduces errors in multi-step problems

❌ Limitations

  • Increased token usage
  • May overthink simple problems
  • Can introduce unnecessary steps
  • Not ideal for creative tasks
Best Use Cases: Mathematical problems, logical puzzles, code generation, analytical reasoning, educational applications where showing work is important.
πŸ”§
Tool-Use Agent
Extending Capabilities with External Tools

Tool-Use agents can interact with external tools, APIs, and functions to extend their capabilities beyond text generation. They decide when and how to use tools to accomplish tasks.

# Tool-Use Agent Implementation
from typing import Dict, List, Any
import json

class ToolUseAgent:
    def __init__(self, llm, tools: Dict[str, callable]):
        self.llm = llm
        self.tools = tools
        self.tool_descriptions = self._generate_tool_descriptions()
    
    def _generate_tool_descriptions(self):
        descriptions = []
        for name, func in self.tools.items():
            descriptions.append({
                "name": name,
                "description": func.__doc__,
                "parameters": self._extract_parameters(func)
            })
        return descriptions
    
    def process(self, user_input: str):
        # Step 1: Determine if tools are needed
        system_prompt = f"""
        You have access to these tools:
        {json.dumps(self.tool_descriptions, indent=2)}
        
        For the user's request, determine:
        1. Which tool(s) to use
        2. What parameters to pass
        3. In what order to use them
        
        Respond in JSON format:
        {{"tools": [{{"name": "tool_name", "params": {{...}}}}]}}
        """
        
        plan = self.llm.generate(system_prompt, user_input)
        tool_calls = json.loads(plan)["tools"]
        
        # Step 2: Execute tools
        results = []
        for call in tool_calls:
            tool_name = call["name"]
            params = call["params"]
            
            if tool_name in self.tools:
                result = self.tools[tool_name](**params)
                results.append({
                    "tool": tool_name,
                    "result": result
                })
        
        # Step 3: Synthesize final response
        final_prompt = f"""
        User request: {user_input}
        Tool results: {json.dumps(results, indent=2)}
        
        Provide a comprehensive response based on the tool results.
        """
        
        return self.llm.generate(final_prompt)

# Example tools
def web_search(query: str) -> str:
    """Search the web for information"""
    # Implementation
    return f"Search results for: {query}"

def calculator(expression: str) -> float:
    """Evaluate mathematical expressions"""
    return eval(expression)  # Note: Use safe eval in production

def send_email(to: str, subject: str, body: str) -> bool:
    """Send an email"""
    # Implementation
    return True

# Usage
agent = ToolUseAgent(
    llm=language_model,
    tools={
        "web_search": web_search,
        "calculator": calculator,
        "send_email": send_email
    }
)

response = agent.process("Find the latest Tesla stock price and calculate 15% of it")
                

βœ… Strengths

  • Extends beyond text capabilities
  • Can access real-time information
  • Performs actual actions
  • Highly versatile and practical

❌ Limitations

  • Requires tool integration
  • Error handling complexity
  • Security considerations
  • Tool selection mistakes
🌳
Tree of Thoughts (ToT) Agent
Exploring Multiple Reasoning Paths

Tree of Thoughts agents explore multiple reasoning paths simultaneously, evaluating different approaches before committing to the best solution. They maintain a search tree of partial solutions.

# Tree of Thoughts Implementation
class TreeOfThoughts:
    def __init__(self, llm, max_depth=3, beam_width=3):
        self.llm = llm
        self.max_depth = max_depth
        self.beam_width = beam_width
    
    def solve(self, problem):
        # Initialize root node
        root = {"state": problem, "value": 0, "children": []}
        
        # Build tree
        self._expand_node(root, depth=0)
        
        # Find best path
        best_path = self._find_best_path(root)
        return best_path
    
    def _expand_node(self, node, depth):
        if depth >= self.max_depth:
            return
        
        # Generate multiple next steps
        prompt = f"""
        Current state: {node['state']}
        Generate {self.beam_width} different approaches to proceed.
        """
        
        approaches = self.llm.generate(prompt)
        
        # Evaluate each approach
        for approach in approaches:
            child = {
                "state": approach,
                "value": self._evaluate(approach),
                "children": []
            }
            node["children"].append(child)
            
            # Recursively expand promising nodes
            if child["value"] > threshold:
                self._expand_node(child, depth + 1)
    
    def _evaluate(self, state):
        """Evaluate the promise of a partial solution"""
        prompt = f"""
        Evaluate this approach on a scale of 0-10:
        {state}
        Consider: correctness, efficiency, completeness
        """
        score = self.llm.generate(prompt)
        return float(score)
    
    def _find_best_path(self, root):
        """DFS to find the highest-scoring complete path"""
        # Implementation of path finding
        pass

# Example: Creative Writing with ToT
"""
Problem: Write an engaging opening for a mystery novel

Branch 1: Start with dialogue
  β†’ "The body's been here for three days," the detective said.
  β†’ Score: 7/10

Branch 2: Start with setting description
  β†’ The lighthouse stood abandoned on the cliff...
  β†’ Score: 6/10

Branch 3: Start with action
  β†’ Sarah ran through the rain-soaked streets...
  β†’ Score: 8/10
  
Selected: Branch 3, then continue exploring...
"""
                
Implementation Tip: ToT is computationally expensive. Use it for high-value problems where exploring multiple solutions is worth the cost. Consider caching evaluations and pruning unpromising branches early.
🎯
Plan-and-Execute Agent
Strategic Planning Before Action

Plan-and-Execute agents first create a comprehensive plan, then systematically execute each step. They separate the planning phase from execution, allowing for more strategic approaches.

# Plan-and-Execute Agent
class PlanAndExecuteAgent:
    def __init__(self, planner_llm, executor_llm, tools):
        self.planner = planner_llm
        self.executor = executor_llm
        self.tools = tools
    
    def solve(self, objective):
        # Phase 1: Planning
        plan = self.create_plan(objective)
        print("Generated Plan:")
        for i, step in enumerate(plan, 1):
            print(f"  {i}. {step}")
        
        # Phase 2: Execution
        results = []
        for step in plan:
            result = self.execute_step(step, results)
            results.append(result)
            
            # Re-plan if needed
            if self.should_replan(result):
                remaining_objective = self.get_remaining_objective(
                    objective, results
                )
                plan = self.create_plan(remaining_objective)
        
        return self.synthesize_results(results)
    
    def create_plan(self, objective):
        prompt = f"""
        Objective: {objective}
        
        Create a detailed step-by-step plan to achieve this objective.
        Each step should be specific and actionable.
        Output as a JSON list of steps.
        """
        
        plan_json = self.planner.generate(prompt)
        return json.loads(plan_json)
    
    def execute_step(self, step, previous_results):
        prompt = f"""
        Execute this step: {step}
        Previous results: {previous_results}
        Available tools: {list(self.tools.keys())}
        """
        
        return self.executor.generate(prompt)

# Example execution:
"""
Objective: Create a market analysis report for electric vehicles

Generated Plan:
1. Research current EV market size and growth rate
2. Identify top 5 EV manufacturers and their market share
3. Analyze consumer sentiment and adoption barriers
4. Research government policies and incentives
5. Project future trends for next 5 years
6. Compile findings into structured report

Executing step 1: Research current EV market size...
Executing step 2: Identify top manufacturers...
[continues...]
"""
                
πŸ”„
Reflexion Agent
Learning from Mistakes

Reflexion agents can reflect on their failures, learn from mistakes, and improve their performance over successive attempts. They maintain a memory of past attempts and reflections.

# Reflexion Agent Implementation
class ReflexionAgent:
    def __init__(self, llm, evaluator):
        self.llm = llm
        self.evaluator = evaluator
        self.memory = []
        self.max_iterations = 3
    
    def solve(self, task):
        for iteration in range(self.max_iterations):
            # Generate solution
            solution = self.generate_solution(task)
            
            # Evaluate solution
            evaluation = self.evaluator.evaluate(solution, task)
            
            if evaluation["success"]:
                return solution
            
            # Reflect on failure
            reflection = self.reflect(task, solution, evaluation)
            
            # Store in memory
            self.memory.append({
                "attempt": iteration + 1,
                "solution": solution,
                "evaluation": evaluation,
                "reflection": reflection
            })
        
        return self.best_attempt()
    
    def generate_solution(self, task):
        prompt = f"""
        Task: {task}
        
        Previous attempts and reflections:
        {self.format_memory()}
        
        Generate an improved solution based on past learnings.
        """
        
        return self.llm.generate(prompt)
    
    def reflect(self, task, solution, evaluation):
        prompt = f"""
        Task: {task}
        Attempted solution: {solution}
        Evaluation: {evaluation}
        
        Reflect on what went wrong and how to improve:
        1. What specific errors were made?
        2. What assumptions were incorrect?
        3. What approach should be tried next?
        """
        
        return self.llm.generate(prompt)

# Example: Code debugging with Reflexion
"""
Iteration 1:
Solution: def factorial(n): return n * factorial(n-1)
Evaluation: Failed - No base case, infinite recursion
Reflection: Need to add base case for n=0 or n=1

Iteration 2:
Solution: def factorial(n): 
    if n == 0: return 1
    return n * factorial(n-1)
Evaluation: Success - Correctly handles all test cases
"""
                

Hybrid Agent Architectures

Modern AI systems often combine multiple agent patterns for optimal performance. Here are common hybrid approaches:

ReAct + Chain of Thought

Combines structured reasoning with action-taking for complex problem-solving.

# Hybrid ReAct-CoT Agent
class ReActCoTAgent:
    def process(self, query):
        # Use CoT for initial reasoning
        thought_chain = self.chain_of_thought(query)
        
        # Use ReAct for execution
        for thought in thought_chain:
            action = self.determine_action(thought)
            observation = self.execute(action)
            
            # Refine reasoning based on observation
            thought = self.refine_thought(thought, observation)
        
        return self.synthesize_answer()
                    

Plan-and-Execute + Tool-Use

Creates strategic plans that involve tool usage for information gathering and action execution.

Tree of Thoughts + Reflexion

Explores multiple paths while learning from failed branches to improve future explorations.

Agent Type Selection Guide

Agent Type Best For Avoid When Complexity Cost
ReAct Multi-step tasks, Research Simple queries Medium High
Chain of Thought Math, Logic puzzles Creative tasks Low Medium
Tool-Use Real-world actions Pure reasoning High Variable
Tree of Thoughts Complex planning Time-sensitive tasks Very High Very High
Plan-and-Execute Project management Dynamic environments Medium Medium
Reflexion Iterative improvement One-shot tasks Medium High

Implementation Best Practices

Key Recommendations:
  • Start simple with CoT or basic Tool-Use agents
  • Add complexity only when needed for your use case
  • Monitor token usage and costs carefully
  • Implement proper error handling and fallbacks
  • Use caching to avoid redundant LLM calls
  • Test with smaller models before scaling up
  • Consider hybrid approaches for complex problems