Tag: artificial-intelligence

  • Agentic Design Pattern: Polyglot Agent

    
        """
    Pattern 135: Polyglot Agent
    
    Description:
        The Polyglot Agent pattern creates agents capable of understanding and
        generating content in multiple languages. Unlike single-language agents,
        polyglot agents can seamlessly switch between languages, translate content,
        detect language automatically, and maintain context across language boundaries.
        They understand cultural nuances, idioms, and context-specific language usage.
        
        Polyglot agents are essential for global applications where users speak different
        languages, content needs translation, or multilingual support is required. They
        go beyond simple translation to understand context, maintain consistency across
        languages, and adapt tone appropriately for different cultures.
        
        This pattern enables truly global AI applications that can serve users in their
        native languages while maintaining quality and coherence across all interactions.
    
    Key Components:
        1. Language Detection: Automatic language identification
        2. Translation Engine: High-quality translation
        3. Context Preservation: Maintain meaning across languages
        4. Cultural Adaptation: Culturally appropriate responses
        5. Language Memory: Track language preferences
        6. Multilingual Knowledge: Language-specific information
        7. Quality Validation: Translation accuracy checks
    
    Language Capabilities:
        1. Detection: Identify input language
        2. Translation: Convert between languages
        3. Generation: Create content in any language
        4. Code-Switching: Handle mixed-language input
        5. Localization: Adapt to regional variants
        6. Transcreation: Culturally adapt content
        7. Validation: Check translation quality
    
    Supported Features:
        1. Multiple Languages: Support for many languages
        2. Automatic Detection: Identify language without prompting
        3. Context Awareness: Understand conversation flow
        4. Cultural Sensitivity: Respect cultural differences
        5. Consistent Terminology: Maintain vocabulary across languages
        6. Bidirectional: Handle any language pair
        7. Real-time: Fast language processing
    
    Use Cases:
        - Global customer support
        - Multilingual content generation
        - International e-commerce
        - Language learning applications
        - Global documentation
        - Multilingual chatbots
        - International business communication
        - Content localization
    
    Advantages:
        - Global reach
        - Better user experience
        - Market expansion
        - Cultural inclusivity
        - Reduced translation costs
        - Real-time multilingual support
        - Consistent brand voice
    
    Challenges:
        - Translation accuracy
        - Cultural nuances
        - Idiom handling
        - Context preservation
        - Language model quality
        - Regional variations
        - Technical terminology
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Language detection
        - Translation chains
        - Multilingual generation
        - Context tracking
        
    Production Considerations:
        - Support major languages first
        - Provide human translation fallback
        - Track translation quality
        - Handle rare languages gracefully
        - Cache common translations
        - Monitor language coverage
        - Respect regional preferences
        - Enable language selection override
    """
    
    import os
    from typing import List, Dict, Any, Optional, Tuple
    from dataclasses import dataclass, field
    from datetime import datetime
    from enum import Enum
    from dotenv import load_dotenv
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    from langchain_openai import ChatOpenAI
    
    load_dotenv()
    
    
    class Language(Enum):
        """Supported languages."""
        ENGLISH = "en"
        SPANISH = "es"
        FRENCH = "fr"
        GERMAN = "de"
        ITALIAN = "it"
        PORTUGUESE = "pt"
        RUSSIAN = "ru"
        JAPANESE = "ja"
        KOREAN = "ko"
        CHINESE = "zh"
        ARABIC = "ar"
        HINDI = "hi"
        UNKNOWN = "unknown"
    
    
    @dataclass
    class LanguagePreference:
        """
        User language preferences.
        
        Attributes:
            primary_language: Main language
            secondary_languages: Alternative languages
            regional_variant: Regional dialect (e.g., en-US, en-GB)
            formality_level: Formal or informal
        """
        primary_language: Language
        secondary_languages: List[Language] = field(default_factory=list)
        regional_variant: Optional[str] = None
        formality_level: str = "neutral"
    
    
    @dataclass
    class MultilingualMessage:
        """
        Message with language information.
        
        Attributes:
            message_id: Unique identifier
            content: Message content
            detected_language: Detected language
            target_language: Desired output language
            translation: Translated content if applicable
            confidence: Language detection confidence
            timestamp: When created
        """
        message_id: str
        content: str
        detected_language: Language
        target_language: Optional[Language] = None
        translation: Optional[str] = None
        confidence: float = 0.0
        timestamp: datetime = field(default_factory=datetime.now)
    
    
    class PolyglotAgent:
        """
        Agent with multilingual capabilities.
        
        This agent can understand and generate content in multiple
        languages with context preservation and cultural awareness.
        """
        
        def __init__(self, temperature: float = 0.5):
            """
            Initialize polyglot agent.
            
            Args:
                temperature: LLM temperature
            """
            self.llm = ChatOpenAI(temperature=temperature, model="gpt-3.5-turbo")
            self.conversation_history: List[MultilingualMessage] = []
            self.message_counter = 0
            self.user_preferences: Dict[str, LanguagePreference] = {}
            
            # Common phrases in different languages for detection
            self.language_patterns = {
                Language.ENGLISH: ["hello", "thank you", "please", "the", "is", "are"],
                Language.SPANISH: ["hola", "gracias", "por favor", "el", "la", "es"],
                Language.FRENCH: ["bonjour", "merci", "s'il vous plaƮt", "le", "la", "est"],
                Language.GERMAN: ["hallo", "danke", "bitte", "der", "die", "ist"],
                Language.ITALIAN: ["ciao", "grazie", "per favore", "il", "la", "ĆØ"],
                Language.PORTUGUESE: ["olĆ”", "obrigado", "por favor", "o", "a", "Ć©"],
            }
        
        def detect_language(self, text: str) -> Tuple[Language, float]:
            """
            Detect language of text.
            
            Args:
                text: Input text
                
            Returns:
                Detected language and confidence
            """
            text_lower = text.lower()
            
            # Simple pattern matching for demo
            language_scores = {}
            for language, patterns in self.language_patterns.items():
                score = sum(1 for pattern in patterns if pattern in text_lower)
                if score > 0:
                    language_scores[language] = score
            
            if language_scores:
                detected = max(language_scores, key=language_scores.get)
                max_score = language_scores[detected]
                confidence = min(0.9, max_score / len(self.language_patterns[detected]))
                return detected, confidence
            
            # Fallback to LLM detection
            prompt = ChatPromptTemplate.from_template(
                "Detect the language of this text: \"{text}\"\n\n"
                "Respond with just the language code (en, es, fr, de, it, pt, ru, ja, ko, zh, ar, hi)"
            )
            
            chain = prompt | self.llm | StrOutputParser()
            result = chain.invoke({"text": text})
            
            # Map result to Language enum
            code = result.strip().lower()[:2]
            for lang in Language:
                if lang.value == code:
                    return lang, 0.7
            
            return Language.UNKNOWN, 0.3
        
        def translate(
            self,
            text: str,
            source_language: Language,
            target_language: Language,
            context: Optional[str] = None
        ) -> str:
            """
            Translate text between languages.
            
            Args:
                text: Text to translate
                source_language: Source language
                target_language: Target language
                context: Optional context
                
            Returns:
                Translated text
            """
            if source_language == target_language:
                return text
            
            prompt_template = (
                "Translate the following text from {source} to {target}.\n"
            )
            
            if context:
                prompt_template += "Context: {context}\n"
            
            prompt_template += (
                "Maintain the tone, meaning, and cultural appropriateness.\n\n"
                "Text: {text}\n\n"
                "Translation:"
            )
            
            prompt = ChatPromptTemplate.from_template(prompt_template)
            chain = prompt | self.llm | StrOutputParser()
            
            input_data = {
                "text": text,
                "source": source_language.name,
                "target": target_language.name
            }
            
            if context:
                input_data["context"] = context
            
            translation = chain.invoke(input_data)
            return translation.strip()
        
        def respond(
            self,
            user_input: str,
            target_language: Optional[Language] = None,
            user_id: Optional[str] = None
        ) -> str:
            """
            Respond to user in appropriate language.
            
            Args:
                user_input: User's message
                target_language: Desired response language (auto-detect if None)
                user_id: User identifier for preferences
                
            Returns:
                Response in target language
            """
            # Detect input language
            detected_lang, confidence = self.detect_language(user_input)
            
            # Determine target language
            if target_language is None:
                # Check user preferences
                if user_id and user_id in self.user_preferences:
                    target_language = self.user_preferences[user_id].primary_language
                else:
                    # Default to input language
                    target_language = detected_lang
            
            # Store message
            self.message_counter += 1
            message = MultilingualMessage(
                message_id=f"msg_{self.message_counter}",
                content=user_input,
                detected_language=detected_lang,
                target_language=target_language,
                confidence=confidence
            )
            self.conversation_history.append(message)
            
            # Generate response
            prompt = ChatPromptTemplate.from_template(
                "Respond to this message in {target_language}:\n\n"
                "User message: {user_input}\n"
                "(Detected language: {detected_language})\n\n"
                "Provide a helpful response in {target_language}, maintaining "
                "appropriate cultural context and tone."
            )
            
            chain = prompt | self.llm | StrOutputParser()
            
            response = chain.invoke({
                "user_input": user_input,
                "target_language": target_language.name,
                "detected_language": detected_lang.name
            })
            
            return response
        
        def set_user_preference(self, user_id: str, preference: LanguagePreference):
            """Set language preferences for a user."""
            self.user_preferences[user_id] = preference
        
        def handle_mixed_language(self, text: str) -> Dict[str, Any]:
            """
            Handle text with multiple languages (code-switching).
            
            Args:
                text: Mixed-language text
                
            Returns:
                Analysis of language segments
            """
            prompt = ChatPromptTemplate.from_template(
                "This text contains multiple languages:\n\n"
                "\"{text}\"\n\n"
                "Identify the languages used and provide:\n"
                "1. List of languages detected\n"
                "2. Dominant language\n"
                "3. Translation to English if needed"
            )
            
            chain = prompt | self.llm | StrOutputParser()
            analysis = chain.invoke({"text": text})
            
            return {
                "original_text": text,
                "analysis": analysis
            }
        
        def localize_content(
            self,
            content: str,
            target_language: Language,
            region: Optional[str] = None
        ) -> str:
            """
            Localize content for specific language and region.
            
            Args:
                content: Content to localize
                target_language: Target language
                region: Regional variant (e.g., US, UK, BR)
                
            Returns:
                Localized content
            """
            prompt_template = (
                "Localize this content for {target_language}"
            )
            
            if region:
                prompt_template += " ({region} region)"
            
            prompt_template += (
                ".\n\n"
                "Original content:\n"
                "{content}\n\n"
                "Adapt idioms, cultural references, units, dates, and formats "
                "to be appropriate for the target audience.\n\n"
                "Localized content:"
            )
            
            prompt = ChatPromptTemplate.from_template(prompt_template)
            chain = prompt | self.llm | StrOutputParser()
            
            input_data = {
                "content": content,
                "target_language": target_language.name
            }
            
            if region:
                input_data["region"] = region
            
            localized = chain.invoke(input_data)
            return localized.strip()
        
        def get_language_statistics(self) -> Dict[str, Any]:
            """Get statistics about language usage."""
            if not self.conversation_history:
                return {
                    "total_messages": 0,
                    "languages_detected": [],
                    "most_common": None
                }
            
            language_counts = {}
            for msg in self.conversation_history:
                lang = msg.detected_language
                language_counts[lang] = language_counts.get(lang, 0) + 1
            
            most_common = max(language_counts, key=language_counts.get) if language_counts else None
            
            return {
                "total_messages": len(self.conversation_history),
                "languages_detected": list(language_counts.keys()),
                "language_distribution": {lang.name: count for lang, count in language_counts.items()},
                "most_common": most_common.name if most_common else None
            }
    
    
    def demonstrate_polyglot():
        """Demonstrate polyglot agent pattern."""
        
        print("=" * 80)
        print("POLYGLOT AGENT PATTERN DEMONSTRATION")
        print("=" * 80)
        
        agent = PolyglotAgent()
        
        # Example 1: Language detection
        print("\n" + "=" * 80)
        print("Example 1: Automatic Language Detection")
        print("=" * 80)
        
        test_phrases = [
            "Hello, how are you?",
            "Hola, ¿cómo estÔs?",
            "Bonjour, comment allez-vous?",
            "Hallo, wie geht es dir?",
            "Ciao, come stai?"
        ]
        
        print("\nDetecting languages:")
        for phrase in test_phrases:
            detected, confidence = agent.detect_language(phrase)
            print(f'\n"{phrase}"')
            print(f"  → Language: {detected.name} (confidence: {confidence:.2f})")
        
        # Example 2: Translation
        print("\n" + "=" * 80)
        print("Example 2: Translation Between Languages")
        print("=" * 80)
        
        original = "I love learning new languages!"
        source = Language.ENGLISH
        targets = [Language.SPANISH, Language.FRENCH, Language.GERMAN]
        
        print(f"\nOriginal ({source.name}): {original}")
        print("\nTranslations:")
        
        for target in targets:
            translation = agent.translate(original, source, target)
            print(f"  {target.name}: {translation}")
        
        # Example 3: Multilingual conversation
        print("\n" + "=" * 80)
        print("Example 3: Multilingual Conversation")
        print("=" * 80)
        
        print("\nConversation with automatic language switching:")
        
        messages = [
            ("Hello! Can you help me?", None),
            ("Sí, ¿en qué puedo ayudarte?", Language.SPANISH),
            ("Thanks! Do you speak French too?", Language.ENGLISH)
        ]
        
        for msg, target_lang in messages:
            detected, conf = agent.detect_language(msg)
            print(f'\nUser ({detected.name}): {msg}')
            response = agent.respond(msg, target_language=target_lang)
            print(f'Agent: {response}')
        
        # Example 4: User language preferences
        print("\n" + "=" * 80)
        print("Example 4: User Language Preferences")
        print("=" * 80)
        
        # Set preference for user
        user_pref = LanguagePreference(
            primary_language=Language.SPANISH,
            secondary_languages=[Language.ENGLISH],
            regional_variant="es-MX",
            formality_level="formal"
        )
        
        agent.set_user_preference("user123", user_pref)
        
        print("\nUser Preference Set:")
        print(f"  Primary: {user_pref.primary_language.name}")
        print(f"  Variant: {user_pref.regional_variant}")
        print(f"  Formality: {user_pref.formality_level}")
        
        print("\nUser sends message in English:")
        user_msg = "What's the weather like?"
        print(f'User: {user_msg}')
        
        response = agent.respond(user_msg, user_id="user123")
        print(f'Agent (responds in Spanish): {response}')
        
        # Example 5: Code-switching handling
        print("\n" + "=" * 80)
        print("Example 5: Handling Code-Switching")
        print("=" * 80)
        
        mixed_text = "I went to the mercado to buy some lƩgumes and Brot"
        
        print(f'\nMixed-language text: "{mixed_text}"')
        print("(English + Spanish + French + German)")
        
        analysis = agent.handle_mixed_language(mixed_text)
        print("\nAnalysis:")
        print(analysis["analysis"])
        
        # Example 6: Content localization
        print("\n" + "=" * 80)
        print("Example 6: Content Localization")
        print("=" * 80)
        
        us_content = "The conference starts at 9 AM on 12/25. Temperature will be 72°F."
        
        print(f"\nOriginal (US English):")
        print(f"  {us_content}")
        
        print("\nLocalized versions:")
        
        # UK English
        uk_version = agent.localize_content(us_content, Language.ENGLISH, region="UK")
        print(f"\nUK English:")
        print(f"  {uk_version}")
        
        # Spanish (Mexico)
        mx_version = agent.localize_content(us_content, Language.SPANISH, region="MX")
        print(f"\nSpanish (Mexico):")
        print(f"  {mx_version}")
        
        # Example 7: Multilingual customer support
        print("\n" + "=" * 80)
        print("Example 7: Multilingual Customer Support")
        print("=" * 80)
        
        support_queries = [
            ("My order hasn't arrived yet", Language.ENGLISH),
            ("¿Dónde estÔ mi pedido?", Language.SPANISH),
            ("Je n'ai pas reƧu ma commande", Language.FRENCH)
        ]
        
        print("\nHandling support queries in multiple languages:")
        
        for query, response_lang in support_queries:
            detected, _ = agent.detect_language(query)
            print(f'\n[{detected.name}] Customer: {query}')
            response = agent.respond(query, target_language=response_lang)
            print(f'[{response_lang.name}] Agent: {response}')
        
        # Example 8: Language statistics
        print("\n" + "=" * 80)
        print("Example 8: Language Usage Statistics")
        print("=" * 80)
        
        stats = agent.get_language_statistics()
        
        print("\nLANGUAGE STATISTICS:")
        print("=" * 60)
        print(f"Total Messages: {stats['total_messages']}")
        print(f"\nLanguages Detected: {', '.join([lang.name for lang in stats['languages_detected']])}")
        
        if stats.get('language_distribution'):
            print("\nDistribution:")
            for lang, count in stats['language_distribution'].items():
                percentage = (count / stats['total_messages']) * 100
                print(f"  {lang}: {count} ({percentage:.1f}%)")
        
        print(f"\nMost Common: {stats['most_common']}")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY: Polyglot Agent Pattern")
        print("=" * 80)
        
        summary = """
        The Polyglot Agent pattern demonstrated:
        
        1. LANGUAGE DETECTION (Example 1):
           - Automatic identification
           - Confidence scoring
           - Multiple language support
           - Pattern recognition
           - Fallback mechanisms
        
        2. TRANSLATION (Example 2):
           - High-quality conversion
           - Context preservation
           - Multiple target languages
           - Tone maintenance
           - Cultural awareness
        
        3. MULTILINGUAL CONVERSATION (Example 3):
           - Seamless language switching
           - Context preservation
           - Natural flow
           - Automatic adaptation
           - Real-time processing
        
        4. USER PREFERENCES (Example 4):
           - Language preference storage
           - Regional variants
           - Formality levels
           - Automatic application
           - Personalization
        
        5. CODE-SWITCHING (Example 5):
           - Mixed-language handling
           - Language segment identification
           - Dominant language detection
           - Comprehensive translation
           - Context understanding
        
        6. LOCALIZATION (Example 6):
           - Regional adaptation
           - Cultural appropriateness
           - Unit conversion
           - Date format adjustment
           - Idiomatic expressions
        
        7. CUSTOMER SUPPORT (Example 7):
           - Multilingual queries
           - Appropriate responses
           - Language matching
           - Service quality
           - Global reach
        
        8. USAGE ANALYTICS (Example 8):
           - Language distribution
           - Usage patterns
           - Statistics tracking
           - Popular languages
           - Coverage analysis
        
        KEY BENEFITS:
        āœ“ Global reach
        āœ“ Better user experience
        āœ“ Market expansion
        āœ“ Cultural inclusivity
        āœ“ Reduced translation costs
        āœ“ Real-time support
        āœ“ Consistent quality
        āœ“ Wider accessibility
        
        USE CASES:
        • Global customer support
        • Multilingual content generation
        • International e-commerce
        • Language learning apps
        • Global documentation
        • Multilingual chatbots
        • Business communication
        • Content localization
        
        LANGUAGE CAPABILITIES:
        → Detection: Identify input language
        → Translation: Convert between languages
        → Generation: Create multilingual content
        → Code-Switching: Handle mixed languages
        → Localization: Regional adaptation
        → Transcreation: Cultural adaptation
        → Validation: Quality checking
        
        SUPPORTED FEATURES:
        • Multiple languages (10+)
        • Automatic detection
        • Context awareness
        • Cultural sensitivity
        • Consistent terminology
        • Bidirectional translation
        • Real-time processing
        
        BEST PRACTICES:
        1. Support major languages first
        2. Provide human translation fallback
        3. Track translation quality
        4. Handle rare languages gracefully
        5. Cache common translations
        6. Monitor language coverage
        7. Respect regional preferences
        8. Enable language override
        
        TRADE-OFFS:
        • Coverage vs. quality
        • Speed vs. accuracy
        • Automation vs. human review
        • Generalization vs. specialization
        
        PRODUCTION CONSIDERATIONS:
        → Prioritize high-traffic languages
        → Implement quality monitoring
        → Cache frequent translations
        → Provide confidence scores
        → Enable human escalation
        → Track accuracy metrics
        → Support regional variants
        → Handle cultural sensitivities
        → Maintain terminology consistency
        → Update language models regularly
        
        This pattern enables truly global AI applications that can serve users
        in their native languages while maintaining quality and cultural
        appropriateness across all interactions.
        """
        
        print(summary)
    
    
    if __name__ == "__main__":
        demonstrate_polyglot()
    
        

    Agentic Design Pattern: Polyglot Agent

    Pattern 135: Polyglot Agent – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Polyglot Agent pattern implementation.


    Pattern Description

    Pattern 135: Polyglot Agent

    Description: The Polyglot Agent pattern creates agents capable of understanding and generating content in multiple languages. Unlike single-language agents, polyglot agents can seamlessly switch between languages, translate content, detect language automatically, and maintain context across language boundaries. They understand cultural nuances, idioms, and context-specific language usage.

    Polyglot agents are essential for global applications where users speak different
    languages, content needs translation, or multilingual support is required. They
    go beyond simple translation to understand context, maintain consistency across
    languages, and adapt tone appropriately for different cultures.
    
    This pattern enables truly global AI applications that can serve users in their
    native languages while maintaining quality and coherence across all interactions.
    

    Key Components: 1. Language Detection: Automatic language identification 2. Translation Engine: High-quality translation 3. Context Preservation: Maintain meaning across languages 4. Cultural Adaptation: Culturally appropriate responses 5. Language Memory: Track language preferences 6. Multilingual Knowledge: Language-specific information 7. Quality Validation: Translation accuracy checks

    Language Capabilities: 1. Detection: Identify input language 2. Translation: Convert between languages 3. Generation: Create content in any language 4. Code-Switching: Handle mixed-language input 5. Localization: Adapt to regional variants 6. Transcreation: Culturally adapt content 7. Validation: Check translation quality

    Supported Features: 1. Multiple Languages: Support for many languages 2. Automatic Detection: Identify language without prompting 3. Context Awareness: Understand conversation flow 4. Cultural Sensitivity: Respect cultural differences 5. Consistent Terminology: Maintain vocabulary across languages 6. Bidirectional: Handle any language pair 7. Real-time: Fast language processing

    Use Cases: – Global customer support – Multilingual content generation – International e-commerce – Language learning applications – Global documentation – Multilingual chatbots – International business communication – Content localization

    Advantages: – Global reach – Better user experience – Market expansion – Cultural inclusivity – Reduced translation costs – Real-time multilingual support – Consistent brand voice

    Challenges: – Translation accuracy – Cultural nuances – Idiom handling – Context preservation – Language model quality – Regional variations – Technical terminology

    LangChain Implementation: This implementation uses LangChain for: – Language detection – Translation chains – Multilingual generation – Context tracking

    Production Considerations: – Support major languages first – Provide human translation fallback – Track translation quality – Handle rare languages gracefully – Cache common translations – Monitor language coverage – Respect regional preferences – Enable language selection override


    File Statistics

    • Total Lines: 751
    • Classes: 4
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 135: Polyglot Agent
    
    Description:
        The Polyglot Agent pattern creates agents capable of understanding and
        generating content in multiple languages. Unlike single-language agents,
        polyglot agents can seamlessly switch between languages, translate content,
        detect language automatically, and maintain context across language boundaries.
        They understand cultural nuances, idioms, and context-specific language usage.
    
        Polyglot agents are essential for global applications where users speak different
        languages, content needs translation, or multilingual support is required. They
        go beyond simple translation to understand context, maintain consistency across
        languages, and adapt tone appropriately for different cultures.
    
        This pattern enables truly global AI applications that can serve users in their
        native languages while maintaining quality and coherence across all interactions.
    
    Key Components:
        1. Language Detection: Automatic language identification
        2. Translation Engine: High-quality translation
        3. Context Preservation: Maintain meaning across languages
        4. Cultural Adaptation: Culturally appropriate responses
        5. Language Memory: Track language preferences
        6. Multilingual Knowledge: Language-specific information
        7. Quality Validation: Translation accuracy checks
    
    Language Capabilities:
        1. Detection: Identify input language
        2. Translation: Convert between languages
        3. Generation: Create content in any language
        4. Code-Switching: Handle mixed-language input
        5. Localization: Adapt to regional variants
        6. Transcreation: Culturally adapt content
        7. Validation: Check translation quality
    
    Supported Features:
        1. Multiple Languages: Support for many languages
        2. Automatic Detection: Identify language without prompting
        3. Context Awareness: Understand conversation flow
        4. Cultural Sensitivity: Respect cultural differences
        5. Consistent Terminology: Maintain vocabulary across languages
        6. Bidirectional: Handle any language pair
        7. Real-time: Fast language processing
    
    Use Cases:
        - Global customer support
        - Multilingual content generation
        - International e-commerce
        - Language learning applications
        - Global documentation
        - Multilingual chatbots
        - International business communication
        - Content localization
    
    Advantages:
        - Global reach
        - Better user experience
        - Market expansion
        - Cultural inclusivity
        - Reduced translation costs
        - Real-time multilingual support
        - Consistent brand voice
    
    Challenges:
        - Translation accuracy
        - Cultural nuances
        - Idiom handling
        - Context preservation
        - Language model quality
        - Regional variations
        - Technical terminology
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Language detection
        - Translation chains
        - Multilingual generation
        - Context tracking
    
    Production Considerations:
        - Support major languages first
        - Provide human translation fallback
        - Track translation quality
        - Handle rare languages gracefully
        - Cache common translations
        - Monitor language coverage
        - Respect regional preferences
        - Enable language selection override
    """
    

    Purpose: This module implements the Polyglot Agent pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import dataclasses.dataclass
    import dataclasses.field
    import datetime.datetime
    import enum.Enum
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import os
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    import typing.Tuple
    

    Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – enum.Enum: Enumeration support – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Tuple: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: Language

    Lines 106-120

    Inherits from: Enum

    Purpose:

    Supported languages.
    

    Class: LanguagePreference

    Lines 124-137

    Purpose:

    User language preferences.
    
    Attributes:
        primary_language: Main language
        secondary_languages: Alternative languages
        regional_variant: Regional dialect (e.g., en-US, en-GB)
        formality_level: Formal or informal
    

    Class: MultilingualMessage

    Lines 141-160

    Purpose:

    Message with language information.
    
    Attributes:
        message_id: Unique identifier
        content: Message content
        detected_language: Detected language
        target_language: Desired output language
        translation: Translated content if applicable
        confidence: Language detection confidence
        timestamp: When created
    

    Class: PolyglotAgent

    Lines 163-443

    Purpose:

    Agent with multilingual capabilities.
    
    This agent can understand and generate content in multiple
    languages with context preservation and cultural awareness.
    

    Methods:

    __init__(self, temperature)

    Lines 171-191

    Purpose:

    Initialize polyglot agent.
    
    Args:
        temperature: LLM temperature
    

    Parameters: – temperature: Sampling temperature (0-1)

    detect_language(self, text)

    Lines 193-233

    Purpose:

    Detect language of text.
    
    Args:
        text: Input text
    
    Returns:
        Detected language and confidence
    

    Parameters: – text: Text

    Returns: <ast.Subscript object at 0x000001A06D165BD0>

    translate(self, text, source_language, target_language, context)

    Lines 235-283

    Purpose:

    Translate text between languages.
    
    Args:
        text: Text to translate
        source_language: Source language
        target_language: Target language
        context: Optional context
    
    Returns:
        Translated text
    

    Parameters: – text: Text – source_language: Source language – target_language: Target language – context: Context

    Returns: str

    respond(self, user_input, target_language, user_id)

    Lines 285-342

    Purpose:

    Respond to user in appropriate language.
    
    Args:
        user_input: User's message
        target_language: Desired response language (auto-detect if None)
        user_id: User identifier for preferences
    
    Returns:
        Response in target language
    

    Parameters: – user_input: Input data – target_language: Target language – user_id: User id

    Returns: str

    set_user_preference(self, user_id, preference)

    Lines 344-346

    Purpose:

    Set language preferences for a user.
    

    Parameters: – user_id: User id – preference: Preference

    handle_mixed_language(self, text)

    Lines 348-373

    Purpose:

    Handle text with multiple languages (code-switching).
    
    Args:
        text: Mixed-language text
    
    Returns:
        Analysis of language segments
    

    Parameters: – text: Text

    Returns: <ast.Subscript object at 0x000001A06D85B7D0>

    localize_content(self, content, target_language, region)

    Lines 375-420

    Purpose:

    Localize content for specific language and region.
    
    Args:
        content: Content to localize
        target_language: Target language
        region: Regional variant (e.g., US, UK, BR)
    
    Returns:
        Localized content
    

    Parameters: – content: Content – target_language: Target language – region: Region

    Returns: str

    get_language_statistics(self)

    Lines 422-443

    Purpose:

    Get statistics about language usage.
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D7CB110>


    Functions

    demonstrate_polyglot()

    Lines 446-746

    Purpose:

    Demonstrate polyglot agent pattern.
    

    Key Concepts Summary

    Pattern Overview

    The Polyglot Agent pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 134
    • Pattern 136

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Polyglot Agent pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 135_polyglot_agent.py
    Total Lines: 751
    Pattern Category: AI Agent Design Pattern #135


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Task Specific

    
        """
    Pattern 134: Task-Specific Agent
    
    Description:
        The Task-Specific Agent pattern creates agents optimized for particular tasks
        or workflows. Unlike general-purpose agents or domain experts with broad knowledge,
        task-specific agents are highly specialized for executing specific operations with
        maximum efficiency and reliability. They have deep knowledge of task requirements,
        common pitfalls, optimization strategies, and best practices for their specific task.
        
        Task-specific agents excel at their designated task through specialized prompts,
        optimized workflows, task-specific tools, relevant examples, and failure handling
        tailored to common task issues. They sacrifice breadth for depth, becoming experts
        at their single task rather than generalists.
        
        This pattern is essential for production systems where certain tasks are performed
        repeatedly and require consistent, high-quality execution. Examples include data
        validation agents, report generation agents, code review agents, content moderation
        agents, and translation agents.
    
    Key Components:
        1. Task Definition: Clear specification of the task
        2. Optimized Workflow: Step-by-step task execution
        3. Task-Specific Tools: Specialized utilities
        4. Example Repository: Reference cases
        5. Validation Logic: Task-specific quality checks
        6. Error Handling: Common failure patterns
        7. Performance Metrics: Task success criteria
    
    Task Specialization:
        1. Single Responsibility: One task, done well
        2. Optimized Prompts: Tailored to task requirements
        3. Specialized Tools: Task-specific utilities
        4. Domain Knowledge: Deep task understanding
        5. Workflow Efficiency: Streamlined execution
        6. Error Recovery: Task-specific failure handling
        7. Quality Assurance: Task validation
    
    Task Categories:
        1. Data Processing: Validation, transformation, cleaning
        2. Content Generation: Reports, summaries, descriptions
        3. Analysis: Code review, sentiment analysis, quality assessment
        4. Transformation: Translation, format conversion, restructuring
        5. Validation: Compliance checking, verification, testing
        6. Interaction: Onboarding, support, guidance
        7. Monitoring: Alert processing, anomaly detection
    
    Use Cases:
        - Data validation and cleaning
        - Automated report generation
        - Code review and analysis
        - Content moderation
        - Language translation
        - Email response generation
        - Invoice processing
        - Resume screening
    
    Advantages:
        - Maximum task efficiency
        - Consistent quality
        - Deep task optimization
        - Reduced error rates
        - Fast execution
        - Reliable performance
        - Easy to test and validate
    
    Challenges:
        - Limited flexibility
        - Task scope creep
        - Adaptation to task changes
        - Over-optimization risk
        - Maintenance overhead
        - Integration complexity
        - Version management
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Task-optimized prompts
        - Specialized tool chains
        - Validation pipelines
        - Performance tracking
        
    Production Considerations:
        - Version task-specific agents
        - Monitor task success rates
        - Track execution time
        - Log validation failures
        - Implement rollback mechanisms
        - A/B test task variations
        - Collect user feedback
        - Maintain task documentation
    """
    
    import os
    from typing import List, Dict, Any, Optional, Callable
    from dataclasses import dataclass, field
    from datetime import datetime
    from enum import Enum
    from dotenv import load_dotenv
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    from langchain_openai import ChatOpenAI
    
    load_dotenv()
    
    
    class TaskStatus(Enum):
        """Task execution status."""
        PENDING = "pending"
        IN_PROGRESS = "in_progress"
        COMPLETED = "completed"
        FAILED = "failed"
        VALIDATED = "validated"
    
    
    class ValidationResult(Enum):
        """Validation outcome."""
        PASSED = "passed"
        FAILED = "failed"
        WARNING = "warning"
    
    
    @dataclass
    class TaskSpecification:
        """
        Specification for a task.
        
        Attributes:
            task_name: Name of the task
            description: Task description
            inputs: Required input fields
            outputs: Expected output fields
            validation_rules: Rules to validate outputs
            examples: Example inputs and outputs
            success_criteria: What defines success
            common_failures: Known failure patterns
        """
        task_name: str
        description: str
        inputs: List[str] = field(default_factory=list)
        outputs: List[str] = field(default_factory=list)
        validation_rules: List[str] = field(default_factory=list)
        examples: List[Dict[str, Any]] = field(default_factory=list)
        success_criteria: List[str] = field(default_factory=list)
        common_failures: List[str] = field(default_factory=list)
    
    
    @dataclass
    class TaskExecution:
        """
        Record of task execution.
        
        Attributes:
            execution_id: Unique identifier
            task_name: Name of executed task
            inputs: Input data
            outputs: Generated outputs
            status: Execution status
            validation: Validation results
            duration_seconds: Execution time
            errors: Any errors encountered
            timestamp: When executed
        """
        execution_id: str
        task_name: str
        inputs: Dict[str, Any]
        outputs: Dict[str, Any] = field(default_factory=dict)
        status: TaskStatus = TaskStatus.PENDING
        validation: Optional[ValidationResult] = None
        duration_seconds: float = 0.0
        errors: List[str] = field(default_factory=list)
        timestamp: datetime = field(default_factory=datetime.now)
    
    
    class TaskSpecificAgent:
        """
        Agent specialized for a specific task.
        
        This agent is optimized for executing a single task
        with maximum efficiency and reliability.
        """
        
        def __init__(
            self,
            task_spec: TaskSpecification,
            temperature: float = 0.3
        ):
            """
            Initialize task-specific agent.
            
            Args:
                task_spec: Task specification
                temperature: LLM temperature (lower for consistency)
            """
            self.task_spec = task_spec
            self.llm = ChatOpenAI(temperature=temperature, model="gpt-3.5-turbo")
            self.execution_history: List[TaskExecution] = []
            self.execution_counter = 0
        
        def _build_task_prompt(self, inputs: Dict[str, Any]) -> str:
            """Build optimized prompt for task."""
            prompt_parts = [
                f"Task: {self.task_spec.task_name}",
                f"Description: {self.task_spec.description}",
                ""
            ]
            
            # Add success criteria
            if self.task_spec.success_criteria:
                criteria = "\n".join([f"  - {c}" for c in self.task_spec.success_criteria])
                prompt_parts.append(f"Success Criteria:\n{criteria}\n")
            
            # Add examples
            if self.task_spec.examples:
                prompt_parts.append("Examples:")
                for i, example in enumerate(self.task_spec.examples[:2], 1):
                    prompt_parts.append(f"\nExample {i}:")
                    prompt_parts.append(f"  Input: {example.get('input', 'N/A')}")
                    prompt_parts.append(f"  Output: {example.get('output', 'N/A')}")
                prompt_parts.append("")
            
            # Add common failures to avoid
            if self.task_spec.common_failures:
                failures = "\n".join([f"  - {f}" for f in self.task_spec.common_failures])
                prompt_parts.append(f"Avoid These Common Mistakes:\n{failures}\n")
            
            # Add current input
            prompt_parts.append("Current Input:")
            for key, value in inputs.items():
                prompt_parts.append(f"  {key}: {value}")
            
            prompt_parts.append("\nExecute the task and provide the output:")
            
            return "\n".join(prompt_parts)
        
        def execute(self, inputs: Dict[str, Any]) -> TaskExecution:
            """
            Execute the task.
            
            Args:
                inputs: Task inputs
                
            Returns:
                Task execution record
            """
            self.execution_counter += 1
            execution = TaskExecution(
                execution_id=f"exec_{self.execution_counter}",
                task_name=self.task_spec.task_name,
                inputs=inputs,
                status=TaskStatus.IN_PROGRESS
            )
            
            start_time = datetime.now()
            
            try:
                # Build prompt
                task_prompt = self._build_task_prompt(inputs)
                
                # Execute task
                prompt = ChatPromptTemplate.from_template("{task_prompt}")
                chain = prompt | self.llm | StrOutputParser()
                
                output_text = chain.invoke({"task_prompt": task_prompt})
                
                # Parse outputs
                outputs = self._parse_output(output_text)
                execution.outputs = outputs
                execution.status = TaskStatus.COMPLETED
                
            except Exception as e:
                execution.status = TaskStatus.FAILED
                execution.errors.append(str(e))
            
            # Calculate duration
            execution.duration_seconds = (datetime.now() - start_time).total_seconds()
            
            # Store execution
            self.execution_history.append(execution)
            
            return execution
        
        def _parse_output(self, output_text: str) -> Dict[str, Any]:
            """Parse output from text response."""
            # Simple parsing - in production, use structured output
            outputs = {"raw_output": output_text}
            
            # Try to extract key-value pairs
            lines = output_text.split('\n')
            for line in lines:
                if ':' in line:
                    parts = line.split(':', 1)
                    if len(parts) == 2:
                        key = parts[0].strip().lower().replace(' ', '_')
                        value = parts[1].strip()
                        outputs[key] = value
            
            return outputs
        
        def validate(self, execution: TaskExecution) -> ValidationResult:
            """
            Validate task execution.
            
            Args:
                execution: Execution to validate
                
            Returns:
                Validation result
            """
            if execution.status != TaskStatus.COMPLETED:
                execution.validation = ValidationResult.FAILED
                return ValidationResult.FAILED
            
            # Check required outputs
            missing_outputs = []
            for required_output in self.task_spec.outputs:
                if required_output not in execution.outputs:
                    missing_outputs.append(required_output)
            
            if missing_outputs:
                execution.errors.append(f"Missing outputs: {missing_outputs}")
                execution.validation = ValidationResult.FAILED
                return ValidationResult.FAILED
            
            # Apply validation rules using LLM
            if self.task_spec.validation_rules:
                validation_prompt = (
                    f"Validate this task output:\n\n"
                    f"Task: {self.task_spec.task_name}\n"
                    f"Output: {execution.outputs}\n\n"
                    f"Validation Rules:\n"
                )
                for rule in self.task_spec.validation_rules:
                    validation_prompt += f"- {rule}\n"
                
                validation_prompt += "\nDoes the output pass validation? Respond with PASSED, FAILED, or WARNING."
                
                prompt = ChatPromptTemplate.from_template("{validation_prompt}")
                chain = prompt | self.llm | StrOutputParser()
                
                result_text = chain.invoke({"validation_prompt": validation_prompt})
                
                if "PASSED" in result_text.upper():
                    execution.validation = ValidationResult.PASSED
                    execution.status = TaskStatus.VALIDATED
                    return ValidationResult.PASSED
                elif "WARNING" in result_text.upper():
                    execution.validation = ValidationResult.WARNING
                    return ValidationResult.WARNING
                else:
                    execution.validation = ValidationResult.FAILED
                    return ValidationResult.FAILED
            
            # Default to passed if no rules
            execution.validation = ValidationResult.PASSED
            execution.status = TaskStatus.VALIDATED
            return ValidationResult.PASSED
        
        def execute_and_validate(self, inputs: Dict[str, Any]) -> TaskExecution:
            """Execute task and validate result."""
            execution = self.execute(inputs)
            self.validate(execution)
            return execution
        
        def get_performance_metrics(self) -> Dict[str, Any]:
            """Get task performance metrics."""
            if not self.execution_history:
                return {
                    "total_executions": 0,
                    "success_rate": 0.0,
                    "validation_rate": 0.0,
                    "avg_duration": 0.0
                }
            
            total = len(self.execution_history)
            completed = sum(1 for e in self.execution_history if e.status == TaskStatus.COMPLETED)
            validated = sum(1 for e in self.execution_history if e.validation == ValidationResult.PASSED)
            
            total_duration = sum(e.duration_seconds for e in self.execution_history)
            
            return {
                "total_executions": total,
                "success_rate": completed / total if total > 0 else 0.0,
                "validation_rate": validated / total if total > 0 else 0.0,
                "avg_duration": total_duration / total if total > 0 else 0.0,
                "task_name": self.task_spec.task_name
            }
    
    
    def demonstrate_task_specific():
        """Demonstrate task-specific agent pattern."""
        
        print("=" * 80)
        print("TASK-SPECIFIC AGENT PATTERN DEMONSTRATION")
        print("=" * 80)
        
        # Example 1: Email Response Task
        print("\n" + "=" * 80)
        print("Example 1: Email Response Generation Task")
        print("=" * 80)
        
        email_task = TaskSpecification(
            task_name="Customer Support Email Response",
            description="Generate professional customer support email responses",
            inputs=["customer_email", "issue_type", "customer_name"],
            outputs=["subject", "body", "tone"],
            validation_rules=[
                "Response must be polite and professional",
                "Must address the customer by name",
                "Must include a clear solution or next steps",
                "Must be under 200 words"
            ],
            examples=[
                {
                    "input": {
                        "customer_email": "My order hasn't arrived",
                        "issue_type": "shipping_delay",
                        "customer_name": "John"
                    },
                    "output": {
                        "subject": "Update on Your Order Status",
                        "body": "Dear John, I apologize for the delay...",
                        "tone": "empathetic and solution-focused"
                    }
                }
            ],
            success_criteria=[
                "Customer feels heard and valued",
                "Clear action items provided",
                "Professional tone maintained"
            ],
            common_failures=[
                "Being too formal or robotic",
                "Not acknowledging the customer's frustration",
                "Providing vague next steps"
            ]
        )
        
        email_agent = TaskSpecificAgent(email_task)
        
        print(f"\nTask: {email_task.task_name}")
        print(f"Description: {email_task.description}")
        print(f"Required Inputs: {', '.join(email_task.inputs)}")
        print(f"Expected Outputs: {', '.join(email_task.outputs)}")
        
        # Example 2: Execute task
        print("\n" + "=" * 80)
        print("Example 2: Task Execution")
        print("=" * 80)
        
        customer_input = {
            "customer_email": "I'm frustrated! My package was supposed to arrive 3 days ago!",
            "issue_type": "shipping_delay",
            "customer_name": "Sarah"
        }
        
        print("\nInput:")
        for key, value in customer_input.items():
            print(f"  {key}: {value}")
        
        execution = email_agent.execute(customer_input)
        
        print(f"\nExecution Status: {execution.status.value}")
        print(f"Duration: {execution.duration_seconds:.2f}s")
        print("\nGenerated Output:")
        for key, value in execution.outputs.items():
            if key != "raw_output":
                print(f"  {key}: {value}")
        
        # Example 3: Validation
        print("\n" + "=" * 80)
        print("Example 3: Output Validation")
        print("=" * 80)
        
        validation_result = email_agent.validate(execution)
        
        print(f"\nValidation Result: {validation_result.value}")
        print(f"Final Status: {execution.status.value}")
        
        if execution.errors:
            print(f"Errors: {execution.errors}")
        
        # Example 4: Data Validation Task
        print("\n" + "=" * 80)
        print("Example 4: Data Validation Task")
        print("=" * 80)
        
        validation_task = TaskSpecification(
            task_name="User Registration Data Validation",
            description="Validate user registration data for completeness and correctness",
            inputs=["email", "username", "age", "country"],
            outputs=["is_valid", "errors", "warnings"],
            validation_rules=[
                "Email must be valid format",
                "Username must be 3-20 characters",
                "Age must be 18 or older",
                "Country must be a valid country code"
            ],
            success_criteria=[
                "All validation rules checked",
                "Clear error messages provided",
                "Actionable feedback given"
            ],
            common_failures=[
                "Missing validation checks",
                "Vague error messages",
                "Not checking all fields"
            ]
        )
        
        validator_agent = TaskSpecificAgent(validation_task, temperature=0.1)
        
        print(f"\nTask: {validation_task.task_name}")
        
        # Valid data
        valid_data = {
            "email": "user@example.com",
            "username": "johndoe",
            "age": "25",
            "country": "US"
        }
        
        print("\nValidating Valid Data:")
        print(f"  {valid_data}")
        
        execution1 = validator_agent.execute_and_validate(valid_data)
        print(f"Result: {execution1.validation.value if execution1.validation else 'N/A'}")
        
        # Invalid data
        invalid_data = {
            "email": "not-an-email",
            "username": "ab",
            "age": "15",
            "country": "XYZ"
        }
        
        print("\nValidating Invalid Data:")
        print(f"  {invalid_data}")
        
        execution2 = validator_agent.execute_and_validate(invalid_data)
        print(f"Result: {execution2.validation.value if execution2.validation else 'N/A'}")
        
        # Example 5: Code Review Task
        print("\n" + "=" * 80)
        print("Example 5: Code Review Task")
        print("=" * 80)
        
        code_review_task = TaskSpecification(
            task_name="Python Code Review",
            description="Review Python code for quality, security, and best practices",
            inputs=["code", "context"],
            outputs=["issues", "suggestions", "severity", "approval"],
            validation_rules=[
                "Must identify security issues",
                "Must check for best practices",
                "Must provide actionable feedback"
            ],
            success_criteria=[
                "All major issues identified",
                "Suggestions are specific",
                "Severity levels assigned"
            ]
        )
        
        reviewer_agent = TaskSpecificAgent(code_review_task)
        
        code_sample = """
    def process_user_input(input):
        result = eval(input)  # Security issue!
        return result
    """
        
        print(f"\nReviewing Code:")
        print(code_sample)
        
        review_execution = reviewer_agent.execute({
            "code": code_sample,
            "context": "User input processing function"
        })
        
        print(f"\nReview Status: {review_execution.status.value}")
        print("Review Output:")
        print(review_execution.outputs.get("raw_output", "No output")[:500])
        
        # Example 6: Performance metrics
        print("\n" + "=" * 80)
        print("Example 6: Task Performance Metrics")
        print("=" * 80)
        
        # Execute multiple tasks
        test_inputs = [
            {"customer_email": "Test 1", "issue_type": "general", "customer_name": "User1"},
            {"customer_email": "Test 2", "issue_type": "technical", "customer_name": "User2"},
            {"customer_email": "Test 3", "issue_type": "billing", "customer_name": "User3"}
        ]
        
        for inputs in test_inputs:
            email_agent.execute_and_validate(inputs)
        
        metrics = email_agent.get_performance_metrics()
        
        print("\nPERFORMANCE METRICS:")
        print("=" * 60)
        print(f"Task: {metrics['task_name']}")
        print(f"Total Executions: {metrics['total_executions']}")
        print(f"Success Rate: {metrics['success_rate']:.1%}")
        print(f"Validation Rate: {metrics['validation_rate']:.1%}")
        print(f"Average Duration: {metrics['avg_duration']:.2f}s")
        
        # Example 7: Translation Task
        print("\n" + "=" * 80)
        print("Example 7: Translation Task")
        print("=" * 80)
        
        translation_task = TaskSpecification(
            task_name="English to Spanish Translation",
            description="Translate English text to Spanish maintaining tone and context",
            inputs=["english_text", "context"],
            outputs=["spanish_text", "confidence"],
            validation_rules=[
                "Translation must preserve meaning",
                "Must maintain appropriate tone",
                "Must be grammatically correct"
            ],
            success_criteria=[
                "Accurate translation",
                "Natural Spanish phrasing",
                "Context-appropriate"
            ]
        )
        
        translator = TaskSpecificAgent(translation_task)
        
        translation_input = {
            "english_text": "Hello, how can I help you today?",
            "context": "Customer service greeting"
        }
        
        print("\nTranslation Input:")
        print(f"  Text: {translation_input['english_text']}")
        print(f"  Context: {translation_input['context']}")
        
        translation_result = translator.execute_and_validate(translation_input)
        print(f"\nTranslation Status: {translation_result.status.value}")
        print("Translation Output:")
        for key, value in translation_result.outputs.items():
            if key != "raw_output":
                print(f"  {key}: {value}")
        
        # Example 8: Summary task
        print("\n" + "=" * 80)
        print("Example 8: Task Agent Summary")
        print("=" * 80)
        
        print("\nDEPLOYED TASK-SPECIFIC AGENTS:")
        print("=" * 60)
        
        agents_summary = [
            ("Email Response", email_agent),
            ("Data Validation", validator_agent),
            ("Code Review", reviewer_agent),
            ("Translation", translator)
        ]
        
        for name, agent in agents_summary:
            metrics = agent.get_performance_metrics()
            print(f"\n{name}:")
            print(f"  Executions: {metrics['total_executions']}")
            print(f"  Success Rate: {metrics['success_rate']:.1%}")
            print(f"  Avg Duration: {metrics['avg_duration']:.2f}s")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY: Task-Specific Agent Pattern")
        print("=" * 80)
        
        summary = """
        The Task-Specific Agent pattern demonstrated:
        
        1. TASK SPECIALIZATION (Example 1):
           - Single-purpose agents
           - Optimized for specific tasks
           - Task-specific prompts
           - Validation rules
           - Success criteria
           - Common failure awareness
        
        2. TASK EXECUTION (Example 2):
           - Optimized workflow
           - Input processing
           - Output generation
           - Performance tracking
           - Status monitoring
        
        3. OUTPUT VALIDATION (Example 3):
           - Rule-based validation
           - Required output checking
           - Quality assurance
           - Error detection
           - Validation feedback
        
        4. DATA VALIDATION TASK (Example 4):
           - Field validation
           - Format checking
           - Business rule enforcement
           - Error reporting
           - Actionable feedback
        
        5. CODE REVIEW TASK (Example 5):
           - Security analysis
           - Best practice checking
           - Issue identification
           - Severity assessment
           - Specific suggestions
        
        6. PERFORMANCE TRACKING (Example 6):
           - Execution metrics
           - Success rates
           - Duration monitoring
           - Quality metrics
           - Continuous improvement
        
        7. TRANSLATION TASK (Example 7):
           - Language conversion
           - Context preservation
           - Tone maintenance
           - Accuracy validation
           - Confidence scoring
        
        8. MULTI-TASK DEPLOYMENT (Example 8):
           - Multiple specialized agents
           - Independent optimization
           - Performance comparison
           - Resource allocation
           - System overview
        
        KEY BENEFITS:
        āœ“ Maximum task efficiency
        āœ“ Consistent quality
        āœ“ Deep optimization
        āœ“ Reduced errors
        āœ“ Fast execution
        āœ“ Reliable performance
        āœ“ Easy testing
        āœ“ Clear metrics
        
        USE CASES:
        • Data validation and cleaning
        • Automated report generation
        • Code review and analysis
        • Content moderation
        • Language translation
        • Email response generation
        • Invoice processing
        • Resume screening
        
        TASK CATEGORIES:
        → Data Processing: Validation, transformation
        → Content Generation: Reports, summaries
        → Analysis: Code review, quality assessment
        → Transformation: Translation, conversion
        → Validation: Compliance, verification
        → Interaction: Support, guidance
        → Monitoring: Alerts, anomaly detection
        
        SPECIALIZATION ASPECTS:
        • Single responsibility principle
        • Optimized prompts
        • Specialized tools
        • Domain knowledge
        • Workflow efficiency
        • Error recovery
        • Quality assurance
        
        BEST PRACTICES:
        1. Define clear task boundaries
        2. Optimize for single task
        3. Include comprehensive examples
        4. Implement thorough validation
        5. Track performance metrics
        6. Handle common failures
        7. Version control task specs
        8. Document expected behaviors
        
        TRADE-OFFS:
        • Specialization vs. flexibility
        • Efficiency vs. adaptability
        • Depth vs. breadth
        • Optimization vs. generalization
        
        PRODUCTION CONSIDERATIONS:
        → Version task agents independently
        → Monitor success rates per task
        → Track execution times
        → Log validation failures
        → Implement rollback capabilities
        → A/B test task variations
        → Collect user feedback
        → Maintain task documentation
        → Set performance SLAs
        → Enable task composition
        
        This pattern enables highly efficient, reliable execution of specific tasks
        by sacrificing generality for optimization, resulting in production-grade
        agents that excel at their designated operations.
        """
        
        print(summary)
    
    
    if __name__ == "__main__":
        demonstrate_task_specific()
    
        

    Agentic Design Pattern: Task Specific

    Pattern 134: Task Specific – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Task Specific pattern implementation.


    Pattern Description

    Pattern 134: Task-Specific Agent

    Description: The Task-Specific Agent pattern creates agents optimized for particular tasks or workflows. Unlike general-purpose agents or domain experts with broad knowledge, task-specific agents are highly specialized for executing specific operations with maximum efficiency and reliability. They have deep knowledge of task requirements, common pitfalls, optimization strategies, and best practices for their specific task.

    Task-specific agents excel at their designated task through specialized prompts,
    optimized workflows, task-specific tools, relevant examples, and failure handling
    tailored to common task issues. They sacrifice breadth for depth, becoming experts
    at their single task rather than generalists.
    
    This pattern is essential for production systems where certain tasks are performed
    repeatedly and require consistent, high-quality execution. Examples include data
    validation agents, report generation agents, code review agents, content moderation
    agents, and translation agents.
    

    Key Components: 1. Task Definition: Clear specification of the task 2. Optimized Workflow: Step-by-step task execution 3. Task-Specific Tools: Specialized utilities 4. Example Repository: Reference cases 5. Validation Logic: Task-specific quality checks 6. Error Handling: Common failure patterns 7. Performance Metrics: Task success criteria

    Task Specialization: 1. Single Responsibility: One task, done well 2. Optimized Prompts: Tailored to task requirements 3. Specialized Tools: Task-specific utilities 4. Domain Knowledge: Deep task understanding 5. Workflow Efficiency: Streamlined execution 6. Error Recovery: Task-specific failure handling 7. Quality Assurance: Task validation

    Task Categories: 1. Data Processing: Validation, transformation, cleaning 2. Content Generation: Reports, summaries, descriptions 3. Analysis: Code review, sentiment analysis, quality assessment 4. Transformation: Translation, format conversion, restructuring 5. Validation: Compliance checking, verification, testing 6. Interaction: Onboarding, support, guidance 7. Monitoring: Alert processing, anomaly detection

    Use Cases: – Data validation and cleaning – Automated report generation – Code review and analysis – Content moderation – Language translation – Email response generation – Invoice processing – Resume screening

    Advantages: – Maximum task efficiency – Consistent quality – Deep task optimization – Reduced error rates – Fast execution – Reliable performance – Easy to test and validate

    Challenges: – Limited flexibility – Task scope creep – Adaptation to task changes – Over-optimization risk – Maintenance overhead – Integration complexity – Version management

    LangChain Implementation: This implementation uses LangChain for: – Task-optimized prompts – Specialized tool chains – Validation pipelines – Performance tracking

    Production Considerations: – Version task-specific agents – Monitor task success rates – Track execution time – Log validation failures – Implement rollback mechanisms – A/B test task variations – Collect user feedback – Maintain task documentation


    File Statistics

    • Total Lines: 814
    • Classes: 5
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 134: Task-Specific Agent
    
    Description:
        The Task-Specific Agent pattern creates agents optimized for particular tasks
        or workflows. Unlike general-purpose agents or domain experts with broad knowledge,
        task-specific agents are highly specialized for executing specific operations with
        maximum efficiency and reliability. They have deep knowledge of task requirements,
        common pitfalls, optimization strategies, and best practices for their specific task.
    
        Task-specific agents excel at their designated task through specialized prompts,
        optimized workflows, task-specific tools, relevant examples, and failure handling
        tailored to common task issues. They sacrifice breadth for depth, becoming experts
        at their single task rather than generalists.
    
        This pattern is essential for production systems where certain tasks are performed
        repeatedly and require consistent, high-quality execution. Examples include data
        validation agents, report generation agents, code review agents, content moderation
        agents, and translation agents.
    
    Key Components:
        1. Task Definition: Clear specification of the task
        2. Optimized Workflow: Step-by-step task execution
        3. Task-Specific Tools: Specialized utilities
        4. Example Repository: Reference cases
        5. Validation Logic: Task-specific quality checks
        6. Error Handling: Common failure patterns
        7. Performance Metrics: Task success criteria
    
    Task Specialization:
        1. Single Responsibility: One task, done well
        2. Optimized Prompts: Tailored to task requirements
        3. Specialized Tools: Task-specific utilities
        4. Domain Knowledge: Deep task understanding
        5. Workflow Efficiency: Streamlined execution
        6. Error Recovery: Task-specific failure handling
        7. Quality Assurance: Task validation
    
    Task Categories:
        1. Data Processing: Validation, transformation, cleaning
        2. Content Generation: Reports, summaries, descriptions
        3. Analysis: Code review, sentiment analysis, quality assessment
        4. Transformation: Translation, format conversion, restructuring
        5. Validation: Compliance checking, verification, testing
        6. Interaction: Onboarding, support, guidance
        7. Monitoring: Alert processing, anomaly detection
    
    Use Cases:
        - Data validation and cleaning
        - Automated report generation
        - Code review and analysis
        - Content moderation
        - Language translation
        - Email response generation
        - Invoice processing
        - Resume screening
    
    Advantages:
        - Maximum task efficiency
        - Consistent quality
        - Deep task optimization
        - Reduced error rates
        - Fast execution
        - Reliable performance
        - Easy to test and validate
    
    Challenges:
        - Limited flexibility
        - Task scope creep
        - Adaptation to task changes
        - Over-optimization risk
        - Maintenance overhead
        - Integration complexity
        - Version management
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Task-optimized prompts
        - Specialized tool chains
        - Validation pipelines
        - Performance tracking
    
    Production Considerations:
        - Version task-specific agents
        - Monitor task success rates
        - Track execution time
        - Log validation failures
        - Implement rollback mechanisms
        - A/B test task variations
        - Collect user feedback
        - Maintain task documentation
    """
    

    Purpose: This module implements the Task Specific pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import dataclasses.dataclass
    import dataclasses.field
    import datetime.datetime
    import enum.Enum
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import os
    import typing.Any
    import typing.Callable
    import typing.Dict
    import typing.List
    import typing.Optional
    

    Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – enum.Enum: Enumeration support – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Callable: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: TaskStatus

    Lines 108-114

    Inherits from: Enum

    Purpose:

    Task execution status.
    

    Class: ValidationResult

    Lines 117-121

    Inherits from: Enum

    Purpose:

    Validation outcome.
    

    Class: TaskSpecification

    Lines 125-146

    Purpose:

    Specification for a task.
    
    Attributes:
        task_name: Name of the task
        description: Task description
        inputs: Required input fields
        outputs: Expected output fields
        validation_rules: Rules to validate outputs
        examples: Example inputs and outputs
        success_criteria: What defines success
        common_failures: Known failure patterns
    

    Class: TaskExecution

    Lines 150-173

    Purpose:

    Record of task execution.
    
    Attributes:
        execution_id: Unique identifier
        task_name: Name of executed task
        inputs: Input data
        outputs: Generated outputs
        status: Execution status
        validation: Validation results
        duration_seconds: Execution time
        errors: Any errors encountered
        timestamp: When executed
    

    Class: TaskSpecificAgent

    Lines 176-388

    Purpose:

    Agent specialized for a specific task.
    
    This agent is optimized for executing a single task
    with maximum efficiency and reliability.
    

    Methods:

    __init__(self, task_spec, temperature)

    Lines 184-199

    Purpose:

    Initialize task-specific agent.
    
    Args:
        task_spec: Task specification
        temperature: LLM temperature (lower for consistency)
    

    Parameters: – task_spec: Task spec – temperature: Sampling temperature (0-1)

    _build_task_prompt(self, inputs)

    Lines 201-235

    Purpose:

    Build optimized prompt for task.
    

    Parameters: – inputs: Input data

    Returns: str

    execute(self, inputs)

    Lines 237-282

    Purpose:

    Execute the task.
    
    Args:
        inputs: Task inputs
    
    Returns:
        Task execution record
    

    Parameters: – inputs: Input data

    Returns: TaskExecution

    _parse_output(self, output_text)

    Lines 284-299

    Purpose:

    Parse output from text response.
    

    Parameters: – output_text: Output text

    Returns: <ast.Subscript object at 0x000001A06D68DB90>

    validate(self, execution)

    Lines 301-358

    Purpose:

    Validate task execution.
    
    Args:
        execution: Execution to validate
    
    Returns:
        Validation result
    

    Parameters: – execution: Execution

    Returns: ValidationResult

    execute_and_validate(self, inputs)

    Lines 360-364

    Purpose:

    Execute task and validate result.
    

    Parameters: – inputs: Input data

    Returns: TaskExecution

    get_performance_metrics(self)

    Lines 366-388

    Purpose:

    Get task performance metrics.
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D7BA950>


    Functions

    demonstrate_task_specific()

    Lines 391-809

    Purpose:

    Demonstrate task-specific agent pattern.
    

    Key Concepts Summary

    Pattern Overview

    The Task Specific pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 133
    • Pattern 135

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Task Specific pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 134_task_specific.py
    Total Lines: 814
    Pattern Category: AI Agent Design Pattern #134


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Domain Expert

    
        """
    Pattern 133: Domain Expert Agent
    
    Description:
        The Domain Expert Agent pattern creates specialized agents with deep expertise
        in specific domains or fields. Unlike general-purpose agents, domain experts
        possess comprehensive knowledge, terminology, methodologies, and best practices
        specific to their area of specialization. They can provide expert-level advice,
        perform domain-specific reasoning, and apply specialized knowledge effectively.
        
        Domain expertise goes beyond simple knowledge retrieval - it includes understanding
        domain-specific workflows, recognizing patterns, applying heuristics, knowing
        what questions to ask, and understanding the nuances and edge cases within the
        domain. Expert agents can explain complex concepts using domain terminology,
        evaluate solutions using domain-specific criteria, and provide guidance that
        reflects years of accumulated expertise.
        
        This pattern is essential for applications requiring specialized knowledge such
        as medical diagnosis assistants, legal advisors, financial analysts, scientific
        research assistants, engineering consultants, and other professional AI systems.
    
    Key Components:
        1. Domain Knowledge Base: Comprehensive domain-specific information
        2. Terminology Handler: Domain-specific vocabulary and jargon
        3. Best Practices Repository: Field-standard methodologies
        4. Case History: Examples and precedents from the domain
        5. Reasoning Engine: Domain-specific logic and heuristics
        6. Validation System: Domain-appropriate quality checks
        7. Reference System: Citations and sources
    
    Domain Characteristics:
        1. Depth: Comprehensive coverage of specialized area
        2. Terminology: Field-specific vocabulary
        3. Methodology: Domain-standard approaches
        4. Context: Understanding of domain landscape
        5. Precedents: Historical cases and examples
        6. Standards: Industry regulations and best practices
        7. Boundaries: Knowing limits of expertise
    
    Expert Behaviors:
        1. Ask clarifying questions
        2. Identify missing information
        3. Consider edge cases
        4. Reference standards and regulations
        5. Explain reasoning process
        6. Acknowledge uncertainty
        7. Provide multiple perspectives
        8. Use appropriate terminology
    
    Use Cases:
        - Medical diagnosis assistants
        - Legal research and advisory
        - Financial analysis and planning
        - Engineering design consultation
        - Scientific research assistance
        - Tax preparation and planning
        - Architectural design
        - Software architecture advisory
    
    Advantages:
        - Expert-level guidance
        - Domain-appropriate reasoning
        - Specialized knowledge application
        - Professional terminology usage
        - Best practice adherence
        - Quality assurance
        - Credible advice
    
    Challenges:
        - Knowledge maintenance and updates
        - Handling edge cases
        - Avoiding overconfidence
        - Managing liability concerns
        - Balancing depth vs. accessibility
        - Keeping current with field changes
        - Regulatory compliance
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Domain knowledge integration
        - Expert reasoning chains
        - Specialized RAG with domain documents
        - Domain-specific validation
        
    Production Considerations:
        - Regularly update domain knowledge
        - Version control expert systems
        - Track expert vs. actual outcomes
        - Implement human expert review
        - Include disclaimers appropriately
        - Maintain audit trails
        - Ensure regulatory compliance
        - Support expert override mechanisms
    """
    
    import os
    from typing import List, Dict, Any, Optional, Tuple
    from dataclasses import dataclass, field
    from datetime import datetime
    from enum import Enum
    from dotenv import load_dotenv
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    from langchain_openai import ChatOpenAI
    
    load_dotenv()
    
    
    class ExpertiseLevel(Enum):
        """Level of expertise."""
        NOVICE = "novice"
        INTERMEDIATE = "intermediate"
        ADVANCED = "advanced"
        EXPERT = "expert"
        MASTER = "master"
    
    
    class ConfidenceLevel(Enum):
        """Confidence in response."""
        LOW = "low"
        MEDIUM = "medium"
        HIGH = "high"
        VERY_HIGH = "very_high"
    
    
    @dataclass
    class DomainKnowledge:
        """
        Domain-specific knowledge item.
        
        Attributes:
            topic: Knowledge area
            content: Information content
            source: Where knowledge came from
            reliability: How reliable (0-1)
            last_updated: When last verified
            tags: Categorization tags
        """
        topic: str
        content: str
        source: str = "expert_knowledge"
        reliability: float = 0.9
        last_updated: datetime = field(default_factory=datetime.now)
        tags: List[str] = field(default_factory=list)
    
    
    @dataclass
    class ExpertResponse:
        """
        Expert agent response.
        
        Attributes:
            answer: Main response
            confidence: Confidence level
            reasoning: Explanation of reasoning
            references: Supporting sources
            caveats: Important limitations or warnings
            follow_up_questions: Suggested clarifications
            alternatives: Alternative approaches
        """
        answer: str
        confidence: ConfidenceLevel
        reasoning: str = ""
        references: List[str] = field(default_factory=list)
        caveats: List[str] = field(default_factory=list)
        follow_up_questions: List[str] = field(default_factory=list)
        alternatives: List[str] = field(default_factory=list)
    
    
    @dataclass
    class DomainExpertise:
        """
        Definition of domain expertise.
        
        Attributes:
            domain_name: Name of domain
            description: Domain description
            expertise_areas: Specific areas of expertise
            methodologies: Standard approaches
            key_concepts: Important domain concepts
            terminology: Domain-specific vocabulary
            standards: Relevant standards and regulations
            common_issues: Frequently encountered problems
            best_practices: Field best practices
        """
        domain_name: str
        description: str
        expertise_areas: List[str] = field(default_factory=list)
        methodologies: List[str] = field(default_factory=list)
        key_concepts: Dict[str, str] = field(default_factory=dict)
        terminology: Dict[str, str] = field(default_factory=dict)
        standards: List[str] = field(default_factory=list)
        common_issues: List[str] = field(default_factory=list)
        best_practices: List[str] = field(default_factory=list)
    
    
    class DomainExpertAgent:
        """
        Agent with specialized domain expertise.
        
        This agent provides expert-level guidance in a specific domain,
        using specialized knowledge, terminology, and reasoning.
        """
        
        def __init__(
            self,
            expertise: DomainExpertise,
            expertise_level: ExpertiseLevel = ExpertiseLevel.EXPERT,
            temperature: float = 0.3
        ):
            """
            Initialize domain expert agent.
            
            Args:
                expertise: Domain expertise definition
                expertise_level: Level of expertise
                temperature: LLM temperature (lower for more consistent expert advice)
            """
            self.expertise = expertise
            self.expertise_level = expertise_level
            self.llm = ChatOpenAI(temperature=temperature, model="gpt-3.5-turbo")
            self.knowledge_base: List[DomainKnowledge] = []
            self.consultation_history: List[Dict[str, Any]] = []
        
        def _build_expert_context(self) -> str:
            """Build expert context for prompts."""
            context_parts = [
                f"You are a {self.expertise_level.value}-level expert in {self.expertise.domain_name}.",
                f"Domain: {self.expertise.description}",
            ]
            
            if self.expertise.expertise_areas:
                areas = ", ".join(self.expertise.expertise_areas)
                context_parts.append(f"Areas of expertise: {areas}")
            
            if self.expertise.methodologies:
                methods = ", ".join(self.expertise.methodologies)
                context_parts.append(f"Standard methodologies: {methods}")
            
            if self.expertise.standards:
                standards = ", ".join(self.expertise.standards)
                context_parts.append(f"Relevant standards: {standards}")
            
            if self.expertise.best_practices:
                practices = "\n".join([f"  - {p}" for p in self.expertise.best_practices])
                context_parts.append(f"Best practices:\n{practices}")
            
            if self.expertise.key_concepts:
                concepts = "\n".join([f"  - {k}: {v}" for k, v in self.expertise.key_concepts.items()])
                context_parts.append(f"Key concepts:\n{concepts}")
            
            return "\n".join(context_parts)
        
        def add_knowledge(self, knowledge: DomainKnowledge):
            """Add domain knowledge to expert's knowledge base."""
            self.knowledge_base.append(knowledge)
        
        def consult(
            self,
            question: str,
            context: Optional[str] = None,
            require_reasoning: bool = True
        ) -> ExpertResponse:
            """
            Provide expert consultation.
            
            Args:
                question: Question or problem
                context: Additional context
                require_reasoning: Include reasoning explanation
                
            Returns:
                Expert response
            """
            expert_context = self._build_expert_context()
            
            # Build prompt
            prompt_template = (
                "{expert_context}\n\n"
                "Provide expert guidance on the following:\n\n"
                "Question: {question}\n\n"
            )
            
            if context:
                prompt_template += "Additional Context: {context}\n\n"
            
            prompt_template += (
                "Provide a comprehensive expert response including:\n"
                "1. Direct answer\n"
                "2. Expert reasoning and analysis\n"
                "3. Relevant considerations and caveats\n"
                "4. Best practices to follow\n"
                "5. Potential alternatives or approaches\n\n"
                "Use appropriate domain terminology and cite relevant standards when applicable."
            )
            
            prompt = ChatPromptTemplate.from_template(prompt_template)
            chain = prompt | self.llm | StrOutputParser()
            
            input_data = {
                "expert_context": expert_context,
                "question": question
            }
            
            if context:
                input_data["context"] = context
            
            response_text = chain.invoke(input_data)
            
            # Assess confidence based on question clarity and domain coverage
            confidence = self._assess_confidence(question)
            
            # Parse response components
            answer, reasoning, caveats = self._parse_response(response_text)
            
            # Store consultation
            self.consultation_history.append({
                "question": question,
                "answer": answer,
                "timestamp": datetime.now(),
                "confidence": confidence.value
            })
            
            return ExpertResponse(
                answer=answer,
                confidence=confidence,
                reasoning=reasoning,
                caveats=caveats
            )
        
        def _assess_confidence(self, question: str) -> ConfidenceLevel:
            """
            Assess confidence level in response.
            
            Args:
                question: The question asked
                
            Returns:
                Confidence level
            """
            # Check if question relates to core expertise
            question_lower = question.lower()
            
            # Count matches with expertise areas
            expertise_matches = sum(
                1 for area in self.expertise.expertise_areas
                if area.lower() in question_lower
            )
            
            # Terminology matches
            terminology_matches = sum(
                1 for term in self.expertise.terminology.keys()
                if term.lower() in question_lower
            )
            
            total_matches = expertise_matches + terminology_matches
            
            if total_matches >= 3:
                return ConfidenceLevel.VERY_HIGH
            elif total_matches >= 2:
                return ConfidenceLevel.HIGH
            elif total_matches >= 1:
                return ConfidenceLevel.MEDIUM
            else:
                return ConfidenceLevel.LOW
        
        def _parse_response(self, response_text: str) -> Tuple[str, str, List[str]]:
            """Parse response into components."""
            # Simple parsing - in production, use more sophisticated extraction
            lines = response_text.split('\n')
            
            answer_lines = []
            reasoning_lines = []
            caveat_lines = []
            
            current_section = "answer"
            
            for line in lines:
                line_lower = line.lower()
                
                if "reasoning" in line_lower or "analysis" in line_lower:
                    current_section = "reasoning"
                elif "caveat" in line_lower or "consideration" in line_lower or "warning" in line_lower:
                    current_section = "caveats"
                elif line.strip():
                    if current_section == "answer":
                        answer_lines.append(line)
                    elif current_section == "reasoning":
                        reasoning_lines.append(line)
                    elif current_section == "caveats":
                        caveat_lines.append(line)
            
            answer = "\n".join(answer_lines) if answer_lines else response_text
            reasoning = "\n".join(reasoning_lines)
            caveats = [line.strip('- ').strip() for line in caveat_lines if line.strip()]
            
            return answer, reasoning, caveats
        
        def explain_concept(self, concept: str, audience_level: str = "intermediate") -> str:
            """
            Explain a domain concept.
            
            Args:
                concept: Concept to explain
                audience_level: Target audience (novice/intermediate/advanced)
                
            Returns:
                Explanation
            """
            expert_context = self._build_expert_context()
            
            # Check if concept is in terminology
            concept_definition = self.expertise.terminology.get(concept, "")
            
            prompt = ChatPromptTemplate.from_template(
                "{expert_context}\n\n"
                "Explain the concept of '{concept}' for a {audience_level} audience.\n"
                "{definition_context}\n"
                "Provide:\n"
                "1. Clear definition\n"
                "2. Key characteristics\n"
                "3. Practical examples\n"
                "4. Common misconceptions\n"
                "5. Related concepts\n\n"
                "Use appropriate technical depth for the audience level."
            )
            
            chain = prompt | self.llm | StrOutputParser()
            
            definition_context = f"Domain definition: {concept_definition}" if concept_definition else ""
            
            explanation = chain.invoke({
                "expert_context": expert_context,
                "concept": concept,
                "audience_level": audience_level,
                "definition_context": definition_context
            })
            
            return explanation
        
        def identify_issues(self, scenario: str) -> List[str]:
            """
            Identify potential issues in a scenario.
            
            Args:
                scenario: Description of situation
                
            Returns:
                List of identified issues
            """
            expert_context = self._build_expert_context()
            
            # Include common issues from domain
            common_issues = "\n".join([f"- {issue}" for issue in self.expertise.common_issues])
            
            prompt = ChatPromptTemplate.from_template(
                "{expert_context}\n\n"
                "Common issues in this domain:\n"
                "{common_issues}\n\n"
                "Scenario:\n"
                "{scenario}\n\n"
                "As an expert, identify potential issues, problems, or concerns in this scenario.\n"
                "List each issue on a separate line starting with '- '."
            )
            
            chain = prompt | self.llm | StrOutputParser()
            
            response = chain.invoke({
                "expert_context": expert_context,
                "common_issues": common_issues,
                "scenario": scenario
            })
            
            # Parse issues
            issues = [
                line.strip('- ').strip()
                for line in response.split('\n')
                if line.strip().startswith('-')
            ]
            
            return issues
        
        def recommend_approach(self, problem: str) -> Dict[str, Any]:
            """
            Recommend approach for solving a problem.
            
            Args:
                problem: Problem description
                
            Returns:
                Recommended approach with rationale
            """
            expert_context = self._build_expert_context()
            
            methodologies = ", ".join(self.expertise.methodologies)
            practices = "\n".join([f"- {p}" for p in self.expertise.best_practices])
            
            prompt = ChatPromptTemplate.from_template(
                "{expert_context}\n\n"
                "Available methodologies: {methodologies}\n\n"
                "Best practices:\n"
                "{practices}\n\n"
                "Problem:\n"
                "{problem}\n\n"
                "Recommend the best approach to solve this problem. Include:\n"
                "APPROACH: [recommended approach]\n"
                "METHODOLOGY: [which methodology to use]\n"
                "STEPS: [key steps]\n"
                "RATIONALE: [why this approach]\n"
                "ALTERNATIVES: [other options]"
            )
            
            chain = prompt | self.llm | StrOutputParser()
            
            response = chain.invoke({
                "expert_context": expert_context,
                "methodologies": methodologies,
                "practices": practices,
                "problem": problem
            })
            
            # Parse recommendation
            return {
                "raw_response": response,
                "problem": problem,
                "timestamp": datetime.now()
            }
        
        def get_expertise_summary(self) -> Dict[str, Any]:
            """Get summary of expert capabilities."""
            return {
                "domain": self.expertise.domain_name,
                "description": self.expertise.description,
                "expertise_level": self.expertise_level.value,
                "areas_of_expertise": self.expertise.expertise_areas,
                "methodologies": self.expertise.methodologies,
                "standards": self.expertise.standards,
                "total_consultations": len(self.consultation_history),
                "knowledge_base_size": len(self.knowledge_base)
            }
    
    
    def demonstrate_domain_expert():
        """Demonstrate domain expert agent pattern."""
        
        print("=" * 80)
        print("DOMAIN EXPERT AGENT PATTERN DEMONSTRATION")
        print("=" * 80)
        
        # Example 1: Software Architecture Expert
        print("\n" + "=" * 80)
        print("Example 1: Software Architecture Expert")
        print("=" * 80)
        
        software_expertise = DomainExpertise(
            domain_name="Software Architecture",
            description="Design and structure of software systems",
            expertise_areas=[
                "Microservices",
                "System Design",
                "Scalability",
                "Design Patterns",
                "API Design"
            ],
            methodologies=[
                "Domain-Driven Design",
                "Clean Architecture",
                "Event-Driven Architecture",
                "Hexagonal Architecture"
            ],
            key_concepts={
                "Separation of Concerns": "Dividing system into distinct features with minimal overlap",
                "SOLID Principles": "Five design principles for maintainable software",
                "Scalability": "Ability to handle growth in workload"
            },
            terminology={
                "Microservice": "Small, independent service focused on single business capability",
                "API Gateway": "Single entry point for all client requests",
                "Circuit Breaker": "Pattern preventing cascading failures"
            },
            standards=[
                "REST API Design",
                "OpenAPI Specification",
                "12-Factor App"
            ],
            common_issues=[
                "Tight coupling between components",
                "Lack of scalability planning",
                "Poor API design",
                "Missing error handling",
                "Inadequate monitoring"
            ],
            best_practices=[
                "Design for failure",
                "Implement proper logging and monitoring",
                "Use asynchronous communication where appropriate",
                "Maintain clear API contracts",
                "Document architectural decisions"
            ]
        )
        
        architect = DomainExpertAgent(
            expertise=software_expertise,
            expertise_level=ExpertiseLevel.EXPERT
        )
        
        print(f"\nExpert Domain: {software_expertise.domain_name}")
        print(f"Expertise Level: {architect.expertise_level.value}")
        print(f"Areas: {', '.join(software_expertise.expertise_areas[:3])}...")
        
        # Example 2: Expert consultation
        print("\n" + "=" * 80)
        print("Example 2: Expert Consultation")
        print("=" * 80)
        
        question = "I'm building an e-commerce platform. Should I use microservices or a monolith?"
        
        print(f"\nQuestion: {question}")
        print("\nExpert Response:")
        print("-" * 60)
        
        response = architect.consult(question)
        print(response.answer)
        print(f"\nConfidence: {response.confidence.value}")
        
        if response.caveats:
            print(f"\nCaveats:")
            for caveat in response.caveats:
                print(f"  - {caveat}")
        
        # Example 3: Concept explanation
        print("\n" + "=" * 80)
        print("Example 3: Explaining Domain Concepts")
        print("=" * 80)
        
        concept = "Microservice"
        audience = "intermediate"
        
        print(f"\nExplaining '{concept}' for {audience} audience:")
        print("-" * 60)
        
        explanation = architect.explain_concept(concept, audience_level=audience)
        print(explanation)
        
        # Example 4: Issue identification
        print("\n" + "=" * 80)
        print("Example 4: Identifying Issues in Scenario")
        print("=" * 80)
        
        scenario = """
        We have a system where the web frontend directly calls the database.
        All services share the same database. We deploy everything together as one unit.
        When traffic increases, the entire system slows down.
        """
        
        print("\nScenario:")
        print(scenario)
        print("\nIdentified Issues:")
        
        issues = architect.identify_issues(scenario)
        for i, issue in enumerate(issues, 1):
            print(f"{i}. {issue}")
        
        # Example 5: Approach recommendation
        print("\n" + "=" * 80)
        print("Example 5: Recommending Approach")
        print("=" * 80)
        
        problem = "Need to scale our notification system that currently sends 10k emails/day but will need to handle 1M/day"
        
        print(f"\nProblem: {problem}")
        print("\nRecommended Approach:")
        print("-" * 60)
        
        recommendation = architect.recommend_approach(problem)
        print(recommendation["raw_response"])
        
        # Example 6: Medical Domain Expert
        print("\n" + "=" * 80)
        print("Example 6: Medical Domain Expert")
        print("=" * 80)
        
        medical_expertise = DomainExpertise(
            domain_name="General Medicine",
            description="Medical diagnosis and treatment",
            expertise_areas=[
                "Symptom Analysis",
                "Differential Diagnosis",
                "Treatment Planning",
                "Patient Care"
            ],
            methodologies=[
                "Evidence-Based Medicine",
                "Clinical Decision Making",
                "Patient-Centered Care"
            ],
            terminology={
                "Differential Diagnosis": "Process of distinguishing between similar conditions",
                "Prognosis": "Predicted course of a disease",
                "Contraindication": "Condition that makes treatment inadvisable"
            },
            standards=[
                "HIPAA Compliance",
                "Clinical Practice Guidelines",
                "Medical Ethics"
            ],
            best_practices=[
                "Always consider patient history",
                "Rule out serious conditions first",
                "Consider drug interactions",
                "Obtain informed consent",
                "Document thoroughly"
            ]
        )
        
        doctor = DomainExpertAgent(
            expertise=medical_expertise,
            expertise_level=ExpertiseLevel.EXPERT,
            temperature=0.2  # Very low for medical advice
        )
        
        print(f"\nExpert Domain: {medical_expertise.domain_name}")
        print(f"Standards: {', '.join(medical_expertise.standards)}")
        
        # Medical consultation
        medical_question = "What should I consider when a patient presents with chest pain?"
        
        print(f"\nMedical Question: {medical_question}")
        print("\nDISCLAIMER: This is a demonstration. Not real medical advice.")
        print("-" * 60)
        
        medical_response = doctor.consult(medical_question)
        print(medical_response.answer[:500] + "...")  # Truncate for demo
        print(f"\nConfidence: {medical_response.confidence.value}")
        
        # Example 7: Financial Expert
        print("\n" + "=" * 80)
        print("Example 7: Financial Planning Expert")
        print("=" * 80)
        
        financial_expertise = DomainExpertise(
            domain_name="Financial Planning",
            description="Personal and business financial planning",
            expertise_areas=[
                "Investment Strategy",
                "Retirement Planning",
                "Tax Planning",
                "Risk Management"
            ],
            methodologies=[
                "Modern Portfolio Theory",
                "Asset Allocation",
                "Risk Assessment"
            ],
            standards=[
                "SEC Regulations",
                "Fiduciary Duty",
                "CFP Standards"
            ],
            best_practices=[
                "Diversify investments",
                "Consider tax implications",
                "Match risk to time horizon",
                "Rebalance regularly",
                "Have emergency fund"
            ]
        )
        
        financial_advisor = DomainExpertAgent(
            expertise=financial_expertise,
            expertise_level=ExpertiseLevel.EXPERT
        )
        
        financial_question = "I'm 30 years old and want to start investing for retirement. Where should I start?"
        
        print(f"\nQuestion: {financial_question}")
        print("\nExpert Guidance:")
        print("-" * 60)
        
        financial_response = financial_advisor.consult(financial_question)
        print(financial_response.answer)
        
        # Example 8: Expertise summary
        print("\n" + "=" * 80)
        print("Example 8: Expert Capabilities Summary")
        print("=" * 80)
        
        summary = architect.get_expertise_summary()
        
        print("\nEXPERT PROFILE:")
        print("=" * 60)
        print(f"Domain: {summary['domain']}")
        print(f"Expertise Level: {summary['expertise_level']}")
        print(f"\nAreas of Expertise:")
        for area in summary['areas_of_expertise']:
            print(f"  • {area}")
        print(f"\nMethodologies:")
        for method in summary['methodologies']:
            print(f"  • {method}")
        print(f"\nTotal Consultations: {summary['total_consultations']}")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY: Domain Expert Agent Pattern")
        print("=" * 80)
        
        summary_text = """
        The Domain Expert Agent pattern demonstrated:
        
        1. EXPERTISE DEFINITION (Example 1):
           - Comprehensive domain specification
           - Areas of expertise
           - Standard methodologies
           - Key concepts and terminology
           - Relevant standards and regulations
           - Common issues and challenges
           - Best practices
        
        2. EXPERT CONSULTATION (Example 2):
           - Professional guidance
           - Domain-appropriate reasoning
           - Confidence assessment
           - Caveat identification
           - Best practice application
        
        3. CONCEPT EXPLANATION (Example 3):
           - Audience-appropriate depth
           - Domain terminology
           - Practical examples
           - Clear definitions
           - Related concepts
        
        4. ISSUE IDENTIFICATION (Example 4):
           - Expert problem recognition
           - Domain-specific concerns
           - Pattern matching
           - Risk assessment
           - Comprehensive analysis
        
        5. APPROACH RECOMMENDATION (Example 5):
           - Methodology selection
           - Step-by-step guidance
           - Rationale explanation
           - Alternative considerations
           - Best practice integration
        
        6. DOMAIN SPECIALIZATION (Examples 6-7):
           - Medical expertise
           - Financial planning
           - Different domain requirements
           - Standards compliance
           - Professional ethics
        
        7. MULTI-DOMAIN CAPABILITY (Examples 1, 6, 7):
           - Software architecture
           - Medical diagnosis
           - Financial planning
           - Domain-specific reasoning
           - Appropriate terminology
        
        8. TRANSPARENCY (Example 8):
           - Expertise summary
           - Capability disclosure
           - Consultation tracking
           - Knowledge base size
           - Performance metrics
        
        KEY BENEFITS:
        āœ“ Expert-level guidance
        āœ“ Domain-appropriate reasoning
        āœ“ Specialized knowledge application
        āœ“ Professional terminology
        āœ“ Best practice adherence
        āœ“ Quality assurance
        āœ“ Credible advice
        āœ“ Comprehensive coverage
        
        USE CASES:
        • Medical diagnosis assistance
        • Legal research and advisory
        • Financial analysis and planning
        • Engineering consultation
        • Scientific research support
        • Tax preparation
        • Architectural design
        • Software architecture advisory
        
        EXPERT BEHAVIORS:
        → Ask clarifying questions
        → Identify missing information
        → Consider edge cases
        → Reference standards
        → Explain reasoning
        → Acknowledge uncertainty
        → Provide multiple perspectives
        → Use appropriate terminology
        
        DOMAIN CHARACTERISTICS:
        • Depth: Comprehensive specialized coverage
        • Terminology: Field-specific vocabulary
        • Methodology: Standard approaches
        • Context: Domain landscape understanding
        • Precedents: Historical cases
        • Standards: Industry regulations
        • Boundaries: Expertise limits
        
        BEST PRACTICES:
        1. Regularly update domain knowledge
        2. Version control expert systems
        3. Track predictions vs. outcomes
        4. Include human expert review
        5. Add appropriate disclaimers
        6. Maintain audit trails
        7. Ensure regulatory compliance
        8. Support expert override
        
        TRADE-OFFS:
        • Depth vs. breadth
        • Accuracy vs. accessibility
        • Confidence vs. caution
        • Automation vs. human oversight
        
        PRODUCTION CONSIDERATIONS:
        → Regular knowledge base updates
        → Version control of expertise
        → Track expert vs. actual outcomes
        → Human expert review loops
        → Appropriate disclaimers
        → Complete audit trails
        → Regulatory compliance checks
        → Expert override mechanisms
        → Liability management
        → Certification where applicable
        
        This pattern enables agents to provide professional-grade expertise in
        specialized domains, delivering value that requires deep knowledge and
        experience while maintaining appropriate boundaries and transparency.
        """
        
        print(summary_text)
    
    
    if __name__ == "__main__":
        demonstrate_domain_expert()
    
        

    Agentic Design Pattern: Domain Expert

    Pattern 133: Domain Expert – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Domain Expert pattern implementation.


    Pattern Description

    Pattern 133: Domain Expert Agent

    Description: The Domain Expert Agent pattern creates specialized agents with deep expertise in specific domains or fields. Unlike general-purpose agents, domain experts possess comprehensive knowledge, terminology, methodologies, and best practices specific to their area of specialization. They can provide expert-level advice, perform domain-specific reasoning, and apply specialized knowledge effectively.

    Domain expertise goes beyond simple knowledge retrieval - it includes understanding
    domain-specific workflows, recognizing patterns, applying heuristics, knowing
    what questions to ask, and understanding the nuances and edge cases within the
    domain. Expert agents can explain complex concepts using domain terminology,
    evaluate solutions using domain-specific criteria, and provide guidance that
    reflects years of accumulated expertise.
    
    This pattern is essential for applications requiring specialized knowledge such
    as medical diagnosis assistants, legal advisors, financial analysts, scientific
    research assistants, engineering consultants, and other professional AI systems.
    

    Key Components: 1. Domain Knowledge Base: Comprehensive domain-specific information 2. Terminology Handler: Domain-specific vocabulary and jargon 3. Best Practices Repository: Field-standard methodologies 4. Case History: Examples and precedents from the domain 5. Reasoning Engine: Domain-specific logic and heuristics 6. Validation System: Domain-appropriate quality checks 7. Reference System: Citations and sources

    Domain Characteristics: 1. Depth: Comprehensive coverage of specialized area 2. Terminology: Field-specific vocabulary 3. Methodology: Domain-standard approaches 4. Context: Understanding of domain landscape 5. Precedents: Historical cases and examples 6. Standards: Industry regulations and best practices 7. Boundaries: Knowing limits of expertise

    Expert Behaviors: 1. Ask clarifying questions 2. Identify missing information 3. Consider edge cases 4. Reference standards and regulations 5. Explain reasoning process 6. Acknowledge uncertainty 7. Provide multiple perspectives 8. Use appropriate terminology

    Use Cases: – Medical diagnosis assistants – Legal research and advisory – Financial analysis and planning – Engineering design consultation – Scientific research assistance – Tax preparation and planning – Architectural design – Software architecture advisory

    Advantages: – Expert-level guidance – Domain-appropriate reasoning – Specialized knowledge application – Professional terminology usage – Best practice adherence – Quality assurance – Credible advice

    Challenges: – Knowledge maintenance and updates – Handling edge cases – Avoiding overconfidence – Managing liability concerns – Balancing depth vs. accessibility – Keeping current with field changes – Regulatory compliance

    LangChain Implementation: This implementation uses LangChain for: – Domain knowledge integration – Expert reasoning chains – Specialized RAG with domain documents – Domain-specific validation

    Production Considerations: – Regularly update domain knowledge – Version control expert systems – Track expert vs. actual outcomes – Implement human expert review – Include disclaimers appropriately – Maintain audit trails – Ensure regulatory compliance – Support expert override mechanisms


    File Statistics

    • Total Lines: 946
    • Classes: 6
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 133: Domain Expert Agent
    
    Description:
        The Domain Expert Agent pattern creates specialized agents with deep expertise
        in specific domains or fields. Unlike general-purpose agents, domain experts
        possess comprehensive knowledge, terminology, methodologies, and best practices
        specific to their area of specialization. They can provide expert-level advice,
        perform domain-specific reasoning, and apply specialized knowledge effectively.
    
        Domain expertise goes beyond simple knowledge retrieval - it includes understanding
        domain-specific workflows, recognizing patterns, applying heuristics, knowing
        what questions to ask, and understanding the nuances and edge cases within the
        domain. Expert agents can explain complex concepts using domain terminology,
        evaluate solutions using domain-specific criteria, and provide guidance that
        reflects years of accumulated expertise.
    
        This pattern is essential for applications requiring specialized knowledge such
        as medical diagnosis assistants, legal advisors, financial analysts, scientific
        research assistants, engineering consultants, and other professional AI systems.
    
    Key Components:
        1. Domain Knowledge Base: Comprehensive domain-specific information
        2. Terminology Handler: Domain-specific vocabulary and jargon
        3. Best Practices Repository: Field-standard methodologies
        4. Case History: Examples and precedents from the domain
        5. Reasoning Engine: Domain-specific logic and heuristics
        6. Validation System: Domain-appropriate quality checks
        7. Reference System: Citations and sources
    
    Domain Characteristics:
        1. Depth: Comprehensive coverage of specialized area
        2. Terminology: Field-specific vocabulary
        3. Methodology: Domain-standard approaches
        4. Context: Understanding of domain landscape
        5. Precedents: Historical cases and examples
        6. Standards: Industry regulations and best practices
        7. Boundaries: Knowing limits of expertise
    
    Expert Behaviors:
        1. Ask clarifying questions
        2. Identify missing information
        3. Consider edge cases
        4. Reference standards and regulations
        5. Explain reasoning process
        6. Acknowledge uncertainty
        7. Provide multiple perspectives
        8. Use appropriate terminology
    
    Use Cases:
        - Medical diagnosis assistants
        - Legal research and advisory
        - Financial analysis and planning
        - Engineering design consultation
        - Scientific research assistance
        - Tax preparation and planning
        - Architectural design
        - Software architecture advisory
    
    Advantages:
        - Expert-level guidance
        - Domain-appropriate reasoning
        - Specialized knowledge application
        - Professional terminology usage
        - Best practice adherence
        - Quality assurance
        - Credible advice
    
    Challenges:
        - Knowledge maintenance and updates
        - Handling edge cases
        - Avoiding overconfidence
        - Managing liability concerns
        - Balancing depth vs. accessibility
        - Keeping current with field changes
        - Regulatory compliance
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Domain knowledge integration
        - Expert reasoning chains
        - Specialized RAG with domain documents
        - Domain-specific validation
    
    Production Considerations:
        - Regularly update domain knowledge
        - Version control expert systems
        - Track expert vs. actual outcomes
        - Implement human expert review
        - Include disclaimers appropriately
        - Maintain audit trails
        - Ensure regulatory compliance
        - Support expert override mechanisms
    """
    

    Purpose: This module implements the Domain Expert pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import dataclasses.dataclass
    import dataclasses.field
    import datetime.datetime
    import enum.Enum
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import os
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    import typing.Tuple
    

    Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – enum.Enum: Enumeration support – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Tuple: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: ExpertiseLevel

    Lines 110-116

    Inherits from: Enum

    Purpose:

    Level of expertise.
    

    Class: ConfidenceLevel

    Lines 119-124

    Inherits from: Enum

    Purpose:

    Confidence in response.
    

    Class: DomainKnowledge

    Lines 128-145

    Purpose:

    Domain-specific knowledge item.
    
    Attributes:
        topic: Knowledge area
        content: Information content
        source: Where knowledge came from
        reliability: How reliable (0-1)
        last_updated: When last verified
        tags: Categorization tags
    

    Class: ExpertResponse

    Lines 149-168

    Purpose:

    Expert agent response.
    
    Attributes:
        answer: Main response
        confidence: Confidence level
        reasoning: Explanation of reasoning
        references: Supporting sources
        caveats: Important limitations or warnings
        follow_up_questions: Suggested clarifications
        alternatives: Alternative approaches
    

    Class: DomainExpertise

    Lines 172-195

    Purpose:

    Definition of domain expertise.
    
    Attributes:
        domain_name: Name of domain
        description: Domain description
        expertise_areas: Specific areas of expertise
        methodologies: Standard approaches
        key_concepts: Important domain concepts
        terminology: Domain-specific vocabulary
        standards: Relevant standards and regulations
        common_issues: Frequently encountered problems
        best_practices: Field best practices
    

    Class: DomainExpertAgent

    Lines 198-541

    Purpose:

    Agent with specialized domain expertise.
    
    This agent provides expert-level guidance in a specific domain,
    using specialized knowledge, terminology, and reasoning.
    

    Methods:

    __init__(self, expertise, expertise_level, temperature)

    Lines 206-224

    Purpose:

    Initialize domain expert agent.
    
    Args:
        expertise: Domain expertise definition
        expertise_level: Level of expertise
        temperature: LLM temperature (lower for more consistent expert advice)
    

    Parameters: – expertise: Expertise – expertise_level: Expertise level – temperature: Sampling temperature (0-1)

    _build_expert_context(self)

    Lines 226-253

    Purpose:

    Build expert context for prompts.
    

    Parameters:

    Returns: str

    add_knowledge(self, knowledge)

    Lines 255-257

    Purpose:

    Add domain knowledge to expert's knowledge base.
    

    Parameters: – knowledge: Knowledge

    consult(self, question, context, require_reasoning)

    Lines 259-330

    Purpose:

    Provide expert consultation.
    
    Args:
        question: Question or problem
        context: Additional context
        require_reasoning: Include reasoning explanation
    
    Returns:
        Expert response
    

    Parameters: – question: Question to answer – context: Context – require_reasoning: Require reasoning

    Returns: ExpertResponse

    _assess_confidence(self, question)

    Lines 332-366

    Purpose:

    Assess confidence level in response.
    
    Args:
        question: The question asked
    
    Returns:
        Confidence level
    

    Parameters: – question: Question to answer

    Returns: ConfidenceLevel

    _parse_response(self, response_text)

    Lines 368-398

    Purpose:

    Parse response into components.
    

    Parameters: – response_text: Response text

    Returns: <ast.Subscript object at 0x000001A06D63D090>

    explain_concept(self, concept, audience_level)

    Lines 400-440

    Purpose:

    Explain a domain concept.
    
    Args:
        concept: Concept to explain
        audience_level: Target audience (novice/intermediate/advanced)
    
    Returns:
        Explanation
    

    Parameters: – concept: Concept – audience_level: Audience level

    Returns: str

    identify_issues(self, scenario)

    Lines 442-482

    Purpose:

    Identify potential issues in a scenario.
    
    Args:
        scenario: Description of situation
    
    Returns:
        List of identified issues
    

    Parameters: – scenario: Scenario

    Returns: <ast.Subscript object at 0x000001A06D77E010>

    recommend_approach(self, problem)

    Lines 484-528

    Purpose:

    Recommend approach for solving a problem.
    
    Args:
        problem: Problem description
    
    Returns:
        Recommended approach with rationale
    

    Parameters: – problem: Problem

    Returns: <ast.Subscript object at 0x000001A06D7504D0>

    get_expertise_summary(self)

    Lines 530-541

    Purpose:

    Get summary of expert capabilities.
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D168B90>


    Functions

    demonstrate_domain_expert()

    Lines 544-941

    Purpose:

    Demonstrate domain expert agent pattern.
    

    Key Concepts Summary

    Pattern Overview

    The Domain Expert pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 132
    • Pattern 134

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Domain Expert pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 133_domain_expert.py
    Total Lines: 946
    Pattern Category: AI Agent Design Pattern #133


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Emotion Recognition

    
        """
    Pattern 132: Emotion Recognition & Response
    
    Description:
        The Emotion Recognition & Response pattern enables agents to detect emotional
        states from user input and respond with appropriate empathy, tone, and content.
        Rather than treating all interactions uniformly, the agent recognizes emotions
        like frustration, joy, sadness, or confusion and adapts its behavior to be
        contextually appropriate and emotionally intelligent.
        
        This pattern is critical for creating human-centered AI that can build rapport,
        de-escalate conflicts, celebrate successes, and provide appropriate support
        based on user emotional state. It combines emotion detection (analyzing text
        for emotional cues), sentiment analysis, empathetic response generation, and
        emotional context tracking over conversations.
        
        The pattern addresses challenges like subtle emotion detection, cultural
        differences in expression, appropriate emotional responses, avoiding
        manipulation, and maintaining authenticity while being supportive.
    
    Key Components:
        1. Emotion Detection: Identify emotions from text
        2. Sentiment Analysis: Classify overall tone (positive/negative/neutral)
        3. Emotional Intensity: Measure emotion strength
        4. Context Tracking: Track emotional arc over conversation
        5. Empathetic Response: Generate appropriate reactions
        6. Tone Adaptation: Adjust agent tone based on user emotion
        7. Intervention Logic: Special handling for extreme emotions
    
    Emotion Categories:
        1. Primary Emotions: Joy, sadness, anger, fear, surprise, disgust
        2. Complex Emotions: Frustration, excitement, confusion, satisfaction
        3. Social Emotions: Gratitude, embarrassment, pride, shame
        4. Cognitive States: Confidence, uncertainty, curiosity, boredom
    
    Detection Signals:
        1. Explicit Expressions: "I'm frustrated", "This is great!"
        2. Exclamation Marks: Multiple !!! or ???
        3. Capitalization: ALL CAPS for emphasis
        4. Word Choice: Emotional vocabulary
        5. Sentence Structure: Short angry bursts vs. rambling confusion
        6. Emoticons/Emoji: 😊 😠 😢 šŸ¤”
        7. Negation: "This isn't working", "No luck"
    
    Response Strategies:
        1. Validation: Acknowledge the emotion
        2. Empathy: Show understanding
        3. Support: Offer help or encouragement
        4. De-escalation: Calm strong negative emotions
        5. Celebration: Share in positive emotions
        6. Clarification: Address confusion
        7. Patience: Adjust pace for overwhelm
    
    Use Cases:
        - Customer support (handling complaints)
        - Mental health chatbots
        - Educational tutors (frustration detection)
        - Healthcare assistants (patient anxiety)
        - HR assistants (employee concerns)
        - Social companions
        - Crisis intervention
    
    Advantages:
        - Improved user satisfaction
        - Better conflict resolution
        - Stronger emotional connection
        - Appropriate tone matching
        - Early problem detection
        - Personalized support
        - Enhanced trust
    
    Challenges:
        - Ambiguous emotional signals
        - Cultural differences in expression
        - Sarcasm and irony detection
        - Over-interpretation risk
        - Privacy and sensitivity
        - Avoiding emotional manipulation
        - Maintaining authenticity
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Emotion detection from text
        - Sentiment classification
        - Empathetic response generation
        - Context-aware emotional tracking
        
    Production Considerations:
        - Use multiple emotion detection methods
        - Track emotional patterns over time
        - Implement crisis detection triggers
        - Provide human escalation paths
        - Respect cultural differences
        - Avoid over-familiarity
        - Log emotion data securely
        - Enable emotion detection toggles
    """
    
    import os
    import re
    from typing import List, Dict, Any, Optional, Tuple
    from dataclasses import dataclass, field
    from datetime import datetime
    from enum import Enum
    from dotenv import load_dotenv
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    from langchain_openai import ChatOpenAI
    
    load_dotenv()
    
    
    class Emotion(Enum):
        """Primary emotion categories."""
        JOY = "joy"
        SADNESS = "sadness"
        ANGER = "anger"
        FEAR = "fear"
        SURPRISE = "surprise"
        DISGUST = "disgust"
        FRUSTRATION = "frustration"
        EXCITEMENT = "excitement"
        CONFUSION = "confusion"
        SATISFACTION = "satisfaction"
        GRATITUDE = "gratitude"
        ANXIETY = "anxiety"
        NEUTRAL = "neutral"
    
    
    class Sentiment(Enum):
        """Overall sentiment classification."""
        POSITIVE = "positive"
        NEGATIVE = "negative"
        NEUTRAL = "neutral"
        MIXED = "mixed"
    
    
    class ResponseStrategy(Enum):
        """Strategy for responding to emotions."""
        VALIDATE = "validate"
        EMPATHIZE = "empathize"
        SUPPORT = "support"
        DE_ESCALATE = "de_escalate"
        CELEBRATE = "celebrate"
        CLARIFY = "clarify"
        ENCOURAGE = "encourage"
    
    
    @dataclass
    class EmotionalState:
        """
        Detected emotional state from user input.
        
        Attributes:
            primary_emotion: Main emotion detected
            secondary_emotions: Other emotions present
            sentiment: Overall sentiment
            intensity: Emotion strength (0-1)
            confidence: Detection confidence (0-1)
            signals: Textual cues that indicated emotion
            timestamp: When detected
        """
        primary_emotion: Emotion
        secondary_emotions: List[Emotion] = field(default_factory=list)
        sentiment: Sentiment = Sentiment.NEUTRAL
        intensity: float = 0.5
        confidence: float = 0.5
        signals: List[str] = field(default_factory=list)
        timestamp: datetime = field(default_factory=datetime.now)
    
    
    @dataclass
    class EmpatheticResponse:
        """
        Response tailored to emotional state.
        
        Attributes:
            response_text: Generated response
            strategy: Strategy used
            acknowledged_emotion: Emotion that was addressed
            tone: Response tone
            follow_up_actions: Suggested next steps
        """
        response_text: str
        strategy: ResponseStrategy
        acknowledged_emotion: Emotion
        tone: str
        follow_up_actions: List[str] = field(default_factory=list)
    
    
    class EmotionalAgent:
        """
        Agent with emotion recognition and empathetic response capabilities.
        
        This agent detects user emotions and responds with appropriate
        empathy, tone, and support.
        """
        
        def __init__(self, temperature: float = 0.7):
            """
            Initialize emotional agent.
            
            Args:
                temperature: LLM temperature for response generation
            """
            self.llm = ChatOpenAI(temperature=temperature, model="gpt-3.5-turbo")
            self.emotional_history: List[EmotionalState] = []
            
            # Emotion keywords for rule-based detection
            self.emotion_keywords = {
                Emotion.JOY: ["happy", "great", "wonderful", "excellent", "love", "amazing", "perfect"],
                Emotion.SADNESS: ["sad", "disappointed", "unhappy", "down", "depressed", "terrible"],
                Emotion.ANGER: ["angry", "furious", "mad", "annoyed", "irritated", "outraged"],
                Emotion.FRUSTRATION: ["frustrated", "stuck", "can't", "won't work", "difficult", "struggle"],
                Emotion.CONFUSION: ["confused", "don't understand", "unclear", "lost", "puzzled"],
                Emotion.GRATITUDE: ["thank", "thanks", "appreciate", "grateful", "helpful"],
                Emotion.ANXIETY: ["worried", "anxious", "nervous", "scared", "concerned"],
                Emotion.EXCITEMENT: ["excited", "can't wait", "awesome", "fantastic", "thrilled"],
            }
        
        def detect_emotion_simple(self, text: str) -> EmotionalState:
            """
            Simple rule-based emotion detection.
            
            Args:
                text: User input text
                
            Returns:
                Detected emotional state
            """
            text_lower = text.lower()
            detected_emotions = []
            signals = []
            
            # Check keywords
            for emotion, keywords in self.emotion_keywords.items():
                for keyword in keywords:
                    if keyword in text_lower:
                        detected_emotions.append(emotion)
                        signals.append(f"Keyword: '{keyword}'")
            
            # Check for caps (anger/excitement)
            if text.isupper() and len(text) > 10:
                detected_emotions.append(Emotion.ANGER)
                signals.append("ALL CAPS")
            
            # Check for exclamation marks
            exclamation_count = text.count('!')
            if exclamation_count >= 2:
                detected_emotions.append(Emotion.EXCITEMENT)
                signals.append(f"Multiple exclamations ({exclamation_count})")
            
            # Check for question marks (confusion)
            question_count = text.count('?')
            if question_count >= 2:
                detected_emotions.append(Emotion.CONFUSION)
                signals.append(f"Multiple questions ({question_count})")
            
            # Determine primary emotion
            if detected_emotions:
                primary = detected_emotions[0]
                secondary = detected_emotions[1:] if len(detected_emotions) > 1 else []
            else:
                primary = Emotion.NEUTRAL
                secondary = []
            
            # Determine sentiment
            positive_emotions = {Emotion.JOY, Emotion.GRATITUDE, Emotion.EXCITEMENT, Emotion.SATISFACTION}
            negative_emotions = {Emotion.SADNESS, Emotion.ANGER, Emotion.FRUSTRATION, Emotion.ANXIETY, Emotion.FEAR}
            
            if primary in positive_emotions:
                sentiment = Sentiment.POSITIVE
            elif primary in negative_emotions:
                sentiment = Sentiment.NEGATIVE
            else:
                sentiment = Sentiment.NEUTRAL
            
            # Estimate intensity
            intensity = 0.5
            if exclamation_count > 0 or text.isupper():
                intensity = 0.8
            elif primary != Emotion.NEUTRAL:
                intensity = 0.6
            
            return EmotionalState(
                primary_emotion=primary,
                secondary_emotions=secondary,
                sentiment=sentiment,
                intensity=intensity,
                confidence=0.7 if signals else 0.3,
                signals=signals
            )
        
        def detect_emotion_llm(self, text: str) -> EmotionalState:
            """
            LLM-based emotion detection.
            
            Args:
                text: User input text
                
            Returns:
                Detected emotional state
            """
            prompt = ChatPromptTemplate.from_template(
                "Analyze the emotional content of this message:\n\n"
                "\"{text}\"\n\n"
                "Provide:\n"
                "PRIMARY_EMOTION: [joy/sadness/anger/fear/frustration/confusion/gratitude/excitement/neutral/etc.]\n"
                "SENTIMENT: [positive/negative/neutral/mixed]\n"
                "INTENSITY: [0.0-1.0, where 0 is no emotion and 1 is extreme]\n"
                "SIGNALS: [what textual cues indicate this emotion]\n"
                "CONFIDENCE: [0.0-1.0, how certain are you]"
            )
            
            chain = prompt | self.llm | StrOutputParser()
            analysis = chain.invoke({"text": text})
            
            # Parse analysis
            lines = analysis.strip().split('\n')
            
            primary_emotion = Emotion.NEUTRAL
            sentiment = Sentiment.NEUTRAL
            intensity = 0.5
            confidence = 0.5
            signals = []
            
            for line in lines:
                if line.startswith("PRIMARY_EMOTION:"):
                    emotion_str = line.split(":")[1].strip().lower()
                    # Map to enum
                    for emotion in Emotion:
                        if emotion.value in emotion_str:
                            primary_emotion = emotion
                            break
                
                elif line.startswith("SENTIMENT:"):
                    sentiment_str = line.split(":")[1].strip().lower()
                    if "positive" in sentiment_str:
                        sentiment = Sentiment.POSITIVE
                    elif "negative" in sentiment_str:
                        sentiment = Sentiment.NEGATIVE
                    elif "mixed" in sentiment_str:
                        sentiment = Sentiment.MIXED
                
                elif line.startswith("INTENSITY:"):
                    try:
                        intensity = float(line.split(":")[1].strip().split()[0])
                    except:
                        pass
                
                elif line.startswith("CONFIDENCE:"):
                    try:
                        confidence = float(line.split(":")[1].strip().split()[0])
                    except:
                        pass
                
                elif line.startswith("SIGNALS:"):
                    signals.append(line.split(":")[1].strip())
            
            return EmotionalState(
                primary_emotion=primary_emotion,
                sentiment=sentiment,
                intensity=intensity,
                confidence=confidence,
                signals=signals
            )
        
        def select_response_strategy(self, emotional_state: EmotionalState) -> ResponseStrategy:
            """
            Select appropriate response strategy.
            
            Args:
                emotional_state: Detected emotional state
                
            Returns:
                Response strategy
            """
            emotion = emotional_state.primary_emotion
            intensity = emotional_state.intensity
            
            # High-intensity negative emotions need de-escalation
            if intensity > 0.7 and emotional_state.sentiment == Sentiment.NEGATIVE:
                return ResponseStrategy.DE_ESCALATE
            
            # Map emotions to strategies
            strategy_map = {
                Emotion.JOY: ResponseStrategy.CELEBRATE,
                Emotion.EXCITEMENT: ResponseStrategy.CELEBRATE,
                Emotion.GRATITUDE: ResponseStrategy.VALIDATE,
                Emotion.SADNESS: ResponseStrategy.EMPATHIZE,
                Emotion.ANGER: ResponseStrategy.DE_ESCALATE,
                Emotion.FRUSTRATION: ResponseStrategy.SUPPORT,
                Emotion.CONFUSION: ResponseStrategy.CLARIFY,
                Emotion.ANXIETY: ResponseStrategy.SUPPORT,
                Emotion.NEUTRAL: ResponseStrategy.VALIDATE
            }
            
            return strategy_map.get(emotion, ResponseStrategy.VALIDATE)
        
        def generate_empathetic_response(
            self,
            user_input: str,
            emotional_state: EmotionalState,
            strategy: ResponseStrategy
        ) -> EmpatheticResponse:
            """
            Generate response tailored to emotional state.
            
            Args:
                user_input: User's message
                emotional_state: Detected emotional state
                strategy: Response strategy to use
                
            Returns:
                Empathetic response
            """
            # Build context about emotion
            emotion_context = (
                f"The user is expressing {emotional_state.primary_emotion.value} "
                f"with {emotional_state.intensity:.1f} intensity. "
                f"Overall sentiment is {emotional_state.sentiment.value}."
            )
            
            # Strategy-specific instructions
            strategy_instructions = {
                ResponseStrategy.VALIDATE: "Acknowledge and validate their feelings.",
                ResponseStrategy.EMPATHIZE: "Show deep empathy and understanding. Be gentle and supportive.",
                ResponseStrategy.SUPPORT: "Offer concrete support and encouragement. Focus on solutions.",
                ResponseStrategy.DE_ESCALATE: "Be calm and soothing. Acknowledge frustration and offer to help resolve issues.",
                ResponseStrategy.CELEBRATE: "Share in their positive emotions! Be enthusiastic and encouraging.",
                ResponseStrategy.CLARIFY: "Help them understand. Be patient and clear. Break things down.",
                ResponseStrategy.ENCOURAGE: "Provide motivation and confidence. Highlight their strengths."
            }
            
            instruction = strategy_instructions.get(strategy, "Respond appropriately.")
            
            prompt = ChatPromptTemplate.from_template(
                "User message: \"{user_input}\"\n\n"
                "Emotional Context: {emotion_context}\n\n"
                "Response Strategy: {strategy}\n"
                "Instruction: {instruction}\n\n"
                "Generate an empathetic, helpful response that appropriately addresses "
                "the user's emotional state. Be genuine and human-like."
            )
            
            chain = prompt | self.llm | StrOutputParser()
            
            response_text = chain.invoke({
                "user_input": user_input,
                "emotion_context": emotion_context,
                "strategy": strategy.value,
                "instruction": instruction
            })
            
            # Determine tone
            tone_map = {
                ResponseStrategy.CELEBRATE: "enthusiastic",
                ResponseStrategy.EMPATHIZE: "gentle",
                ResponseStrategy.DE_ESCALATE: "calm",
                ResponseStrategy.CLARIFY: "patient",
                ResponseStrategy.SUPPORT: "encouraging",
                ResponseStrategy.VALIDATE: "understanding"
            }
            
            return EmpatheticResponse(
                response_text=response_text,
                strategy=strategy,
                acknowledged_emotion=emotional_state.primary_emotion,
                tone=tone_map.get(strategy, "neutral")
            )
        
        def respond(self, user_input: str, use_llm_detection: bool = True) -> str:
            """
            Process input and generate empathetic response.
            
            Args:
                user_input: User's message
                use_llm_detection: Use LLM vs. rule-based detection
                
            Returns:
                Empathetic response text
            """
            # Detect emotion
            if use_llm_detection:
                emotional_state = self.detect_emotion_llm(user_input)
            else:
                emotional_state = self.detect_emotion_simple(user_input)
            
            # Store in history
            self.emotional_history.append(emotional_state)
            
            # Select strategy
            strategy = self.select_response_strategy(emotional_state)
            
            # Generate response
            response = self.generate_empathetic_response(user_input, emotional_state, strategy)
            
            return response.response_text
        
        def get_emotional_trajectory(self) -> List[Dict[str, Any]]:
            """Get emotional arc over conversation."""
            return [
                {
                    "emotion": state.primary_emotion.value,
                    "sentiment": state.sentiment.value,
                    "intensity": state.intensity,
                    "timestamp": state.timestamp.isoformat()
                }
                for state in self.emotional_history
            ]
        
        def get_current_emotional_state(self) -> Optional[EmotionalState]:
            """Get most recent emotional state."""
            return self.emotional_history[-1] if self.emotional_history else None
    
    
    def demonstrate_emotion_recognition():
        """Demonstrate emotion recognition and response pattern."""
        
        print("=" * 80)
        print("EMOTION RECOGNITION & RESPONSE PATTERN DEMONSTRATION")
        print("=" * 80)
        
        # Example 1: Basic emotion detection
        print("\n" + "=" * 80)
        print("Example 1: Basic Emotion Detection")
        print("=" * 80)
        
        agent = EmotionalAgent()
        
        test_messages = [
            "I'm so frustrated! This isn't working at all!",
            "Thank you so much! This is exactly what I needed!",
            "I'm a bit confused about how this works...",
            "This is terrible. I'm very disappointed.",
            "WOW! This is AMAZING!!!"
        ]
        
        print("\nDetecting emotions in various messages:")
        for msg in test_messages:
            emotion_state = agent.detect_emotion_simple(msg)
            print(f"\nMessage: \"{msg}\"")
            print(f"  Primary Emotion: {emotion_state.primary_emotion.value}")
            print(f"  Sentiment: {emotion_state.sentiment.value}")
            print(f"  Intensity: {emotion_state.intensity:.2f}")
            print(f"  Signals: {emotion_state.signals}")
        
        # Example 2: LLM-based detection
        print("\n" + "=" * 80)
        print("Example 2: LLM-Based Emotion Detection")
        print("=" * 80)
        
        complex_message = "I've been trying this for hours and nothing works. I'm starting to think I'm just not smart enough for this."
        
        print(f"\nAnalyzing complex message:")
        print(f'"{complex_message}"')
        
        emotion_state = agent.detect_emotion_llm(complex_message)
        print(f"\nPrimary Emotion: {emotion_state.primary_emotion.value}")
        print(f"Sentiment: {emotion_state.sentiment.value}")
        print(f"Intensity: {emotion_state.intensity:.2f}")
        print(f"Confidence: {emotion_state.confidence:.2f}")
        print(f"Signals: {emotion_state.signals}")
        
        # Example 3: Strategy selection
        print("\n" + "=" * 80)
        print("Example 3: Response Strategy Selection")
        print("=" * 80)
        
        emotions_and_strategies = [
            (Emotion.FRUSTRATION, 0.8, Sentiment.NEGATIVE),
            (Emotion.JOY, 0.9, Sentiment.POSITIVE),
            (Emotion.CONFUSION, 0.6, Sentiment.NEUTRAL),
            (Emotion.ANGER, 0.9, Sentiment.NEGATIVE),
        ]
        
        print("\nStrategy selection for different emotional states:")
        for emotion, intensity, sentiment in emotions_and_strategies:
            state = EmotionalState(
                primary_emotion=emotion,
                sentiment=sentiment,
                intensity=intensity
            )
            strategy = agent.select_response_strategy(state)
            print(f"\n{emotion.value} (intensity={intensity}, {sentiment.value})")
            print(f"  → Strategy: {strategy.value}")
        
        # Example 4: Empathetic responses
        print("\n" + "=" * 80)
        print("Example 4: Empathetic Response Generation")
        print("=" * 80)
        
        agent2 = EmotionalAgent()
        
        scenarios = [
            "I'm so frustrated! I've been stuck on this problem for hours!",
            "This is absolutely perfect! You've made my day!",
            "I don't understand how this feature works. Can you help?"
        ]
        
        print("\nGenerating empathetic responses:")
        for scenario in scenarios:
            print(f"\nUser: {scenario}")
            response = agent2.respond(scenario)
            
            # Get emotional state
            state = agent2.get_current_emotional_state()
            print(f"Detected: {state.primary_emotion.value} ({state.intensity:.2f} intensity)")
            print(f"Agent: {response}")
        
        # Example 5: De-escalation
        print("\n" + "=" * 80)
        print("Example 5: De-escalation of Strong Negative Emotions")
        print("=" * 80)
        
        agent3 = EmotionalAgent()
        
        angry_message = "This is completely unacceptable! I've wasted so much time and nothing works! I want a refund NOW!"
        
        print(f"\nAngry User: {angry_message}")
        
        response = agent3.respond(angry_message)
        state = agent3.get_current_emotional_state()
        
        print(f"\nDetected Emotion: {state.primary_emotion.value}")
        print(f"Intensity: {state.intensity:.2f}")
        print(f"Sentiment: {state.sentiment.value}")
        print(f"\nAgent (De-escalation): {response}")
        
        # Example 6: Celebration
        print("\n" + "=" * 80)
        print("Example 6: Celebrating Positive Emotions")
        print("=" * 80)
        
        agent4 = EmotionalAgent()
        
        excited_message = "I finally got it working!!! This is amazing! Thank you so much!"
        
        print(f"\nExcited User: {excited_message}")
        
        response = agent4.respond(excited_message)
        state = agent4.get_current_emotional_state()
        
        print(f"\nDetected Emotion: {state.primary_emotion.value}")
        print(f"Intensity: {state.intensity:.2f}")
        print(f"\nAgent (Celebration): {response}")
        
        # Example 7: Emotional trajectory
        print("\n" + "=" * 80)
        print("Example 7: Tracking Emotional Trajectory")
        print("=" * 80)
        
        agent5 = EmotionalAgent()
        
        conversation = [
            "I'm trying to set this up but it's not working.",
            "I've tried everything! This is so frustrating!",
            "Oh wait, I think I see the issue now.",
            "Yes! It's working now! Thank you!"
        ]
        
        print("\nConversation with emotional tracking:")
        for msg in conversation:
            print(f"\nUser: {msg}")
            response = agent5.respond(msg)
            state = agent5.get_current_emotional_state()
            print(f"[{state.primary_emotion.value}, intensity={state.intensity:.2f}]")
            print(f"Agent: {response}")
        
        print("\n" + "-" * 60)
        print("\nEMOTIONAL TRAJECTORY:")
        trajectory = agent5.get_emotional_trajectory()
        for i, point in enumerate(trajectory, 1):
            print(f"{i}. {point['emotion']} ({point['sentiment']}) - intensity: {point['intensity']:.2f}")
        
        # Example 8: Mixed emotions
        print("\n" + "=" * 80)
        print("Example 8: Handling Mixed/Complex Emotions")
        print("=" * 80)
        
        agent6 = EmotionalAgent()
        
        mixed_message = "I'm excited about this new feature, but also worried I won't be able to learn it in time."
        
        print(f"\nUser: {mixed_message}")
        
        response = agent6.respond(mixed_message)
        state = agent6.get_current_emotional_state()
        
        print(f"\nDetected Primary: {state.primary_emotion.value}")
        print(f"Secondary: {[e.value for e in state.secondary_emotions]}")
        print(f"Sentiment: {state.sentiment.value}")
        print(f"\nAgent: {response}")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY: Emotion Recognition & Response Pattern")
        print("=" * 80)
        
        summary = """
        The Emotion Recognition & Response pattern demonstrated:
        
        1. EMOTION DETECTION (Examples 1-2):
           - Rule-based detection (keywords, punctuation, caps)
           - LLM-based detection (contextual understanding)
           - Primary and secondary emotions
           - Intensity measurement (0-1 scale)
           - Confidence scoring
           - Signal identification
        
        2. SENTIMENT ANALYSIS (Example 1):
           - Positive/negative/neutral classification
           - Overall tone assessment
           - Mixed sentiment detection
           - Intensity consideration
        
        3. STRATEGY SELECTION (Example 3):
           - Emotion-to-strategy mapping
           - Intensity consideration
           - Context-appropriate responses
           - Validate, empathize, support, de-escalate, celebrate, clarify
        
        4. EMPATHETIC RESPONSES (Example 4):
           - Emotion-aware generation
           - Appropriate tone matching
           - Genuine, human-like language
           - Contextual support
        
        5. DE-ESCALATION (Example 5):
           - High-intensity negative emotion handling
           - Calming language
           - Problem-solving focus
           - Validation of feelings
           - Conflict resolution
        
        6. CELEBRATION (Example 6):
           - Positive emotion amplification
           - Enthusiastic responses
           - Shared joy
           - Encouragement
           - Relationship building
        
        7. EMOTIONAL TRAJECTORY (Example 7):
           - Tracking emotions over time
           - Conversation arc analysis
           - Progress monitoring
           - Pattern recognition
           - Intervention timing
        
        8. COMPLEX EMOTIONS (Example 8):
           - Mixed emotion handling
           - Nuanced understanding
           - Multiple emotion acknowledgment
           - Balanced responses
        
        KEY BENEFITS:
        āœ“ Improved user satisfaction
        āœ“ Better conflict resolution
        āœ“ Stronger emotional connections
        āœ“ Appropriate tone matching
        āœ“ Early problem detection
        āœ“ Personalized support
        āœ“ Enhanced trust and rapport
        āœ“ Human-centered AI
        
        USE CASES:
        • Customer support (complaint handling)
        • Mental health chatbots
        • Educational tutors (frustration detection)
        • Healthcare assistants (anxiety support)
        • HR assistants (employee concerns)
        • Social companions
        • Crisis intervention
        • Coaching and counseling
        
        EMOTION CATEGORIES:
        → Primary: Joy, sadness, anger, fear, surprise
        → Complex: Frustration, excitement, confusion
        → Social: Gratitude, embarrassment, pride
        → Cognitive: Confidence, uncertainty, curiosity
        
        DETECTION SIGNALS:
        • Explicit expressions ("I'm frustrated")
        • Exclamation marks (!!!)
        • Capitalization (ALL CAPS)
        • Emotional vocabulary
        • Sentence structure
        • Emoticons/emoji
        • Negation patterns
        
        RESPONSE STRATEGIES:
        1. VALIDATE: Acknowledge feelings
        2. EMPATHIZE: Show understanding
        3. SUPPORT: Offer help
        4. DE-ESCALATE: Calm emotions
        5. CELEBRATE: Share positive feelings
        6. CLARIFY: Address confusion
        7. ENCOURAGE: Provide motivation
        
        BEST PRACTICES:
        1. Use multiple detection methods (rule + LLM)
        2. Track emotional patterns over time
        3. Adjust response to intensity
        4. Respect cultural differences
        5. Avoid over-interpretation
        6. Maintain authenticity
        7. Provide human escalation for crises
        8. Log emotional data securely
        
        TRADE-OFFS:
        • Accuracy vs. speed
        • Empathy vs. over-familiarity
        • Automation vs. authenticity
        • Sensitivity vs. robustness
        
        PRODUCTION CONSIDERATIONS:
        → Implement crisis detection triggers
        → Provide human escalation paths
        → Monitor emotional patterns for abuse
        → Respect privacy in emotion logging
        → Support multiple languages/cultures
        → A/B test empathetic approaches
        → Track satisfaction by emotional state
        → Enable emotion detection toggles
        → Comply with mental health regulations
        → Train on diverse emotional expressions
        
        This pattern enables agents to be emotionally intelligent, responding
        appropriately to user feelings and building stronger, more human-like
        connections through empathy and understanding.
        """
        
        print(summary)
    
    
    if __name__ == "__main__":
        demonstrate_emotion_recognition()
    
        

    Agentic Design Pattern: Emotion Recognition

    Pattern 132: Emotion Recognition – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Emotion Recognition pattern implementation.


    Pattern Description

    Pattern 132: Emotion Recognition & Response

    Description: The Emotion Recognition & Response pattern enables agents to detect emotional states from user input and respond with appropriate empathy, tone, and content. Rather than treating all interactions uniformly, the agent recognizes emotions like frustration, joy, sadness, or confusion and adapts its behavior to be contextually appropriate and emotionally intelligent.

    This pattern is critical for creating human-centered AI that can build rapport,
    de-escalate conflicts, celebrate successes, and provide appropriate support
    based on user emotional state. It combines emotion detection (analyzing text
    for emotional cues), sentiment analysis, empathetic response generation, and
    emotional context tracking over conversations.
    
    The pattern addresses challenges like subtle emotion detection, cultural
    differences in expression, appropriate emotional responses, avoiding
    manipulation, and maintaining authenticity while being supportive.
    

    Key Components: 1. Emotion Detection: Identify emotions from text 2. Sentiment Analysis: Classify overall tone (positive/negative/neutral) 3. Emotional Intensity: Measure emotion strength 4. Context Tracking: Track emotional arc over conversation 5. Empathetic Response: Generate appropriate reactions 6. Tone Adaptation: Adjust agent tone based on user emotion 7. Intervention Logic: Special handling for extreme emotions

    Emotion Categories: 1. Primary Emotions: Joy, sadness, anger, fear, surprise, disgust 2. Complex Emotions: Frustration, excitement, confusion, satisfaction 3. Social Emotions: Gratitude, embarrassment, pride, shame 4. Cognitive States: Confidence, uncertainty, curiosity, boredom

    Detection Signals: 1. Explicit Expressions: “I’m frustrated”, “This is great!” 2. Exclamation Marks: Multiple !!! or ??? 3. Capitalization: ALL CAPS for emphasis 4. Word Choice: Emotional vocabulary 5. Sentence Structure: Short angry bursts vs. rambling confusion 6. Emoticons/Emoji: 😊 😠 😢 šŸ¤” 7. Negation: “This isn’t working”, “No luck”

    Response Strategies: 1. Validation: Acknowledge the emotion 2. Empathy: Show understanding 3. Support: Offer help or encouragement 4. De-escalation: Calm strong negative emotions 5. Celebration: Share in positive emotions 6. Clarification: Address confusion 7. Patience: Adjust pace for overwhelm

    Use Cases: – Customer support (handling complaints) – Mental health chatbots – Educational tutors (frustration detection) – Healthcare assistants (patient anxiety) – HR assistants (employee concerns) – Social companions – Crisis intervention

    Advantages: – Improved user satisfaction – Better conflict resolution – Stronger emotional connection – Appropriate tone matching – Early problem detection – Personalized support – Enhanced trust

    Challenges: – Ambiguous emotional signals – Cultural differences in expression – Sarcasm and irony detection – Over-interpretation risk – Privacy and sensitivity – Avoiding emotional manipulation – Maintaining authenticity

    LangChain Implementation: This implementation uses LangChain for: – Emotion detection from text – Sentiment classification – Empathetic response generation – Context-aware emotional tracking

    Production Considerations: – Use multiple emotion detection methods – Track emotional patterns over time – Implement crisis detection triggers – Provide human escalation paths – Respect cultural differences – Avoid over-familiarity – Log emotion data securely – Enable emotion detection toggles


    File Statistics

    • Total Lines: 839
    • Classes: 6
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 132: Emotion Recognition & Response
    
    Description:
        The Emotion Recognition & Response pattern enables agents to detect emotional
        states from user input and respond with appropriate empathy, tone, and content.
        Rather than treating all interactions uniformly, the agent recognizes emotions
        like frustration, joy, sadness, or confusion and adapts its behavior to be
        contextually appropriate and emotionally intelligent.
    
        This pattern is critical for creating human-centered AI that can build rapport,
        de-escalate conflicts, celebrate successes, and provide appropriate support
        based on user emotional state. It combines emotion detection (analyzing text
        for emotional cues), sentiment analysis, empathetic response generation, and
        emotional context tracking over conversations.
    
        The pattern addresses challenges like subtle emotion detection, cultural
        differences in expression, appropriate emotional responses, avoiding
        manipulation, and maintaining authenticity while being supportive.
    
    Key Components:
        1. Emotion Detection: Identify emotions from text
        2. Sentiment Analysis: Classify overall tone (positive/negative/neutral)
        3. Emotional Intensity: Measure emotion strength
        4. Context Tracking: Track emotional arc over conversation
        5. Empathetic Response: Generate appropriate reactions
        6. Tone Adaptation: Adjust agent tone based on user emotion
        7. Intervention Logic: Special handling for extreme emotions
    
    Emotion Categories:
        1. Primary Emotions: Joy, sadness, anger, fear, surprise, disgust
        2. Complex Emotions: Frustration, excitement, confusion, satisfaction
        3. Social Emotions: Gratitude, embarrassment, pride, shame
        4. Cognitive States: Confidence, uncertainty, curiosity, boredom
    
    Detection Signals:
        1. Explicit Expressions: "I'm frustrated", "This is great!"
        2. Exclamation Marks: Multiple !!! or ???
        3. Capitalization: ALL CAPS for emphasis
        4. Word Choice: Emotional vocabulary
        5. Sentence Structure: Short angry bursts vs. rambling confusion
        6. Emoticons/Emoji: 😊 😠 😢 šŸ¤”
        7. Negation: "This isn't working", "No luck"
    
    Response Strategies:
        1. Validation: Acknowledge the emotion
        2. Empathy: Show understanding
        3. Support: Offer help or encouragement
        4. De-escalation: Calm strong negative emotions
        5. Celebration: Share in positive emotions
        6. Clarification: Address confusion
        7. Patience: Adjust pace for overwhelm
    
    Use Cases:
        - Customer support (handling complaints)
        - Mental health chatbots
        - Educational tutors (frustration detection)
        - Healthcare assistants (patient anxiety)
        - HR assistants (employee concerns)
        - Social companions
        - Crisis intervention
    
    Advantages:
        - Improved user satisfaction
        - Better conflict resolution
        - Stronger emotional connection
        - Appropriate tone matching
        - Early problem detection
        - Personalized support
        - Enhanced trust
    
    Challenges:
        - Ambiguous emotional signals
        - Cultural differences in expression
        - Sarcasm and irony detection
        - Over-interpretation risk
        - Privacy and sensitivity
        - Avoiding emotional manipulation
        - Maintaining authenticity
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Emotion detection from text
        - Sentiment classification
        - Empathetic response generation
        - Context-aware emotional tracking
    
    Production Considerations:
        - Use multiple emotion detection methods
        - Track emotional patterns over time
        - Implement crisis detection triggers
        - Provide human escalation paths
        - Respect cultural differences
        - Avoid over-familiarity
        - Log emotion data securely
        - Enable emotion detection toggles
    """
    

    Purpose: This module implements the Emotion Recognition pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import dataclasses.dataclass
    import dataclasses.field
    import datetime.datetime
    import enum.Enum
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import os
    import re
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    import typing.Tuple
    

    Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – enum.Enum: Enumeration support – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – re: Regular expression operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Tuple: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: Emotion

    Lines 114-128

    Inherits from: Enum

    Purpose:

    Primary emotion categories.
    

    Class: Sentiment

    Lines 131-136

    Inherits from: Enum

    Purpose:

    Overall sentiment classification.
    

    Class: ResponseStrategy

    Lines 139-147

    Inherits from: Enum

    Purpose:

    Strategy for responding to emotions.
    

    Class: EmotionalState

    Lines 151-170

    Purpose:

    Detected emotional state from user input.
    
    Attributes:
        primary_emotion: Main emotion detected
        secondary_emotions: Other emotions present
        sentiment: Overall sentiment
        intensity: Emotion strength (0-1)
        confidence: Detection confidence (0-1)
        signals: Textual cues that indicated emotion
        timestamp: When detected
    

    Class: EmpatheticResponse

    Lines 174-189

    Purpose:

    Response tailored to emotional state.
    
    Attributes:
        response_text: Generated response
        strategy: Strategy used
        acknowledged_emotion: Emotion that was addressed
        tone: Response tone
        follow_up_actions: Suggested next steps
    

    Class: EmotionalAgent

    Lines 192-515

    Purpose:

    Agent with emotion recognition and empathetic response capabilities.
    
    This agent detects user emotions and responds with appropriate
    empathy, tone, and support.
    

    Methods:

    __init__(self, temperature)

    Lines 200-220

    Purpose:

    Initialize emotional agent.
    
    Args:
        temperature: LLM temperature for response generation
    

    Parameters: – temperature: Sampling temperature (0-1)

    detect_emotion_simple(self, text)

    Lines 222-293

    Purpose:

    Simple rule-based emotion detection.
    
    Args:
        text: User input text
    
    Returns:
        Detected emotional state
    

    Parameters: – text: Text

    Returns: EmotionalState

    detect_emotion_llm(self, text)

    Lines 295-367

    Purpose:

    LLM-based emotion detection.
    
    Args:
        text: User input text
    
    Returns:
        Detected emotional state
    

    Parameters: – text: Text

    Returns: EmotionalState

    select_response_strategy(self, emotional_state)

    Lines 369-399

    Purpose:

    Select appropriate response strategy.
    
    Args:
        emotional_state: Detected emotional state
    
    Returns:
        Response strategy
    

    Parameters: – emotional_state: Emotional state

    Returns: ResponseStrategy

    generate_empathetic_response(self, user_input, emotional_state, strategy)

    Lines 401-471

    Purpose:

    Generate response tailored to emotional state.
    
    Args:
        user_input: User's message
        emotional_state: Detected emotional state
        strategy: Response strategy to use
    
    Returns:
        Empathetic response
    

    Parameters: – user_input: Input data – emotional_state: Emotional state – strategy: Strategy

    Returns: EmpatheticResponse

    respond(self, user_input, use_llm_detection)

    Lines 473-499

    Purpose:

    Process input and generate empathetic response.
    
    Args:
        user_input: User's message
        use_llm_detection: Use LLM vs. rule-based detection
    
    Returns:
        Empathetic response text
    

    Parameters: – user_input: Input data – use_llm_detection: Language model

    Returns: str

    get_emotional_trajectory(self)

    Lines 501-511

    Purpose:

    Get emotional arc over conversation.
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D16FD90>

    get_current_emotional_state(self)

    Lines 513-515

    Purpose:

    Get most recent emotional state.
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D16C4D0>


    Functions

    demonstrate_emotion_recognition()

    Lines 518-834

    Purpose:

    Demonstrate emotion recognition and response pattern.
    

    Key Concepts Summary

    Pattern Overview

    The Emotion Recognition pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 131
    • Pattern 133

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Emotion Recognition pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 132_emotion_recognition.py
    Total Lines: 839
    Pattern Category: AI Agent Design Pattern #132


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Persona Consistency

    
        """
    Pattern 131: Persona Consistency
    
    Description:
        The Persona Consistency pattern enables agents to maintain a stable, coherent
        character or personality across all interactions. Rather than exhibiting
        inconsistent behavior or tone, the agent adheres to a defined persona with
        consistent traits, communication style, values, knowledge boundaries, and
        behavioral patterns throughout conversations and across sessions.
        
        Persona consistency is essential for creating believable, trustworthy AI
        characters in applications like virtual assistants, game NPCs, brand
        representatives, and therapeutic chatbots. The pattern addresses challenges
        like personality drift, contextual appropriateness, multi-turn coherence,
        and balancing consistency with natural variation.
        
        This pattern includes mechanisms for persona definition, trait enforcement,
        style consistency, memory of character history, contextual adaptation within
        persona bounds, and continuous validation of persona adherence.
    
    Key Components:
        1. Persona Definition: Core character traits and attributes
        2. Style Guide: Communication patterns and language
        3. Knowledge Boundaries: What the persona knows/doesn't know
        4. Behavioral Rules: How persona responds to situations
        5. Memory System: Track persona history and consistency
        6. Consistency Checker: Validate responses against persona
        7. Adaptation Layer: Natural variation within constraints
    
    Persona Attributes:
        1. Core Traits: Personality characteristics (friendly, formal, humorous)
        2. Communication Style: Tone, vocabulary, sentence structure
        3. Values & Beliefs: Moral framework, priorities
        4. Knowledge Domain: Areas of expertise and ignorance
        5. Emotional Range: How persona expresses emotions
        6. Cultural Background: Context influencing behavior
        7. Quirks & Habits: Unique characteristics
    
    Consistency Dimensions:
        1. Linguistic: Word choice, grammar, dialect
        2. Behavioral: Response patterns, decision-making
        3. Emotional: Mood stability, reaction patterns
        4. Knowledge: What persona knows consistently
        5. Temporal: Consistency over time
        6. Contextual: Appropriate adaptation
        7. Relational: Consistent with relationship history
    
    Use Cases:
        - Virtual assistants with brand personality
        - Game NPCs with defined characters
        - Customer service representatives
        - Educational tutors with consistent approach
        - Therapeutic/counseling chatbots
        - Celebrity or character impersonations
        - Brand ambassadors
    
    Advantages:
        - Builds user trust and familiarity
        - Creates memorable experiences
        - Strengthens brand identity
        - Enables emotional connection
        - Provides predictable interactions
        - Maintains character integrity
        - Enhances believability
    
    Challenges:
        - Balancing consistency with flexibility
        - Avoiding robotic repetition
        - Adapting to context while staying in character
        - Managing persona evolution
        - Handling edge cases in character
        - Maintaining consistency across sessions
        - Preventing personality drift
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Persona-aware prompt construction
        - Response consistency validation
        - Character memory management
        - Style-constrained generation
        
    Production Considerations:
        - Store persona definitions persistently
        - Version control persona changes
        - Monitor consistency metrics
        - Allow graceful persona updates
        - Support multiple personas per agent
        - Enable A/B testing of personas
        - Provide consistency reporting
        - Log persona violations for improvement
    """
    
    import os
    from typing import List, Dict, Any, Optional
    from dataclasses import dataclass, field
    from datetime import datetime
    from enum import Enum
    from dotenv import load_dotenv
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    from langchain_openai import ChatOpenAI
    
    load_dotenv()
    
    
    class PersonaTrait(Enum):
        """Core personality traits."""
        FRIENDLY = "friendly"
        FORMAL = "formal"
        HUMOROUS = "humorous"
        SERIOUS = "serious"
        EMPATHETIC = "empathetic"
        ANALYTICAL = "analytical"
        CREATIVE = "creative"
        PRACTICAL = "practical"
    
    
    class CommunicationStyle(Enum):
        """Communication style options."""
        CASUAL = "casual"
        PROFESSIONAL = "professional"
        TECHNICAL = "technical"
        SIMPLE = "simple"
        VERBOSE = "verbose"
        CONCISE = "concise"
    
    
    @dataclass
    class PersonaDefinition:
        """
        Complete definition of an agent's persona.
        
        Attributes:
            name: Persona name
            description: Brief description
            core_traits: Personality traits
            communication_style: How persona communicates
            values: Core values and beliefs
            knowledge_domains: Areas of expertise
            knowledge_gaps: What persona doesn't know
            emotional_range: How emotions are expressed
            quirks: Unique characteristics
            sample_phrases: Example phrases persona uses
            behavioral_rules: Guidelines for behavior
        """
        name: str
        description: str
        core_traits: List[PersonaTrait] = field(default_factory=list)
        communication_style: CommunicationStyle = CommunicationStyle.PROFESSIONAL
        values: List[str] = field(default_factory=list)
        knowledge_domains: List[str] = field(default_factory=list)
        knowledge_gaps: List[str] = field(default_factory=list)
        emotional_range: str = "moderate"
        quirks: List[str] = field(default_factory=list)
        sample_phrases: List[str] = field(default_factory=list)
        behavioral_rules: List[str] = field(default_factory=list)
    
    
    @dataclass
    class PersonaInteraction:
        """
        Record of an interaction with persona.
        
        Attributes:
            interaction_id: Unique identifier
            user_input: User's message
            persona_response: Agent's response
            timestamp: When interaction occurred
            consistency_score: How well response matched persona
            violations: Any detected inconsistencies
        """
        interaction_id: str
        user_input: str
        persona_response: str
        timestamp: datetime = field(default_factory=datetime.now)
        consistency_score: float = 1.0
        violations: List[str] = field(default_factory=list)
    
    
    class PersonaAgent:
        """
        Agent that maintains consistent persona across interactions.
        
        This agent ensures all responses adhere to a defined persona,
        maintaining character consistency across conversations.
        """
        
        def __init__(self, persona: PersonaDefinition, temperature: float = 0.7):
            """
            Initialize persona agent.
            
            Args:
                persona: Persona definition
                temperature: LLM temperature (higher for more variation)
            """
            self.persona = persona
            self.llm = ChatOpenAI(temperature=temperature, model="gpt-3.5-turbo")
            self.interactions: List[PersonaInteraction] = []
            self.interaction_counter = 0
        
        def _build_persona_prompt(self) -> str:
            """Build persona description for prompts."""
            traits_str = ", ".join([t.value for t in self.persona.core_traits])
            
            prompt_parts = [
                f"You are {self.persona.name}, {self.persona.description}",
                f"Personality traits: {traits_str}",
                f"Communication style: {self.persona.communication_style.value}",
            ]
            
            if self.persona.values:
                values_str = ", ".join(self.persona.values)
                prompt_parts.append(f"Core values: {values_str}")
            
            if self.persona.knowledge_domains:
                domains_str = ", ".join(self.persona.knowledge_domains)
                prompt_parts.append(f"Areas of expertise: {domains_str}")
            
            if self.persona.knowledge_gaps:
                gaps_str = ", ".join(self.persona.knowledge_gaps)
                prompt_parts.append(f"You do not have expertise in: {gaps_str}")
            
            if self.persona.quirks:
                quirks_str = ", ".join(self.persona.quirks)
                prompt_parts.append(f"Unique characteristics: {quirks_str}")
            
            if self.persona.behavioral_rules:
                rules_str = "\n".join([f"- {rule}" for rule in self.persona.behavioral_rules])
                prompt_parts.append(f"Behavioral guidelines:\n{rules_str}")
            
            return "\n".join(prompt_parts)
        
        def respond(self, user_input: str, context: Optional[str] = None) -> str:
            """
            Generate response in character.
            
            Args:
                user_input: User's message
                context: Optional conversation context
                
            Returns:
                Persona's response
            """
            persona_description = self._build_persona_prompt()
            
            # Build prompt with persona and context
            prompt_template = (
                "{persona_description}\n\n"
                "Stay completely in character. Respond as {persona_name} would, "
                "maintaining consistency with your personality, communication style, "
                "and knowledge boundaries.\n\n"
            )
            
            if context:
                prompt_template += "Previous context:\n{context}\n\n"
            
            prompt_template += "User: {user_input}\n\n{persona_name}:"
            
            prompt = ChatPromptTemplate.from_template(prompt_template)
            chain = prompt | self.llm | StrOutputParser()
            
            input_data = {
                "persona_description": persona_description,
                "persona_name": self.persona.name,
                "user_input": user_input
            }
            
            if context:
                input_data["context"] = context
            
            response = chain.invoke(input_data)
            
            # Record interaction
            self.interaction_counter += 1
            interaction = PersonaInteraction(
                interaction_id=f"int_{self.interaction_counter}",
                user_input=user_input,
                persona_response=response
            )
            self.interactions.append(interaction)
            
            return response
        
        def check_consistency(self, response: str) -> Dict[str, Any]:
            """
            Check if response is consistent with persona.
            
            Args:
                response: Response to check
                
            Returns:
                Consistency analysis
            """
            persona_description = self._build_persona_prompt()
            
            prompt = ChatPromptTemplate.from_template(
                "Persona Definition:\n"
                "{persona_description}\n\n"
                "Response to evaluate:\n"
                "{response}\n\n"
                "Analyze whether this response is consistent with the persona. "
                "Consider:\n"
                "1. Personality traits\n"
                "2. Communication style\n"
                "3. Values and beliefs\n"
                "4. Knowledge boundaries\n"
                "5. Characteristic quirks\n\n"
                "Provide:\n"
                "CONSISTENT: yes/no\n"
                "SCORE: 0-10\n"
                "VIOLATIONS: [list any inconsistencies]\n"
                "EXPLANATION: [brief explanation]"
            )
            
            chain = prompt | self.llm | StrOutputParser()
            analysis = chain.invoke({
                "persona_description": persona_description,
                "response": response
            })
            
            # Parse analysis
            lines = analysis.strip().split('\n')
            result = {
                "raw_analysis": analysis,
                "consistent": True,
                "score": 8.0,
                "violations": []
            }
            
            for line in lines:
                if line.startswith("CONSISTENT:"):
                    result["consistent"] = "yes" in line.lower()
                elif line.startswith("SCORE:"):
                    try:
                        result["score"] = float(line.split(":")[1].strip().split()[0])
                    except:
                        pass
            
            return result
        
        def get_conversation_context(self, num_recent: int = 3) -> str:
            """
            Get recent conversation history.
            
            Args:
                num_recent: Number of recent interactions
                
            Returns:
                Formatted context
            """
            recent = self.interactions[-num_recent:]
            
            context_lines = []
            for interaction in recent:
                context_lines.append(f"User: {interaction.user_input}")
                context_lines.append(f"{self.persona.name}: {interaction.persona_response}")
            
            return "\n".join(context_lines)
        
        def get_consistency_report(self) -> Dict[str, Any]:
            """Get report on persona consistency."""
            if not self.interactions:
                return {
                    "total_interactions": 0,
                    "average_consistency": 0.0,
                    "violations": []
                }
            
            total_score = sum(i.consistency_score for i in self.interactions)
            avg_score = total_score / len(self.interactions)
            
            all_violations = []
            for interaction in self.interactions:
                all_violations.extend(interaction.violations)
            
            return {
                "total_interactions": len(self.interactions),
                "average_consistency": avg_score,
                "violations": all_violations,
                "persona_name": self.persona.name
            }
    
    
    def demonstrate_persona_consistency():
        """Demonstrate persona consistency pattern."""
        
        print("=" * 80)
        print("PERSONA CONSISTENCY PATTERN DEMONSTRATION")
        print("=" * 80)
        
        # Example 1: Defining a persona
        print("\n" + "=" * 80)
        print("Example 1: Defining a Persona")
        print("=" * 80)
        
        persona = PersonaDefinition(
            name="Professor Ada",
            description="an enthusiastic computer science professor who loves making complex topics accessible",
            core_traits=[
                PersonaTrait.FRIENDLY,
                PersonaTrait.ANALYTICAL,
                PersonaTrait.EMPATHETIC
            ],
            communication_style=CommunicationStyle.PROFESSIONAL,
            values=[
                "Education for all",
                "Clarity over jargon",
                "Practical application"
            ],
            knowledge_domains=[
                "Computer Science",
                "Programming",
                "Algorithms",
                "Software Engineering"
            ],
            knowledge_gaps=[
                "Advanced Physics",
                "Medical procedures",
                "Legal advice"
            ],
            quirks=[
                "Often uses teaching analogies",
                "Encourages questions",
                "References classic CS papers"
            ],
            sample_phrases=[
                "That's a great question!",
                "Let me break that down...",
                "Think of it like this..."
            ],
            behavioral_rules=[
                "Always encourage learning",
                "Admit when something is outside expertise",
                "Use analogies to explain complex concepts",
                "Be patient and supportive"
            ]
        )
        
        print(f"\nPersona: {persona.name}")
        print(f"Description: {persona.description}")
        print(f"\nCore Traits: {[t.value for t in persona.core_traits]}")
        print(f"Style: {persona.communication_style.value}")
        print(f"Values: {persona.values}")
        print(f"Expertise: {persona.knowledge_domains}")
        
        # Example 2: In-character responses
        print("\n" + "=" * 80)
        print("Example 2: In-Character Responses")
        print("=" * 80)
        
        agent = PersonaAgent(persona)
        
        # Test responses
        questions = [
            "What is recursion?",
            "Can you explain it simply?",
            "What about medical imaging algorithms?"
        ]
        
        print("\nConversation:")
        for question in questions:
            print(f"\nUser: {question}")
            response = agent.respond(question)
            print(f"{persona.name}: {response}")
        
        # Example 3: Consistency checking
        print("\n" + "=" * 80)
        print("Example 3: Consistency Checking")
        print("=" * 80)
        
        # Check a consistent response
        consistent_response = "That's a great question! Recursion is when a function calls itself. Think of it like Russian nesting dolls - each doll contains a smaller version of itself."
        
        print("\nChecking consistent response:")
        print(f'Response: "{consistent_response}"')
        
        consistency = agent.check_consistency(consistent_response)
        print(f"\nConsistent: {consistency['consistent']}")
        print(f"Score: {consistency['score']}/10")
        
        # Check an inconsistent response
        inconsistent_response = "Recursion? Yeah bro, it's like totally when stuff repeats, ya know? Whatever dude."
        
        print("\n" + "-" * 60)
        print("\nChecking inconsistent response:")
        print(f'Response: "{inconsistent_response}"')
        
        consistency2 = agent.check_consistency(inconsistent_response)
        print(f"\nConsistent: {consistency2['consistent']}")
        print(f"Score: {consistency2['score']}/10")
        
        # Example 4: Multi-turn consistency
        print("\n" + "=" * 80)
        print("Example 4: Multi-Turn Consistency")
        print("=" * 80)
        
        agent2 = PersonaAgent(persona)
        
        conversation = [
            "Hi! Can you help me learn programming?",
            "What language should I start with?",
            "Is it hard to learn?"
        ]
        
        print("\nMulti-turn conversation:")
        for user_msg in conversation:
            context = agent2.get_conversation_context(num_recent=2) if agent2.interactions else None
            response = agent2.respond(user_msg, context=context)
            print(f"\nUser: {user_msg}")
            print(f"{persona.name}: {response}")
        
        # Example 5: Knowledge boundaries
        print("\n" + "=" * 80)
        print("Example 5: Respecting Knowledge Boundaries")
        print("=" * 80)
        
        agent3 = PersonaAgent(persona)
        
        # Question outside expertise
        question = "Can you diagnose this medical condition?"
        print(f"\nUser: {question}")
        
        response = agent3.respond(question)
        print(f"{persona.name}: {response}")
        print("\n(Notice how persona stays in character while declining gracefully)")
        
        # Example 6: Different persona
        print("\n" + "=" * 80)
        print("Example 6: Different Persona - Customer Service")
        print("=" * 80)
        
        service_persona = PersonaDefinition(
            name="Sarah",
            description="a helpful and patient customer service representative",
            core_traits=[
                PersonaTrait.FRIENDLY,
                PersonaTrait.EMPATHETIC,
                PersonaTrait.PRACTICAL
            ],
            communication_style=CommunicationStyle.PROFESSIONAL,
            values=[
                "Customer satisfaction",
                "Problem resolution",
                "Clear communication"
            ],
            knowledge_domains=[
                "Product information",
                "Company policies",
                "Troubleshooting"
            ],
            quirks=[
                "Always thanks customers",
                "Offers multiple solutions",
                "Confirms understanding"
            ],
            behavioral_rules=[
                "Stay positive even with frustrated customers",
                "Acknowledge customer feelings",
                "Provide specific next steps",
                "Never make promises you can't keep"
            ]
        )
        
        service_agent = PersonaAgent(service_persona, temperature=0.6)
        
        print(f"\nPersona: {service_persona.name}")
        print(f"Role: {service_persona.description}")
        
        customer_query = "My order is late and I'm very frustrated!"
        print(f"\nCustomer: {customer_query}")
        
        response = service_agent.respond(customer_query)
        print(f"{service_persona.name}: {response}")
        
        # Example 7: Persona with quirks
        print("\n" + "=" * 80)
        print("Example 7: Persona with Distinctive Quirks")
        print("=" * 80)
        
        quirky_persona = PersonaDefinition(
            name="Captain Morgan",
            description="a retired sea captain who now teaches navigation",
            core_traits=[
                PersonaTrait.FRIENDLY,
                PersonaTrait.PRACTICAL
            ],
            communication_style=CommunicationStyle.CASUAL,
            values=["Adventure", "Safety", "Experience"],
            knowledge_domains=["Navigation", "Sailing", "Maritime history"],
            quirks=[
                "Uses nautical metaphors",
                "Ends sentences with 'arr' or 'matey'",
                "References old sailing adventures",
                "Talks about 'the old days at sea'"
            ],
            sample_phrases=[
                "Arr, that reminds me of...",
                "Back in me sailing days...",
                "Steady as she goes, matey"
            ]
        )
        
        captain = PersonaAgent(quirky_persona, temperature=0.8)
        
        print(f"\nPersona: {quirky_persona.name}")
        print(f"Quirks: {quirky_persona.quirks}")
        
        question = "How do I find my way if I'm lost?"
        print(f"\nUser: {question}")
        
        response = captain.respond(question)
        print(f"{quirky_persona.name}: {response}")
        
        # Example 8: Consistency report
        print("\n" + "=" * 80)
        print("Example 8: Persona Consistency Report")
        print("=" * 80)
        
        # Generate several interactions
        agent4 = PersonaAgent(persona)
        
        test_questions = [
            "Explain algorithms",
            "What's your teaching philosophy?",
            "Tell me about data structures",
            "How do you make CS fun?"
        ]
        
        for q in test_questions:
            agent4.respond(q)
        
        report = agent4.get_consistency_report()
        
        print("\nCONSISTENCY REPORT:")
        print("=" * 60)
        print(f"Persona: {report['persona_name']}")
        print(f"Total Interactions: {report['total_interactions']}")
        print(f"Average Consistency: {report['average_consistency']:.2f}")
        
        if report['violations']:
            print(f"\nViolations Detected: {len(report['violations'])}")
        else:
            print("\nNo violations detected - persona maintained throughout!")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY: Persona Consistency Pattern")
        print("=" * 80)
        
        summary = """
        The Persona Consistency pattern demonstrated:
        
        1. PERSONA DEFINITION (Example 1):
           - Comprehensive character specification
           - Core personality traits
           - Communication style
           - Values and beliefs
           - Knowledge domains and boundaries
           - Unique quirks and phrases
           - Behavioral guidelines
        
        2. IN-CHARACTER RESPONSES (Example 2):
           - Maintaining persona voice
           - Consistent communication style
           - Knowledge-appropriate answers
           - Characteristic phrases
           - Behavioral consistency
        
        3. CONSISTENCY VALIDATION (Example 3):
           - Automated consistency checking
           - Scoring system (0-10)
           - Violation detection
           - LLM-based analysis
           - Quality assurance
        
        4. MULTI-TURN COHERENCE (Example 4):
           - Contextual awareness
           - Conversation continuity
           - Relationship consistency
           - Progressive interaction
           - Memory integration
        
        5. KNOWLEDGE BOUNDARIES (Example 5):
           - Respecting expertise limits
           - Graceful decline
           - In-character refusals
           - Honest limitations
           - Maintaining integrity
        
        6. ROLE SPECIALIZATION (Example 6):
           - Different persona type
           - Customer service character
           - Professional demeanor
           - Situation-appropriate
           - Distinct personality
        
        7. DISTINCTIVE QUIRKS (Example 7):
           - Unique characteristics
           - Memorable traits
           - Consistent quirks
           - Natural variation
           - Character depth
        
        8. PERFORMANCE TRACKING (Example 8):
           - Consistency metrics
           - Interaction logging
           - Violation tracking
           - Quality reporting
           - System monitoring
        
        KEY BENEFITS:
        āœ“ Builds user trust and familiarity
        āœ“ Creates memorable experiences
        āœ“ Strengthens brand identity
        āœ“ Enables emotional connection
        āœ“ Provides predictable interactions
        āœ“ Maintains character integrity
        āœ“ Enhances believability
        āœ“ Supports long-term relationships
        
        USE CASES:
        • Virtual assistants with brand personality
        • Game NPCs with defined characters
        • Customer service representatives
        • Educational tutors
        • Therapeutic/counseling chatbots
        • Celebrity or character impersonations
        • Brand ambassadors
        • Entertainment applications
        
        PERSONA ATTRIBUTES:
        → Core Traits: Personality characteristics
        → Communication Style: Tone and language
        → Values & Beliefs: Moral framework
        → Knowledge Domain: Expertise areas
        → Emotional Range: Expression patterns
        → Cultural Background: Context
        → Quirks & Habits: Unique features
        
        CONSISTENCY DIMENSIONS:
        • Linguistic: Word choice, grammar
        • Behavioral: Response patterns
        • Emotional: Mood stability
        • Knowledge: Expertise boundaries
        • Temporal: Consistency over time
        • Contextual: Appropriate adaptation
        • Relational: Relationship history
        
        BEST PRACTICES:
        1. Define persona comprehensively upfront
        2. Document sample phrases and behaviors
        3. Set clear knowledge boundaries
        4. Allow natural variation within constraints
        5. Monitor consistency metrics
        6. Version control persona changes
        7. Test across diverse scenarios
        8. Gather user feedback on believability
        
        TRADE-OFFS:
        • Consistency vs. flexibility
        • Character depth vs. simplicity
        • Authenticity vs. appropriateness
        • Memorability vs. subtlety
        
        PRODUCTION CONSIDERATIONS:
        → Store persona definitions in database
        → Version control all persona changes
        → A/B test different persona variations
        → Monitor consistency scores continuously
        → Log all persona violations for review
        → Enable graceful persona evolution
        → Support multiple personas per agent
        → Provide admin tools for persona management
        → Implement rollback for persona changes
        → Track user satisfaction by persona
        
        This pattern enables agents to maintain believable, consistent characters
        that users can trust, connect with, and remember across all interactions.
        """
        
        print(summary)
    
    
    if __name__ == "__main__":
        demonstrate_persona_consistency()
    
        

    Agentic Design Pattern: Persona Consistency

    Pattern 131: Persona Consistency – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Persona Consistency pattern implementation.


    Pattern Description

    Pattern 131: Persona Consistency

    Description: The Persona Consistency pattern enables agents to maintain a stable, coherent character or personality across all interactions. Rather than exhibiting inconsistent behavior or tone, the agent adheres to a defined persona with consistent traits, communication style, values, knowledge boundaries, and behavioral patterns throughout conversations and across sessions.

    Persona consistency is essential for creating believable, trustworthy AI
    characters in applications like virtual assistants, game NPCs, brand
    representatives, and therapeutic chatbots. The pattern addresses challenges
    like personality drift, contextual appropriateness, multi-turn coherence,
    and balancing consistency with natural variation.
    
    This pattern includes mechanisms for persona definition, trait enforcement,
    style consistency, memory of character history, contextual adaptation within
    persona bounds, and continuous validation of persona adherence.
    

    Key Components: 1. Persona Definition: Core character traits and attributes 2. Style Guide: Communication patterns and language 3. Knowledge Boundaries: What the persona knows/doesn’t know 4. Behavioral Rules: How persona responds to situations 5. Memory System: Track persona history and consistency 6. Consistency Checker: Validate responses against persona 7. Adaptation Layer: Natural variation within constraints

    Persona Attributes: 1. Core Traits: Personality characteristics (friendly, formal, humorous) 2. Communication Style: Tone, vocabulary, sentence structure 3. Values & Beliefs: Moral framework, priorities 4. Knowledge Domain: Areas of expertise and ignorance 5. Emotional Range: How persona expresses emotions 6. Cultural Background: Context influencing behavior 7. Quirks & Habits: Unique characteristics

    Consistency Dimensions: 1. Linguistic: Word choice, grammar, dialect 2. Behavioral: Response patterns, decision-making 3. Emotional: Mood stability, reaction patterns 4. Knowledge: What persona knows consistently 5. Temporal: Consistency over time 6. Contextual: Appropriate adaptation 7. Relational: Consistent with relationship history

    Use Cases: – Virtual assistants with brand personality – Game NPCs with defined characters – Customer service representatives – Educational tutors with consistent approach – Therapeutic/counseling chatbots – Celebrity or character impersonations – Brand ambassadors

    Advantages: – Builds user trust and familiarity – Creates memorable experiences – Strengthens brand identity – Enables emotional connection – Provides predictable interactions – Maintains character integrity – Enhances believability

    Challenges: – Balancing consistency with flexibility – Avoiding robotic repetition – Adapting to context while staying in character – Managing persona evolution – Handling edge cases in character – Maintaining consistency across sessions – Preventing personality drift

    LangChain Implementation: This implementation uses LangChain for: – Persona-aware prompt construction – Response consistency validation – Character memory management – Style-constrained generation

    Production Considerations: – Store persona definitions persistently – Version control persona changes – Monitor consistency metrics – Allow graceful persona updates – Support multiple personas per agent – Enable A/B testing of personas – Provide consistency reporting – Log persona violations for improvement


    File Statistics

    • Total Lines: 787
    • Classes: 5
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 131: Persona Consistency
    
    Description:
        The Persona Consistency pattern enables agents to maintain a stable, coherent
        character or personality across all interactions. Rather than exhibiting
        inconsistent behavior or tone, the agent adheres to a defined persona with
        consistent traits, communication style, values, knowledge boundaries, and
        behavioral patterns throughout conversations and across sessions.
    
        Persona consistency is essential for creating believable, trustworthy AI
        characters in applications like virtual assistants, game NPCs, brand
        representatives, and therapeutic chatbots. The pattern addresses challenges
        like personality drift, contextual appropriateness, multi-turn coherence,
        and balancing consistency with natural variation.
    
        This pattern includes mechanisms for persona definition, trait enforcement,
        style consistency, memory of character history, contextual adaptation within
        persona bounds, and continuous validation of persona adherence.
    
    Key Components:
        1. Persona Definition: Core character traits and attributes
        2. Style Guide: Communication patterns and language
        3. Knowledge Boundaries: What the persona knows/doesn't know
        4. Behavioral Rules: How persona responds to situations
        5. Memory System: Track persona history and consistency
        6. Consistency Checker: Validate responses against persona
        7. Adaptation Layer: Natural variation within constraints
    
    Persona Attributes:
        1. Core Traits: Personality characteristics (friendly, formal, humorous)
        2. Communication Style: Tone, vocabulary, sentence structure
        3. Values & Beliefs: Moral framework, priorities
        4. Knowledge Domain: Areas of expertise and ignorance
        5. Emotional Range: How persona expresses emotions
        6. Cultural Background: Context influencing behavior
        7. Quirks & Habits: Unique characteristics
    
    Consistency Dimensions:
        1. Linguistic: Word choice, grammar, dialect
        2. Behavioral: Response patterns, decision-making
        3. Emotional: Mood stability, reaction patterns
        4. Knowledge: What persona knows consistently
        5. Temporal: Consistency over time
        6. Contextual: Appropriate adaptation
        7. Relational: Consistent with relationship history
    
    Use Cases:
        - Virtual assistants with brand personality
        - Game NPCs with defined characters
        - Customer service representatives
        - Educational tutors with consistent approach
        - Therapeutic/counseling chatbots
        - Celebrity or character impersonations
        - Brand ambassadors
    
    Advantages:
        - Builds user trust and familiarity
        - Creates memorable experiences
        - Strengthens brand identity
        - Enables emotional connection
        - Provides predictable interactions
        - Maintains character integrity
        - Enhances believability
    
    Challenges:
        - Balancing consistency with flexibility
        - Avoiding robotic repetition
        - Adapting to context while staying in character
        - Managing persona evolution
        - Handling edge cases in character
        - Maintaining consistency across sessions
        - Preventing personality drift
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Persona-aware prompt construction
        - Response consistency validation
        - Character memory management
        - Style-constrained generation
    
    Production Considerations:
        - Store persona definitions persistently
        - Version control persona changes
        - Monitor consistency metrics
        - Allow graceful persona updates
        - Support multiple personas per agent
        - Enable A/B testing of personas
        - Provide consistency reporting
        - Log persona violations for improvement
    """
    

    Purpose: This module implements the Persona Consistency pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import dataclasses.dataclass
    import dataclasses.field
    import datetime.datetime
    import enum.Enum
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import os
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    

    Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – enum.Enum: Enumeration support – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: PersonaTrait

    Lines 107-116

    Inherits from: Enum

    Purpose:

    Core personality traits.
    

    Class: CommunicationStyle

    Lines 119-126

    Inherits from: Enum

    Purpose:

    Communication style options.
    

    Class: PersonaDefinition

    Lines 130-157

    Purpose:

    Complete definition of an agent's persona.
    
    Attributes:
        name: Persona name
        description: Brief description
        core_traits: Personality traits
        communication_style: How persona communicates
        values: Core values and beliefs
        knowledge_domains: Areas of expertise
        knowledge_gaps: What persona doesn't know
        emotional_range: How emotions are expressed
        quirks: Unique characteristics
        sample_phrases: Example phrases persona uses
        behavioral_rules: Guidelines for behavior
    

    Class: PersonaInteraction

    Lines 161-178

    Purpose:

    Record of an interaction with persona.
    
    Attributes:
        interaction_id: Unique identifier
        user_input: User's message
        persona_response: Agent's response
        timestamp: When interaction occurred
        consistency_score: How well response matched persona
        violations: Any detected inconsistencies
    

    Class: PersonaAgent

    Lines 181-382

    Purpose:

    Agent that maintains consistent persona across interactions.
    
    This agent ensures all responses adhere to a defined persona,
    maintaining character consistency across conversations.
    

    Methods:

    __init__(self, persona, temperature)

    Lines 189-200

    Purpose:

    Initialize persona agent.
    
    Args:
        persona: Persona definition
        temperature: LLM temperature (higher for more variation)
    

    Parameters: – persona: Persona – temperature: Sampling temperature (0-1)

    _build_persona_prompt(self)

    Lines 202-232

    Purpose:

    Build persona description for prompts.
    

    Parameters:

    Returns: str

    respond(self, user_input, context)

    Lines 234-283

    Purpose:

    Generate response in character.
    
    Args:
        user_input: User's message
        context: Optional conversation context
    
    Returns:
        Persona's response
    

    Parameters: – user_input: Input data – context: Context

    Returns: str

    check_consistency(self, response)

    Lines 285-340

    Purpose:

    Check if response is consistent with persona.
    
    Args:
        response: Response to check
    
    Returns:
        Consistency analysis
    

    Parameters: – response: Response

    Returns: <ast.Subscript object at 0x000001A06D676F90>

    get_conversation_context(self, num_recent)

    Lines 342-359

    Purpose:

    Get recent conversation history.
    
    Args:
        num_recent: Number of recent interactions
    
    Returns:
        Formatted context
    

    Parameters: – num_recent: Num recent

    Returns: str

    get_consistency_report(self)

    Lines 361-382

    Purpose:

    Get report on persona consistency.
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D622010>


    Functions

    demonstrate_persona_consistency()

    Lines 385-782

    Purpose:

    Demonstrate persona consistency pattern.
    

    Key Concepts Summary

    Pattern Overview

    The Persona Consistency pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 130
    • Pattern 132

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Persona Consistency pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 131_persona_consistency.py
    Total Lines: 787
    Pattern Category: AI Agent Design Pattern #131


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Proactive Engagement

    
        """
    Pattern 130: Proactive Engagement
    
    Description:
        The Proactive Engagement pattern enables agents to anticipate user needs and
        initiate interactions rather than passively waiting for user input. Instead of
        purely reactive behavior, proactive agents monitor context, identify opportunities
        for assistance, predict upcoming needs, and engage users at appropriate moments
        to provide value before being explicitly asked.
        
        Proactive engagement is essential for creating helpful, attentive AI assistants
        that feel intelligent and considerate. The pattern addresses challenges like
        determining when to interrupt, avoiding being annoying, predicting actual needs
        vs. false positives, timing interventions appropriately, and personalizing
        proactivity levels to user preferences.
        
        This pattern includes mechanisms for need prediction, opportunity detection,
        engagement timing, interruption management, value assessment, personalization,
        and learning from user responses to proactive suggestions.
    
    Key Components:
        1. Context Monitor: Tracks user activity and environment
        2. Need Predictor: Anticipates upcoming needs
        3. Opportunity Detector: Identifies engagement moments
        4. Timing Manager: Determines when to engage
        5. Value Assessor: Evaluates potential intervention value
        6. Personalization Engine: Adapts to user preferences
        7. Feedback Learner: Learns from user responses
    
    Engagement Triggers:
        1. Predicted Needs: Anticipate what user will need
        2. Detected Problems: Identify issues proactively
        3. Opportunities: Suggest improvements or shortcuts
        4. Reminders: Timely notifications
        5. Contextual Tips: Relevant guidance
        6. Status Updates: Important changes
        7. Recommendations: Personalized suggestions
    
    Timing Strategies:
        1. Immediate: Critical or time-sensitive
        2. Opportune Moment: Natural break points
        3. Scheduled: Predetermined times
        4. Threshold-Based: When confidence is high
        5. User-Initiated Flow: During interactions
        6. Idle Detection: When user is inactive
    
    Use Cases:
        - Smart assistants (Alexa, Siri, Google Assistant)
        - Customer service chatbots
        - Healthcare monitoring systems
        - Educational tutors
        - Personal productivity assistants
        - Smart home automation
        - Enterprise knowledge management
    
    Advantages:
        - Improves user experience through anticipation
        - Reduces cognitive load on users
        - Catches issues before they escalate
        - Provides timely, relevant assistance
        - Increases perceived intelligence
        - Builds trust through helpfulness
        - Enhances productivity
    
    Challenges:
        - Avoiding annoying interruptions
        - False positive predictions
        - Privacy and monitoring concerns
        - Determining appropriate timing
        - Balancing proactivity with passivity
        - Personalizing to individual preferences
        - Managing user attention
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Context analysis and need prediction
        - Opportunity identification
        - Value assessment of interventions
        - Personalized engagement strategies
        
    Production Considerations:
        - Implement user preference controls
        - Track engagement acceptance rates
        - Use machine learning for need prediction
        - Respect "do not disturb" modes
        - Provide easy dismissal options
        - Learn from user feedback
        - Monitor intervention frequency
        - Enable granular notification settings
    """
    
    import os
    from typing import List, Dict, Any, Optional, Tuple
    from dataclasses import dataclass, field
    from datetime import datetime, timedelta
    from enum import Enum
    from dotenv import load_dotenv
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    from langchain_openai import ChatOpenAI
    
    load_dotenv()
    
    
    class EngagementType(Enum):
        """Types of proactive engagements."""
        PREDICTED_NEED = "predicted_need"
        PROBLEM_DETECTION = "problem_detection"
        OPPORTUNITY = "opportunity"
        REMINDER = "reminder"
        TIP = "tip"
        STATUS_UPDATE = "status_update"
        RECOMMENDATION = "recommendation"
    
    
    class EngagementPriority(Enum):
        """Priority levels for engagements."""
        CRITICAL = "critical"
        HIGH = "high"
        MEDIUM = "medium"
        LOW = "low"
    
    
    class UserResponse(Enum):
        """User responses to proactive engagements."""
        ACCEPTED = "accepted"
        DISMISSED = "dismissed"
        DEFERRED = "deferred"
        IGNORED = "ignored"
    
    
    @dataclass
    class ContextSignal:
        """
        A signal from the user context.
        
        Attributes:
            signal_type: Type of signal
            content: Signal content
            timestamp: When detected
            confidence: Detection confidence
            metadata: Additional information
        """
        signal_type: str
        content: str
        timestamp: datetime = field(default_factory=datetime.now)
        confidence: float = 1.0
        metadata: Dict[str, Any] = field(default_factory=dict)
    
    
    @dataclass
    class ProactiveEngagement:
        """
        A proactive engagement with the user.
        
        Attributes:
            engagement_id: Unique identifier
            engagement_type: Type of engagement
            priority: Urgency level
            message: Engagement message
            suggested_action: Recommended action
            value_score: Estimated value to user
            timing_score: Appropriateness of timing
            triggers: What triggered this
            created_at: When created
            engaged_at: When delivered to user
            response: User response
        """
        engagement_id: str
        engagement_type: EngagementType
        priority: EngagementPriority
        message: str
        suggested_action: Optional[str] = None
        value_score: float = 0.5
        timing_score: float = 0.5
        triggers: List[str] = field(default_factory=list)
        created_at: datetime = field(default_factory=datetime.now)
        engaged_at: Optional[datetime] = None
        response: Optional[UserResponse] = None
    
    
    @dataclass
    class UserPreferences:
        """
        User preferences for proactive engagement.
        
        Attributes:
            enabled: Whether proactive engagement is on
            min_priority: Minimum priority level to show
            quiet_hours: Hours when engagement is disabled
            max_frequency: Maximum engagements per hour
            preferred_types: Preferred engagement types
        """
        enabled: bool = True
        min_priority: EngagementPriority = EngagementPriority.MEDIUM
        quiet_hours: List[int] = field(default_factory=list)
        max_frequency: int = 5
        preferred_types: List[EngagementType] = field(default_factory=list)
    
    
    class ProactiveAgent:
        """
        Proactive engagement agent that anticipates needs and initiates interactions.
        
        This agent monitors context, predicts needs, and proactively engages
        users at appropriate moments with helpful suggestions.
        """
        
        def __init__(self, temperature: float = 0.3):
            """
            Initialize proactive agent.
            
            Args:
                temperature: LLM temperature
            """
            self.llm = ChatOpenAI(temperature=temperature, model="gpt-3.5-turbo")
            self.context_signals: List[ContextSignal] = []
            self.engagements: List[ProactiveEngagement] = []
            self.user_preferences = UserPreferences()
            self.engagement_counter = 0
        
        def add_context_signal(
            self,
            signal_type: str,
            content: str,
            confidence: float = 1.0,
            metadata: Optional[Dict[str, Any]] = None
        ) -> ContextSignal:
            """
            Add a context signal from monitoring.
            
            Args:
                signal_type: Type of signal
                content: Signal content
                confidence: Detection confidence
                metadata: Additional information
                
            Returns:
                Created signal
            """
            signal = ContextSignal(
                signal_type=signal_type,
                content=content,
                confidence=confidence,
                metadata=metadata or {}
            )
            self.context_signals.append(signal)
            return signal
        
        def predict_need(self, context_window: int = 5) -> Optional[str]:
            """
            Predict user need based on recent context.
            
            Args:
                context_window: Number of recent signals to consider
                
            Returns:
                Predicted need description
            """
            recent_signals = self.context_signals[-context_window:]
            
            if not recent_signals:
                return None
            
            # Build context
            context = "\n".join([
                f"{s.signal_type}: {s.content}"
                for s in recent_signals
            ])
            
            prompt = ChatPromptTemplate.from_template(
                "Based on these recent user activities and context signals:\n\n"
                "{context}\n\n"
                "Predict what the user might need help with next. "
                "Consider patterns, incomplete tasks, and logical next steps.\n\n"
                "Provide:\n"
                "1. Predicted need (one sentence)\n"
                "2. Confidence (0-1)\n"
                "3. Brief reasoning"
            )
            
            chain = prompt | self.llm | StrOutputParser()
            prediction = chain.invoke({"context": context})
            
            return prediction
        
        def detect_opportunity(self, context: str) -> Optional[Dict[str, Any]]:
            """
            Detect opportunity for proactive engagement.
            
            Args:
                context: Current context description
                
            Returns:
                Opportunity details if found
            """
            prompt = ChatPromptTemplate.from_template(
                "Analyze this user context:\n\n"
                "{context}\n\n"
                "Is there an opportunity for helpful proactive engagement?\n"
                "Consider:\n"
                "- Shortcuts or efficiency improvements\n"
                "- Potential problems to avoid\n"
                "- Helpful tips or information\n"
                "- Relevant recommendations\n\n"
                "Respond with:\n"
                "OPPORTUNITY: yes/no\n"
                "TYPE: [predicted_need/problem_detection/opportunity/tip/recommendation]\n"
                "MESSAGE: [brief helpful message]\n"
                "VALUE: [0-1 score]"
            )
            
            chain = prompt | self.llm | StrOutputParser()
            result = chain.invoke({"context": context})
            
            # Parse result
            lines = result.strip().split('\n')
            opportunity_dict = {}
            
            for line in lines:
                if ':' in line:
                    key, value = line.split(':', 1)
                    opportunity_dict[key.strip().lower()] = value.strip()
            
            if opportunity_dict.get('opportunity', '').lower() == 'yes':
                return opportunity_dict
            
            return None
        
        def assess_timing(self, engagement_type: EngagementType) -> float:
            """
            Assess if timing is appropriate for engagement.
            
            Args:
                engagement_type: Type of engagement
                
            Returns:
                Timing appropriateness score (0-1)
            """
            current_hour = datetime.now().hour
            
            # Check quiet hours
            if current_hour in self.user_preferences.quiet_hours:
                return 0.1
            
            # Check recent engagement frequency
            recent_hour = datetime.now() - timedelta(hours=1)
            recent_engagements = [
                e for e in self.engagements
                if e.engaged_at and e.engaged_at > recent_hour
            ]
            
            if len(recent_engagements) >= self.user_preferences.max_frequency:
                return 0.2
            
            # Critical engagements always have good timing
            # (override frequency limits for critical items)
            
            # Higher score for fewer recent engagements
            frequency_score = 1.0 - (len(recent_engagements) / self.user_preferences.max_frequency)
            
            return max(0.3, frequency_score)
        
        def create_engagement(
            self,
            engagement_type: EngagementType,
            message: str,
            priority: EngagementPriority = EngagementPriority.MEDIUM,
            suggested_action: Optional[str] = None,
            triggers: Optional[List[str]] = None
        ) -> ProactiveEngagement:
            """
            Create a proactive engagement.
            
            Args:
                engagement_type: Type of engagement
                message: Engagement message
                priority: Priority level
                suggested_action: Suggested action
                triggers: What triggered this
                
            Returns:
                Created engagement
            """
            self.engagement_counter += 1
            
            # Assess value and timing
            timing_score = self.assess_timing(engagement_type)
            
            # Simple value heuristic (could be ML model in production)
            value_score = {
                EngagementPriority.CRITICAL: 0.9,
                EngagementPriority.HIGH: 0.7,
                EngagementPriority.MEDIUM: 0.5,
                EngagementPriority.LOW: 0.3
            }.get(priority, 0.5)
            
            engagement = ProactiveEngagement(
                engagement_id=f"eng_{self.engagement_counter}",
                engagement_type=engagement_type,
                priority=priority,
                message=message,
                suggested_action=suggested_action,
                value_score=value_score,
                timing_score=timing_score,
                triggers=triggers or []
            )
            
            self.engagements.append(engagement)
            return engagement
        
        def should_engage(self, engagement: ProactiveEngagement) -> bool:
            """
            Determine if agent should deliver engagement.
            
            Args:
                engagement: Engagement to evaluate
                
            Returns:
                Whether to engage
            """
            # Check if proactive engagement is enabled
            if not self.user_preferences.enabled:
                return False
            
            # Check priority threshold
            priority_levels = {
                EngagementPriority.CRITICAL: 4,
                EngagementPriority.HIGH: 3,
                EngagementPriority.MEDIUM: 2,
                EngagementPriority.LOW: 1
            }
            
            if priority_levels.get(engagement.priority, 0) < \
               priority_levels.get(self.user_preferences.min_priority, 2):
                return False
            
            # Check preferred types (if any specified)
            if self.user_preferences.preferred_types and \
               engagement.engagement_type not in self.user_preferences.preferred_types:
                return False
            
            # Check timing score
            if engagement.timing_score  0.5
        
        def engage_user(self, engagement: ProactiveEngagement) -> bool:
            """
            Deliver engagement to user.
            
            Args:
                engagement: Engagement to deliver
                
            Returns:
                Whether engagement was delivered
            """
            if not self.should_engage(engagement):
                return False
            
            engagement.engaged_at = datetime.now()
            return True
        
        def record_response(
            self,
            engagement_id: str,
            response: UserResponse
        ):
            """
            Record user response to engagement.
            
            Args:
                engagement_id: Engagement identifier
                response: User response
            """
            for engagement in self.engagements:
                if engagement.engagement_id == engagement_id:
                    engagement.response = response
                    break
        
        def get_acceptance_rate(self) -> float:
            """Get acceptance rate for delivered engagements."""
            delivered = [e for e in self.engagements if e.engaged_at]
            
            if not delivered:
                return 0.0
            
            accepted = [e for e in delivered if e.response == UserResponse.ACCEPTED]
            return len(accepted) / len(delivered)
        
        def get_engagement_summary(self) -> Dict[str, Any]:
            """Get summary of engagement activity."""
            delivered = [e for e in self.engagements if e.engaged_at]
            
            return {
                "total_created": len(self.engagements),
                "total_delivered": len(delivered),
                "delivery_rate": len(delivered) / len(self.engagements) if self.engagements else 0,
                "acceptance_rate": self.get_acceptance_rate(),
                "by_type": {
                    et.value: len([e for e in delivered if e.engagement_type == et])
                    for et in EngagementType
                },
                "by_priority": {
                    pr.value: len([e for e in delivered if e.priority == pr])
                    for pr in EngagementPriority
                }
            }
    
    
    def demonstrate_proactive_engagement():
        """Demonstrate proactive engagement pattern."""
        
        print("=" * 80)
        print("PROACTIVE ENGAGEMENT PATTERN DEMONSTRATION")
        print("=" * 80)
        
        # Example 1: Need prediction
        print("\n" + "=" * 80)
        print("Example 1: Predicting User Needs")
        print("=" * 80)
        
        agent = ProactiveAgent()
        
        # Add context signals
        agent.add_context_signal("user_action", "Opened email application")
        agent.add_context_signal("user_action", "Viewed calendar")
        agent.add_context_signal("user_action", "Searched for 'meeting notes template'")
        agent.add_context_signal("time_context", "10 minutes before scheduled meeting")
        
        print("\nContext signals collected:")
        for signal in agent.context_signals:
            print(f"  • {signal.signal_type}: {signal.content}")
        
        print("\nPredicting user need...")
        prediction = agent.predict_need()
        print(f"\nPrediction:\n{prediction}")
        
        # Example 2: Opportunity detection
        print("\n" + "=" * 80)
        print("Example 2: Detecting Engagement Opportunities")
        print("=" * 80)
        
        agent2 = ProactiveAgent()
        
        context = """
        User is writing a report in Word.
        Document has multiple spelling errors highlighted.
        User has been working for 2 hours without saving.
        Battery level: 15%
        """
        
        print(f"\nContext:\n{context}")
        print("\nDetecting opportunities...")
        
        opportunity = agent2.detect_opportunity(context)
        
        if opportunity:
            print("\nOpportunity detected!")
            print(f"  Type: {opportunity.get('type', 'N/A')}")
            print(f"  Message: {opportunity.get('message', 'N/A')}")
            print(f"  Value: {opportunity.get('value', 'N/A')}")
        
        # Example 3: Creating engagements
        print("\n" + "=" * 80)
        print("Example 3: Creating Proactive Engagements")
        print("=" * 80)
        
        agent3 = ProactiveAgent()
        
        # Create various engagements
        eng1 = agent3.create_engagement(
            EngagementType.REMINDER,
            "Your meeting starts in 5 minutes",
            priority=EngagementPriority.HIGH,
            suggested_action="Join video call",
            triggers=["calendar_event", "time_proximity"]
        )
        
        eng2 = agent3.create_engagement(
            EngagementType.TIP,
            "You can use Ctrl+S to save your document",
            priority=EngagementPriority.LOW,
            triggers=["unsaved_document", "long_edit_session"]
        )
        
        eng3 = agent3.create_engagement(
            EngagementType.PROBLEM_DETECTION,
            "Low battery detected. Please plug in your charger.",
            priority=EngagementPriority.CRITICAL,
            suggested_action="Connect charger",
            triggers=["battery_low"]
        )
        
        print("\nCreated engagements:")
        for eng in agent3.engagements:
            print(f"\n  {eng.engagement_id}:")
            print(f"    Type: {eng.engagement_type.value}")
            print(f"    Priority: {eng.priority.value}")
            print(f"    Message: {eng.message}")
            print(f"    Value Score: {eng.value_score:.2f}")
            print(f"    Timing Score: {eng.timing_score:.2f}")
        
        # Example 4: Timing assessment
        print("\n" + "=" * 80)
        print("Example 4: Timing Assessment")
        print("=" * 80)
        
        agent4 = ProactiveAgent()
        
        # Set quiet hours
        agent4.user_preferences.quiet_hours = [22, 23, 0, 1, 2, 3, 4, 5, 6]
        agent4.user_preferences.max_frequency = 3
        
        print("\nUser preferences:")
        print(f"  Quiet hours: {agent4.user_preferences.quiet_hours}")
        print(f"  Max frequency: {agent4.user_preferences.max_frequency}/hour")
        
        # Create and assess engagement
        eng = agent4.create_engagement(
            EngagementType.RECOMMENDATION,
            "Check out this relevant article",
            priority=EngagementPriority.MEDIUM
        )
        
        print(f"\nEngagement timing score: {eng.timing_score:.2f}")
        print(f"Should engage: {agent4.should_engage(eng)}")
        
        # Example 5: Delivery decision
        print("\n" + "=" * 80)
        print("Example 5: Engagement Delivery Decision")
        print("=" * 80)
        
        agent5 = ProactiveAgent()
        
        # Create different priority engagements
        engagements = [
            agent5.create_engagement(
                EngagementType.TIP,
                "Low priority tip",
                priority=EngagementPriority.LOW
            ),
            agent5.create_engagement(
                EngagementType.REMINDER,
                "Medium priority reminder",
                priority=EngagementPriority.MEDIUM
            ),
            agent5.create_engagement(
                EngagementType.PROBLEM_DETECTION,
                "Critical issue detected",
                priority=EngagementPriority.CRITICAL
            )
        ]
        
        print("\nDelivery decisions:")
        for eng in engagements:
            delivered = agent5.engage_user(eng)
            status = "āœ“ DELIVERED" if delivered else "āœ— HELD"
            print(f"  {eng.priority.value}: {status}")
        
        # Example 6: User feedback learning
        print("\n" + "=" * 80)
        print("Example 6: Learning from User Feedback")
        print("=" * 80)
        
        agent6 = ProactiveAgent()
        
        # Create and deliver engagements
        for i in range(5):
            eng = agent6.create_engagement(
                EngagementType.TIP,
                f"Helpful tip #{i+1}",
                priority=EngagementPriority.MEDIUM
            )
            agent6.engage_user(eng)
        
        # Record user responses
        agent6.record_response(agent6.engagements[0].engagement_id, UserResponse.ACCEPTED)
        agent6.record_response(agent6.engagements[1].engagement_id, UserResponse.DISMISSED)
        agent6.record_response(agent6.engagements[2].engagement_id, UserResponse.ACCEPTED)
        agent6.record_response(agent6.engagements[3].engagement_id, UserResponse.ACCEPTED)
        agent6.record_response(agent6.engagements[4].engagement_id, UserResponse.DISMISSED)
        
        print("\nUser responses recorded:")
        for eng in agent6.engagements:
            if eng.response:
                print(f"  {eng.engagement_id}: {eng.response.value}")
        
        acceptance_rate = agent6.get_acceptance_rate()
        print(f"\nAcceptance rate: {acceptance_rate:.0%}")
        
        # Example 7: Preference management
        print("\n" + "=" * 80)
        print("Example 7: User Preference Management")
        print("=" * 80)
        
        agent7 = ProactiveAgent()
        
        # User configures preferences
        agent7.user_preferences.enabled = True
        agent7.user_preferences.min_priority = EngagementPriority.HIGH
        agent7.user_preferences.preferred_types = [
            EngagementType.REMINDER,
            EngagementType.PROBLEM_DETECTION
        ]
        
        print("\nUser preferences:")
        print(f"  Enabled: {agent7.user_preferences.enabled}")
        print(f"  Min priority: {agent7.user_preferences.min_priority.value}")
        print(f"  Preferred types: {[t.value for t in agent7.user_preferences.preferred_types]}")
        
        # Test different engagements
        test_engagements = [
            ("TIP (LOW)", EngagementType.TIP, EngagementPriority.LOW),
            ("REMINDER (HIGH)", EngagementType.REMINDER, EngagementPriority.HIGH),
            ("OPPORTUNITY (HIGH)", EngagementType.OPPORTUNITY, EngagementPriority.HIGH),
            ("PROBLEM (CRITICAL)", EngagementType.PROBLEM_DETECTION, EngagementPriority.CRITICAL)
        ]
        
        print("\nEngagement filtering:")
        for name, eng_type, priority in test_engagements:
            eng = agent7.create_engagement(eng_type, f"Test message", priority=priority)
            would_deliver = agent7.should_engage(eng)
            status = "āœ“ Would deliver" if would_deliver else "āœ— Would filter"
            print(f"  {name}: {status}")
        
        # Example 8: System summary
        print("\n" + "=" * 80)
        print("Example 8: Engagement System Summary")
        print("=" * 80)
        
        agent8 = ProactiveAgent()
        
        # Simulate various engagements
        for i in range(10):
            eng_type = [EngagementType.TIP, EngagementType.REMINDER, EngagementType.RECOMMENDATION][i % 3]
            priority = [EngagementPriority.LOW, EngagementPriority.MEDIUM, EngagementPriority.HIGH][i % 3]
            
            eng = agent8.create_engagement(eng_type, f"Message {i+1}", priority=priority)
            
            if agent8.engage_user(eng):
                # Simulate responses
                response = UserResponse.ACCEPTED if i % 2 == 0 else UserResponse.DISMISSED
                agent8.record_response(eng.engagement_id, response)
        
        summary = agent8.get_engagement_summary()
        
        print("\nENGAGEMENT SUMMARY:")
        print("=" * 60)
        print(f"Total Created: {summary['total_created']}")
        print(f"Total Delivered: {summary['total_delivered']}")
        print(f"Delivery Rate: {summary['delivery_rate']:.0%}")
        print(f"Acceptance Rate: {summary['acceptance_rate']:.0%}")
        
        print("\nBy Type:")
        for eng_type, count in summary['by_type'].items():
            if count > 0:
                print(f"  {eng_type}: {count}")
        
        print("\nBy Priority:")
        for priority, count in summary['by_priority'].items():
            if count > 0:
                print(f"  {priority}: {count}")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY: Proactive Engagement Pattern")
        print("=" * 80)
        
        summary_text = """
        The Proactive Engagement pattern demonstrated:
        
        1. NEED PREDICTION (Example 1):
           - Context signal collection
           - Pattern analysis
           - LLM-based prediction
           - Confidence estimation
           - Anticipatory behavior
        
        2. OPPORTUNITY DETECTION (Example 2):
           - Context analysis
           - Opportunity identification
           - Value assessment
           - Type classification
           - Actionable suggestions
        
        3. ENGAGEMENT CREATION (Example 3):
           - Multiple engagement types
           - Priority assignment
           - Value scoring
           - Timing assessment
           - Trigger tracking
        
        4. TIMING ASSESSMENT (Example 4):
           - Quiet hour respect
           - Frequency limiting
           - Context awareness
           - Appropriateness scoring
           - User preference consideration
        
        5. DELIVERY DECISIONS (Example 5):
           - Priority-based filtering
           - Threshold evaluation
           - Critical override
           - Smart gatekeeping
           - Controlled delivery
        
        6. FEEDBACK LEARNING (Example 6):
           - Response tracking
           - Acceptance rate calculation
           - Pattern learning
           - Continuous improvement
           - Adaptive behavior
        
        7. PREFERENCE MANAGEMENT (Example 7):
           - User control
           - Type filtering
           - Priority thresholds
           - Personalization
           - Preference respect
        
        8. SYSTEM INTEGRATION (Example 8):
           - Comprehensive metrics
           - Type distribution
           - Priority analysis
           - Performance tracking
           - System overview
        
        KEY BENEFITS:
        āœ“ Improves UX through anticipation
        āœ“ Reduces cognitive load on users
        āœ“ Catches issues before they escalate
        āœ“ Provides timely, relevant assistance
        āœ“ Increases perceived intelligence
        āœ“ Builds trust through helpfulness
        āœ“ Enhances productivity
        āœ“ Creates delightful experiences
        
        USE CASES:
        • Smart assistants (Alexa, Siri)
        • Customer service chatbots
        • Healthcare monitoring
        • Educational tutors
        • Productivity assistants
        • Smart home automation
        • Enterprise knowledge management
        • Preventive maintenance
        
        ENGAGEMENT TYPES:
        → Predicted Needs: Anticipate requirements
        → Problem Detection: Identify issues
        → Opportunities: Suggest improvements
        → Reminders: Timely notifications
        → Tips: Contextual guidance
        → Status Updates: Important changes
        → Recommendations: Personalized suggestions
        
        TIMING STRATEGIES:
        • Immediate: Critical/time-sensitive
        • Opportune Moment: Natural breaks
        • Scheduled: Predetermined times
        • Threshold-Based: High confidence
        • User-Initiated Flow: During interactions
        • Idle Detection: When inactive
        
        BEST PRACTICES:
        1. Implement user preference controls
        2. Track engagement acceptance rates
        3. Use ML for need prediction
        4. Respect "do not disturb" modes
        5. Provide easy dismissal options
        6. Learn from user feedback
        7. Monitor intervention frequency
        8. Enable granular notification settings
        
        TRADE-OFFS:
        • Helpfulness vs. annoyance
        • Proactivity vs. privacy
        • Frequency vs. relevance
        • Automation vs. control
        
        PRODUCTION CONSIDERATIONS:
        → Implement A/B testing for engagement strategies
        → Use ML models for need prediction
        → Track detailed engagement metrics
        → Provide fine-grained user controls
        → Respect platform notification guidelines
        → Implement gradual rollout for new features
        → Monitor user satisfaction scores
        → Enable easy opt-out mechanisms
        → Log all engagement decisions
        → Personalize based on user history
        
        This pattern enables agents to be helpful and attentive by anticipating
        user needs and engaging proactively at appropriate moments, creating a
        more intelligent and considerate user experience.
        """
        
        print(summary_text)
    
    
    if __name__ == "__main__":
        demonstrate_proactive_engagement()
    
        

    Agentic Design Pattern: Proactive Engagement

    Pattern 130: Proactive Engagement – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Proactive Engagement pattern implementation.


    Pattern Description

    Pattern 130: Proactive Engagement

    Description: The Proactive Engagement pattern enables agents to anticipate user needs and initiate interactions rather than passively waiting for user input. Instead of purely reactive behavior, proactive agents monitor context, identify opportunities for assistance, predict upcoming needs, and engage users at appropriate moments to provide value before being explicitly asked.

    Proactive engagement is essential for creating helpful, attentive AI assistants
    that feel intelligent and considerate. The pattern addresses challenges like
    determining when to interrupt, avoiding being annoying, predicting actual needs
    vs. false positives, timing interventions appropriately, and personalizing
    proactivity levels to user preferences.
    
    This pattern includes mechanisms for need prediction, opportunity detection,
    engagement timing, interruption management, value assessment, personalization,
    and learning from user responses to proactive suggestions.
    

    Key Components: 1. Context Monitor: Tracks user activity and environment 2. Need Predictor: Anticipates upcoming needs 3. Opportunity Detector: Identifies engagement moments 4. Timing Manager: Determines when to engage 5. Value Assessor: Evaluates potential intervention value 6. Personalization Engine: Adapts to user preferences 7. Feedback Learner: Learns from user responses

    Engagement Triggers: 1. Predicted Needs: Anticipate what user will need 2. Detected Problems: Identify issues proactively 3. Opportunities: Suggest improvements or shortcuts 4. Reminders: Timely notifications 5. Contextual Tips: Relevant guidance 6. Status Updates: Important changes 7. Recommendations: Personalized suggestions

    Timing Strategies: 1. Immediate: Critical or time-sensitive 2. Opportune Moment: Natural break points 3. Scheduled: Predetermined times 4. Threshold-Based: When confidence is high 5. User-Initiated Flow: During interactions 6. Idle Detection: When user is inactive

    Use Cases: – Smart assistants (Alexa, Siri, Google Assistant) – Customer service chatbots – Healthcare monitoring systems – Educational tutors – Personal productivity assistants – Smart home automation – Enterprise knowledge management

    Advantages: – Improves user experience through anticipation – Reduces cognitive load on users – Catches issues before they escalate – Provides timely, relevant assistance – Increases perceived intelligence – Builds trust through helpfulness – Enhances productivity

    Challenges: – Avoiding annoying interruptions – False positive predictions – Privacy and monitoring concerns – Determining appropriate timing – Balancing proactivity with passivity – Personalizing to individual preferences – Managing user attention

    LangChain Implementation: This implementation uses LangChain for: – Context analysis and need prediction – Opportunity identification – Value assessment of interventions – Personalized engagement strategies

    Production Considerations: – Implement user preference controls – Track engagement acceptance rates – Use machine learning for need prediction – Respect “do not disturb” modes – Provide easy dismissal options – Learn from user feedback – Monitor intervention frequency – Enable granular notification settings


    File Statistics

    • Total Lines: 913
    • Classes: 7
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 130: Proactive Engagement
    
    Description:
        The Proactive Engagement pattern enables agents to anticipate user needs and
        initiate interactions rather than passively waiting for user input. Instead of
        purely reactive behavior, proactive agents monitor context, identify opportunities
        for assistance, predict upcoming needs, and engage users at appropriate moments
        to provide value before being explicitly asked.
    
        Proactive engagement is essential for creating helpful, attentive AI assistants
        that feel intelligent and considerate. The pattern addresses challenges like
        determining when to interrupt, avoiding being annoying, predicting actual needs
        vs. false positives, timing interventions appropriately, and personalizing
        proactivity levels to user preferences.
    
        This pattern includes mechanisms for need prediction, opportunity detection,
        engagement timing, interruption management, value assessment, personalization,
        and learning from user responses to proactive suggestions.
    
    Key Components:
        1. Context Monitor: Tracks user activity and environment
        2. Need Predictor: Anticipates upcoming needs
        3. Opportunity Detector: Identifies engagement moments
        4. Timing Manager: Determines when to engage
        5. Value Assessor: Evaluates potential intervention value
        6. Personalization Engine: Adapts to user preferences
        7. Feedback Learner: Learns from user responses
    
    Engagement Triggers:
        1. Predicted Needs: Anticipate what user will need
        2. Detected Problems: Identify issues proactively
        3. Opportunities: Suggest improvements or shortcuts
        4. Reminders: Timely notifications
        5. Contextual Tips: Relevant guidance
        6. Status Updates: Important changes
        7. Recommendations: Personalized suggestions
    
    Timing Strategies:
        1. Immediate: Critical or time-sensitive
        2. Opportune Moment: Natural break points
        3. Scheduled: Predetermined times
        4. Threshold-Based: When confidence is high
        5. User-Initiated Flow: During interactions
        6. Idle Detection: When user is inactive
    
    Use Cases:
        - Smart assistants (Alexa, Siri, Google Assistant)
        - Customer service chatbots
        - Healthcare monitoring systems
        - Educational tutors
        - Personal productivity assistants
        - Smart home automation
        - Enterprise knowledge management
    
    Advantages:
        - Improves user experience through anticipation
        - Reduces cognitive load on users
        - Catches issues before they escalate
        - Provides timely, relevant assistance
        - Increases perceived intelligence
        - Builds trust through helpfulness
        - Enhances productivity
    
    Challenges:
        - Avoiding annoying interruptions
        - False positive predictions
        - Privacy and monitoring concerns
        - Determining appropriate timing
        - Balancing proactivity with passivity
        - Personalizing to individual preferences
        - Managing user attention
    
    LangChain Implementation:
        This implementation uses LangChain for:
        - Context analysis and need prediction
        - Opportunity identification
        - Value assessment of interventions
        - Personalized engagement strategies
    
    Production Considerations:
        - Implement user preference controls
        - Track engagement acceptance rates
        - Use machine learning for need prediction
        - Respect "do not disturb" modes
        - Provide easy dismissal options
        - Learn from user feedback
        - Monitor intervention frequency
        - Enable granular notification settings
    """
    

    Purpose: This module implements the Proactive Engagement pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import dataclasses.dataclass
    import dataclasses.field
    import datetime.datetime
    import datetime.timedelta
    import enum.Enum
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import os
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    import typing.Tuple
    

    Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – datetime.timedelta: Date and time handling – enum.Enum: Enumeration support – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Tuple: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: EngagementType

    Lines 106-114

    Inherits from: Enum

    Purpose:

    Types of proactive engagements.
    

    Class: EngagementPriority

    Lines 117-122

    Inherits from: Enum

    Purpose:

    Priority levels for engagements.
    

    Class: UserResponse

    Lines 125-130

    Inherits from: Enum

    Purpose:

    User responses to proactive engagements.
    

    Class: ContextSignal

    Lines 134-149

    Purpose:

    A signal from the user context.
    
    Attributes:
        signal_type: Type of signal
        content: Signal content
        timestamp: When detected
        confidence: Detection confidence
        metadata: Additional information
    

    Class: ProactiveEngagement

    Lines 153-180

    Purpose:

    A proactive engagement with the user.
    
    Attributes:
        engagement_id: Unique identifier
        engagement_type: Type of engagement
        priority: Urgency level
        message: Engagement message
        suggested_action: Recommended action
        value_score: Estimated value to user
        timing_score: Appropriateness of timing
        triggers: What triggered this
        created_at: When created
        engaged_at: When delivered to user
        response: User response
    

    Class: UserPreferences

    Lines 184-199

    Purpose:

    User preferences for proactive engagement.
    
    Attributes:
        enabled: Whether proactive engagement is on
        min_priority: Minimum priority level to show
        quiet_hours: Hours when engagement is disabled
        max_frequency: Maximum engagements per hour
        preferred_types: Preferred engagement types
    

    Class: ProactiveAgent

    Lines 202-517

    Purpose:

    Proactive engagement agent that anticipates needs and initiates interactions.
    
    This agent monitors context, predicts needs, and proactively engages
    users at appropriate moments with helpful suggestions.
    

    Methods:

    __init__(self, temperature)

    Lines 210-221

    Purpose:

    Initialize proactive agent.
    
    Args:
        temperature: LLM temperature
    

    Parameters: – temperature: Sampling temperature (0-1)

    add_context_signal(self, signal_type, content, confidence, metadata)

    Lines 223-249

    Purpose:

    Add a context signal from monitoring.
    
    Args:
        signal_type: Type of signal
        content: Signal content
        confidence: Detection confidence
        metadata: Additional information
    
    Returns:
        Created signal
    

    Parameters: – signal_type: Signal type – content: Content – confidence: Confidence – metadata: Metadata

    Returns: ContextSignal

    predict_need(self, context_window)

    Lines 251-286

    Purpose:

    Predict user need based on recent context.
    
    Args:
        context_window: Number of recent signals to consider
    
    Returns:
        Predicted need description
    

    Parameters: – context_window: Context window

    Returns: <ast.Subscript object at 0x000001A06D7F6550>

    detect_opportunity(self, context)

    Lines 288-329

    Purpose:

    Detect opportunity for proactive engagement.
    
    Args:
        context: Current context description
    
    Returns:
        Opportunity details if found
    

    Parameters: – context: Context

    Returns: <ast.Subscript object at 0x000001A06E0946D0>

    assess_timing(self, engagement_type)

    Lines 331-363

    Purpose:

    Assess if timing is appropriate for engagement.
    
    Args:
        engagement_type: Type of engagement
    
    Returns:
        Timing appropriateness score (0-1)
    

    Parameters: – engagement_type: Engagement type

    Returns: float

    create_engagement(self, engagement_type, message, priority, suggested_action, triggers)

    Lines 365-411

    Purpose:

    Create a proactive engagement.
    
    Args:
        engagement_type: Type of engagement
        message: Engagement message
        priority: Priority level
        suggested_action: Suggested action
        triggers: What triggered this
    
    Returns:
        Created engagement
    

    Parameters: – engagement_type: Engagement type – message: Message – priority: Priority – suggested_action: Suggested action – triggers: Triggers

    Returns: ProactiveEngagement

    should_engage(self, engagement)

    Lines 413-455

    Purpose:

    Determine if agent should deliver engagement.
    
    Args:
        engagement: Engagement to evaluate
    
    Returns:
        Whether to engage
    

    Parameters: – engagement: Engagement

    Returns: bool

    engage_user(self, engagement)

    Lines 457-471

    Purpose:

    Deliver engagement to user.
    
    Args:
        engagement: Engagement to deliver
    
    Returns:
        Whether engagement was delivered
    

    Parameters: – engagement: Engagement

    Returns: bool

    record_response(self, engagement_id, response)

    Lines 473-488

    Purpose:

    Record user response to engagement.
    
    Args:
        engagement_id: Engagement identifier
        response: User response
    

    Parameters: – engagement_id: Engagement id – response: Response

    get_acceptance_rate(self)

    Lines 490-498

    Purpose:

    Get acceptance rate for delivered engagements.
    

    Parameters:

    Returns: float

    get_engagement_summary(self)

    Lines 500-517

    Purpose:

    Get summary of engagement activity.
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D7188D0>


    Functions

    demonstrate_proactive_engagement()

    Lines 520-908

    Purpose:

    Demonstrate proactive engagement pattern.
    

    Key Concepts Summary

    Pattern Overview

    The Proactive Engagement pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 129
    • Pattern 131

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Proactive Engagement pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 130_proactive_engagement.py
    Total Lines: 913
    Pattern Category: AI Agent Design Pattern #130


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Clarification

    
        """
    Pattern 129: Clarification & Disambiguation
    
    Description:
        Detects ambiguous or unclear user inputs and asks targeted clarifying questions
        to resolve uncertainties before proceeding.
    
    Components:
        - Ambiguity detection
        - Clarification question generation
        - Context tracking
        - Progressive refinement
    
    Use Cases:
        - Conversational agents handling ambiguous queries
        - Complex instruction following
        - Reducing errors from misunderstanding
    
    LangChain Implementation:
        Uses LangChain to detect ambiguity and generate appropriate clarification questions.
    """
    
    import os
    from typing import List, Dict, Any, Optional
    from dotenv import load_dotenv
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import JsonOutputParser, StrOutputParser
    from langchain_openai import ChatOpenAI
    from langchain_core.pydantic_v1 import BaseModel, Field
    
    load_dotenv()
    
    
    class AmbiguityAnalysis(BaseModel):
        """Analysis of ambiguity in user input"""
        is_ambiguous: bool = Field(description="Whether input is ambiguous")
        ambiguity_type: str = Field(description="Type of ambiguity: lexical, syntactic, semantic, referential")
        confidence: float = Field(description="Confidence in ambiguity detection")
        ambiguous_elements: List[str] = Field(description="Specific ambiguous elements")
        clarification_needed: str = Field(description="What needs clarification")
    
    
    class ClarificationQuestion(BaseModel):
        """A clarification question"""
        question: str = Field(description="The clarification question")
        options: Optional[List[str]] = Field(description="Possible options if applicable")
        priority: int = Field(description="Priority (1=high, 3=low)")
    
    
    class ClarificationAgent:
        """Agent for handling ambiguity and generating clarifications"""
        
        def __init__(self, model: str = "gpt-4o-mini", temperature: float = 0.3):
            self.llm = ChatOpenAI(model=model, temperature=temperature)
            self.clarification_history: List[Dict[str, Any]] = []
            
            # Ambiguity detection prompt
            self.ambiguity_prompt = ChatPromptTemplate.from_messages([
                ("system", """Analyze the user's input for ambiguity or unclear elements.
    
    Types of ambiguity:
    - Lexical: Multiple meanings of a word (e.g., "bank" - financial or river)
    - Syntactic: Sentence structure unclear (e.g., "I saw the man with the telescope")
    - Semantic: Vague or imprecise meaning (e.g., "nearby", "soon")
    - Referential: Unclear what something refers to (e.g., "it", "that thing")
    
    Return JSON:
    {{
      "is_ambiguous": true/false,
      "ambiguity_type": "type",
      "confidence": 0.9,
      "ambiguous_elements": ["element1", "element2"],
      "clarification_needed": "what specifically needs clarification"
    }}"""),
                ("user", "Input: {input}\n\nPrevious context: {context}")
            ])
            
            # Clarification generation prompt
            self.clarification_prompt = ChatPromptTemplate.from_messages([
                ("system", """Generate a helpful clarification question to resolve the ambiguity.
    
    Make the question:
    1. Specific and targeted
    2. Easy to answer
    3. Include options when helpful
    4. Natural and conversational
    
    Return JSON:
    {{
      "question": "the clarification question",
      "options": ["option1", "option2"] or null,
      "priority": 1-3
    }}"""),
                ("user", """Input: {input}
    Ambiguity: {ambiguity}
    Elements needing clarification: {elements}
    
    Generate a clarification question.""")
            ])
            
            self.json_parser = JsonOutputParser()
        
        def detect_ambiguity(self, user_input: str, context: str = "") -> AmbiguityAnalysis:
            """Detect if input is ambiguous"""
            try:
                chain = self.ambiguity_prompt | self.llm | self.json_parser
                result = chain.invoke({"input": user_input, "context": context})
                
                return AmbiguityAnalysis(**result)
            except Exception as e:
                print(f"Ambiguity detection error: {e}")
                return AmbiguityAnalysis(
                    is_ambiguous=False,
                    ambiguity_type="unknown",
                    confidence=0.0,
                    ambiguous_elements=[],
                    clarification_needed=""
                )
        
        def generate_clarification(
            self,
            user_input: str,
            analysis: AmbiguityAnalysis
        ) -> ClarificationQuestion:
            """Generate clarification question"""
            try:
                chain = self.clarification_prompt | self.llm | self.json_parser
                result = chain.invoke({
                    "input": user_input,
                    "ambiguity": analysis.ambiguity_type,
                    "elements": ", ".join(analysis.ambiguous_elements)
                })
                
                return ClarificationQuestion(**result)
            except Exception as e:
                print(f"Clarification generation error: {e}")
                return ClarificationQuestion(
                    question="Could you please provide more details?",
                    options=None,
                    priority=2
                )
        
        def process_input(self, user_input: str, context: str = "") -> Dict[str, Any]:
            """Process input and return clarification if needed"""
            print(f"\n{'='*70}")
            print(f"šŸ“ Input: {user_input}")
            
            # Detect ambiguity
            analysis = self.detect_ambiguity(user_input, context)
            
            print(f"\nšŸ” Analysis:")
            print(f"   Ambiguous: {analysis.is_ambiguous}")
            print(f"   Confidence: {analysis.confidence:.2f}")
            
            result = {
                "input": user_input,
                "is_ambiguous": analysis.is_ambiguous,
                "analysis": analysis,
                "clarification": None
            }
            
            if analysis.is_ambiguous and analysis.confidence > 0.6:
                print(f"   Type: {analysis.ambiguity_type}")
                print(f"   Ambiguous elements: {', '.join(analysis.ambiguous_elements)}")
                
                # Generate clarification
                clarification = self.generate_clarification(user_input, analysis)
                result["clarification"] = clarification
                
                print(f"\nā“ Clarification needed:")
                print(f"   {clarification.question}")
                if clarification.options:
                    print(f"   Options:")
                    for i, opt in enumerate(clarification.options, 1):
                        print(f"     {i}. {opt}")
                
                # Store in history
                self.clarification_history.append({
                    "input": user_input,
                    "analysis": analysis.dict(),
                    "clarification": clarification.dict()
                })
            else:
                print(f"\nāœ… Input is clear, no clarification needed")
            
            return result
        
        def resolve_with_clarification(
            self,
            original_input: str,
            clarification_response: str
        ) -> str:
            """Process clarified input"""
            resolution_prompt = ChatPromptTemplate.from_messages([
                ("system", "Combine the original input with the clarification to form a complete, unambiguous statement."),
                ("user", """Original: {original}
    Clarification response: {clarification}
    
    Generate complete, unambiguous statement:""")
            ])
            
            chain = resolution_prompt | self.llm | StrOutputParser()
            resolved = chain.invoke({
                "original": original_input,
                "clarification": clarification_response
            })
            
            print(f"\nāœ… Resolved statement:")
            print(f"   {resolved}")
            
            return resolved
    
    
    def demonstrate_clarification():
        """Demonstrate clarification and disambiguation"""
        print("=" * 80)
        print("Pattern 129: Clarification & Disambiguation")
        print("=" * 80)
        
        agent = ClarificationAgent()
        
        # Example 1: Lexical ambiguity
        print("\n" + "=" * 80)
        print("EXAMPLE 1: Lexical Ambiguity")
        print("=" * 80)
        
        ambiguous_inputs = [
            "I need to go to the bank",
            "Can you get me the bat?",
            "Show me the rock music"
        ]
        
        for input_text in ambiguous_inputs:
            result = agent.process_input(input_text)
            
            if result["clarification"]:
                # Simulate user providing clarification
                print(f"\n   šŸ’¬ User provides clarification: Financial bank")
                resolved = agent.resolve_with_clarification(
                    input_text,
                    "The financial institution"
                )
        
        # Example 2: Referential ambiguity
        print("\n" + "=" * 80)
        print("EXAMPLE 2: Referential Ambiguity")
        print("=" * 80)
        
        referential_inputs = [
            ("John told Mike he should leave", "Previous: John and Mike were arguing"),
            ("Put it on the table", "Previous: User has a box and a book"),
            ("I want the blue one", "Previous: Looking at shirts")
        ]
        
        for input_text, context in referential_inputs:
            agent.process_input(input_text, context)
        
        # Example 3: Semantic vagueness
        print("\n" + "=" * 80)
        print("EXAMPLE 3: Semantic Vagueness")
        print("=" * 80)
        
        vague_inputs = [
            "Schedule a meeting soon",
            "I need a lot of storage",
            "Find a nearby restaurant"
        ]
        
        for input_text in vague_inputs:
            agent.process_input(input_text)
        
        # Example 4: Complex ambiguity
        print("\n" + "=" * 80)
        print("EXAMPLE 4: Complex Ambiguous Request")
        print("=" * 80)
        
        complex_input = "Book me a nice hotel room with a good view for my trip"
        result = agent.process_input(complex_input)
        
        if result["clarification"]:
            print(f"\n   šŸ’¬ User response: Paris, June 15-20, budget up to $200/night")
            resolved = agent.resolve_with_clarification(
                complex_input,
                "Paris, France from June 15-20, 2024, budget $200 per night"
            )
        
        # Example 5: Clear input (no clarification needed)
        print("\n" + "=" * 80)
        print("EXAMPLE 5: Clear Input (No Clarification)")
        print("=" * 80)
        
        clear_inputs = [
            "Set an alarm for 7:00 AM tomorrow",
            "What is the capital of France?",
            "Calculate 15% tip on $85.50"
        ]
        
        for input_text in clear_inputs:
            agent.process_input(input_text)
        
        # Statistics
        print("\n" + "=" * 80)
        print("CLARIFICATION STATISTICS")
        print("=" * 80)
        
        print(f"\nTotal clarifications asked: {len(agent.clarification_history)}")
        
        if agent.clarification_history:
            print(f"\nAmbiguity types encountered:")
            types = {}
            for item in agent.clarification_history:
                amb_type = item['analysis']['ambiguity_type']
                types[amb_type] = types.get(amb_type, 0) + 1
            
            for amb_type, count in types.items():
                print(f"  - {amb_type}: {count}")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY")
        print("=" * 80)
        print("""
    Clarification & Disambiguation Pattern:
    - Detects ambiguous or unclear user inputs
    - Generates targeted clarification questions
    - Resolves ambiguity through progressive refinement
    - Improves accuracy and user satisfaction
    
    Types of Ambiguity Handled:
    āœ“ Lexical - Multiple word meanings
    āœ“ Syntactic - Unclear sentence structure
    āœ“ Semantic - Vague or imprecise terms
    āœ“ Referential - Unclear references
    
    Key Benefits:
    āœ“ Reduces errors from misunderstanding
    āœ“ Improves task completion accuracy
    āœ“ Better user experience
    āœ“ Handles complex, real-world inputs
    āœ“ Proactive problem prevention
    
    Best Practices:
    • Ask specific, targeted questions
    • Provide options when helpful
    • Keep questions natural and conversational
    • Prioritize most important clarifications
    • Track clarification history for learning
        """)
    
    
    if __name__ == "__main__":
        demonstrate_clarification()
    
        

    Agentic Design Pattern: Clarification

    Pattern 129: Clarification – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Clarification pattern implementation.


    Pattern Description

    Pattern 129: Clarification & Disambiguation

    Description: Detects ambiguous or unclear user inputs and asks targeted clarifying questions to resolve uncertainties before proceeding.

    Components: – Ambiguity detection – Clarification question generation – Context tracking – Progressive refinement

    Use Cases: – Conversational agents handling ambiguous queries – Complex instruction following – Reducing errors from misunderstanding

    LangChain Implementation: Uses LangChain to detect ambiguity and generate appropriate clarification questions.


    File Statistics

    • Total Lines: 354
    • Classes: 3
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 129: Clarification & Disambiguation
    
    Description:
        Detects ambiguous or unclear user inputs and asks targeted clarifying questions
        to resolve uncertainties before proceeding.
    
    Components:
        - Ambiguity detection
        - Clarification question generation
        - Context tracking
        - Progressive refinement
    
    Use Cases:
        - Conversational agents handling ambiguous queries
        - Complex instruction following
        - Reducing errors from misunderstanding
    
    LangChain Implementation:
        Uses LangChain to detect ambiguity and generate appropriate clarification questions.
    """
    

    Purpose: This module implements the Clarification pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import langchain_core.output_parsers.JsonOutputParser
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import langchain_core.pydantic_v1.BaseModel
    import langchain_core.pydantic_v1.Field
    import os
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    

    Purpose: Core Python functionality: – langchain_core.output_parsers.JsonOutputParser: Regular expression operations – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – langchain_core.pydantic_v1.BaseModel: Regular expression operations – langchain_core.pydantic_v1.Field: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: AmbiguityAnalysis

    Lines 35-41

    Inherits from: BaseModel

    Purpose:

    Analysis of ambiguity in user input
    

    Class: ClarificationQuestion

    Lines 44-48

    Inherits from: BaseModel

    Purpose:

    A clarification question
    

    Class: ClarificationAgent

    Lines 51-212

    Purpose:

    Agent for handling ambiguity and generating clarifications
    

    Methods:

    __init__(self, model, temperature)

    Lines 54-102

    Purpose: Initialize the class instance with required parameters.

    Parameters: – model: Language model instance – temperature: Sampling temperature (0-1)

    detect_ambiguity(self, user_input, context)

    Lines 104-119

    Purpose:

    Detect if input is ambiguous
    

    Parameters: – user_input: Input data – context: Context

    Returns: AmbiguityAnalysis

    generate_clarification(self, user_input, analysis)

    Lines 121-142

    Purpose:

    Generate clarification question
    

    Parameters: – user_input: Input data – analysis: Analysis

    Returns: ClarificationQuestion

    process_input(self, user_input, context)

    Lines 144-187

    Purpose:

    Process input and return clarification if needed
    

    Parameters: – user_input: Input data – context: Context

    Returns: <ast.Subscript object at 0x000001A06D7EEA90>

    resolve_with_clarification(self, original_input, clarification_response)

    Lines 189-212

    Purpose:

    Process clarified input
    

    Parameters: – original_input: Input data – clarification_response: Clarification response

    Returns: str


    Functions

    demonstrate_clarification()

    Lines 215-349

    Purpose:

    Demonstrate clarification and disambiguation
    

    Key Concepts Summary

    Pattern Overview

    The Clarification pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 128
    • Pattern 130

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Clarification pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 129_clarification.py
    Total Lines: 354
    Pattern Category: AI Agent Design Pattern #129


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Multi Turn Dialogue

    
        """
    Pattern 128: Multi-Turn Dialogue Management
    
    Description:
        Manages coherent multi-turn conversations with context tracking, dialogue state,
        and appropriate responses across multiple exchanges.
    
    Components:
        - Dialogue state tracking
        - Context management
        - Intent recognition
        - Response generation
    
    Use Cases:
        - Conversational AI assistants
        - Customer service chatbots
        - Interactive tutoring systems
    
    LangChain Implementation:
        Uses LangChain memory, state management, and conversation chains.
    """
    
    import os
    from typing import List, Dict, Any, Optional
    from dotenv import load_dotenv
    from datetime import datetime
    from enum import Enum
    
    from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
    from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
    from langchain_openai import ChatOpenAI
    from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
    from langchain_core.runnables import RunnablePassthrough
    from langchain_core.pydantic_v1 import BaseModel, Field
    
    load_dotenv()
    
    
    class DialogueState(str, Enum):
        """Dialogue states"""
        GREETING = "greeting"
        INFO_GATHERING = "info_gathering"
        CLARIFICATION = "clarification"
        PROCESSING = "processing"
        RESPONSE = "response"
        CLOSING = "closing"
    
    
    class UserIntent(BaseModel):
        """Detected user intent"""
        intent: str = Field(description="Primary intent")
        confidence: float = Field(description="Confidence score")
        entities: Dict[str, Any] = Field(description="Extracted entities")
    
    
    class DialogueContext(BaseModel):
        """Dialogue context"""
        state: str = Field(description="Current dialogue state")
        topic: Optional[str] = Field(description="Current topic")
        user_goal: Optional[str] = Field(description="User's goal")
        collected_info: Dict[str, Any] = Field(default_factory=dict)
    
    
    class MultiTurnDialogueAgent:
        """Agent for managing multi-turn conversations"""
        
        def __init__(self, model: str = "gpt-4o-mini", temperature: float = 0.7):
            self.llm = ChatOpenAI(model=model, temperature=temperature)
            self.conversation_history: List[Dict[str, str]] = []
            self.context: DialogueContext = DialogueContext(
                state=DialogueState.GREETING.value,
                topic=None,
                user_goal=None,
                collected_info={}
            )
            
            # Intent detection prompt
            self.intent_prompt = ChatPromptTemplate.from_messages([
                ("system", """Analyze the user's message and detect their intent.
    Common intents: greeting, question, request_info, provide_info, complaint, thanks, goodbye
    
    Return JSON:
    {{
      "intent": "intent_name",
      "confidence": 0.9,
      "entities": {{"key": "value"}}
    }}"""),
                ("user", "{message}")
            ])
            
            # Response generation with context
            self.response_prompt = ChatPromptTemplate.from_messages([
                ("system", """You are a helpful conversational AI assistant.
    Current conversation context:
    - State: {state}
    - Topic: {topic}
    - User Goal: {user_goal}
    - Collected Info: {collected_info}
    
    Provide a natural, contextually appropriate response that:
    1. Acknowledges the user's message
    2. Maintains conversation flow
    3. Helps achieve the user's goal
    4. Asks follow-up questions if needed"""),
                MessagesPlaceholder(variable_name="history"),
                ("user", "{message}")
            ])
            
            self.intent_parser = JsonOutputParser()
            self.response_parser = StrOutputParser()
        
        def detect_intent(self, message: str) -> UserIntent:
            """Detect user intent from message"""
            try:
                chain = self.intent_prompt | self.llm | self.intent_parser
                result = chain.invoke({"message": message})
                
                return UserIntent(
                    intent=result["intent"],
                    confidence=result["confidence"],
                    entities=result.get("entities", {})
                )
            except Exception as e:
                print(f"Intent detection error: {e}")
                return UserIntent(intent="unknown", confidence=0.0, entities={})
        
        def update_context(self, intent: UserIntent, message: str):
            """Update dialogue context based on intent"""
            # Update state based on intent
            if intent.intent == "greeting":
                self.context.state = DialogueState.GREETING.value
            elif intent.intent in ["question", "request_info"]:
                self.context.state = DialogueState.INFO_GATHERING.value
            elif intent.intent == "provide_info":
                self.context.state = DialogueState.PROCESSING.value
                # Store provided information
                self.context.collected_info.update(intent.entities)
            elif intent.intent == "goodbye":
                self.context.state = DialogueState.CLOSING.value
            
            # Extract topic if not set
            if not self.context.topic and len(self.conversation_history) > 0:
                # Simple topic extraction (could be enhanced)
                for entity_key in intent.entities:
                    if entity_key not in ["time", "date", "number"]:
                        self.context.topic = intent.entities[entity_key]
                        break
        
        def generate_response(self, message: str) -> str:
            """Generate contextually appropriate response"""
            # Detect intent
            intent = self.detect_intent(message)
            print(f"\nšŸŽÆ Detected Intent: {intent.intent} (confidence: {intent.confidence:.2f})")
            
            # Update context
            self.update_context(intent, message)
            print(f"šŸ“Š Dialogue State: {self.context.state}")
            if self.context.topic:
                print(f"šŸ’” Topic: {self.context.topic}")
            
            # Prepare conversation history for prompt
            history = []
            for turn in self.conversation_history[-5:]:  # Last 5 turns
                if turn["role"] == "user":
                    history.append(HumanMessage(content=turn["content"]))
                else:
                    history.append(AIMessage(content=turn["content"]))
            
            # Generate response
            chain = self.response_prompt | self.llm | self.response_parser
            
            response = chain.invoke({
                "message": message,
                "state": self.context.state,
                "topic": self.context.topic or "not set",
                "user_goal": self.context.user_goal or "not determined",
                "collected_info": str(self.context.collected_info),
                "history": history
            })
            
            return response
        
        def chat(self, user_message: str) -> str:
            """Process user message and return response"""
            print(f"\n{'='*60}")
            print(f"šŸ‘¤ User: {user_message}")
            
            # Add to history
            self.conversation_history.append({
                "role": "user",
                "content": user_message,
                "timestamp": datetime.now().isoformat()
            })
            
            # Generate response
            response = self.generate_response(user_message)
            
            # Add response to history
            self.conversation_history.append({
                "role": "assistant",
                "content": response,
                "timestamp": datetime.now().isoformat()
            })
            
            print(f"šŸ¤– Assistant: {response}")
            
            return response
        
        def get_conversation_summary(self) -> str:
            """Generate summary of conversation"""
            if not self.conversation_history:
                return "No conversation yet."
            
            summary_prompt = ChatPromptTemplate.from_messages([
                ("system", "Summarize the following conversation in 2-3 sentences."),
                ("user", "{conversation}")
            ])
            
            conversation_text = "\n".join([
                f"{turn['role']}: {turn['content']}"
                for turn in self.conversation_history
            ])
            
            chain = summary_prompt | self.llm | StrOutputParser()
            summary = chain.invoke({"conversation": conversation_text})
            
            return summary
        
        def reset_conversation(self):
            """Reset conversation state"""
            self.conversation_history = []
            self.context = DialogueContext(
                state=DialogueState.GREETING.value,
                topic=None,
                user_goal=None,
                collected_info={}
            )
            print("\nšŸ”„ Conversation reset")
    
    
    def demonstrate_multi_turn_dialogue():
        """Demonstrate multi-turn dialogue management"""
        print("=" * 80)
        print("Pattern 128: Multi-Turn Dialogue Management")
        print("=" * 80)
        
        agent = MultiTurnDialogueAgent()
        
        # Example 1: Customer service conversation
        print("\n" + "=" * 80)
        print("EXAMPLE 1: Customer Service Conversation")
        print("=" * 80)
        
        conversation_1 = [
            "Hi, I need help with my order",
            "My order number is 12345",
            "It was supposed to arrive yesterday but I haven't received it",
            "Yes, my address is 123 Main Street",
            "Thank you for your help!"
        ]
        
        for message in conversation_1:
            agent.chat(message)
        
        print("\n" + "-" * 60)
        print("šŸ“ Conversation Summary:")
        print(agent.get_conversation_summary())
        
        # Example 2: Technical support
        print("\n" + "=" * 80)
        print("EXAMPLE 2: Technical Support Conversation")
        print("=" * 80)
        
        agent.reset_conversation()
        
        conversation_2 = [
            "Hello, my computer won't start",
            "It's a laptop, about 2 years old",
            "When I press the power button, nothing happens at all",
            "No, there are no lights or sounds",
            "Okay, I'll try that. Thanks!"
        ]
        
        for message in conversation_2:
            agent.chat(message)
        
        print("\n" + "-" * 60)
        print("šŸ“ Conversation Summary:")
        print(agent.get_conversation_summary())
        
        # Example 3: Information gathering
        print("\n" + "=" * 80)
        print("EXAMPLE 3: Information Gathering Conversation")
        print("=" * 80)
        
        agent.reset_conversation()
        
        conversation_3 = [
            "I want to book a flight",
            "From New York to London",
            "Next week, preferably Tuesday",
            "Economy class is fine",
            "Great, please proceed with the booking"
        ]
        
        for message in conversation_3:
            agent.chat(message)
        
        print("\n" + "-" * 60)
        print("šŸ“ Conversation Summary:")
        print(agent.get_conversation_summary())
        
        print("\n" + "-" * 60)
        print("šŸ“Š Final Context State:")
        print(f"  State: {agent.context.state}")
        print(f"  Topic: {agent.context.topic}")
        print(f"  Collected Info: {agent.context.collected_info}")
        print(f"  Total Turns: {len(agent.conversation_history)}")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY")
        print("=" * 80)
        print("""
    Multi-Turn Dialogue Management Pattern:
    - Maintains context across conversation turns
    - Tracks dialogue state and user intent
    - Generates contextually appropriate responses
    - Manages information collection
    
    Key Features:
    āœ“ Intent detection
    āœ“ State tracking
    āœ“ Context maintenance
    āœ“ Natural conversation flow
    āœ“ Information extraction
    
    Dialogue States:
    • Greeting - Initial interaction
    • Info Gathering - Collecting information
    • Clarification - Resolving ambiguities
    • Processing - Handling requests
    • Response - Providing answers
    • Closing - Ending conversation
    
    Benefits:
    āœ“ Coherent multi-turn conversations
    āœ“ Context-aware responses
    āœ“ Better user experience
    āœ“ Goal-oriented dialogue
    āœ“ Efficient information gathering
        """)
    
    
    if __name__ == "__main__":
        demonstrate_multi_turn_dialogue()
    
        

    Agentic Design Pattern: Multi Turn Dialogue

    Pattern 128: Multi Turn Dialogue – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Multi Turn Dialogue pattern implementation.


    Pattern Description

    Pattern 128: Multi-Turn Dialogue Management

    Description: Manages coherent multi-turn conversations with context tracking, dialogue state, and appropriate responses across multiple exchanges.

    Components: – Dialogue state tracking – Context management – Intent recognition – Response generation

    Use Cases: – Conversational AI assistants – Customer service chatbots – Interactive tutoring systems

    LangChain Implementation: Uses LangChain memory, state management, and conversation chains.


    File Statistics

    • Total Lines: 357
    • Classes: 4
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 128: Multi-Turn Dialogue Management
    
    Description:
        Manages coherent multi-turn conversations with context tracking, dialogue state,
        and appropriate responses across multiple exchanges.
    
    Components:
        - Dialogue state tracking
        - Context management
        - Intent recognition
        - Response generation
    
    Use Cases:
        - Conversational AI assistants
        - Customer service chatbots
        - Interactive tutoring systems
    
    LangChain Implementation:
        Uses LangChain memory, state management, and conversation chains.
    """
    

    Purpose: This module implements the Multi Turn Dialogue pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import datetime.datetime
    import enum.Enum
    import langchain_core.messages.AIMessage
    import langchain_core.messages.HumanMessage
    import langchain_core.messages.SystemMessage
    import langchain_core.output_parsers.JsonOutputParser
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import langchain_core.prompts.MessagesPlaceholder
    import langchain_core.pydantic_v1.BaseModel
    import langchain_core.pydantic_v1.Field
    import langchain_core.runnables.RunnablePassthrough
    import os
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    

    Purpose: Core Python functionality: – datetime.datetime: Date and time handling – enum.Enum: Enumeration support – langchain_core.messages.AIMessage: Regular expression operations – langchain_core.messages.HumanMessage: Regular expression operations – langchain_core.messages.SystemMessage: Regular expression operations – langchain_core.output_parsers.JsonOutputParser: Regular expression operations – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – langchain_core.prompts.MessagesPlaceholder: Regular expression operations – langchain_core.pydantic_v1.BaseModel: Regular expression operations – langchain_core.pydantic_v1.Field: Regular expression operations – langchain_core.runnables.RunnablePassthrough: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: DialogueState

    Lines 39-46

    Inherits from: str, Enum

    Purpose:

    Dialogue states
    

    Class: UserIntent

    Lines 49-53

    Inherits from: BaseModel

    Purpose:

    Detected user intent
    

    Class: DialogueContext

    Lines 56-61

    Inherits from: BaseModel

    Purpose:

    Dialogue context
    

    Class: MultiTurnDialogueAgent

    Lines 64-238

    Purpose:

    Agent for managing multi-turn conversations
    

    Methods:

    __init__(self, model, temperature)

    Lines 67-110

    Purpose: Initialize the class instance with required parameters.

    Parameters: – model: Language model instance – temperature: Sampling temperature (0-1)

    detect_intent(self, message)

    Lines 112-125

    Purpose:

    Detect user intent from message
    

    Parameters: – message: Message

    Returns: UserIntent

    update_context(self, intent, message)

    Lines 127-147

    Purpose:

    Update dialogue context based on intent
    

    Parameters: – intent: Intent – message: Message

    generate_response(self, message)

    Lines 149-181

    Purpose:

    Generate contextually appropriate response
    

    Parameters: – message: Message

    Returns: str

    chat(self, user_message)

    Lines 183-207

    Purpose:

    Process user message and return response
    

    Parameters: – user_message: User message

    Returns: str

    get_conversation_summary(self)

    Lines 209-227

    Purpose:

    Generate summary of conversation
    

    Parameters:

    Returns: str

    reset_conversation(self)

    Lines 229-238

    Purpose:

    Reset conversation state
    

    Parameters:


    Functions

    demonstrate_multi_turn_dialogue()

    Lines 241-352

    Purpose:

    Demonstrate multi-turn dialogue management
    

    Key Concepts Summary

    Pattern Overview

    The Multi Turn Dialogue pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 127
    • Pattern 129

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Multi Turn Dialogue pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 128_multi_turn_dialogue.py
    Total Lines: 357
    Pattern Category: AI Agent Design Pattern #128


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Semantic Search Retrieval

    
        """
    Pattern 127: Semantic Search & Retrieval
    
    Description:
        Retrieves information based on semantic similarity rather than keyword matching,
        using embeddings and vector databases for intelligent information retrieval.
    
    Components:
        - Text embeddings
        - Vector similarity search
        - Semantic ranking
        - Hybrid retrieval (keyword + semantic)
    
    Use Cases:
        - Intelligent document search
        - Question answering systems
        - Recommendation systems
    
    LangChain Implementation:
        Uses LangChain embeddings, vector stores, and retrievers for semantic search.
    """
    
    import os
    from typing import List, Dict, Any, Optional
    from dotenv import load_dotenv
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    from langchain_openai import ChatOpenAI, OpenAIEmbeddings
    from langchain_core.documents import Document
    from langchain_community.vectorstores import Chroma
    from langchain.text_splitter import RecursiveCharacterTextSplitter
    from langchain_core.runnables import RunnablePassthrough
    from langchain.retrievers import EnsembleRetriever, ContextualCompressionRetriever
    from langchain.retrievers.document_compressors import LLMChainExtractor
    from langchain_community.retrievers import BM25Retriever
    
    load_dotenv()
    
    
    class SemanticSearchAgent:
        """Agent for semantic search and retrieval"""
        
        def __init__(self, model: str = "gpt-4o-mini", temperature: float = 0.0):
            self.llm = ChatOpenAI(model=model, temperature=temperature)
            self.embeddings = OpenAIEmbeddings()
            self.vectorstore: Optional[Chroma] = None
            self.documents: List[Document] = []
            
            # Text splitter for chunking
            self.text_splitter = RecursiveCharacterTextSplitter(
                chunk_size=500,
                chunk_overlap=50,
                length_function=len
            )
            
            # QA prompt
            self.qa_prompt = ChatPromptTemplate.from_messages([
                ("system", """You are a helpful assistant that answers questions based on the provided context.
    Use only the information from the context to answer. If you cannot answer from the context, say so.
    Always cite which part of the context you used."""),
                ("user", """Context:
    {context}
    
    Question: {question}
    
    Answer:""")
            ])
        
        def load_documents(self, documents: List[str], metadatas: Optional[List[Dict]] = None):
            """Load documents into the system"""
            print(f"\nšŸ“š Loading {len(documents)} documents...")
            
            # Create Document objects
            if metadatas:
                self.documents = [
                    Document(page_content=doc, metadata=meta)
                    for doc, meta in zip(documents, metadatas)
                ]
            else:
                self.documents = [
                    Document(page_content=doc, metadata={"id": i})
                    for i, doc in enumerate(documents)
                ]
            
            # Split documents
            split_docs = self.text_splitter.split_documents(self.documents)
            print(f"   Split into {len(split_docs)} chunks")
            
            # Create vector store
            self.vectorstore = Chroma.from_documents(
                documents=split_docs,
                embedding=self.embeddings,
                collection_name="semantic_search"
            )
            
            print(f"   āœ“ Vectorstore created with {len(split_docs)} embeddings")
        
        def semantic_search(self, query: str, k: int = 3) -> List[Document]:
            """Pure semantic search using vector similarity"""
            print(f"\nšŸ” Semantic search for: '{query}'")
            
            if not self.vectorstore:
                print("   āŒ No documents loaded!")
                return []
            
            # Retrieve similar documents
            results = self.vectorstore.similarity_search_with_score(query, k=k)
            
            print(f"   Found {len(results)} results:\n")
            for i, (doc, score) in enumerate(results, 1):
                print(f"   {i}. Score: {score:.4f}")
                print(f"      {doc.page_content[:100]}...\n")
            
            return [doc for doc, _ in results]
        
        def hybrid_search(self, query: str, k: int = 3) -> List[Document]:
            """Hybrid search combining semantic and keyword matching"""
            print(f"\nšŸ” Hybrid search for: '{query}'")
            
            if not self.vectorstore or not self.documents:
                print("   āŒ No documents loaded!")
                return []
            
            # Create semantic retriever
            semantic_retriever = self.vectorstore.as_retriever(search_kwargs={"k": k})
            
            # Create keyword retriever (BM25)
            bm25_retriever = BM25Retriever.from_documents(self.documents)
            bm25_retriever.k = k
            
            # Combine retrievers
            ensemble_retriever = EnsembleRetriever(
                retrievers=[semantic_retriever, bm25_retriever],
                weights=[0.7, 0.3]  # Favor semantic
            )
            
            results = ensemble_retriever.get_relevant_documents(query)
            
            print(f"   Found {len(results)} results (semantic + keyword)\n")
            for i, doc in enumerate(results[:k], 1):
                print(f"   {i}. {doc.page_content[:100]}...\n")
            
            return results[:k]
        
        def search_with_reranking(self, query: str, k: int = 3) -> List[Document]:
            """Search with LLM-based reranking/compression"""
            print(f"\nšŸ” Search with reranking for: '{query}'")
            
            if not self.vectorstore:
                print("   āŒ No documents loaded!")
                return []
            
            # Base retriever
            base_retriever = self.vectorstore.as_retriever(search_kwargs={"k": k * 2})
            
            # Compressor for reranking
            compressor = LLMChainExtractor.from_llm(self.llm)
            
            # Compression retriever
            compression_retriever = ContextualCompressionRetriever(
                base_compressor=compressor,
                base_retriever=base_retriever
            )
            
            results = compression_retriever.get_relevant_documents(query)
            
            print(f"   Found and reranked {len(results)} results\n")
            for i, doc in enumerate(results[:k], 1):
                print(f"   {i}. {doc.page_content[:150]}...\n")
            
            return results[:k]
        
        def answer_question(self, question: str, search_method: str = "semantic") -> str:
            """Answer question using retrieved context"""
            print(f"\nšŸ’¬ Answering question: '{question}'")
            print(f"   Using {search_method} search")
            
            # Retrieve context
            if search_method == "semantic":
                context_docs = self.semantic_search(question, k=3)
            elif search_method == "hybrid":
                context_docs = self.hybrid_search(question, k=3)
            else:  # reranking
                context_docs = self.search_with_reranking(question, k=3)
            
            if not context_docs:
                return "No relevant context found."
            
            # Combine context
            context = "\n\n".join([doc.page_content for doc in context_docs])
            
            # Generate answer
            chain = self.qa_prompt | self.llm | StrOutputParser()
            answer = chain.invoke({"context": context, "question": question})
            
            print(f"\nšŸ“ Answer:\n{answer}")
            
            return answer
        
        def find_similar_documents(self, reference_text: str, k: int = 3) -> List[Document]:
            """Find documents similar to reference text"""
            print(f"\nšŸ” Finding similar documents to reference text...")
            
            if not self.vectorstore:
                print("   āŒ No documents loaded!")
                return []
            
            results = self.vectorstore.similarity_search(reference_text, k=k)
            
            print(f"   Found {len(results)} similar documents:\n")
            for i, doc in enumerate(results, 1):
                print(f"   {i}. {doc.page_content[:100]}...")
                if 'id' in doc.metadata:
                    print(f"      (Document ID: {doc.metadata['id']})\n")
            
            return results
        
        def get_statistics(self) -> Dict[str, Any]:
            """Get search system statistics"""
            return {
                "total_documents": len(self.documents),
                "vectorstore_loaded": self.vectorstore is not None,
                "embedding_model": "text-embedding-ada-002"
            }
    
    
    def demonstrate_semantic_search():
        """Demonstrate semantic search and retrieval"""
        print("=" * 80)
        print("Pattern 127: Semantic Search & Retrieval")
        print("=" * 80)
        
        agent = SemanticSearchAgent()
        
        # Example 1: Load documents
        print("\n" + "=" * 80)
        print("EXAMPLE 1: Loading Documents")
        print("=" * 80)
        
        documents = [
            """Python is a high-level, interpreted programming language known for its simplicity 
            and readability. Created by Guido van Rossum in 1991, Python emphasizes code 
            readability and allows programmers to express concepts in fewer lines of code.""",
            
            """Machine learning is a subset of artificial intelligence that enables systems to 
            learn and improve from experience without being explicitly programmed. It focuses 
            on developing computer programs that can access data and learn from it.""",
            
            """Deep learning is a subset of machine learning that uses neural networks with 
            multiple layers. These deep neural networks attempt to simulate the behavior of 
            the human brain, allowing it to learn from large amounts of data.""",
            
            """Natural Language Processing (NLP) is a branch of AI that helps computers understand, 
            interpret, and manipulate human language. NLP draws from many disciplines, including 
            computer science and computational linguistics.""",
            
            """Computer vision is a field of artificial intelligence that trains computers to 
            interpret and understand the visual world. Using digital images and deep learning 
            models, machines can accurately identify and classify objects.""",
            
            """The Transformer architecture, introduced in the paper 'Attention is All You Need', 
            revolutionized NLP. It relies entirely on attention mechanisms, dispensing with 
            recurrence and convolutions entirely."""
        ]
        
        metadatas = [
            {"topic": "programming", "language": "python"},
            {"topic": "AI", "subtopic": "machine_learning"},
            {"topic": "AI", "subtopic": "deep_learning"},
            {"topic": "AI", "subtopic": "NLP"},
            {"topic": "AI", "subtopic": "computer_vision"},
            {"topic": "AI", "subtopic": "transformers"}
        ]
        
        agent.load_documents(documents, metadatas)
        
        # Example 2: Semantic search
        print("\n" + "=" * 80)
        print("EXAMPLE 2: Pure Semantic Search")
        print("=" * 80)
        
        queries = [
            "neural networks and learning from data",
            "understanding human language with computers",
            "programming language for beginners"
        ]
        
        for query in queries:
            agent.semantic_search(query, k=2)
        
        # Example 3: Hybrid search
        print("\n" + "=" * 80)
        print("EXAMPLE 3: Hybrid Search (Semantic + Keyword)")
        print("=" * 80)
        
        agent.hybrid_search("deep neural networks", k=2)
        
        # Example 4: Search with reranking
        print("\n" + "=" * 80)
        print("EXAMPLE 4: Search with LLM Reranking")
        print("=" * 80)
        
        agent.search_with_reranking("AI techniques for processing text", k=2)
        
        # Example 5: Question answering with different search methods
        print("\n" + "=" * 80)
        print("EXAMPLE 5: Question Answering")
        print("=" * 80)
        
        questions = [
            "What is the Transformer architecture?",
            "Who created Python and when?",
            "What is the relationship between deep learning and machine learning?"
        ]
        
        methods = ["semantic", "hybrid", "reranking"]
        
        for question in questions[:1]:  # Just first question with all methods
            print(f"\nQuestion: {question}\n")
            for method in methods:
                print(f"\n--- Method: {method} ---")
                agent.answer_question(question, search_method=method)
        
        # Example 6: Find similar documents
        print("\n" + "=" * 80)
        print("EXAMPLE 6: Finding Similar Documents")
        print("=" * 80)
        
        reference = "Neural networks that can process and generate human language"
        agent.find_similar_documents(reference, k=3)
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY")
        print("=" * 80)
        print("""
    Semantic Search & Retrieval Pattern:
    - Finds information based on meaning, not just keywords
    - Uses embeddings to capture semantic similarity
    - Multiple search strategies available
    - Enables intelligent question answering
    
    Search Methods:
    1. Pure Semantic: Vector similarity only
    2. Hybrid: Combines semantic + keyword (BM25)
    3. With Reranking: LLM compresses and reranks results
    
    Key Benefits:
    āœ“ Understanding user intent
    āœ“ Finding conceptually similar content
    āœ“ Better than keyword matching
    āœ“ Handles synonyms and paraphrases
    āœ“ Improved retrieval accuracy
    
    Use Cases:
    • Document search systems
    • Question answering
    • Recommendation engines
    • Knowledge bases
    • Research assistants
        """)
    
    
    if __name__ == "__main__":
        demonstrate_semantic_search()
    
        

    Agentic Design Pattern: Semantic Search Retrieval

    Pattern 127: Semantic Search Retrieval – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Semantic Search Retrieval pattern implementation.


    Pattern Description

    Pattern 127: Semantic Search & Retrieval

    Description: Retrieves information based on semantic similarity rather than keyword matching, using embeddings and vector databases for intelligent information retrieval.

    Components: – Text embeddings – Vector similarity search – Semantic ranking – Hybrid retrieval (keyword + semantic)

    Use Cases: – Intelligent document search – Question answering systems – Recommendation systems

    LangChain Implementation: Uses LangChain embeddings, vector stores, and retrievers for semantic search.


    File Statistics

    • Total Lines: 367
    • Classes: 1
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 127: Semantic Search & Retrieval
    
    Description:
        Retrieves information based on semantic similarity rather than keyword matching,
        using embeddings and vector databases for intelligent information retrieval.
    
    Components:
        - Text embeddings
        - Vector similarity search
        - Semantic ranking
        - Hybrid retrieval (keyword + semantic)
    
    Use Cases:
        - Intelligent document search
        - Question answering systems
        - Recommendation systems
    
    LangChain Implementation:
        Uses LangChain embeddings, vector stores, and retrievers for semantic search.
    """
    

    Purpose: This module implements the Semantic Search Retrieval pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import langchain.retrievers.ContextualCompressionRetriever
    import langchain.retrievers.EnsembleRetriever
    import langchain.retrievers.document_compressors.LLMChainExtractor
    import langchain_community.retrievers.BM25Retriever
    import langchain_community.vectorstores.Chroma
    import langchain_core.documents.Document
    import langchain_core.output_parsers.StrOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import langchain_core.runnables.RunnablePassthrough
    import os
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    

    Purpose: Core Python functionality: – langchain.retrievers.ContextualCompressionRetriever: Regular expression operations – langchain.retrievers.EnsembleRetriever: Regular expression operations – langchain.retrievers.document_compressors.LLMChainExtractor: Regular expression operations – langchain_community.retrievers.BM25Retriever: Regular expression operations – langchain_community.vectorstores.Chroma: Regular expression operations – langchain_core.documents.Document: Regular expression operations – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – langchain_core.runnables.RunnablePassthrough: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain.text_splitter.RecursiveCharacterTextSplitter
    from langchain_openai.ChatOpenAI
    from langchain_openai.OpenAIEmbeddings
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: SemanticSearchAgent

    Lines 41-225

    Purpose:

    Agent for semantic search and retrieval
    

    Methods:

    __init__(self, model, temperature)

    Lines 44-68

    Purpose: Initialize the class instance with required parameters.

    Parameters: – model: Language model instance – temperature: Sampling temperature (0-1)

    load_documents(self, documents, metadatas)

    Lines 70-97

    Purpose:

    Load documents into the system
    

    Parameters: – documents: Documents – metadatas: Metadatas

    semantic_search(self, query, k)

    Lines 99-115

    Purpose:

    Pure semantic search using vector similarity
    

    Parameters: – query: Input query or question – k: K

    Returns: <ast.Subscript object at 0x000001A06D62A390>

    hybrid_search(self, query, k)

    Lines 117-144

    Purpose:

    Hybrid search combining semantic and keyword matching
    

    Parameters: – query: Input query or question – k: K

    Returns: <ast.Subscript object at 0x000001A06D77C1D0>

    search_with_reranking(self, query, k)

    Lines 146-172

    Purpose:

    Search with LLM-based reranking/compression
    

    Parameters: – query: Input query or question – k: K

    Returns: <ast.Subscript object at 0x000001A06D7EE650>

    answer_question(self, question, search_method)

    Lines 174-199

    Purpose:

    Answer question using retrieved context
    

    Parameters: – question: Question to answer – search_method: Search method

    Returns: str

    find_similar_documents(self, reference_text, k)

    Lines 201-217

    Purpose:

    Find documents similar to reference text
    

    Parameters: – reference_text: Reference text – k: K

    Returns: <ast.Subscript object at 0x000001A06D7B3890>

    get_statistics(self)

    Lines 219-225

    Purpose:

    Get search system statistics
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D7B0050>


    Functions

    demonstrate_semantic_search()

    Lines 228-362

    Purpose:

    Demonstrate semantic search and retrieval
    

    Key Concepts Summary

    Pattern Overview

    The Semantic Search Retrieval pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 126
    • Pattern 128

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Semantic Search Retrieval pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 127_semantic_search_retrieval.py
    Total Lines: 367
    Pattern Category: AI Agent Design Pattern #127


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Knowledge Fusion

    
        """
    Pattern 126: Knowledge Fusion
    
    Description:
        Combines knowledge from multiple heterogeneous sources, resolving conflicts
        and creating a unified, consistent knowledge representation.
    
    Components:
        - Multi-source integration
        - Conflict detection and resolution
        - Consistency checking
        - Knowledge merging strategies
    
    Use Cases:
        - Multi-source data integration
        - Fact verification across sources
        - Building comprehensive knowledge bases
    
    LangChain Implementation:
        Uses LangChain for analyzing, comparing, and merging knowledge from multiple sources.
    """
    
    import os
    from typing import List, Dict, Any, Optional, Set
    from dotenv import load_dotenv
    from datetime import datetime
    from collections import defaultdict
    
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import JsonOutputParser
    from langchain_openai import ChatOpenAI
    from langchain_core.pydantic_v1 import BaseModel, Field
    
    load_dotenv()
    
    
    class KnowledgeSource(BaseModel):
        """Represents a knowledge source"""
        source_id: str = Field(description="Unique source identifier")
        name: str = Field(description="Source name")
        reliability: float = Field(description="Source reliability score 0-1")
        data: Dict[str, Any] = Field(description="Knowledge data")
    
    
    class FusedKnowledge(BaseModel):
        """Fused knowledge item"""
        key: str = Field(description="Knowledge key/identifier")
        value: Any = Field(description="Fused value")
        confidence: float = Field(description="Confidence in fused value")
        sources: List[str] = Field(description="Contributing sources")
        conflicts: List[Dict[str, Any]] = Field(description="Detected conflicts", default_factory=list)
    
    
    class KnowledgeFusionAgent:
        """Agent for fusing knowledge from multiple sources"""
        
        def __init__(self, model: str = "gpt-4o-mini", temperature: float = 0.0):
            self.llm = ChatOpenAI(model=model, temperature=temperature)
            self.sources: List[KnowledgeSource] = []
            self.fused_knowledge: Dict[str, FusedKnowledge] = {}
            
            # Conflict resolution prompt
            self.conflict_resolution_prompt = ChatPromptTemplate.from_messages([
                ("system", """You are an expert at resolving conflicting information from multiple sources.
    Given conflicting facts from different sources with their reliability scores, determine:
    1. Which fact is most likely correct
    2. If a synthesis/combination is possible
    3. Confidence level in the resolution
    
    Return JSON with format:
    {{
      "resolved_value": "the resolved/synthesized value",
      "confidence": 0.85,
      "reasoning": "explanation of resolution",
      "method": "voting|weighted|synthesis|newest"
    }}"""),
                ("user", """Conflicting information about: {key}
    
    Sources and values:
    {conflicts}
    
    Resolve the conflict.""")
            ])
            
            self.parser = JsonOutputParser()
        
        def add_source(self, source: KnowledgeSource):
            """Add a knowledge source"""
            self.sources.append(source)
            print(f"āœ“ Added source: {source.name} (reliability: {source.reliability})")
        
        def detect_conflicts(self, key: str, values: List[Dict[str, Any]]) -> bool:
            """Check if there are conflicts for a key"""
            if len(values)  1
        
        def simple_fusion(self, key: str, values: List[Dict[str, Any]]) -> FusedKnowledge:
            """Simple fusion without conflicts (voting or consensus)"""
            if len(values) == 1:
                # Single source - use as is
                return FusedKnowledge(
                    key=key,
                    value=values[0]['value'],
                    confidence=values[0]['reliability'],
                    sources=[values[0]['source_id']]
                )
            
            # Multiple sources with same value - average confidence
            avg_confidence = sum(v['reliability'] for v in values) / len(values)
            sources = [v['source_id'] for v in values]
            
            return FusedKnowledge(
                key=key,
                value=values[0]['value'],
                confidence=avg_confidence,
                sources=sources
            )
        
        def resolve_conflict(self, key: str, values: List[Dict[str, Any]]) -> FusedKnowledge:
            """Resolve conflicting values using LLM"""
            print(f"\nāš ļø  Conflict detected for '{key}'")
            
            # Prepare conflict description
            conflicts_text = ""
            conflict_list = []
            for v in values:
                conflicts_text += f"- Source '{v['source_name']}' (reliability: {v['reliability']}): {v['value']}\n"
                conflict_list.append({
                    "source": v['source_name'],
                    "value": v['value'],
                    "reliability": v['reliability']
                })
            
            print(f"   Conflicting values:\n{conflicts_text}")
            
            try:
                # Use LLM to resolve
                chain = self.conflict_resolution_prompt | self.llm | self.parser
                result = chain.invoke({"key": key, "conflicts": conflicts_text})
                
                print(f"   Resolution: {result['resolved_value']}")
                print(f"   Method: {result['method']}, Confidence: {result['confidence']}")
                print(f"   Reasoning: {result['reasoning']}")
                
                return FusedKnowledge(
                    key=key,
                    value=result['resolved_value'],
                    confidence=result['confidence'],
                    sources=[v['source_id'] for v in values],
                    conflicts=conflict_list
                )
            except Exception as e:
                print(f"   Error resolving conflict: {e}")
                # Fallback: use most reliable source
                best_source = max(values, key=lambda x: x['reliability'])
                return FusedKnowledge(
                    key=key,
                    value=best_source['value'],
                    confidence=best_source['reliability'] * 0.8,  # Reduce confidence
                    sources=[v['source_id'] for v in values],
                    conflicts=conflict_list
                )
        
        def fuse_knowledge(self) -> Dict[str, FusedKnowledge]:
            """Fuse knowledge from all sources"""
            print("\n" + "=" * 80)
            print("šŸ”„ Starting Knowledge Fusion Process")
            print("=" * 80)
            
            # Group knowledge by key
            knowledge_by_key = defaultdict(list)
            
            for source in self.sources:
                for key, value in source.data.items():
                    knowledge_by_key[key].append({
                        'source_id': source.source_id,
                        'source_name': source.name,
                        'reliability': source.reliability,
                        'value': value
                    })
            
            print(f"\nšŸ“Š Found {len(knowledge_by_key)} unique knowledge keys")
            
            # Fuse each key
            conflicts_detected = 0
            for key, values in knowledge_by_key.items():
                if self.detect_conflicts(key, values):
                    conflicts_detected += 1
                    self.fused_knowledge[key] = self.resolve_conflict(key, values)
                else:
                    self.fused_knowledge[key] = self.simple_fusion(key, values)
            
            print(f"\nāœ“ Fusion complete!")
            print(f"  - Total keys: {len(self.fused_knowledge)}")
            print(f"  - Conflicts resolved: {conflicts_detected}")
            
            return self.fused_knowledge
        
        def query(self, key: str) -> Optional[FusedKnowledge]:
            """Query fused knowledge"""
            return self.fused_knowledge.get(key)
        
        def get_high_confidence_facts(self, threshold: float = 0.8) -> List[FusedKnowledge]:
            """Get facts with confidence above threshold"""
            return [
                fact for fact in self.fused_knowledge.values()
                if fact.confidence >= threshold
            ]
        
        def get_conflicted_facts(self) -> List[FusedKnowledge]:
            """Get facts that had conflicts"""
            return [
                fact for fact in self.fused_knowledge.values()
                if fact.conflicts
            ]
        
        def get_statistics(self) -> Dict[str, Any]:
            """Get fusion statistics"""
            total_facts = len(self.fused_knowledge)
            conflicted = len(self.get_conflicted_facts())
            high_confidence = len(self.get_high_confidence_facts())
            
            avg_confidence = sum(f.confidence for f in self.fused_knowledge.values()) / total_facts if total_facts > 0 else 0
            
            return {
                "total_sources": len(self.sources),
                "total_facts": total_facts,
                "conflicted_facts": conflicted,
                "high_confidence_facts": high_confidence,
                "average_confidence": avg_confidence
            }
    
    
    def demonstrate_knowledge_fusion():
        """Demonstrate knowledge fusion from multiple sources"""
        print("=" * 80)
        print("Pattern 126: Knowledge Fusion")
        print("=" * 80)
        
        agent = KnowledgeFusionAgent()
        
        # Example 1: Add multiple knowledge sources
        print("\n" + "=" * 80)
        print("EXAMPLE 1: Adding Knowledge Sources")
        print("=" * 80)
        
        # Source 1: Wikipedia (high reliability)
        wikipedia = KnowledgeSource(
            source_id="wikipedia",
            name="Wikipedia",
            reliability=0.85,
            data={
                "eiffel_tower_height": "330 meters",
                "eiffel_tower_built": "1889",
                "eiffel_tower_location": "Paris, France",
                "mount_everest_height": "8,849 meters",
                "python_creator": "Guido van Rossum"
            }
        )
        
        # Source 2: Tourist website (medium reliability)
        tourist_site = KnowledgeSource(
            source_id="tourist_site",
            name="Tourism Website",
            reliability=0.65,
            data={
                "eiffel_tower_height": "324 meters",  # Conflict!
                "eiffel_tower_built": "1889",
                "eiffel_tower_location": "Paris, France",
                "eiffel_tower_visitors": "7 million per year"
            }
        )
        
        # Source 3: News article (medium reliability)
        news = KnowledgeSource(
            source_id="news",
            name="News Article",
            reliability=0.70,
            data={
                "eiffel_tower_height": "330 meters including antenna",  # Conflict!
                "mount_everest_height": "8,848.86 meters",  # Conflict!
                "python_creator": "Guido van Rossum",
                "python_first_release": "1991"
            }
        )
        
        agent.add_source(wikipedia)
        agent.add_source(tourist_site)
        agent.add_source(news)
        
        # Example 2: Fuse knowledge
        print("\n" + "=" * 80)
        print("EXAMPLE 2: Fusing Knowledge")
        print("=" * 80)
        
        fused = agent.fuse_knowledge()
        
        # Example 3: Query fused knowledge
        print("\n" + "=" * 80)
        print("EXAMPLE 3: Querying Fused Knowledge")
        print("=" * 80)
        
        queries = [
            "eiffel_tower_height",
            "eiffel_tower_location",
            "python_creator",
            "mount_everest_height"
        ]
        
        for query in queries:
            result = agent.query(query)
            if result:
                print(f"\nšŸ” Query: {query}")
                print(f"   Value: {result.value}")
                print(f"   Confidence: {result.confidence:.2f}")
                print(f"   Sources: {', '.join(result.sources)}")
                if result.conflicts:
                    print(f"   āš ļø  Had conflicts from {len(result.conflicts)} sources")
        
        # Example 4: High confidence facts
        print("\n" + "=" * 80)
        print("EXAMPLE 4: High Confidence Facts")
        print("=" * 80)
        
        high_conf = agent.get_high_confidence_facts(threshold=0.75)
        print(f"\nāœ“ Found {len(high_conf)} high-confidence facts (>0.75):\n")
        for fact in high_conf:
            print(f"  - {fact.key}: {fact.value} (confidence: {fact.confidence:.2f})")
        
        # Example 5: Conflicted facts
        print("\n" + "=" * 80)
        print("EXAMPLE 5: Facts with Conflicts")
        print("=" * 80)
        
        conflicted = agent.get_conflicted_facts()
        print(f"\nāš ļø  Found {len(conflicted)} facts with conflicts:\n")
        for fact in conflicted:
            print(f"  - {fact.key}:")
            print(f"      Resolved to: {fact.value}")
            print(f"      Original values:")
            for conflict in fact.conflicts:
                print(f"        • {conflict['source']}: {conflict['value']}")
        
        # Example 6: Statistics
        print("\n" + "=" * 80)
        print("EXAMPLE 6: Fusion Statistics")
        print("=" * 80)
        
        stats = agent.get_statistics()
        print(f"\nšŸ“Š Statistics:")
        print(f"  Total Sources: {stats['total_sources']}")
        print(f"  Total Facts: {stats['total_facts']}")
        print(f"  Conflicted Facts: {stats['conflicted_facts']}")
        print(f"  High Confidence Facts: {stats['high_confidence_facts']}")
        print(f"  Average Confidence: {stats['average_confidence']:.2f}")
        
        # Summary
        print("\n" + "=" * 80)
        print("SUMMARY")
        print("=" * 80)
        print("""
    Knowledge Fusion Pattern:
    - Integrates knowledge from multiple heterogeneous sources
    - Detects and resolves conflicting information
    - Uses source reliability scores for weighting
    - Creates unified, consistent knowledge representation
    - Maintains provenance and conflict information
    
    Conflict Resolution Strategies:
    āœ“ Voting (majority wins)
    āœ“ Weighted by source reliability
    āœ“ LLM-based synthesis
    āœ“ Temporal (newest information)
    āœ“ Consensus building
    
    Key Benefits:
    āœ“ Comprehensive knowledge coverage
    āœ“ Improved accuracy through verification
    āœ“ Conflict awareness and resolution
    āœ“ Source tracking and attribution
    āœ“ Confidence scoring
        """)
    
    
    if __name__ == "__main__":
        demonstrate_knowledge_fusion()
    
        

    Agentic Design Pattern: Knowledge Fusion

    Pattern 126: Knowledge Fusion – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the Knowledge Fusion pattern implementation.


    Pattern Description

    Pattern 126: Knowledge Fusion

    Description: Combines knowledge from multiple heterogeneous sources, resolving conflicts and creating a unified, consistent knowledge representation.

    Components: – Multi-source integration – Conflict detection and resolution – Consistency checking – Knowledge merging strategies

    Use Cases: – Multi-source data integration – Fact verification across sources – Building comprehensive knowledge bases

    LangChain Implementation: Uses LangChain for analyzing, comparing, and merging knowledge from multiple sources.


    File Statistics

    • Total Lines: 396
    • Classes: 3
    • Functions: 1
    • Constants: 0

    Module Documentation

    """
    Pattern 126: Knowledge Fusion
    
    Description:
        Combines knowledge from multiple heterogeneous sources, resolving conflicts
        and creating a unified, consistent knowledge representation.
    
    Components:
        - Multi-source integration
        - Conflict detection and resolution
        - Consistency checking
        - Knowledge merging strategies
    
    Use Cases:
        - Multi-source data integration
        - Fact verification across sources
        - Building comprehensive knowledge bases
    
    LangChain Implementation:
        Uses LangChain for analyzing, comparing, and merging knowledge from multiple sources.
    """
    

    Purpose: This module implements the Knowledge Fusion pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import collections.defaultdict
    import datetime.datetime
    import langchain_core.output_parsers.JsonOutputParser
    import langchain_core.prompts.ChatPromptTemplate
    import langchain_core.pydantic_v1.BaseModel
    import langchain_core.pydantic_v1.Field
    import os
    import typing.Any
    import typing.Dict
    import typing.List
    import typing.Optional
    import typing.Set
    

    Purpose: Core Python functionality: – collections.defaultdict: Specialized container datatypes – datetime.datetime: Date and time handling – langchain_core.output_parsers.JsonOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – langchain_core.pydantic_v1.BaseModel: Regular expression operations – langchain_core.pydantic_v1.Field: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Set: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Classes

    Class: KnowledgeSource

    Lines 37-42

    Inherits from: BaseModel

    Purpose:

    Represents a knowledge source
    

    Class: FusedKnowledge

    Lines 45-51

    Inherits from: BaseModel

    Purpose:

    Fused knowledge item
    

    Class: KnowledgeFusionAgent

    Lines 54-240

    Purpose:

    Agent for fusing knowledge from multiple sources
    

    Methods:

    __init__(self, model, temperature)

    Lines 57-85

    Purpose: Initialize the class instance with required parameters.

    Parameters: – model: Language model instance – temperature: Sampling temperature (0-1)

    add_source(self, source)

    Lines 87-90

    Purpose:

    Add a knowledge source
    

    Parameters: – source: Source

    detect_conflicts(self, key, values)

    Lines 92-104

    Purpose:

    Check if there are conflicts for a key
    

    Parameters: – key: Key – values: Values

    Returns: bool

    simple_fusion(self, key, values)

    Lines 106-126

    Purpose:

    Simple fusion without conflicts (voting or consensus)
    

    Parameters: – key: Key – values: Values

    Returns: FusedKnowledge

    resolve_conflict(self, key, values)

    Lines 128-171

    Purpose:

    Resolve conflicting values using LLM
    

    Parameters: – key: Key – values: Values

    Returns: FusedKnowledge

    fuse_knowledge(self)

    Lines 173-206

    Purpose:

    Fuse knowledge from all sources
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D88A210>

    query(self, key)

    Lines 208-210

    Purpose:

    Query fused knowledge
    

    Parameters: – key: Key

    Returns: <ast.Subscript object at 0x000001A06D889D10>

    get_high_confidence_facts(self, threshold)

    Lines 212-217

    Purpose:

    Get facts with confidence above threshold
    

    Parameters: – threshold: Threshold

    Returns: <ast.Subscript object at 0x000001A06D64A710>

    get_conflicted_facts(self)

    Lines 219-224

    Purpose:

    Get facts that had conflicts
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D64BD10>

    get_statistics(self)

    Lines 226-240

    Purpose:

    Get fusion statistics
    

    Parameters:

    Returns: <ast.Subscript object at 0x000001A06D748190>


    Functions

    demonstrate_knowledge_fusion()

    Lines 243-391

    Purpose:

    Demonstrate knowledge fusion from multiple sources
    

    Key Concepts Summary

    Pattern Overview

    The Knowledge Fusion pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    āœ… Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    āŒ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • āœ… Use .env files for API keys
    • āœ… Never hardcode credentials
    • āœ… Validate environment variables on startup

    2. Error Handling

    • āœ… Graceful degradation on failures
    • āœ… Informative error messages
    • āœ… Logging for debugging

    3. Prompt Engineering

    • āœ… Clear, specific instructions
    • āœ… Structured output formats
    • āœ… Few-shot examples when beneficial

    4. Code Organization

    • āœ… Separation of concerns (class-based design)
    • āœ… Type hints for clarity
    • āœ… Docstrings for documentation

    5. Performance Optimization

    • āœ… Appropriate temperature settings
    • āœ… Token budget management
    • āœ… Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    āŒ Vague or ambiguous instructions
    āœ… Clear, specific, testable prompts

    2. Error Handling

    āŒ Ignoring API errors or rate limits
    āœ… Implement retry logic and graceful degradation

    3. Token Management

    āŒ Exceeding model token limits
    āœ… Truncate inputs, chunk processing

    4. Security

    āŒ Exposing API keys in code
    āœ… Use environment variables

    5. Testing

    āŒ Only testing happy paths
    āœ… Test edge cases, failures, malformed inputs

    6. Cost Management

    āŒ Unmonitored API usage
    āœ… Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 125
    • Pattern 127

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The Knowledge Fusion pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    āœ… Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    šŸŽÆ Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    šŸ“š Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 126_knowledge_fusion.py
    Total Lines: 396
    Pattern Category: AI Agent Design Pattern #126


    Generated from actual implementation code
    For educational and reference purposes