Agentic Architecture Pattern: Goal Oriented Agent

Written by

in


    """
Pattern 08: Goal-Oriented Agent Pattern
Agent that explicitly pursues and manages goals.
"""

from typing import Dict, Any, List, Optional
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 GoalStatus(Enum):
    """Status of a goal."""
    PENDING = "pending"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    FAILED = "failed"
    ABANDONED = "abandoned"


@dataclass
class Goal:
    """A goal the agent pursues."""
    id: str
    description: str
    priority: int  # 1-10
    status: GoalStatus = GoalStatus.PENDING
    sub_goals: List[str] = field(default_factory=list)
    progress: float = 0.0  # 0.0 to 1.0
    created_at: datetime = field(default_factory=datetime.now)
    deadline: Optional[datetime] = None


class GoalOrientedAgentPattern:
    """
    Goal-Oriented Agent that:
    - Maintains explicit goals
    - Prioritizes goals
    - Decomposes goals into sub-goals
    - Tracks progress
    - Adapts when goals fail
    """
    
    def __init__(self, name: str = "GoalAgent", model_name: str = "gpt-4"):
        self.name = name
        self.llm = ChatOpenAI(model=model_name, temperature=0.6)
        self.goals: Dict[str, Goal] = {}
        self.goal_counter = 0
        
    def add_goal(self, description: str, priority: int = 5, deadline: Optional[datetime] = None) -> str:
        """Add a new goal."""
        goal_id = f"goal_{self.goal_counter}"
        self.goal_counter += 1
        
        goal = Goal(
            id=goal_id,
            description=description,
            priority=priority,
            deadline=deadline
        )
        self.goals[goal_id] = goal
        
        print(f"🎯 New goal: {description} (priority: {priority})")
        return goal_id
    
    def decompose_goal(self, goal_id: str) -> List[str]:
        """Decompose a goal into sub-goals."""
        goal = self.goals[goal_id]
        
        prompt = ChatPromptTemplate.from_messages([
            ("system", f"You are {self.name}. Decompose goals into achievable sub-goals."),
            ("human", "Goal: {goal}\n\nBreak this down into 3-5 concrete sub-goals:")
        ])
        
        chain = prompt | self.llm
        response = chain.invoke({"goal": goal.description})
        
        # Parse sub-goals (simplified)
        sub_goals_text = str(response.content)
        sub_goals = [line.strip() for line in sub_goals_text.split("\n") if line.strip() and any(c.isdigit() for c in line)]
        
        # Create sub-goal IDs
        sub_goal_ids = []
        for sub_goal_desc in sub_goals[:5]:  # Limit to 5
            sub_id = self.add_goal(sub_goal_desc, priority=goal.priority - 1)
            sub_goal_ids.append(sub_id)
        
        goal.sub_goals = sub_goal_ids
        print(f"📋 Decomposed into {len(sub_goal_ids)} sub-goals")
        
        return sub_goal_ids
    
    def select_next_goal(self) -> Optional[Goal]:
        """Select the next goal to work on."""
        active_goals = [g for g in self.goals.values() 
                       if g.status in [GoalStatus.PENDING, GoalStatus.IN_PROGRESS]]
        
        if not active_goals:
            return None
        
        # Sort by priority, then by deadline
        active_goals.sort(key=lambda g: (
            -g.priority,  # Higher priority first
            g.deadline if g.deadline else datetime.max  # Earlier deadline first
        ))
        
        return active_goals[0]
    
    def work_on_goal(self, goal_id: str) -> Dict[str, Any]:
        """Work on achieving a goal."""
        goal = self.goals[goal_id]
        goal.status = GoalStatus.IN_PROGRESS
        
        prompt = ChatPromptTemplate.from_messages([
            ("system", f"You are {self.name} working on a goal."),
            ("human", """Goal: {goal}
            Priority: {priority}
            Current progress: {progress:.0%}
            
            What actions should I take to make progress on this goal?""")
        ])
        
        chain = prompt | self.llm
        response = chain.invoke({
            "goal": goal.description,
            "priority": goal.priority,
            "progress": goal.progress
        })
        
        actions = str(response.content)
        
        # Simulate progress
        goal.progress = min(1.0, goal.progress + 0.3)
        
        if goal.progress >= 1.0:
            goal.status = GoalStatus.COMPLETED
            print(f"✅ Goal completed: {goal.description}")
        
        return {
            "goal_id": goal_id,
            "actions": actions,
            "progress": goal.progress,
            "status": goal.status.value
        }
    
    def run(self, initial_goals: List[Dict[str, Any]], cycles: int = 3) -> Dict[str, Any]:
        """
        Run goal-oriented agent.
        
        Args:
            initial_goals: List of dicts with 'description' and 'priority'
            cycles: Number of work cycles
            
        Returns:
            Results of goal pursuit
        """
        # Add initial goals
        for goal_spec in initial_goals:
            goal_id = self.add_goal(
                goal_spec['description'],
                goal_spec.get('priority', 5)
            )
            # Optionally decompose complex goals
            if goal_spec.get('decompose', False):
                self.decompose_goal(goal_id)
        
        # Work on goals
        results = []
        for cycle in range(cycles):
            print(f"\n--- Cycle {cycle + 1}/{cycles} ---")
            goal = self.select_next_goal()
            if not goal:
                print("No active goals remaining")
                break
            
            result = self.work_on_goal(goal.id)
            results.append(result)
        
        # Summary
        completed = sum(1 for g in self.goals.values() if g.status == GoalStatus.COMPLETED)
        in_progress = sum(1 for g in self.goals.values() if g.status == GoalStatus.IN_PROGRESS)
        
        return {
            "agent": self.name,
            "total_goals": len(self.goals),
            "completed": completed,
            "in_progress": in_progress,
            "cycles_executed": len(results),
            "work_results": results
        }


# Example usage
if __name__ == "__main__":
    print("\n=== Goal-Oriented Agent Example ===")
    
    agent = GoalOrientedAgentPattern(name="GoalBot")
    
    initial_goals = [
        {"description": "Learn a new programming language", "priority": 8, "decompose": True},
        {"description": "Improve physical fitness", "priority": 6},
        {"description": "Complete project documentation", "priority": 7}
    ]
    
    result = agent.run(initial_goals, cycles=4)
    
    print("\n=== Results ===")
    print(f"Agent: {result['agent']}")
    print(f"Total goals created: {result['total_goals']}")
    print(f"Completed: {result['completed']}")
    print(f"In progress: {result['in_progress']}")
    print(f"Cycles executed: {result['cycles_executed']}")
    print("\nWork done:")
    for i, work in enumerate(result['work_results'], 1):
        print(f"\n  Cycle {i}: {work['goal_id']}")
        print(f"    Progress: {work['progress']:.0%}")
        print(f"    Status: {work['status']}")

    

Agentic Architecture Pattern: Goal Oriented Agent

Pattern 08: 08 Goal Oriented Agent – Line-by-Line Explanation

Overview

Pattern 08: Goal-Oriented Agent Pattern Agent that explicitly pursues and manages goals.


Code Structure Analysis

File Information

  • Pattern Number: 08
  • Pattern Name: 08 Goal Oriented Agent
  • File Path: patterns\core_agent\08_goal_oriented_agent.py
  • Total Lines: 220

Detailed Code Explanation

Module Docstring

"""
Pattern 08: Goal-Oriented Agent Pattern
Agent that explicitly pursues and manages goals.
"""

Explanation: This module docstring describes the purpose and key features of the 08 Goal Oriented Agent pattern.


Imports Section

from typing import Dict, Any, List, Optional
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: 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

GoalStatus (Line 14)

class GoalStatus(Enum):
    PENDING
    IN_PROGRESS
    COMPLETED
    FAILED
    ABANDONED

Purpose: Status of a goal.

Values: – PENDING: Initial state, not yet processed – IN_PROGRESS: Represents in progress – COMPLETED: Successfully finished – FAILED: Execution failed – ABANDONED: Represents abandoned


Classes

GoalStatus (Line 14)

Description: Status of a goal.

Goal (Line 24)

Description: A goal the agent pursues.

GoalOrientedAgentPattern (Line 36)

Description: Goal-Oriented Agent that: – Maintains explicit goals – Prioritizes goals – Decomposes goals into sub-goals – Tracks progress – Adapts when goals fail

Methods:

__init__ (Line 46)
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”)

add_goal (Line 52)
def add_goal(self, description, priority, deadline):
    """Add a new goal."""

Purpose: Add a new goal.

Parameters: – self: Instance reference – description: Parameter for description – priority: Parameter for priority – deadline: Parameter for deadline

decompose_goal (Line 68)
def decompose_goal(self, goal_id):
    """Decompose a goal into sub-goals."""

Purpose: Decompose a goal into sub-goals.

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

select_next_goal (Line 95)
def select_next_goal(self):
    """Select the next goal to work on."""

Purpose: Select the next goal to work on.

Parameters: – self: Instance reference

work_on_goal (Line 111)
def work_on_goal(self, goal_id):
    """Work on achieving a goal."""

Purpose: Work on achieving a goal.

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

run (Line 148)
def run(self, initial_goals, cycles):
    """Run goal-oriented agent.

Args:
    initial_goals: List of dicts with 'description' and 'priority'
    cycles: Number of work cycles

Returns:
    Results of goal pursuit"""

Purpose: Run goal-oriented agent.

Args: initial_goals: List of dicts with ‘description’ and ‘priority’ cycles: Number of work cycles

Returns: Results of goal pursuit

Parameters: – self: Instance reference – initial_goals: Parameter for initial_goals – cycles: Parameter for cycles


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