Agentic Design Pattern: Few Shot Learning

Written by

in


    """
Pattern 083: Few-Shot Learning Pattern

Description:
    The Few-Shot Learning pattern uses example-based prompting to teach the LLM
    how to perform tasks through demonstrations. Instead of relying on zero-shot
    capabilities, this pattern provides the model with a few examples of input-output
    pairs that illustrate the desired behavior. This approach leverages the LLM's
    in-context learning abilities to generalize from examples.

    Few-shot learning is one of the most fundamental prompt engineering techniques
    and is particularly effective when:
    - The task format is non-standard or complex
    - Consistent output format is required
    - Specific style or tone needs to be maintained
    - Domain-specific knowledge needs to be demonstrated
    - Edge cases need to be handled in specific ways

Components:
    1. Example Selection
       - Static examples (fixed set)
       - Dynamic examples (selected based on similarity)
       - Diverse examples (covering different scenarios)
       - Representative examples (typical cases)

    2. Example Formatting
       - Clear input-output structure
       - Consistent formatting across examples
       - Annotations and explanations (when needed)
       - Order considerations (easy to hard, chronological)

    3. Example Storage
       - In-prompt storage (small example sets)
       - Vector database storage (large example sets)
       - Retrieval mechanisms (similarity-based)
       - Example caching strategies

    4. Generalization Strategy
       - Pattern recognition from examples
       - Analogical reasoning
       - Template extraction
       - Feature learning

Use Cases:
    1. Text Classification
       - Sentiment analysis with custom categories
       - Intent recognition for domain-specific applications
       - Content moderation with nuanced rules
       - Topic categorization with specific taxonomies

    2. Data Extraction
       - Structured information extraction from unstructured text
       - Entity recognition with custom entity types
       - Relationship extraction between entities
       - Attribute extraction with specific formats

    3. Code Generation
       - API usage examples for specific libraries
       - Code style consistency (following project conventions)
       - Design pattern implementation
       - Test case generation

    4. Creative Writing
       - Style mimicry (writing in specific author's style)
       - Format consistency (poems, stories, articles)
       - Tone control (formal, casual, humorous)
       - Genre-specific writing (sci-fi, mystery, romance)

    5. Translation and Transformation
       - Domain-specific translation (legal, medical, technical)
       - Format conversion (JSON to YAML, CSV to markdown)
       - Data normalization (various formats to standard)
       - Code refactoring patterns

LangChain Implementation:
    LangChain provides excellent support for few-shot learning through:
    - FewShotChatMessagePromptTemplate for chat models
    - FewShotPromptTemplate for completion models
    - Example selectors (semantic similarity, length-based, max marginal relevance)
    - Vector store-backed example selection
    - Custom example formatting

Key Features:
    1. Static Few-Shot Learning
       - Predefined set of examples
       - Fast and deterministic
       - Good for stable tasks
       - No retrieval overhead

    2. Dynamic Few-Shot Learning
       - Examples selected based on input similarity
       - More adaptive to diverse inputs
       - Requires vector database
       - Better generalization

    3. Example Quality Management
       - Diverse examples covering edge cases
       - Clear and unambiguous examples
       - Representative of target distribution
       - Regularly updated based on performance

    4. Performance Optimization
       - Token budget management (limiting example count)
       - Example compression (removing redundancy)
       - Caching frequently used example sets
       - Lazy loading for large example sets

Best Practices:
    1. Example Selection
       - Use 3-5 examples for most tasks (sweet spot)
       - Include diverse examples covering different patterns
       - Order examples from simple to complex
       - Ensure examples are correct and high-quality

    2. Example Formatting
       - Use consistent structure across all examples
       - Clearly separate input from output
       - Add brief explanations for complex cases
       - Use delimiters to avoid confusion

    3. Dynamic Selection
       - Use semantic similarity for input-dependent selection
       - Balance diversity and relevance in selection
       - Cache embeddings for better performance
       - Set appropriate k value (number of examples)

    4. Iteration and Improvement
       - Start with few examples, add more if needed
       - A/B test different example sets
       - Monitor performance across different inputs
       - Update examples based on failure cases

Trade-offs:
    Advantages:
    - Significantly improves task performance vs zero-shot
    - More reliable than instructions alone
    - Enables consistent output formatting
    - Works well for complex or ambiguous tasks
    - Reduces need for fine-tuning

    Disadvantages:
    - Increases token usage (more expensive)
    - May not scale to tasks requiring many examples
    - Examples can bias the model inappropriately
    - Requires careful example curation
    - Dynamic selection adds latency and complexity

Production Considerations:
    1. Token Budget Management
       - Monitor tokens used by examples
       - Balance example count with context window
       - Use example compression when possible
       - Consider model's context limit

    2. Example Maintenance
       - Version control for example sets
       - Regular review and updates
       - Performance tracking per example
       - A/B testing of example variations

    3. Scalability
       - Cache example embeddings
       - Use efficient vector stores
       - Batch process when possible
       - Consider example pruning strategies

    4. Quality Assurance
       - Validate examples are correct
       - Test examples independently
       - Monitor output quality metrics
       - Handle example selection failures gracefully

    5. Cost Optimization
       - Balance example count with quality
       - Use dynamic selection judiciously
       - Cache common example sets
       - Monitor cost per query
"""

import os
from typing import List, Dict, Any, Optional
from dataclasses import dataclass
from enum import Enum
from dotenv import load_dotenv

from langchain_core.prompts import (
    ChatPromptTemplate,
    FewShotChatMessagePromptTemplate,
    PromptTemplate
)
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.example_selectors import (
    SemanticSimilarityExampleSelector,
    MaxMarginalRelevanceExampleSelector
)
from langchain_chroma import Chroma

load_dotenv()


class ExampleSelectionStrategy(Enum):
    """Strategy for selecting examples"""
    STATIC = "static"  # Fixed set of examples
    SEMANTIC_SIMILARITY = "semantic_similarity"  # Based on input similarity
    MAX_MARGINAL_RELEVANCE = "max_marginal_relevance"  # Diverse + relevant


@dataclass
class FewShotExample:
    """Represents a single few-shot example"""
    input: str
    output: str
    explanation: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None


@dataclass
class FewShotConfig:
    """Configuration for few-shot learning"""
    num_examples: int = 3
    selection_strategy: ExampleSelectionStrategy = ExampleSelectionStrategy.STATIC
    temperature: float = 0.3
    model_name: str = "gpt-3.5-turbo"
    include_explanations: bool = False


class FewShotLearningAgent:
    """
    Agent that uses few-shot learning to teach LLM through examples.
    
    This agent demonstrates various few-shot learning approaches:
    1. Static few-shot (fixed examples)
    2. Dynamic few-shot (similarity-based selection)
    3. Task-specific few-shot applications
    """
    
    def __init__(self, config: Optional[FewShotConfig] = None):
        """
        Initialize few-shot learning agent.
        
        Args:
            config: Configuration for few-shot learning
        """
        self.config = config or FewShotConfig()
        self.llm = ChatOpenAI(
            model=self.config.model_name,
            temperature=self.config.temperature
        )
        self.embeddings = OpenAIEmbeddings()
    
    def create_static_few_shot_chain(
        self,
        examples: List[FewShotExample],
        task_instruction: str,
        input_variable: str = "input"
    ):
        """
        Create a chain with static few-shot examples.
        
        Args:
            examples: List of few-shot examples
            task_instruction: Instruction for the task
            input_variable: Name of input variable
            
        Returns:
            Runnable chain with few-shot prompting
        """
        # Format examples as dictionaries
        example_dicts = [
            {"input": ex.input, "output": ex.output}
            for ex in examples
        ]
        
        # Create example prompt template
        example_prompt = ChatPromptTemplate.from_messages([
            ("human", "{input}"),
            ("ai", "{output}")
        ])
        
        # Create few-shot prompt
        few_shot_prompt = FewShotChatMessagePromptTemplate(
            example_prompt=example_prompt,
            examples=example_dicts
        )
        
        # Create final prompt
        final_prompt = ChatPromptTemplate.from_messages([
            ("system", task_instruction),
            few_shot_prompt,
            ("human", "{" + input_variable + "}")
        ])
        
        # Create chain
        chain = final_prompt | self.llm | StrOutputParser()
        
        return chain
    
    def create_dynamic_few_shot_chain(
        self,
        examples: List[FewShotExample],
        task_instruction: str,
        input_variable: str = "input",
        k: int = 3
    ):
        """
        Create a chain with dynamic example selection based on similarity.
        
        Args:
            examples: Pool of examples to select from
            task_instruction: Instruction for the task
            input_variable: Name of input variable
            k: Number of examples to select
            
        Returns:
            Runnable chain with dynamic few-shot prompting
        """
        # Format examples as dictionaries
        example_dicts = [
            {"input": ex.input, "output": ex.output}
            for ex in examples
        ]
        
        # Create example selector using semantic similarity
        example_selector = SemanticSimilarityExampleSelector.from_examples(
            example_dicts,
            self.embeddings,
            Chroma,
            k=k,
            input_keys=["input"]
        )
        
        # Create example prompt template
        example_prompt = ChatPromptTemplate.from_messages([
            ("human", "{input}"),
            ("ai", "{output}")
        ])
        
        # Create few-shot prompt with selector
        few_shot_prompt = FewShotChatMessagePromptTemplate(
            example_prompt=example_prompt,
            example_selector=example_selector,
            input_variables=[input_variable]
        )
        
        # Create final prompt
        final_prompt = ChatPromptTemplate.from_messages([
            ("system", task_instruction),
            few_shot_prompt,
            ("human", "{" + input_variable + "}")
        ])
        
        # Create chain
        chain = final_prompt | self.llm | StrOutputParser()
        
        return chain
    
    def sentiment_analysis_few_shot(
        self,
        text: str,
        examples: Optional[List[FewShotExample]] = None,
        use_dynamic: bool = False
    ) -> str:
        """
        Perform sentiment analysis using few-shot learning.
        
        Args:
            text: Text to analyze
            examples: Optional custom examples
            use_dynamic: Whether to use dynamic selection
            
        Returns:
            Sentiment classification
        """
        # Default examples if none provided
        if examples is None:
            examples = [
                FewShotExample(
                    input="This movie was absolutely fantastic! I loved every minute.",
                    output="Positive"
                ),
                FewShotExample(
                    input="The product broke after one day. Terrible quality.",
                    output="Negative"
                ),
                FewShotExample(
                    input="It's okay, nothing special but not bad either.",
                    output="Neutral"
                ),
                FewShotExample(
                    input="I'm thrilled with this purchase! Exceeded expectations.",
                    output="Positive"
                ),
                FewShotExample(
                    input="Complete waste of money. Very disappointed.",
                    output="Negative"
                )
            ]
        
        task_instruction = """You are a sentiment analyzer. Classify the sentiment of the given text as Positive, Negative, or Neutral.
Look at the examples to understand the task."""
        
        # Create chain based on selection strategy
        if use_dynamic:
            chain = self.create_dynamic_few_shot_chain(
                examples,
                task_instruction,
                k=3
            )
        else:
            # Use first 3 examples for static
            chain = self.create_static_few_shot_chain(
                examples[:3],
                task_instruction
            )
        
        result = chain.invoke({"input": text})
        return result
    
    def entity_extraction_few_shot(
        self,
        text: str,
        examples: Optional[List[FewShotExample]] = None
    ) -> str:
        """
        Extract entities using few-shot learning.
        
        Args:
            text: Text to extract entities from
            examples: Optional custom examples
            
        Returns:
            Extracted entities in JSON format
        """
        # Default examples
        if examples is None:
            examples = [
                FewShotExample(
                    input="Apple Inc. announced a new iPhone model in Cupertino on September 12th.",
                    output='{"organization": "Apple Inc.", "product": "iPhone", "location": "Cupertino", "date": "September 12th"}'
                ),
                FewShotExample(
                    input="Elon Musk tweeted about Tesla's production numbers from the Fremont factory.",
                    output='{"person": "Elon Musk", "organization": "Tesla", "location": "Fremont factory"}'
                ),
                FewShotExample(
                    input="The meeting at Microsoft headquarters in Seattle was attended by Satya Nadella.",
                    output='{"organization": "Microsoft", "location": "Seattle", "person": "Satya Nadella"}'
                )
            ]
        
        task_instruction = """Extract entities from the text and format them as JSON.
Include: person, organization, location, date, product (if present).
Follow the format shown in the examples."""
        
        chain = self.create_static_few_shot_chain(
            examples,
            task_instruction
        )
        
        result = chain.invoke({"input": text})
        return result
    
    def code_generation_few_shot(
        self,
        description: str,
        examples: Optional[List[FewShotExample]] = None
    ) -> str:
        """
        Generate code using few-shot learning.
        
        Args:
            description: Description of desired code
            examples: Optional custom examples
            
        Returns:
            Generated code
        """
        # Default examples
        if examples is None:
            examples = [
                FewShotExample(
                    input="Create a function that returns the sum of two numbers",
                    output="""def add_numbers(a, b):
    \"\"\"Return the sum of two numbers.\"\"\"
    return a + b"""
                ),
                FewShotExample(
                    input="Create a function that checks if a string is a palindrome",
                    output="""def is_palindrome(s):
    \"\"\"Check if a string is a palindrome.\"\"\"
    return s == s[::-1]"""
                ),
                FewShotExample(
                    input="Create a function that finds the maximum value in a list",
                    output="""def find_max(lst):
    \"\"\"Find the maximum value in a list.\"\"\"
    if not lst:
        return None
    return max(lst)"""
                )
            ]
        
        task_instruction = """Generate Python code based on the description.
Follow the style and format shown in the examples.
Include docstrings and proper formatting."""
        
        chain = self.create_static_few_shot_chain(
            examples,
            task_instruction,
            input_variable="input"
        )
        
        result = chain.invoke({"input": description})
        return result
    
    def style_transfer_few_shot(
        self,
        text: str,
        target_style: str,
        examples: Optional[List[FewShotExample]] = None
    ) -> str:
        """
        Transfer text to a specific style using few-shot learning.
        
        Args:
            text: Text to transform
            target_style: Target style (e.g., "formal", "casual", "poetic")
            examples: Optional custom examples
            
        Returns:
            Transformed text
        """
        # Style-specific examples
        style_examples = {
            "formal": [
                FewShotExample(
                    input="Hey, can you help me out with this?",
                    output="I would appreciate your assistance with this matter."
                ),
                FewShotExample(
                    input="That's totally wrong!",
                    output="I respectfully disagree with that assessment."
                ),
                FewShotExample(
                    input="Thanks a lot for everything!",
                    output="I extend my sincere gratitude for your comprehensive support."
                )
            ],
            "casual": [
                FewShotExample(
                    input="I would like to request your assistance.",
                    output="Hey, could you help me out?"
                ),
                FewShotExample(
                    input="This is highly problematic.",
                    output="This is a real problem."
                ),
                FewShotExample(
                    input="I appreciate your effort.",
                    output="Thanks for trying!"
                )
            ],
            "poetic": [
                FewShotExample(
                    input="The sun set over the mountains.",
                    output="Golden rays bid farewell, as peaks embrace the fading light."
                ),
                FewShotExample(
                    input="Rain started falling.",
                    output="Heaven's tears descended, kissing the earth below."
                ),
                FewShotExample(
                    input="The bird flew away.",
                    output="On wings of freedom, it soared beyond the horizon's edge."
                )
            ]
        }
        
        examples = examples or style_examples.get(target_style.lower(), [])
        
        if not examples:
            return "Style not supported. Available: formal, casual, poetic"
        
        task_instruction = f"""Transform the text into {target_style} style.
Follow the transformation pattern shown in the examples."""
        
        chain = self.create_static_few_shot_chain(
            examples,
            task_instruction
        )
        
        result = chain.invoke({"input": text})
        return result
    
    def compare_zero_shot_vs_few_shot(
        self,
        text: str,
        task: str = "sentiment"
    ) -> Dict[str, str]:
        """
        Compare zero-shot vs few-shot performance.
        
        Args:
            text: Input text
            task: Task to perform
            
        Returns:
            Dictionary with both results
        """
        # Zero-shot prompt
        zero_shot_prompt = ChatPromptTemplate.from_messages([
            ("system", "Classify the sentiment as Positive, Negative, or Neutral."),
            ("human", "{input}")
        ])
        zero_shot_chain = zero_shot_prompt | self.llm | StrOutputParser()
        zero_shot_result = zero_shot_chain.invoke({"input": text})
        
        # Few-shot result
        few_shot_result = self.sentiment_analysis_few_shot(text)
        
        return {
            "zero_shot": zero_shot_result,
            "few_shot": few_shot_result
        }


def demonstrate_few_shot_learning():
    """Demonstrate few-shot learning patterns"""
    print("=" * 80)
    print("FEW-SHOT LEARNING PATTERN DEMONSTRATION")
    print("=" * 80)
    
    agent = FewShotLearningAgent()
    
    # Example 1: Sentiment Analysis
    print("\n" + "=" * 80)
    print("EXAMPLE 1: Sentiment Analysis with Few-Shot Learning")
    print("=" * 80)
    
    test_texts = [
        "This restaurant exceeded all my expectations! Amazing food!",
        "The service was slow and the food was cold. Not going back.",
        "It was fine. Nothing special but acceptable."
    ]
    
    for text in test_texts:
        print(f"\nText: {text}")
        sentiment = agent.sentiment_analysis_few_shot(text)
        print(f"Sentiment: {sentiment}")
    
    # Example 2: Entity Extraction
    print("\n" + "=" * 80)
    print("EXAMPLE 2: Entity Extraction with Few-Shot Learning")
    print("=" * 80)
    
    test_text = "Jeff Bezos announced Amazon's expansion into the healthcare sector at a conference in Las Vegas last Monday."
    print(f"\nText: {test_text}")
    entities = agent.entity_extraction_few_shot(test_text)
    print(f"Entities: {entities}")
    
    # Example 3: Code Generation
    print("\n" + "=" * 80)
    print("EXAMPLE 3: Code Generation with Few-Shot Learning")
    print("=" * 80)
    
    code_requests = [
        "Create a function that calculates factorial of a number",
        "Create a function that reverses a string"
    ]
    
    for request in code_requests:
        print(f"\nRequest: {request}")
        code = agent.code_generation_few_shot(request)
        print(f"Generated Code:\n{code}")
    
    # Example 4: Style Transfer
    print("\n" + "=" * 80)
    print("EXAMPLE 4: Style Transfer with Few-Shot Learning")
    print("=" * 80)
    
    original_text = "I need your help with this problem."
    styles = ["formal", "casual", "poetic"]
    
    print(f"\nOriginal: {original_text}")
    for style in styles:
        transformed = agent.style_transfer_few_shot(original_text, style)
        print(f"{style.title()} style: {transformed}")
    
    # Example 5: Zero-Shot vs Few-Shot Comparison
    print("\n" + "=" * 80)
    print("EXAMPLE 5: Zero-Shot vs Few-Shot Comparison")
    print("=" * 80)
    
    ambiguous_text = "The movie was interesting and thought-provoking, though quite challenging to follow."
    print(f"\nAmbiguous Text: {ambiguous_text}")
    
    comparison = agent.compare_zero_shot_vs_few_shot(ambiguous_text)
    print(f"\nZero-Shot Result: {comparison['zero_shot']}")
    print(f"Few-Shot Result: {comparison['few_shot']}")
    print("\nNote: Few-shot learning often provides more consistent and format-compliant outputs")
    
    # Example 6: Dynamic Example Selection
    print("\n" + "=" * 80)
    print("EXAMPLE 6: Dynamic Example Selection (Similarity-Based)")
    print("=" * 80)
    
    test_text = "I'm so excited about this purchase! Best decision ever!"
    print(f"\nText: {test_text}")
    print("\nStatic Selection:")
    static_result = agent.sentiment_analysis_few_shot(test_text, use_dynamic=False)
    print(f"Result: {static_result}")
    
    print("\nDynamic Selection (picks most similar examples):")
    dynamic_result = agent.sentiment_analysis_few_shot(test_text, use_dynamic=True)
    print(f"Result: {dynamic_result}")
    
    # Summary
    print("\n" + "=" * 80)
    print("FEW-SHOT LEARNING SUMMARY")
    print("=" * 80)
    print("""
Few-Shot Learning Pattern Benefits:
1. Improved Accuracy: Examples guide the model to better performance
2. Consistency: Output format matches examples consistently
3. Task Clarity: Examples disambiguate task requirements
4. Style Control: Examples demonstrate desired tone and style
5. No Fine-Tuning: Achieves good results without model retraining

Key Techniques Demonstrated:
1. Static Few-Shot: Fixed examples for consistent tasks
2. Dynamic Few-Shot: Similarity-based example selection
3. Task-Specific Examples: Domain-appropriate demonstrations
4. Style Transfer: Teaching specific writing styles
5. Format Control: Ensuring structured outputs

Best Practices:
1. Use 3-5 examples for most tasks (sweet spot)
2. Ensure examples are diverse and representative
3. Order examples from simple to complex
4. Include edge cases in examples
5. Keep examples concise to save tokens
6. Use dynamic selection for varied inputs
7. Validate examples are correct and high-quality
8. Monitor token usage and costs

When to Use Few-Shot vs Zero-Shot:
- Use few-shot when: output format is specific, task is ambiguous, consistency matters
- Use zero-shot when: task is simple, tokens are limited, speed is critical
- Use dynamic selection when: inputs are diverse, quality is paramount

Production Considerations:
- Cache example embeddings for performance
- Monitor token usage (examples increase costs)
- A/B test different example sets
- Version control example datasets
- Update examples based on failure cases
- Balance example count with quality needs
""")
    
    print("\n" + "=" * 80)
    print("Pattern 083 (Few-Shot Learning) demonstration complete!")
    print("=" * 80)


if __name__ == "__main__":
    demonstrate_few_shot_learning()

    

Agentic Design Pattern: Few Shot Learning

Pattern 083: Few Shot Learning – Line-by-Line Explanation

Overview

This document provides a detailed line-by-line explanation of the Few Shot Learning pattern implementation.


Pattern Description

Pattern 083: Few-Shot Learning Pattern

Description: The Few-Shot Learning pattern uses example-based prompting to teach the LLM how to perform tasks through demonstrations. Instead of relying on zero-shot capabilities, this pattern provides the model with a few examples of input-output pairs that illustrate the desired behavior. This approach leverages the LLM’s in-context learning abilities to generalize from examples.

Few-shot learning is one of the most fundamental prompt engineering techniques
and is particularly effective when:
- The task format is non-standard or complex
- Consistent output format is required
- Specific style or tone needs to be maintained
- Domain-specific knowledge needs to be demonstrated
- Edge cases need to be handled in specific ways

Components: 1. Example Selection – Static examples (fixed set) – Dynamic examples (selected based on similarity) – Diverse examples (covering different scenarios) – Representative examples (typical cases)

2. Example Formatting
   - Clear input-output structure
   - Consistent formatting across examples
   - Annotations and explanations (when needed)
   - Order considerations (easy to hard, chronological)

3. Example Storage
   - In-prompt storage (small example sets)
   - Vector database storage (large example sets)
   - Retrieval mechanisms (similarity-based)
   - Example caching strategies

4. Generalization Strategy
   - Pattern recognition from examples
   - Analogical reasoning
   - Template extraction
   - Feature learning

Use Cases: 1. Text Classification – Sentiment analysis with custom categories – Intent recognition for domain-specific applications – Content moderation with nuanced rules – Topic categorization with specific taxonomies

2. Data Extraction
   - Structured information extraction from unstructured text
   - Entity recognition with custom entity types
   - Relationship extraction between entities
   - Attribute extraction with specific formats

3. Code Generation
   - API usage examples for specific libraries
   - Code style consistency (following project conventions)
   - Design pattern implementation
   - Test case generation

4. Creative Writing
   - Style mimicry (writing in specific author's style)
   - Format consistency (poems, stories, articles)
   - Tone control (formal, casual, humorous)
   - Genre-specific writing (sci-fi, mystery, romance)

5. Translation and Transformation
   - Domain-specific translation (legal, medical, technical)
   - Format conversion (JSON to YAML, CSV to markdown)
   - Data normalization (various formats to standard)
   - Code refactoring patterns

LangChain Implementation: LangChain provides excellent support for few-shot learning through: – FewShotChatMessagePromptTemplate for chat models – FewShotPromptTemplate for completion models – Example selectors (semantic similarity, length-based, max marginal relevance) – Vector store-backed example selection – Custom example formatting

Key Features: 1. Static Few-Shot Learning – Predefined set of examples – Fast and deterministic – Good for stable tasks – No retrieval overhead

2. Dynamic Few-Shot Learning
   - Examples selected based on input similarity
   - More adaptive to diverse inputs
   - Requires vector database
   - Better generalization

3. Example Quality Management
   - Diverse examples covering edge cases
   - Clear and unambiguous examples
   - Representative of target distribution
   - Regularly updated based on performance

4. Performance Optimization
   - Token budget management (limiting example count)
   - Example compression (removing redundancy)
   - Caching frequently used example sets
   - Lazy loading for large example sets

Best Practices: 1. Example Selection – Use 3-5 examples for most tasks (sweet spot) – Include diverse examples covering different patterns – Order examples from simple to complex – Ensure examples are correct and high-quality

2. Example Formatting
   - Use consistent structure across all examples
   - Clearly separate input from output
   - Add brief explanations for complex cases
   - Use delimiters to avoid confusion

3. Dynamic Selection
   - Use semantic similarity for input-dependent selection
   - Balance diversity and relevance in selection
   - Cache embeddings for better performance
   - Set appropriate k value (number of examples)

4. Iteration and Improvement
   - Start with few examples, add more if needed
   - A/B test different example sets
   - Monitor performance across different inputs
   - Update examples based on failure cases

Trade-offs: Advantages: – Significantly improves task performance vs zero-shot – More reliable than instructions alone – Enables consistent output formatting – Works well for complex or ambiguous tasks – Reduces need for fine-tuning

Disadvantages:
- Increases token usage (more expensive)
- May not scale to tasks requiring many examples
- Examples can bias the model inappropriately
- Requires careful example curation
- Dynamic selection adds latency and complexity

Production Considerations: 1. Token Budget Management – Monitor tokens used by examples – Balance example count with context window – Use example compression when possible – Consider model’s context limit

2. Example Maintenance
   - Version control for example sets
   - Regular review and updates
   - Performance tracking per example
   - A/B testing of example variations

3. Scalability
   - Cache example embeddings
   - Use efficient vector stores
   - Batch process when possible
   - Consider example pruning strategies

4. Quality Assurance
   - Validate examples are correct
   - Test examples independently
   - Monitor output quality metrics
   - Handle example selection failures gracefully

5. Cost Optimization
   - Balance example count with quality
   - Use dynamic selection judiciously
   - Cache common example sets
   - Monitor cost per query

File Statistics

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

Module Documentation

"""
Pattern 083: Few-Shot Learning Pattern

Description:
    The Few-Shot Learning pattern uses example-based prompting to teach the LLM
    how to perform tasks through demonstrations. Instead of relying on zero-shot
    capabilities, this pattern provides the model with a few examples of input-output
    pairs that illustrate the desired behavior. This approach leverages the LLM's
    in-context learning abilities to generalize from examples.

    Few-shot learning is one of the most fundamental prompt engineering techniques
    and is particularly effective when:
    - The task format is non-standard or complex
    - Consistent output format is required
    - Specific style or tone needs to be maintained
    - Domain-specific knowledge needs to be demonstrated
    - Edge cases need to be handled in specific ways

Components:
    1. Example Selection
       - Static examples (fixed set)
       - Dynamic examples (selected based on similarity)
       - Diverse examples (covering different scenarios)
       - Representative examples (typical cases)

    2. Example Formatting
       - Clear input-output structure
       - Consistent formatting across examples
       - Annotations and explanations (when needed)
       - Order considerations (easy to hard, chronological)

    3. Example Storage
       - In-prompt storage (small example sets)
       - Vector database storage (large example sets)
       - Retrieval mechanisms (similarity-based)
       - Example caching strategies

    4. Generalization Strategy
       - Pattern recognition from examples
       - Analogical reasoning
       - Template extraction
       - Feature learning

Use Cases:
    1. Text Classification
       - Sentiment analysis with custom categories
       - Intent recognition for domain-specific applications
       - Content moderation with nuanced rules
       - Topic categorization with specific taxonomies

    2. Data Extraction
       - Structured information extraction from unstructured text
       - Entity recognition with custom entity types
       - Relationship extraction between entities
       - Attribute extraction with specific formats

    3. Code Generation
       - API usage examples for specific libraries
       - Code style consistency (following project conventions)
       - Design pattern implementation
       - Test case generation

    4. Creative Writing
       - Style mimicry (writing in specific author's style)
       - Format consistency (poems, stories, articles)
       - Tone control (formal, casual, humorous)
       - Genre-specific writing (sci-fi, mystery, romance)

    5. Translation and Transformation
       - Domain-specific translation (legal, medical, technical)
       - Format conversion (JSON to YAML, CSV to markdown)
       - Data normalization (various formats to standard)
       - Code refactoring patterns

LangChain Implementation:
    LangChain provides excellent support for few-shot learning through:
    - FewShotChatMessagePromptTemplate for chat models
    - FewShotPromptTemplate for completion models
    - Example selectors (semantic similarity, length-based, max marginal relevance)
    - Vector store-backed example selection
    - Custom example formatting

Key Features:
    1. Static Few-Shot Learning
       - Predefined set of examples
       - Fast and deterministic
       - Good for stable tasks
       - No retrieval overhead

    2. Dynamic Few-Shot Learning
       - Examples selected based on input similarity
       - More adaptive to diverse inputs
       - Requires vector database
       - Better generalization

    3. Example Quality Management
       - Diverse examples covering edge cases
       - Clear and unambiguous examples
       - Representative of target distribution
       - Regularly updated based on performance

    4. Performance Optimization
       - Token budget management (limiting example count)
       - Example compression (removing redundancy)
       - Caching frequently used example sets
       - Lazy loading for large example sets

Best Practices:
    1. Example Selection
       - Use 3-5 examples for most tasks (sweet spot)
       - Include diverse examples covering different patterns
       - Order examples from simple to complex
       - Ensure examples are correct and high-quality

    2. Example Formatting
       - Use consistent structure across all examples
       - Clearly separate input from output
       - Add brief explanations for complex cases
       - Use delimiters to avoid confusion

    3. Dynamic Selection
       - Use semantic similarity for input-dependent selection
       - Balance diversity and relevance in selection
       - Cache embeddings for better performance
       - Set appropriate k value (number of examples)

    4. Iteration and Improvement
       - Start with few examples, add more if needed
       - A/B test different example sets
       - Monitor performance across different inputs
       - Update examples based on failure cases

Trade-offs:
    Advantages:
    - Significantly improves task performance vs zero-shot
    - More reliable than instructions alone
    - Enables consistent output formatting
    - Works well for complex or ambiguous tasks
    - Reduces need for fine-tuning

    Disadvantages:
    - Increases token usage (more expensive)
    - May not scale to tasks requiring many examples
    - Examples can bias the model inappropriately
    - Requires careful example curation
    - Dynamic selection adds latency and complexity

Production Considerations:
    1. Token Budget Management
       - Monitor tokens used by examples
       - Balance example count with context window
       - Use example compression when possible
       - Consider model's context limit

    2. Example Maintenance
       - Version control for example sets
       - Regular review and updates
       - Performance tracking per example
       - A/B testing of example variations

    3. Scalability
       - Cache example embeddings
       - Use efficient vector stores
       - Batch process when possible
       - Consider example pruning strategies

    4. Quality Assurance
       - Validate examples are correct
       - Test examples independently
       - Monitor output quality metrics
       - Handle example selection failures gracefully

    5. Cost Optimization
       - Balance example count with quality
       - Use dynamic selection judiciously
       - Cache common example sets
       - Monitor cost per query
"""

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


Import Statements

Standard Library Imports

import dataclasses.dataclass
import enum.Enum
import langchain_core.example_selectors.MaxMarginalRelevanceExampleSelector
import langchain_core.example_selectors.SemanticSimilarityExampleSelector
import langchain_core.output_parsers.StrOutputParser
import langchain_core.prompts.ChatPromptTemplate
import langchain_core.prompts.FewShotChatMessagePromptTemplate
import langchain_core.prompts.PromptTemplate
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 – enum.Enum: Enumeration support – langchain_core.example_selectors.MaxMarginalRelevanceExampleSelector: Regular expression operations – langchain_core.example_selectors.SemanticSimilarityExampleSelector: Regular expression operations – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – langchain_core.prompts.FewShotChatMessagePromptTemplate: Regular expression operations – langchain_core.prompts.PromptTemplate: 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_chroma.Chroma
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: ExampleSelectionStrategy

Lines 202-206

Inherits from: Enum

Purpose:

Strategy for selecting examples

Class: FewShotExample

Lines 210-215

Purpose:

Represents a single few-shot example

Class: FewShotConfig

Lines 219-225

Purpose:

Configuration for few-shot learning

Class: FewShotLearningAgent

Lines 228-625

Purpose:

Agent that uses few-shot learning to teach LLM through examples.

This agent demonstrates various few-shot learning approaches:
1. Static few-shot (fixed examples)
2. Dynamic few-shot (similarity-based selection)
3. Task-specific few-shot applications

Methods:

__init__(self, config)

Lines 238-250

Purpose:

Initialize few-shot learning agent.

Args:
    config: Configuration for few-shot learning

Parameters: – config: Config

create_static_few_shot_chain(self, examples, task_instruction, input_variable)

Lines 252-297

Purpose:

Create a chain with static few-shot examples.

Args:
    examples: List of few-shot examples
    task_instruction: Instruction for the task
    input_variable: Name of input variable

Returns:
    Runnable chain with few-shot prompting

Parameters: – examples: Examples – task_instruction: Task instruction – input_variable: Input data

create_dynamic_few_shot_chain(self, examples, task_instruction, input_variable, k)

Lines 299-356

Purpose:

Create a chain with dynamic example selection based on similarity.

Args:
    examples: Pool of examples to select from
    task_instruction: Instruction for the task
    input_variable: Name of input variable
    k: Number of examples to select

Returns:
    Runnable chain with dynamic few-shot prompting

Parameters: – examples: Examples – task_instruction: Task instruction – input_variable: Input data – k: K

sentiment_analysis_few_shot(self, text, examples, use_dynamic)

Lines 358-418

Purpose:

Perform sentiment analysis using few-shot learning.

Args:
    text: Text to analyze
    examples: Optional custom examples
    use_dynamic: Whether to use dynamic selection

Returns:
    Sentiment classification

Parameters: – text: Text – examples: Examples – use_dynamic: Use dynamic

Returns: str

entity_extraction_few_shot(self, text, examples)

Lines 420-462

Purpose:

Extract entities using few-shot learning.

Args:
    text: Text to extract entities from
    examples: Optional custom examples

Returns:
    Extracted entities in JSON format

Parameters: – text: Text – examples: Examples

Returns: str

code_generation_few_shot(self, description, examples)

Lines 464-515

Purpose:

Generate code using few-shot learning.

Args:
    description: Description of desired code
    examples: Optional custom examples

Returns:
    Generated code

Parameters: – description: Description – examples: Examples

Returns: str

style_transfer_few_shot(self, text, target_style, examples)

Lines 517-594

Purpose:

Transfer text to a specific style using few-shot learning.

Args:
    text: Text to transform
    target_style: Target style (e.g., "formal", "casual", "poetic")
    examples: Optional custom examples

Returns:
    Transformed text

Parameters: – text: Text – target_style: Target style – examples: Examples

Returns: str

compare_zero_shot_vs_few_shot(self, text, task)

Lines 596-625

Purpose:

Compare zero-shot vs few-shot performance.

Args:
    text: Input text
    task: Task to perform

Returns:
    Dictionary with both results

Parameters: – text: Text – task: Task

Returns: <ast.Subscript object at 0x000001A06D853AD0>


Functions

demonstrate_few_shot_learning()

Lines 628-763

Purpose:

Demonstrate few-shot learning patterns

Key Concepts Summary

Pattern Overview

The Few Shot Learning 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 082
  • Pattern 084

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 Few Shot Learning 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: 083_few_shot_learning.py
Total Lines: 768
Pattern Category: AI Agent Design Pattern #083


Generated from actual implementation code
For educational and reference purposes

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *