Agentic Architecture Pattern: Prompt Engineering

Written by

in


    """
Pattern 191: Prompt Engineering Pattern

Systematic design and optimization of prompts for LLMs.
Implements multiple prompt engineering techniques for effective LLM interaction.
"""

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, PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI


class PromptTechnique(Enum):
    """Prompt engineering techniques."""
    ZERO_SHOT = "zero_shot"
    FEW_SHOT = "few_shot"
    CHAIN_OF_THOUGHT = "chain_of_thought"
    ROLE_BASED = "role_based"
    TEMPLATE = "template"
    STRUCTURED = "structured"


@dataclass
class PromptExample:
    """Example for few-shot learning."""
    input: str
    output: str
    explanation: Optional[str] = None


@dataclass
class PromptTemplate:
    """Prompt template with variables."""
    name: str
    technique: PromptTechnique
    system_message: str
    user_template: str
    variables: List[str]
    examples: List[PromptExample] = field(default_factory=list)
    output_format: Optional[str] = None


@dataclass
class PromptResult:
    """Result of prompt execution."""
    prompt_used: str
    technique: PromptTechnique
    response: str
    metadata: Dict[str, Any] = field(default_factory=dict)
    timestamp: datetime = field(default_factory=datetime.now)


class PromptEngineer:
    """Engineer with multiple prompt techniques."""
    
    def __init__(self, model_name: str = "gpt-4", temperature: float = 0.7):
        self.llm = ChatOpenAI(model=model_name, temperature=temperature)
        self.templates: Dict[str, PromptTemplate] = {}
        self.results: List[PromptResult] = []
    
    def create_zero_shot_prompt(self, task: str, context: Optional[str] = None) -> str:
        """Create zero-shot prompt."""
        if context:
            return f"Context: {context}\n\nTask: {task}\n\nProvide a clear and comprehensive answer."
        return f"Task: {task}\n\nProvide a clear and comprehensive answer."
    
    def create_few_shot_prompt(self, task: str, examples: List[PromptExample]) -> str:
        """Create few-shot prompt with examples."""
        prompt_parts = ["Here are some examples:\n"]
        
        for i, ex in enumerate(examples, 1):
            prompt_parts.append(f"\nExample {i}:")
            prompt_parts.append(f"Input: {ex.input}")
            prompt_parts.append(f"Output: {ex.output}")
            if ex.explanation:
                prompt_parts.append(f"Why: {ex.explanation}")
        
        prompt_parts.append(f"\n\nNow, apply the same pattern:")
        prompt_parts.append(f"Input: {task}")
        prompt_parts.append("Output:")
        
        return "\n".join(prompt_parts)
    
    def create_chain_of_thought_prompt(self, task: str) -> str:
        """Create chain-of-thought prompt."""
        return (f"{task}\n\n"
                f"Let's approach this step-by-step:\n"
                f"1. First, identify the key components\n"
                f"2. Then, analyze the relationships\n"
                f"3. Finally, synthesize the answer\n\n"
                f"Think through each step carefully:")
    
    def create_role_based_prompt(self, task: str, role: str, expertise: List[str]) -> str:
        """Create role-based prompt."""
        expertise_text = ", ".join(expertise)
        return (f"You are a {role} with expertise in {expertise_text}. "
                f"Use your specialized knowledge to address this:\n\n{task}")
    
    def execute_prompt(self, prompt: str, technique: PromptTechnique, 
                      system_message: Optional[str] = None) -> PromptResult:
        """Execute prompt and return result."""
        messages = []
        
        if system_message:
            messages.append(("system", system_message))
        
        messages.append(("human", prompt))
        
        chat_prompt = ChatPromptTemplate.from_messages(messages)
        chain = chat_prompt | self.llm | StrOutputParser()
        
        response = chain.invoke({})
        
        result = PromptResult(
            prompt_used=prompt,
            technique=technique,
            response=response,
            metadata={"system_message": system_message}
        )
        
        self.results.append(result)
        return result
    
    def register_template(self, template: PromptTemplate):
        """Register a reusable prompt template."""
        self.templates[template.name] = template
    
    def use_template(self, template_name: str, **kwargs) -> PromptResult:
        """Use a registered template with variables."""
        if template_name not in self.templates:
            raise ValueError(f"Template '{template_name}' not found")
        
        template = self.templates[template_name]
        
        # Substitute variables
        prompt = template.user_template
        for var in template.variables:
            if var in kwargs:
                prompt = prompt.replace(f"{{{var}}}", str(kwargs[var]))
        
        # Add examples if few-shot
        if template.technique == PromptTechnique.FEW_SHOT and template.examples:
            prompt = self.create_few_shot_prompt(prompt, template.examples)
        
        # Add output format if specified
        if template.output_format:
            prompt += f"\n\nOutput format: {template.output_format}"
        
        return self.execute_prompt(prompt, template.technique, template.system_message)


class PromptEngineeringPattern:
    """
    Prompt Engineering Pattern - Systematic prompt design and optimization.
    
    Provides multiple techniques for crafting effective prompts including
    zero-shot, few-shot, chain-of-thought, and role-based prompting.
    """
    
    def __init__(self, model_name: str = "gpt-4"):
        self.engineer = PromptEngineer(model_name)
        self.technique_usage: Dict[PromptTechnique, int] = {t: 0 for t in PromptTechnique}
    
    def zero_shot(self, task: str, context: Optional[str] = None) -> PromptResult:
        """Execute zero-shot prompting."""
        prompt = self.engineer.create_zero_shot_prompt(task, context)
        result = self.engineer.execute_prompt(prompt, PromptTechnique.ZERO_SHOT)
        self.technique_usage[PromptTechnique.ZERO_SHOT] += 1
        return result
    
    def few_shot(self, task: str, examples: List[PromptExample]) -> PromptResult:
        """Execute few-shot prompting."""
        prompt = self.engineer.create_few_shot_prompt(task, examples)
        result = self.engineer.execute_prompt(prompt, PromptTechnique.FEW_SHOT)
        self.technique_usage[PromptTechnique.FEW_SHOT] += 1
        return result
    
    def chain_of_thought(self, task: str) -> PromptResult:
        """Execute chain-of-thought prompting."""
        prompt = self.engineer.create_chain_of_thought_prompt(task)
        result = self.engineer.execute_prompt(
            prompt, 
            PromptTechnique.CHAIN_OF_THOUGHT,
            "You are a careful thinker who explains reasoning step-by-step."
        )
        self.technique_usage[PromptTechnique.CHAIN_OF_THOUGHT] += 1
        return result
    
    def role_based(self, task: str, role: str, expertise: List[str]) -> PromptResult:
        """Execute role-based prompting."""
        prompt = self.engineer.create_role_based_prompt(task, role, expertise)
        result = self.engineer.execute_prompt(prompt, PromptTechnique.ROLE_BASED)
        self.technique_usage[PromptTechnique.ROLE_BASED] += 1
        return result
    
    def create_template(self, name: str, technique: PromptTechnique, 
                       system_message: str, user_template: str, 
                       variables: List[str], **kwargs) -> PromptTemplate:
        """Create and register a prompt template."""
        template = PromptTemplate(
            name=name,
            technique=technique,
            system_message=system_message,
            user_template=user_template,
            variables=variables,
            examples=kwargs.get('examples', []),
            output_format=kwargs.get('output_format')
        )
        self.engineer.register_template(template)
        return template
    
    def get_statistics(self) -> Dict[str, Any]:
        """Get usage statistics."""
        total = sum(self.technique_usage.values())
        
        return {
            "total_prompts": total,
            "techniques_used": {t.value: count for t, count in self.technique_usage.items() if count > 0},
            "unique_templates": len(self.engineer.templates),
            "avg_response_length": sum(len(r.response) for r in self.engineer.results) / max(len(self.engineer.results), 1)
        }


# Example usage
if __name__ == "__main__":
    print("=== Prompt Engineering Pattern Demo ===\n")
    
    # Create pattern
    print("1. Creating prompt engineering pattern...")
    pattern = PromptEngineeringPattern()
    
    # Test zero-shot
    print(f"\n{'='*70}")
    print("šŸ“ Zero-Shot Prompting")
    print(f"{'='*70}\n")
    
    result = pattern.zero_shot(
        "Explain the concept of 'emergence' in complex systems",
        context="Focus on practical examples"
    )
    print(f"Task: Explain emergence")
    print(f"Technique: {result.technique.value}")
    print(f"Response: {result.response[:200]}...\n")
    
    # Test few-shot
    print(f"\n{'='*70}")
    print("šŸ“š Few-Shot Prompting")
    print(f"{'='*70}\n")
    
    examples = [
        PromptExample(
            input="What is photosynthesis?",
            output="Photosynthesis is the process plants use to convert light energy into chemical energy (glucose).",
            explanation="Simple, clear definition with key components"
        ),
        PromptExample(
            input="What is mitosis?",
            output="Mitosis is cell division that produces two identical daughter cells from one parent cell.",
            explanation="Concise explanation of the core process"
        )
    ]
    
    result = pattern.few_shot("What is osmosis?", examples)
    print(f"Task: What is osmosis?")
    print(f"Technique: {result.technique.value}")
    print(f"Examples provided: {len(examples)}")
    print(f"Response: {result.response[:200]}...\n")
    
    # Test chain-of-thought
    print(f"\n{'='*70}")
    print("šŸ”— Chain-of-Thought Prompting")
    print(f"{'='*70}\n")
    
    result = pattern.chain_of_thought(
        "If a store has a 20% discount and then adds 8% sales tax, "
        "how much would a $50 item cost?"
    )
    print(f"Task: Calculate final price with discount and tax")
    print(f"Technique: {result.technique.value}")
    print(f"Response: {result.response[:300]}...\n")
    
    # Test role-based
    print(f"\n{'='*70}")
    print("šŸŽ­ Role-Based Prompting")
    print(f"{'='*70}\n")
    
    result = pattern.role_based(
        "How should I optimize database queries for a high-traffic application?",
        role="Senior Database Administrator",
        expertise=["SQL optimization", "indexing strategies", "query planning"]
    )
    print(f"Task: Database optimization advice")
    print(f"Technique: {result.technique.value}")
    print(f"Role: Senior Database Administrator")
    print(f"Response: {result.response[:200]}...\n")
    
    # Create and use template
    print(f"\n{'='*70}")
    print("šŸ“‹ Template-Based Prompting")
    print(f"{'='*70}\n")
    
    template = pattern.create_template(
        name="code_review",
        technique=PromptTechnique.STRUCTURED,
        system_message="You are an expert code reviewer focusing on best practices.",
        user_template="Review this {language} code for {aspect}:\n\n{code}",
        variables=["language", "aspect", "code"],
        output_format="1. Issues found\n2. Recommendations\n3. Severity"
    )
    
    result = pattern.engineer.use_template(
        "code_review",
        language="Python",
        aspect="performance and readability",
        code="def calc(x):\n    return [i*2 for i in range(x)]"
    )
    
    print(f"Template: {template.name}")
    print(f"Response: {result.response[:200]}...\n")
    
    # Statistics
    print(f"\n{'='*70}")
    print("šŸ“Š Usage Statistics")
    print(f"{'='*70}")
    
    stats = pattern.get_statistics()
    
    print(f"   Total prompts executed: {stats['total_prompts']}")
    print(f"   Unique templates created: {stats['unique_templates']}")
    print(f"   Avg response length: {stats['avg_response_length']:.0f} chars")
    
    print(f"\n   Techniques used:")
    for technique, count in stats['techniques_used'].items():
        print(f"   - {technique}: {count} times")
    
    print("\nāœ“ Prompt engineering pattern demonstrated multiple techniques!")

    

Agentic Architecture Pattern: Prompt Engineering

Pattern 191: 191 Prompt Engineering Pattern – Line-by-Line Explanation

Overview

Pattern 191: Prompt Engineering Pattern

Systematic design and optimization of prompts for LLMs. Implements multiple prompt engineering techniques for effective LLM interaction.


Code Structure Analysis

File Information

  • Pattern Number: 191
  • Pattern Name: 191 Prompt Engineering Pattern
  • File Path: patterns\llm_specific\191_prompt_engineering_pattern.py
  • Total Lines: 341

Detailed Code Explanation

Module Docstring

"""
Pattern 191: Prompt Engineering Pattern

Systematic design and optimization of prompts for LLMs.
Implements multiple prompt engineering techniques for effective LLM interaction.
"""

Explanation: This module docstring describes the purpose and key features of the 191 Prompt Engineering Pattern 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, PromptTemplate
from langchain_core.output_parsers import StrOutputParser
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, PromptTemplate: LangChain framework integration – from langchain_core.output_parsers import StrOutputParser: LangChain framework integration – from langchain_openai import ChatOpenAI: LangChain framework integration


Enumerations

PromptTechnique (Line 17)

class PromptTechnique(Enum):
    ZERO_SHOT
    FEW_SHOT
    CHAIN_OF_THOUGHT
    ROLE_BASED
    TEMPLATE
    STRUCTURED

Purpose: Prompt engineering techniques.

Values: – ZERO_SHOT: Represents zero shot – FEW_SHOT: Represents few shot – CHAIN_OF_THOUGHT: Represents chain of thought – ROLE_BASED: Represents role based – TEMPLATE: Represents template – STRUCTURED: Represents structured


Classes

PromptTechnique (Line 17)

Description: Prompt engineering techniques.

PromptExample (Line 28)

Description: Example for few-shot learning.

PromptTemplate (Line 36)

Description: Prompt template with variables.

PromptResult (Line 48)

Description: Result of prompt execution.

PromptEngineer (Line 57)

Description: Engineer with multiple prompt techniques.

Methods:

__init__ (Line 60)
def __init__(self, model_name, temperature):
    """No method docstring."""

Purpose: No method docstring.

Parameters: – self: Instance reference – model_name: LLM model to use (e.g., “gpt-4”) – temperature: Randomness in LLM responses (0.0-1.0)

create_zero_shot_prompt (Line 65)
def create_zero_shot_prompt(self, task, context):
    """Create zero-shot prompt."""

Purpose: Create zero-shot prompt.

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

create_few_shot_prompt (Line 71)
def create_few_shot_prompt(self, task, examples):
    """Create few-shot prompt with examples."""

Purpose: Create few-shot prompt with examples.

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

create_chain_of_thought_prompt (Line 88)
def create_chain_of_thought_prompt(self, task):
    """Create chain-of-thought prompt."""

Purpose: Create chain-of-thought prompt.

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

create_role_based_prompt (Line 97)
def create_role_based_prompt(self, task, role, expertise):
    """Create role-based prompt."""

Purpose: Create role-based prompt.

Parameters: – self: Instance reference – task: Parameter for task – role: Parameter for role – expertise: Parameter for expertise

execute_prompt (Line 103)
def execute_prompt(self, prompt, technique, system_message):
    """Execute prompt and return result."""

Purpose: Execute prompt and return result.

Parameters: – self: Instance reference – prompt: Parameter for prompt – technique: Parameter for technique – system_message: Parameter for system_message

register_template (Line 128)
def register_template(self, template):
    """Register a reusable prompt template."""

Purpose: Register a reusable prompt template.

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

use_template (Line 132)
def use_template(self, template_name):
    """Use a registered template with variables."""

Purpose: Use a registered template with variables.

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

PromptEngineeringPattern (Line 156)

Description: Prompt Engineering Pattern – Systematic prompt design and optimization.

Provides multiple techniques for crafting effective prompts including zero-shot, few-shot, chain-of-thought, and role-based prompting.

Methods:

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

zero_shot (Line 168)
def zero_shot(self, task, context):
    """Execute zero-shot prompting."""

Purpose: Execute zero-shot prompting.

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

few_shot (Line 175)
def few_shot(self, task, examples):
    """Execute few-shot prompting."""

Purpose: Execute few-shot prompting.

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

chain_of_thought (Line 182)
def chain_of_thought(self, task):
    """Execute chain-of-thought prompting."""

Purpose: Execute chain-of-thought prompting.

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

role_based (Line 193)
def role_based(self, task, role, expertise):
    """Execute role-based prompting."""

Purpose: Execute role-based prompting.

Parameters: – self: Instance reference – task: Parameter for task – role: Parameter for role – expertise: Parameter for expertise

create_template (Line 200)
def create_template(self, name, technique, system_message, user_template, variables):
    """Create and register a prompt template."""

Purpose: Create and register a prompt template.

Parameters: – self: Instance reference – name: Identifier or label – technique: Parameter for technique – system_message: Parameter for system_message – user_template: Parameter for user_template – variables: Parameter for variables

get_statistics (Line 216)
def get_statistics(self):
    """Get usage statistics."""

Purpose: Get usage 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 = PromptTechnique(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 *