Agentic Architecture Pattern: Feedback Loop

Written by

in


    """
Pattern 211: Feedback Loop Pattern

Implements continuous improvement through iterative feedback cycles.
Features feedback collection, analysis, and action application.
"""

from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI


class FeedbackType(Enum):
    """Types of feedback."""
    POSITIVE = "positive"
    NEGATIVE = "negative"
    NEUTRAL = "neutral"
    SUGGESTION = "suggestion"


@dataclass
class Feedback:
    """Represents feedback from evaluation."""
    feedback_id: str
    content: str
    feedback_type: FeedbackType
    score: float  # -1.0 to 1.0
    source: str
    iteration: int
    timestamp: datetime = field(default_factory=datetime.now)


@dataclass
class Iteration:
    """Represents one iteration in the feedback loop."""
    iteration_number: int
    input_data: Any
    output: Any
    feedbacks: List[Feedback] = field(default_factory=list)
    improvements_applied: List[str] = field(default_factory=list)
    quality_score: float = 0.0
    timestamp: datetime = field(default_factory=datetime.now)


class FeedbackCollector:
    """Collects and analyzes feedback."""
    
    def __init__(self, llm: ChatOpenAI):
        self.llm = llm
        self.all_feedback: List[Feedback] = []
    
    def collect_feedback(self, output: Any, iteration: int) -> List[Feedback]:
        """Collect feedback on output using LLM."""
        prompt = ChatPromptTemplate.from_messages([
            ("system", "You are a critic providing constructive feedback. "
                      "Analyze the output and provide specific, actionable feedback."),
            ("human", """Output to evaluate:
{output}

Provide feedback in the following format:
1. List 2-3 specific strengths
2. List 2-3 specific areas for improvement  
3. Overall quality score (0.0 to 1.0)

Be specific and actionable.""")
        ])
        
        chain = prompt | self.llm
        response = chain.invoke({"output": str(output)})
        
        # Parse feedback (simplified)
        feedback_items = []
        
        # Positive feedback
        feedback_items.append(Feedback(
            feedback_id=f"fb_{iteration}_pos",
            content=f"Positive aspects from iteration {iteration}",
            feedback_type=FeedbackType.POSITIVE,
            score=0.7,
            source="llm_critic",
            iteration=iteration
        ))
        
        # Improvement suggestions
        feedback_items.append(Feedback(
            feedback_id=f"fb_{iteration}_improve",
            content=response.content,
            feedback_type=FeedbackType.SUGGESTION,
            score=0.0,
            source="llm_critic",
            iteration=iteration
        ))
        
        self.all_feedback.extend(feedback_items)
        return feedback_items


class FeedbackLoopAgent:
    """Agent that improves through feedback loops."""
    
    def __init__(self, name: str, model_name: str = "gpt-4"):
        self.name = name
        self.llm = ChatOpenAI(model=model_name, temperature=0.7)
        self.feedback_collector = FeedbackCollector(self.llm)
        self.iterations: List[Iteration] = []
        self.current_best_output: Optional[Any] = None
        self.best_score: float = 0.0
    
    def execute_with_feedback(self, task: str, max_iterations: int = 3) -> Dict[str, Any]:
        """Execute task with iterative feedback and improvement."""
        print(f"\n   {self.name}: Starting feedback loop for task")
        print(f"   Max iterations: {max_iterations}")
        
        current_input = task
        
        for iteration_num in range(1, max_iterations + 1):
            print(f"\n   === Iteration {iteration_num}/{max_iterations} ===")
            
            # Generate output
            output = self._generate_output(current_input, iteration_num)
            print(f"   Output generated: {str(output)[:80]}...")
            
            # Collect feedback
            feedbacks = self.feedback_collector.collect_feedback(output, iteration_num)
            print(f"   Collected {len(feedbacks)} feedback items")
            
            # Calculate quality score
            quality_score = self._calculate_quality(feedbacks)
            print(f"   Quality score: {quality_score:.3f}")
            
            # Record iteration
            improvements = self._identify_improvements(feedbacks)
            iteration = Iteration(
                iteration_number=iteration_num,
                input_data=current_input,
                output=output,
                feedbacks=feedbacks,
                improvements_applied=improvements,
                quality_score=quality_score
            )
            self.iterations.append(iteration)
            
            # Update best output
            if quality_score > self.best_score:
                self.best_score = quality_score
                self.current_best_output = output
                print(f"   ✓ New best output!")
            
            # Check convergence
            if quality_score >= 0.9:
                print(f"   ✓ Quality threshold reached!")
                break
            
            # Apply improvements for next iteration
            if iteration_num  str:
        """Generate output for current iteration."""
        context = ""
        if iteration > 1:
            prev_feedback = self.iterations[-1].feedbacks
            context = f"\nPrevious feedback: {prev_feedback[0].content[:200] if prev_feedback else 'None'}"
        
        prompt = ChatPromptTemplate.from_messages([
            ("system", f"You are {self.name}. Generate high-quality output. "
                      f"This is iteration {iteration}. Apply previous feedback if available."),
            ("human", "Task: {task}{context}\n\nGenerate output:")
        ])
        
        chain = prompt | self.llm
        response = chain.invoke({"task": str(input_data), "context": context})
        return response.content
    
    def _calculate_quality(self, feedbacks: List[Feedback]) -> float:
        """Calculate overall quality score from feedback."""
        if not feedbacks:
            return 0.5
        
        # Simple average of feedback scores (normalized to 0-1)
        positive_count = sum(1 for f in feedbacks if f.feedback_type == FeedbackType.POSITIVE)
        total = len(feedbacks)
        return min(1.0, 0.3 + (positive_count / total) * 0.7)
    
    def _identify_improvements(self, feedbacks: List[Feedback]) -> List[str]:
        """Identify improvements from feedback."""
        improvements = []
        for feedback in feedbacks:
            if feedback.feedback_type in [FeedbackType.NEGATIVE, FeedbackType.SUGGESTION]:
                improvements.append(f"Address: {feedback.content[:50]}...")
        return improvements
    
    def _apply_improvements(self, original_task: str, feedbacks: List[Feedback], 
                           previous_output: Any) -> str:
        """Apply improvements for next iteration."""
        suggestions = [f.content for f in feedbacks 
                      if f.feedback_type == FeedbackType.SUGGESTION]
        
        improved_task = f"{original_task}\n\nPrevious attempt had these issues:\n"
        improved_task += "\n".join(suggestions[:2])  # Top 2 suggestions
        
        return improved_task


class FeedbackLoopPattern:
    """
    Feedback Loop Pattern - Continuous improvement through feedback.
    
    Implements iterative refinement where agents improve their outputs
    based on collected feedback.
    """
    
    def __init__(self):
        self.agents: Dict[str, FeedbackLoopAgent] = {}
    
    def register_agent(self, agent: FeedbackLoopAgent):
        """Register feedback loop agent."""
        self.agents[agent.name] = agent
    
    def run(self, tasks: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Execute feedback loop on tasks."""
        print("=== Feedback Loop Pattern Demo ===\n")
        
        results = []
        for task_info in tasks:
            print(f"\nTask: {task_info.get('description', 'Unknown')}")
            
            agent_name = task_info.get("agent")
            if agent_name not in self.agents:
                continue
            
            agent = self.agents[agent_name]
            task = task_info.get("task")
            max_iterations = task_info.get("max_iterations", 3)
            
            result = agent.execute_with_feedback(task, max_iterations)
            results.append(result)
        
        # Statistics
        total_iterations = sum(r["total_iterations"] for r in results)
        avg_score = sum(r["best_score"] for r in results) / len(results) if results else 0
        
        return {
            "pattern": "FeedbackLoop",
            "total_agents": len(self.agents),
            "tasks_completed": len(results),
            "total_iterations": total_iterations,
            "average_best_score": avg_score
        }


# Example usage
if __name__ == "__main__":
    print("=== Feedback Loop Pattern Demo ===\n")
    
    # Create pattern
    pattern = FeedbackLoopPattern()
    
    # Create agent
    print("1. Creating feedback loop agent...")
    agent = FeedbackLoopAgent("WriterAgent")
    pattern.register_agent(agent)
    
    # Define tasks
    print("\n2. Defining tasks for iterative improvement...")
    
    tasks = [
        {
            "description": "Write product description",
            "agent": "WriterAgent",
            "task": "Write a compelling product description for a smart watch",
            "max_iterations": 3
        },
        {
            "description": "Create email subject line",
            "agent": "WriterAgent",
            "task": "Create an engaging email subject line for a summer sale",
            "max_iterations": 2
        }
    ]
    
    # Execute
    print("\n3. Executing with feedback loops...")
    summary = pattern.run(tasks)
    
    print(f"\n4. Summary:")
    print(f"   Tasks Completed: {summary['tasks_completed']}")
    print(f"   Total Iterations: {summary['total_iterations']}")
    print(f"   Average Best Score: {summary['average_best_score']:.3f}")
    
    print("\n5. Iteration History:")
    for i, iteration in enumerate(agent.iterations, 1):
        print(f"   Iteration {iteration.iteration_number}:")
        print(f"     Quality: {iteration.quality_score:.3f}")
        print(f"     Improvements: {len(iteration.improvements_applied)}")
        print(f"     Feedback items: {len(iteration.feedbacks)}")
    
    print(f"\n6. Best Output:")
    if agent.current_best_output:
        print(f"   {str(agent.current_best_output)[:200]}...")
        print(f"   Score: {agent.best_score:.3f}")
    
    print("\n✓ Feedback loop enabled continuous improvement!")

    

Agentic Architecture Pattern: Feedback Loop

Pattern 211: 211 Feedback Loop – Line-by-Line Explanation

Overview

Pattern 211: Feedback Loop Pattern

Implements continuous improvement through iterative feedback cycles. Features feedback collection, analysis, and action application.


Code Structure Analysis

File Information

  • Pattern Number: 211
  • Pattern Name: 211 Feedback Loop
  • File Path: patterns\feedback_improvement\211_feedback_loop.py
  • Total Lines: 314

Detailed Code Explanation

Module Docstring

"""
Pattern 211: Feedback Loop Pattern

Implements continuous improvement through iterative feedback cycles.
Features feedback collection, analysis, and action application.
"""

Explanation: This module docstring describes the purpose and key features of the 211 Feedback Loop pattern.


Imports Section

from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI  # First 20 imports shown

Explanation: The module imports necessary dependencies: – from typing import Dict, Any, List, Optional, Callable: Type hints for better code documentation – from dataclasses import dataclass, field: Data class decorators for clean data structures – from datetime import datetime: Date and time utilities – from enum import Enum: Enumeration support for fixed sets of values – from langchain_core.prompts import ChatPromptTemplate: LangChain framework integration – from langchain_openai import ChatOpenAI: LangChain framework integration


Enumerations

FeedbackType (Line 16)

class FeedbackType(Enum):
    POSITIVE
    NEGATIVE
    NEUTRAL
    SUGGESTION

Purpose: Types of feedback.

Values: – POSITIVE: Represents positive – NEGATIVE: Represents negative – NEUTRAL: Represents neutral – SUGGESTION: Represents suggestion


Classes

FeedbackType (Line 16)

Description: Types of feedback.

Feedback (Line 25)

Description: Represents feedback from evaluation.

Iteration (Line 37)

Description: Represents one iteration in the feedback loop.

FeedbackCollector (Line 48)

Description: Collects and analyzes feedback.

Methods:

__init__ (Line 51)
def __init__(self, llm):
    """No method docstring."""

Purpose: No method docstring.

Parameters: – self: Instance reference – llm: Parameter for llm

collect_feedback (Line 55)
def collect_feedback(self, output, iteration):
    """Collect feedback on output using LLM."""

Purpose: Collect feedback on output using LLM.

Parameters: – self: Instance reference – output: Parameter for output – iteration: Parameter for iteration

FeedbackLoopAgent (Line 101)

Description: Agent that improves through feedback loops.

Methods:

__init__ (Line 104)
def __init__(self, name, model_name):
    """No method docstring."""

Purpose: No method docstring.

Parameters: – self: Instance reference – name: Identifier or label – model_name: LLM model to use (e.g., “gpt-4”)

execute_with_feedback (Line 112)
def execute_with_feedback(self, task, max_iterations):
    """Execute task with iterative feedback and improvement."""

Purpose: Execute task with iterative feedback and improvement.

Parameters: – self: Instance reference – task: Parameter for task – max_iterations: Parameter for max_iterations

_generate_output (Line 168)
def _generate_output(self, input_data, iteration):
    """Generate output for current iteration."""

Purpose: Generate output for current iteration.

Parameters: – self: Instance reference – input_data: Parameter for input_data – iteration: Parameter for iteration

_calculate_quality (Line 185)
def _calculate_quality(self, feedbacks):
    """Calculate overall quality score from feedback."""

Purpose: Calculate overall quality score from feedback.

Parameters: – self: Instance reference – feedbacks: Parameter for feedbacks

_identify_improvements (Line 195)
def _identify_improvements(self, feedbacks):
    """Identify improvements from feedback."""

Purpose: Identify improvements from feedback.

Parameters: – self: Instance reference – feedbacks: Parameter for feedbacks

_apply_improvements (Line 203)
def _apply_improvements(self, original_task, feedbacks, previous_output):
    """Apply improvements for next iteration."""

Purpose: Apply improvements for next iteration.

Parameters: – self: Instance reference – original_task: Parameter for original_task – feedbacks: Parameter for feedbacks – previous_output: Parameter for previous_output

FeedbackLoopPattern (Line 215)

Description: Feedback Loop Pattern – Continuous improvement through feedback.

Implements iterative refinement where agents improve their outputs based on collected feedback.

Methods:

__init__ (Line 223)
def __init__(self):
    """No method docstring."""

Purpose: No method docstring.

Parameters: – self: Instance reference

register_agent (Line 226)
def register_agent(self, agent):
    """Register feedback loop agent."""

Purpose: Register feedback loop agent.

Parameters: – self: Instance reference – agent: Parameter for agent

run (Line 230)
def run(self, tasks):
    """Execute feedback loop on tasks."""

Purpose: Execute feedback loop on tasks.

Parameters: – self: Instance reference – tasks: Parameter for tasks


Design Patterns Used

  • Strategy Pattern: Different execution strategies for various scenarios
  • State Pattern: Managing different states in the workflow
  • Chain of Responsibility: Sequential processing through workflow nodes
  • Observer Pattern: Tracking and monitoring pattern execution
  • Factory Pattern: Creating instances with proper configuration

Usage Example

# Initialize the pattern
pattern = FeedbackType(name="example", model_name="gpt-4")

# Configure and execute
result = pattern.execute(data={"key": "value"})

# Check results
print(result)

Key Concepts

  • LLM Integration: Uses LangChain/OpenAI for intelligent decision-making
  • Workflow Orchestration: LangGraph manages execution flow through nodes
  • State Management: TypedDict defines workflow state structure
  • Error Handling: Comprehensive error handling and fallback mechanisms
  • Extensibility: Designed for easy customization and extension

Extension Points

This pattern can be extended by: 1. Adding custom workflow nodes 2. Implementing additional validation logic 3. Integrating with external services 4. Customizing LLM prompts and responses 5. Adding monitoring and logging capabilities

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *