"""
Pattern 143: Orchestrator Pattern
Central orchestrator that coordinates complex workflows involving multiple agents.
Implements workflow orchestration with LangGraph state machines.
"""
from dataclasses import dataclass, field
from datetime import datetime
from typing import Dict, Any, List, Optional, Callable
from enum import Enum
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langgraph.graph import StateGraph, END
from typing_extensions import TypedDict
class StepStatus(Enum):
"""Status of workflow step."""
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
SKIPPED = "skipped"
@dataclass
class WorkflowStep:
"""Represents a step in a workflow."""
step_id: str
name: str
agent_id: str
depends_on: List[str] = field(default_factory=list)
status: StepStatus = StepStatus.PENDING
input_data: Optional[Any] = None
output_data: Optional[Any] = None
started_at: Optional[datetime] = None
completed_at: Optional[datetime] = None
error: Optional[str] = None
@dataclass
class Workflow:
"""Represents a complete workflow."""
workflow_id: str
name: str
description: str
steps: List[WorkflowStep] = field(default_factory=list)
status: str = "pending"
created_at: datetime = field(default_factory=datetime.now)
completed_at: Optional[datetime] = None
class OrchestratedAgent:
"""Agent that can be orchestrated."""
def __init__(self, agent_id: str, name: str, capabilities: List[str], model_name: str = "gpt-4"):
self.agent_id = agent_id
self.name = name
self.capabilities = capabilities
self.llm = ChatOpenAI(model=model_name, temperature=0.7)
def execute(self, step: WorkflowStep) -> Any:
"""Execute a workflow step."""
prompt = ChatPromptTemplate.from_messages([
("system", f"You are {self.name}, an agent with capabilities: {', '.join(self.capabilities)}"),
("human", """Execute this workflow step:
Step: {step_name}
Input: {input_data}
Provide the output for this step:""")
])
chain = prompt | self.llm
response = chain.invoke({
"step_name": step.name,
"input_data": step.input_data or "No input provided"
})
return str(response.content)
class OrchestratorAgent:
"""
Orchestrator that coordinates workflow execution across multiple agents.
"""
def __init__(self, name: str = "Orchestrator", model_name: str = "gpt-4"):
self.name = name
self.llm = ChatOpenAI(model=model_name, temperature=0.3)
self.agents: Dict[str, OrchestratedAgent] = {}
self.workflows: Dict[str, Workflow] = {}
def register_agent(self, agent: OrchestratedAgent):
"""Register an agent for orchestration."""
self.agents[agent.agent_id] = agent
def create_workflow(self, workflow: Workflow):
"""Register a workflow."""
self.workflows[workflow.workflow_id] = workflow
def execute_workflow(self, workflow_id: str) -> Dict[str, Any]:
"""Execute a workflow by orchestrating its steps."""
if workflow_id not in self.workflows:
return {"success": False, "error": "Workflow not found"}
workflow = self.workflows[workflow_id]
workflow.status = "running"
execution_results = []
completed_steps = set()
# Build dependency graph
steps_by_id = {step.step_id: step for step in workflow.steps}
# Execute steps in dependency order
while len(completed_steps) Dict[str, Any]:
"""Execute a single workflow step."""
step.status = StepStatus.RUNNING
step.started_at = datetime.now()
# Get agent for this step
agent = self.agents.get(step.agent_id)
if not agent:
step.status = StepStatus.FAILED
step.error = f"Agent {step.agent_id} not found"
return {
"success": False,
"step_id": step.step_id,
"error": step.error
}
# Collect outputs from dependency steps
if step.depends_on:
dependency_outputs = {}
for dep_id in step.depends_on:
if dep_id in steps_by_id:
dep_step = steps_by_id[dep_id]
dependency_outputs[dep_id] = dep_step.output_data
step.input_data = dependency_outputs
try:
# Execute step
output = agent.execute(step)
step.output_data = output
step.status = StepStatus.COMPLETED
step.completed_at = datetime.now()
return {
"success": True,
"step_id": step.step_id,
"step_name": step.name,
"agent_id": step.agent_id,
"output": output
}
except Exception as e:
step.status = StepStatus.FAILED
step.error = str(e)
return {
"success": False,
"step_id": step.step_id,
"error": str(e)
}
def get_workflow_status(self, workflow_id: str) -> Dict[str, Any]:
"""Get status of a workflow."""
if workflow_id not in self.workflows:
return {"error": "Workflow not found"}
workflow = self.workflows[workflow_id]
steps_status = [
{
"step_id": step.step_id,
"name": step.name,
"status": step.status.value,
"agent": step.agent_id
}
for step in workflow.steps
]
return {
"workflow_id": workflow_id,
"name": workflow.name,
"status": workflow.status,
"total_steps": len(workflow.steps),
"completed_steps": len([s for s in workflow.steps if s.status == StepStatus.COMPLETED]),
"steps": steps_status
}
class OrchestratorPattern:
"""
LangGraph-based orchestrator pattern for complex workflows.
"""
def __init__(self, model_name: str = "gpt-4"):
self.orchestrator = OrchestratorAgent(model_name=model_name)
def run(self, workflow_id: str) -> Dict[str, Any]:
"""Run an orchestrated workflow."""
return self.orchestrator.execute_workflow(workflow_id)
def main():
"""Example usage of Orchestrator Pattern."""
print("=" * 80)
print("Orchestrator Pattern - Complex Workflow Demo")
print("=" * 80)
# Create orchestrator pattern
pattern = OrchestratorPattern()
orchestrator = pattern.orchestrator
# Create agents with different capabilities
agents = [
OrchestratedAgent(
agent_id="data-collector",
name="Data Collector",
capabilities=["data_collection", "api_calls", "web_scraping"]
),
OrchestratedAgent(
agent_id="data-processor",
name="Data Processor",
capabilities=["data_cleaning", "transformation", "validation"]
),
OrchestratedAgent(
agent_id="analyzer",
name="Data Analyzer",
capabilities=["analysis", "statistics", "insights"]
),
OrchestratedAgent(
agent_id="visualizer",
name="Visualizer",
capabilities=["charts", "graphs", "dashboards"]
),
OrchestratedAgent(
agent_id="reporter",
name="Report Generator",
capabilities=["report_writing", "summarization", "formatting"]
)
]
# Register agents
for agent in agents:
orchestrator.register_agent(agent)
# Create a complex workflow: Data Analysis Pipeline
workflow = Workflow(
workflow_id="wf-analysis-001",
name="Data Analysis Pipeline",
description="Collect, process, analyze, visualize, and report on data",
steps=[
WorkflowStep(
step_id="step-1",
name="Collect Data",
agent_id="data-collector",
depends_on=[],
input_data="Collect customer transaction data"
),
WorkflowStep(
step_id="step-2",
name="Process Data",
agent_id="data-processor",
depends_on=["step-1"],
),
WorkflowStep(
step_id="step-3",
name="Analyze Data",
agent_id="analyzer",
depends_on=["step-2"],
),
WorkflowStep(
step_id="step-4",
name="Create Visualizations",
agent_id="visualizer",
depends_on=["step-3"],
),
WorkflowStep(
step_id="step-5",
name="Generate Report",
agent_id="reporter",
depends_on=["step-3", "step-4"],
)
]
)
# Register workflow
orchestrator.create_workflow(workflow)
# Display workflow structure
print("\nš Workflow Structure:")
print(f"ID: {workflow.workflow_id}")
print(f"Name: {workflow.name}")
print(f"Description: {workflow.description}")
print(f"\nSteps:")
for step in workflow.steps:
deps = f" (depends on: {', '.join(step.depends_on)})" if step.depends_on else ""
print(f" {step.step_id}: {step.name} ā {step.agent_id}{deps}")
# Execute workflow
print("\n" + "=" * 80)
print("š Executing Workflow...")
print("=" * 80)
result = pattern.run(workflow.workflow_id)
# Display results
print("\nā
Execution Results:")
print(f"Success: {result['success']}")
if result["success"]:
print(f"\nWorkflow: {result['workflow_id']}")
print(f"Steps Executed: {len(result['results'])}")
print("\n" + "=" * 80)
print("Step Results:")
print("=" * 80)
for step_result in result["results"]:
print(f"\n{step_result['step_name']} ({step_result['step_id']})")
print(f" Agent: {step_result['agent_id']}")
print(f" Output: {str(step_result['output'])[:150]}...")
else:
print(f"Error: {result.get('error', 'Unknown error')}")
# Display workflow status
print("\n" + "=" * 80)
print("š Workflow Status")
print("=" * 80)
status = orchestrator.get_workflow_status(workflow.workflow_id)
print(f"Status: {status['status']}")
print(f"Progress: {status['completed_steps']}/{status['total_steps']} steps")
print("\nStep Status:")
for step_status in status["steps"]:
print(f" {step_status['name']}: {step_status['status']}")
if __name__ == "__main__":
main()
Agentic Architecture Pattern: Orchestrator
Pattern 143: 143 Orchestrator – Line-by-Line Explanation
Overview
Pattern 143: Orchestrator Pattern
Central orchestrator that coordinates complex workflows involving multiple agents. Implements workflow orchestration with LangGraph state machines.
Code Structure Analysis
File Information
- Pattern Number: 143
- Pattern Name: 143 Orchestrator
- File Path:
patterns\workflow\143_orchestrator.py - Total Lines: 393
Detailed Code Explanation
Module Docstring
"""
Pattern 143: Orchestrator Pattern
Central orchestrator that coordinates complex workflows involving multiple agents.
Implements workflow orchestration with LangGraph state machines.
"""
Explanation: This module docstring describes the purpose and key features of the 143 Orchestrator pattern.
Imports Section
from dataclasses import dataclass, field
from datetime import datetime
from typing import Dict, Any, List, Optional, Callable
from enum import Enum
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langgraph.graph import StateGraph, END
from typing_extensions import TypedDict # First 20 imports shown
Explanation: The module imports necessary dependencies:
– from dataclasses import dataclass, field: Data class decorators for clean data structures
– from datetime import datetime: Date and time utilities
– from typing import Dict, Any, List, Optional, Callable: Type hints for better code documentation
– from enum import Enum: Enumeration support for fixed sets of values
– from langchain_openai import ChatOpenAI: LangChain framework integration
– from langchain_core.prompts import ChatPromptTemplate: LangChain framework integration
– from langgraph.graph import StateGraph, END: LangGraph for workflow orchestration
– from typing_extensions import TypedDict: Type hints for better code documentation
Enumerations
StepStatus (Line 18)
class StepStatus(Enum):
PENDING
RUNNING
COMPLETED
FAILED
SKIPPED
Purpose: Status of workflow step.
Values:
– PENDING: Initial state, not yet processed
– RUNNING: Currently executing
– COMPLETED: Successfully finished
– FAILED: Execution failed
– SKIPPED: Represents skipped
Classes
StepStatus (Line 18)
Description: Status of workflow step.
WorkflowStep (Line 28)
Description: Represents a step in a workflow.
Workflow (Line 43)
Description: Represents a complete workflow.
OrchestratedAgent (Line 54)
Description: Agent that can be orchestrated.
Methods:
__init__ (Line 57)
def __init__(self, agent_id, name, capabilities, model_name):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
– agent_id: Parameter for agent_id
– name: Identifier or label
– capabilities: Parameter for capabilities
– model_name: LLM model to use (e.g., “gpt-4”)
execute (Line 63)
def execute(self, step):
"""Execute a workflow step."""
Purpose: Execute a workflow step.
Parameters:
– self: Instance reference
– step: Parameter for step
OrchestratorAgent (Line 84)
Description: Orchestrator that coordinates workflow execution across multiple agents.
Methods:
__init__ (Line 89)
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”)
register_agent (Line 95)
def register_agent(self, agent):
"""Register an agent for orchestration."""
Purpose: Register an agent for orchestration.
Parameters:
– self: Instance reference
– agent: Parameter for agent
create_workflow (Line 99)
def create_workflow(self, workflow):
"""Register a workflow."""
Purpose: Register a workflow.
Parameters:
– self: Instance reference
– workflow: Parameter for workflow
execute_workflow (Line 103)
def execute_workflow(self, workflow_id):
"""Execute a workflow by orchestrating its steps."""
Purpose: Execute a workflow by orchestrating its steps.
Parameters:
– self: Instance reference
– workflow_id: Parameter for workflow_id
_execute_step (Line 162)
def _execute_step(self, step, steps_by_id, completed_steps):
"""Execute a single workflow step."""
Purpose: Execute a single workflow step.
Parameters:
– self: Instance reference
– step: Parameter for step
– steps_by_id: Parameter for steps_by_id
– completed_steps: Parameter for completed_steps
get_workflow_status (Line 217)
def get_workflow_status(self, workflow_id):
"""Get status of a workflow."""
Purpose: Get status of a workflow.
Parameters:
– self: Instance reference
– workflow_id: Parameter for workflow_id
OrchestratorPattern (Line 244)
Description: LangGraph-based orchestrator pattern for complex workflows.
Methods:
__init__ (Line 249)
def __init__(self, model_name):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
– model_name: LLM model to use (e.g., “gpt-4”)
run (Line 252)
def run(self, workflow_id):
"""Run an orchestrated workflow."""
Purpose: Run an orchestrated workflow.
Parameters:
– self: Instance reference
– workflow_id: Parameter for workflow_id
Functions
main (Line 257)
def main():
"""Example usage of Orchestrator Pattern."""
Purpose: Example usage of Orchestrator Pattern.
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 = StepStatus(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
Leave a Reply