Agentic Architecture Pattern: Pipeline

Written by

in


    """
Pattern 73: Pipeline Pattern

Data flows through a series of processing stages with transformations
at each stage. Similar to Unix pipes or data processing pipelines.
"""

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


@dataclass
class PipelineStage:
    """Stage in the processing pipeline."""
    name: str
    processor: Callable[[Any], Any]
    description: str = ""
    input_type: Optional[str] = None
    output_type: Optional[str] = None


@dataclass
class PipelineResult:
    """Result from pipeline execution."""
    success: bool
    input_data: Any
    output_data: Optional[Any]
    stages_executed: List[str]
    stage_outputs: Dict[str, Any]
    execution_time: float
    error: Optional[str] = None


class PipelineAgent:
    """Agent that acts as a pipeline stage."""
    
    def __init__(self, name: str, role: str, model_name: str = "gpt-4"):
        self.name = name
        self.role = role
        self.llm = ChatOpenAI(model=model_name, temperature=0.7)
    
    def transform(self, data: Any) -> Any:
        """Transform input data."""
        prompt = ChatPromptTemplate.from_messages([
            ("system", f"You are {self.name}, a {self.role}. "
                      f"Transform the input data according to your role."),
            ("human", f"Input: {data}\n\nProvide transformed output.")
        ])
        
        chain = prompt | self.llm
        response = chain.invoke({})
        return str(response.content)


class PipelinePattern:
    """
    Pipeline Pattern - Sequential data transformation chain.
    
    Data flows through stages with each stage transforming the data.
    Stages can be agents, functions, or any callable processor.
    """
    
    def __init__(self):
        self.stages: List[PipelineStage] = []
        self.execution_log: List[PipelineResult] = []
    
    def add_stage(self, stage: PipelineStage):
        """Add stage to pipeline."""
        self.stages.append(stage)
    
    def add_agent_stage(self, agent: PipelineAgent, description: str = ""):
        """Add agent as pipeline stage."""
        stage = PipelineStage(
            name=agent.name,
            processor=agent.transform,
            description=description or f"{agent.role} processing"
        )
        self.stages.append(stage)
    
    def add_function_stage(self, name: str, func: Callable[[Any], Any], description: str = ""):
        """Add function as pipeline stage."""
        stage = PipelineStage(
            name=name,
            processor=func,
            description=description
        )
        self.stages.append(stage)
    
    def execute(self, input_data: Any) -> PipelineResult:
        """Execute data through pipeline."""
        start_time = datetime.now()
        
        stages_executed = []
        stage_outputs = {}
        current_data = input_data
        
        try:
            for stage in self.stages:
                print(f"   Executing stage: {stage.name}...")
                
                # Process data through stage
                current_data = stage.processor(current_data)
                
                # Log execution
                stages_executed.append(stage.name)
                stage_outputs[stage.name] = current_data
            
            execution_time = (datetime.now() - start_time).total_seconds()
            
            result = PipelineResult(
                success=True,
                input_data=input_data,
                output_data=current_data,
                stages_executed=stages_executed,
                stage_outputs=stage_outputs,
                execution_time=execution_time
            )
            
        except Exception as e:
            execution_time = (datetime.now() - start_time).total_seconds()
            
            result = PipelineResult(
                success=False,
                input_data=input_data,
                output_data=None,
                stages_executed=stages_executed,
                stage_outputs=stage_outputs,
                execution_time=execution_time,
                error=str(e)
            )
        
        self.execution_log.append(result)
        return result
    
    def run(self, input_data: Any) -> Dict[str, Any]:
        """Run pipeline and return results."""
        result = self.execute(input_data)
        
        return {
            "pattern": "Pipeline",
            "success": result.success,
            "stages_executed": len(result.stages_executed),
            "total_stages": len(self.stages),
            "execution_time": result.execution_time,
            "output": result.output_data,
            "error": result.error
        }
    
    def get_statistics(self) -> Dict[str, Any]:
        """Get pipeline statistics."""
        if not self.execution_log:
            return {"total_runs": 0}
        
        return {
            "total_runs": len(self.execution_log),
            "successful_runs": sum(1 for r in self.execution_log if r.success),
            "failed_runs": sum(1 for r in self.execution_log if not r.success),
            "avg_execution_time": sum(r.execution_time for r in self.execution_log) / len(self.execution_log),
            "total_stages": len(self.stages)
        }


# Example usage
if __name__ == "__main__":
    print("=== Pipeline Pattern Demo ===\n")
    
    # Create pipeline
    pipeline = PipelinePattern()
    
    # Add agent-based stages
    print("1. Building pipeline with agents...")
    extractor = PipelineAgent("Extractor", "data extractor")
    transformer = PipelineAgent("Transformer", "data transformer")
    validator = PipelineAgent("Validator", "data validator")
    
    pipeline.add_agent_stage(extractor, "Extract key information")
    pipeline.add_agent_stage(transformer, "Transform to target format")
    pipeline.add_agent_stage(validator, "Validate output quality")
    
    # Add function-based stage
    def format_output(data: Any) -> str:
        return f"[FORMATTED] {str(data).upper()}"
    
    pipeline.add_function_stage("Formatter", format_output, "Format final output")
    
    # Execute pipeline
    print("\n2. Executing pipeline...")
    input_text = "Process this customer feedback: The product is great but shipping was slow."
    result = pipeline.run(input_text)
    
    print(f"\n3. Pipeline Results:")
    print(f"   Success: {result['success']}")
    print(f"   Stages Executed: {result['stages_executed']}/{result['total_stages']}")
    print(f"   Execution Time: {result['execution_time']:.2f}s")
    
    if result['output']:
        print(f"\n4. Final Output:")
        print(f"   {str(result['output'])[:150]}...")
    
    # Statistics
    stats = pipeline.get_statistics()
    print(f"\n5. Pipeline Statistics:")
    print(f"   Total Runs: {stats['total_runs']}")
    print(f"   Success Rate: {stats['successful_runs']}/{stats['total_runs']}")
    
    print("\nāœ“ Pipeline pattern processed data through transformation stages!")

    

Agentic Architecture Pattern: Pipeline

Pattern 73: 73 Pipeline – Line-by-Line Explanation

Overview

Pattern 73: Pipeline Pattern

Data flows through a series of processing stages with transformations at each stage. Similar to Unix pipes or data processing pipelines.


Code Structure Analysis

File Information

  • Pattern Number: 73
  • Pattern Name: 73 Pipeline
  • File Path: patterns\execution_control\73_pipeline.py
  • Total Lines: 210

Detailed Code Explanation

Module Docstring

"""
Pattern 73: Pipeline Pattern

Data flows through a series of processing stages with transformations
at each stage. Similar to Unix pipes or data processing pipelines.
"""

Explanation: This module docstring describes the purpose and key features of the 73 Pipeline pattern.


Imports Section

from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, field
from datetime import datetime
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 langchain_core.prompts import ChatPromptTemplate: LangChain framework integration – from langchain_openai import ChatOpenAI: LangChain framework integration


Classes

PipelineStage (Line 16)

Description: Stage in the processing pipeline.

PipelineResult (Line 26)

Description: Result from pipeline execution.

PipelineAgent (Line 37)

Description: Agent that acts as a pipeline stage.

Methods:

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

Purpose: No method docstring.

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

transform (Line 45)
def transform(self, data):
    """Transform input data."""

Purpose: Transform input data.

Parameters: – self: Instance reference – data: Input data to process

PipelinePattern (Line 58)

Description: Pipeline Pattern – Sequential data transformation chain.

Data flows through stages with each stage transforming the data. Stages can be agents, functions, or any callable processor.

Methods:

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

Purpose: No method docstring.

Parameters: – self: Instance reference

add_stage (Line 70)
def add_stage(self, stage):
    """Add stage to pipeline."""

Purpose: Add stage to pipeline.

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

add_agent_stage (Line 74)
def add_agent_stage(self, agent, description):
    """Add agent as pipeline stage."""

Purpose: Add agent as pipeline stage.

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

add_function_stage (Line 83)
def add_function_stage(self, name, func, description):
    """Add function as pipeline stage."""

Purpose: Add function as pipeline stage.

Parameters: – self: Instance reference – name: Identifier or label – func: Parameter for func – description: Parameter for description

execute (Line 92)
def execute(self, input_data):
    """Execute data through pipeline."""

Purpose: Execute data through pipeline.

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

run (Line 138)
def run(self, input_data):
    """Run pipeline and return results."""

Purpose: Run pipeline and return results.

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

get_statistics (Line 152)
def get_statistics(self):
    """Get pipeline statistics."""

Purpose: Get pipeline statistics.

Parameters: – self: Instance reference


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 = PipelineStage(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 *