• Getting Started
  • Core Concepts
  • Reinforcement Learning
  • Model Context Protocol (MCP)
  • Workflow Patterns
  • Advanced Agent Patterns
  • Guides

Advanced Agent Patterns

Agent Pattern Router

Dynamically route queries to specialized agents based on task requirements and agent capabilities.

Factory for creating advanced agent patterns with a unified interface. Simplifies instantiation and configuration of different reasoning patterns.

Overview

The AgentPatternRouter provides a clean, unified interface for creating any of Arc's advanced agent patterns. Instead of manually instantiating different pattern classes, you specify the pattern type and configuration, and the router handles creation.

When to Use

  • Simplified pattern creation: One interface for all patterns
  • Dynamic pattern selection: Choose pattern at runtime
  • Configuration management: Centralized pattern configuration
  • Experimentation: Easy switching between patterns
  • Production systems: Consistent pattern instantiation

Basic Usage

from azcore.agents import AgentPatternRouter
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4")

# Create a self-consistency agent
router = AgentPatternRouter(
    pattern="self-consistency",
    name="my_agent",
    llm=llm,
    prompt="You are a helpful assistant.",
    num_samples=5,  # Pattern-specific parameter
)

# Get the agent instance
agent = router.create_agent()

# Or invoke directly
state = {"messages": [{"role": "user", "content": "What is 2+2?"}]}
result = router.invoke(state)

Supported Patterns

Pattern Names and Aliases

# Self-Consistency
pattern="self-consistency"  # or "consistency"

# Reflexion
pattern="reflexion"

# Reasoning Duo
pattern="reasoning-duo"  # or "duo"

# Agent Judge
pattern="agent-judge"  # or "judge"

# Standard ReAct
pattern="react"  # default

Configuration Options

Common Parameters

All patterns accept these base parameters:

router = AgentPatternRouter(
    pattern="reflexion",           # Pattern type
    name="my_agent",               # Agent name
    llm=llm,                       # Language model (required)
    tools=[tool1, tool2],          # Optional tools
    prompt="System prompt...",     # System prompt
    description="Agent desc...",   # Agent description
)

Pattern-Specific Parameters

Self-Consistency

router = AgentPatternRouter(
    pattern="self-consistency",
    llm=llm,
    num_samples=5,                    # Number of independent generations
    majority_voting_prompt="...",     # Custom voting prompt
    eval_mode=False,                  # Enable evaluation mode
    rl_enabled=False,                 # Enable RL
    rl_manager=None,                  # RL manager instance
    reward_calculator=None,           # Reward calculator
)

Reflexion

router = AgentPatternRouter(
    pattern="reflexion",
    llm=llm,
    max_loops=3,                      # Reflection iterations
    memory_capacity=100,              # Memory system capacity
    rl_enabled=False,                 # Enable RL
    rl_manager=None,                  # RL manager instance
    reward_calculator=None,           # Reward calculator
)

Reasoning Duo

router = AgentPatternRouter(
    pattern="reasoning-duo",
    llm=llm,
    max_loops=1,                      # Reasoning iterations
    rl_enabled=False,                 # Enable RL
    rl_manager=None,                  # RL manager instance
    reward_calculator=None,           # Reward calculator
)

Agent Judge

router = AgentPatternRouter(
    pattern="agent-judge",
    llm=llm,
    evaluation_criteria=None,         # Dict[str, float] - criteria with weights
    return_score=False,               # Return score instead of text
    max_loops=1,                      # Evaluation iterations
)

ReAct (Standard)

router = AgentPatternRouter(
    pattern="react",
    llm=llm,
    tools=[tool1, tool2],             # Tools for ReAct agent
    rl_enabled=False,                 # Enable RL
    rl_manager=None,                  # RL manager instance
    reward_calculator=None,           # Reward calculator
)

Usage Patterns

Direct Invocation

# Create and invoke in one step
router = AgentPatternRouter(
    pattern="reflexion",
    llm=llm,
    max_loops=3,
)

state = {"messages": [{"role": "user", "content": "Solve this problem..."}]}
result = router.invoke(state)
print(result)

Agent Instance Creation

# Create agent instance for reuse
router = AgentPatternRouter(
    pattern="self-consistency",
    llm=llm,
    num_samples=5,
)

agent = router.create_agent()

# Use agent multiple times
result1 = agent.invoke(state1)
result2 = agent.invoke(state2)

Async Execution

# Async invocation
router = AgentPatternRouter(
    pattern="reasoning-duo",
    llm=llm,
)

result = await router.ainvoke(state)

Batch Processing

# Process multiple states
router = AgentPatternRouter(
    pattern="reflexion",
    llm=llm,
)

states = [state1, state2, state3]
results = router.run_batch(states)

Advanced Examples

Dynamic Pattern Selection

from azcore.agents import AgentPatternRouter

def create_agent_for_task(task, llm):
    """Dynamically select pattern based on task type"""

    # Analyze task
    if "math" in task.lower() or "calculate" in task.lower():
        # Math problems benefit from self-consistency
        return AgentPatternRouter(
            pattern="self-consistency",
            llm=llm,
            num_samples=5,
            prompt="Solve math problems step by step."
        ).create_agent()

    elif "code" in task.lower() or "implement" in task.lower():
        # Code tasks benefit from reflexion
        return AgentPatternRouter(
            pattern="reflexion",
            llm=llm,
            max_loops=3,
            prompt="Write clean, efficient code."
        ).create_agent()

    elif "design" in task.lower() or "strategy" in task.lower():
        # Design/strategy benefits from reasoning duo
        return AgentPatternRouter(
            pattern="reasoning-duo",
            llm=llm,
            max_loops=2,
            prompt="Develop thoughtful solutions."
        ).create_agent()

    else:
        # Default to standard ReAct
        return AgentPatternRouter(
            pattern="react",
            llm=llm,
            prompt="You are a helpful assistant."
        ).create_agent()

# Usage
agent = create_agent_for_task("Calculate the area of a circle", llm)
result = agent.invoke(state)

Configuration Management

# Define pattern configurations
PATTERN_CONFIGS = {
    "fast": {
        "pattern": "react",
        "prompt": "Quick responses",
    },
    "accurate": {
        "pattern": "self-consistency",
        "num_samples": 7,
        "prompt": "Careful, accurate responses",
    },
    "thorough": {
        "pattern": "reflexion",
        "max_loops": 5,
        "prompt": "Thorough, refined responses",
    },
    "collaborative": {
        "pattern": "reasoning-duo",
        "max_loops=3,
        "prompt": "Thoughtful, well-reasoned responses",
    }
}

def create_configured_agent(config_name, llm):
    """Create agent from predefined configuration"""
    config = PATTERN_CONFIGS[config_name]

    router = AgentPatternRouter(
        llm=llm,
        **config
    )

    return router.create_agent()

# Usage
fast_agent = create_configured_agent("fast", llm)
accurate_agent = create_configured_agent("accurate", llm)

A/B Testing Framework

import random
from collections import defaultdict

class PatternABTester:
    """Test different patterns against each other"""

    def __init__(self, llm):
        self.llm = llm
        self.patterns = {
            "A": {"pattern": "self-consistency", "num_samples": 5},
            "B": {"pattern": "reflexion", "max_loops": 3},
            "C": {"pattern": "reasoning-duo", "max_loops": 2},
        }
        self.results = defaultdict(list)

    def run_test(self, task):
        # Randomly assign pattern
        variant = random.choice(list(self.patterns.keys()))
        config = self.patterns[variant]

        # Create agent with selected pattern
        router = AgentPatternRouter(
            llm=self.llm,
            **config
        )

        # Execute and measure
        import time
        start = time.time()

        state = {"messages": [{"role": "user", "content": task}]}
        result = router.invoke(state)

        latency = time.time() - start

        # Record results
        self.results[variant].append({
            "latency": latency,
            "result": result,
        })

        return result

    def analyze(self):
        """Analyze A/B test results"""
        for variant, results in self.results.items():
            avg_latency = sum(r["latency"] for r in results) / len(results)
            print(f"\nVariant {variant}:")
            print(f"  Pattern: {self.patterns[variant]['pattern']}")
            print(f"  Samples: {len(results)}")
            print(f"  Avg Latency: {avg_latency:.2f}s")

# Usage
tester = PatternABTester(llm)

for task in test_tasks:
    tester.run_test(task)

tester.analyze()

Pattern Switching System

class AdaptiveAgentSystem:
    """System that switches patterns based on performance"""

    def __init__(self, llm):
        self.llm = llm
        self.current_pattern = "react"
        self.performance_history = []

    def run(self, task):
        # Create agent with current pattern
        router = AgentPatternRouter(
            pattern=self.current_pattern,
            llm=self.llm,
            num_samples=5 if self.current_pattern == "self-consistency" else None,
            max_loops=3 if self.current_pattern == "reflexion" else None,
        )

        state = {"messages": [{"role": "user", "content": task}]}
        result = router.invoke(state)

        # Evaluate result quality
        quality = self.evaluate_quality(result)
        self.performance_history.append(quality)

        # Adapt if performance is poor
        if len(self.performance_history) >= 10:
            avg_quality = sum(self.performance_history[-10:]) / 10

            if avg_quality < 0.7:
                # Switch to more sophisticated pattern
                self.upgrade_pattern()

        return result

    def upgrade_pattern(self):
        """Upgrade to more sophisticated pattern"""
        upgrades = {
            "react": "self-consistency",
            "self-consistency": "reflexion",
            "reflexion": "reasoning-duo",
        }

        if self.current_pattern in upgrades:
            old_pattern = self.current_pattern
            self.current_pattern = upgrades[old_pattern]
            print(f"Upgraded from {old_pattern} to {self.current_pattern}")

    def evaluate_quality(self, result):
        # Your quality evaluation logic
        return 0.85  # Placeholder

Convenience Function

Quick agent creation without router instance:

from azcore.agents.agent_pattern_router import create_agent

# One-line agent creation
agent = create_agent(
    pattern="self-consistency",
    llm=llm,
    num_samples=5,
    prompt="You are a helpful assistant.",
)

# Use immediately
state = {"messages": [{"role": "user", "content": "What is 2+2?"}]}
result = agent.invoke(state)

Introspection

Get information about current configuration:

router = AgentPatternRouter(
    pattern="reflexion",
    name="my_agent",
    llm=llm,
    max_loops=3,
)

info = router.get_pattern_info()
print(info)
# {
#     "pattern": "reflexion",
#     "name": "my_agent",
#     "llm": "ChatOpenAI(...)",
#     "tools_count": 0,
#     "description": "An intelligent agent for problem-solving.",
#     "config": {"max_loops": 3}
# }

Best Practices

1. Validate Configuration

# Check if pattern is supported
supported_patterns = [
    "self-consistency", "consistency",
    "reflexion",
    "reasoning-duo", "duo",
    "agent-judge", "judge",
    "react"
]

if my_pattern in supported_patterns:
    router = AgentPatternRouter(pattern=my_pattern, llm=llm)

2. Reuse Agent Instances

# Good: Create once, use multiple times
router = AgentPatternRouter(pattern="reflexion", llm=llm)
agent = router.create_agent()

for task in tasks:
    result = agent.invoke({"messages": [{"role": "user", "content": task}]})

# Bad: Recreate for each task
for task in tasks:
    router = AgentPatternRouter(pattern="reflexion", llm=llm)
    agent = router.create_agent()
    result = agent.invoke({"messages": [{"role": "user", "content": task}]})

3. Handle Validation Errors

try:
    router = AgentPatternRouter(
        pattern=user_selected_pattern,
        llm=llm,
    )
    agent = router.create_agent()
except ValueError as e:
    print(f"Invalid configuration: {e}")
    # Fall back to default
    router = AgentPatternRouter(pattern="react", llm=llm)
    agent = router.create_agent()

4. Document Pattern Choices

def create_production_agent(task_type, llm):
    """
    Create agent for production use.

    Pattern selection rationale:
    - Math/logic tasks: self-consistency (accuracy via voting)
    - Code tasks: reflexion (iterative improvement)
    - Design tasks: reasoning-duo (structured critique)
    - General tasks: react (fast, flexible)
    """

    pattern_map = {
        "math": "self-consistency",
        "code": "reflexion",
        "design": "reasoning-duo",
        "general": "react",
    }

    pattern = pattern_map.get(task_type, "react")

    return AgentPatternRouter(
        pattern=pattern,
        llm=llm,
    ).create_agent()

Error Handling

Common errors and solutions:

# Missing LLM
try:
    router = AgentPatternRouter(pattern="reflexion")  # No llm!
except ValueError as e:
    print("Error: LLM is required")

# Invalid pattern
try:
    router = AgentPatternRouter(pattern="invalid-pattern", llm=llm)
except ValueError as e:
    print(f"Error: {e}")
    # Use default
    router = AgentPatternRouter(pattern="react", llm=llm)

# Invalid pattern-specific config
try:
    router = AgentPatternRouter(
        pattern="self-consistency",
        llm=llm,
        num_samples=-5,  # Invalid!
    )
except Exception as e:
    print(f"Configuration error: {e}")

Performance Considerations

Pattern Overhead

Different patterns have different costs:

# Fast (1x cost)
router = AgentPatternRouter(pattern="react", llm=llm)

# Medium (5x cost)
router = AgentPatternRouter(
    pattern="self-consistency",
    llm=llm,
    num_samples=5,
)

# High (3-10x cost)
router = AgentPatternRouter(
    pattern="reflexion",
    llm=llm,
    max_loops=3,
)

# Medium (2-6x cost)
router = AgentPatternRouter(
    pattern="reasoning-duo",
    llm=llm,
    max_loops=2,
)

Lazy Instantiation

Agent is only created when needed:

# Router is lightweight
router = AgentPatternRouter(pattern="reflexion", llm=llm)

# Agent created here (heavier)
agent = router.create_agent()

# Or created implicitly on first invoke
result = router.invoke(state)  # Creates agent internally

Comparison with Direct Instantiation

# Using Router (recommended)
from azcore.agents import AgentPatternRouter

agent = AgentPatternRouter(
    pattern="reflexion",
    llm=llm,
    max_loops=3,
).create_agent()

# Direct instantiation (alternative)
from azcore.agents import ReflexionAgent

agent = ReflexionAgent(
    name="agent",
    llm=llm,
    prompt="You are a helpful assistant.",
    max_loops=3,
)

Benefits of Router:

  • Unified interface for all patterns
  • Dynamic pattern selection
  • Easier configuration management
  • Better for systems that switch patterns

Benefits of Direct:

  • More explicit
  • Better IDE autocomplete
  • Direct access to pattern-specific features
Edit this page on GitHub
AzrienLabs logo

AzrienLabs

Craftedby Team AzrienLabs