Agentic Architecture Pattern: Few Shot Learning

Written by

in


    """
Pattern 192: Few-Shot Learning Pattern

LLM learns to perform tasks from a small number of examples provided in the prompt.
Demonstrates in-context learning where the model adapts based on examples.
"""

from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from langchain_core.prompts import ChatPromptTemplate, FewShotPromptTemplate, PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI


class ExampleFormat(Enum):
    """Format for few-shot examples."""
    QA_PAIRS = "qa_pairs"  # Question-Answer format
    INPUT_OUTPUT = "input_output"  # Input-Output format
    DEMONSTRATION = "demonstration"  # Step-by-step demonstration
    LABELED = "labeled"  # Labeled examples with categories


@dataclass
class Example:
    """A single few-shot example."""
    input: str
    output: str
    explanation: Optional[str] = None
    label: Optional[str] = None
    metadata: Dict[str, Any] = field(default_factory=dict)


@dataclass
class FewShotTask:
    """A task to be performed using few-shot learning."""
    task_name: str
    description: str
    examples: List[Example]
    example_format: ExampleFormat
    instruction: Optional[str] = None


@dataclass
class FewShotResult:
    """Result from few-shot learning."""
    task_name: str
    input: str
    output: str
    examples_used: int
    confidence: Optional[float] = None
    timestamp: datetime = field(default_factory=datetime.now)


class FewShotLearner:
    """Agent that learns from few examples."""
    
    def __init__(self, name: str, model_name: str = "gpt-4", temperature: float = 0.7):
        self.name = name
        self.llm = ChatOpenAI(model=model_name, temperature=temperature)
        self.learned_tasks: Dict[str, FewShotTask] = {}
        self.results: List[FewShotResult] = []
    
    def learn_task(self, task: FewShotTask):
        """Learn a new task from examples."""
        self.learned_tasks[task.task_name] = task
        print(f"šŸ“š {self.name} learned task '{task.task_name}' from {len(task.examples)} examples")
    
    def create_few_shot_prompt(self, task: FewShotTask, input_text: str) -> str:
        """Create prompt with few-shot examples."""
        prompt_parts = []
        
        # Add task description
        if task.description:
            prompt_parts.append(f"Task: {task.description}\n")
        
        if task.instruction:
            prompt_parts.append(f"Instructions: {task.instruction}\n")
        
        # Add examples based on format
        if task.example_format == ExampleFormat.QA_PAIRS:
            prompt_parts.append("Examples:")
            for i, ex in enumerate(task.examples, 1):
                prompt_parts.append(f"\nQ{i}: {ex.input}")
                prompt_parts.append(f"A{i}: {ex.output}")
                if ex.explanation:
                    prompt_parts.append(f"Explanation: {ex.explanation}")
        
        elif task.example_format == ExampleFormat.INPUT_OUTPUT:
            prompt_parts.append("Examples:")
            for i, ex in enumerate(task.examples, 1):
                prompt_parts.append(f"\nInput {i}: {ex.input}")
                prompt_parts.append(f"Output {i}: {ex.output}")
        
        elif task.example_format == ExampleFormat.DEMONSTRATION:
            prompt_parts.append("Here's how to do it:")
            for i, ex in enumerate(task.examples, 1):
                prompt_parts.append(f"\nExample {i}:")
                prompt_parts.append(f"Given: {ex.input}")
                prompt_parts.append(f"Steps: {ex.explanation or 'See output'}")
                prompt_parts.append(f"Result: {ex.output}")
        
        elif task.example_format == ExampleFormat.LABELED:
            prompt_parts.append("Labeled examples:")
            for ex in task.examples:
                label = ex.label or "unlabeled"
                prompt_parts.append(f"\n[{label}] {ex.input} → {ex.output}")
        
        # Add new input
        prompt_parts.append(f"\n\nNow apply the same pattern:")
        if task.example_format == ExampleFormat.QA_PAIRS:
            prompt_parts.append(f"Q: {input_text}")
            prompt_parts.append("A:")
        else:
            prompt_parts.append(f"Input: {input_text}")
            prompt_parts.append("Output:")
        
        return "\n".join(prompt_parts)
    
    def execute_task(self, task_name: str, input_text: str) -> FewShotResult:
        """Execute learned task on new input."""
        if task_name not in self.learned_tasks:
            raise ValueError(f"Task '{task_name}' not learned yet")
        
        task = self.learned_tasks[task_name]
        prompt_text = self.create_few_shot_prompt(task, input_text)
        
        # Execute with LLM
        prompt = ChatPromptTemplate.from_messages([
            ("system", f"You are {self.name}. Follow the pattern shown in the examples."),
            ("human", "{prompt}")
        ])
        
        chain = prompt | self.llm | StrOutputParser()
        output = chain.invoke({"prompt": prompt_text})
        
        result = FewShotResult(
            task_name=task_name,
            input=input_text,
            output=output,
            examples_used=len(task.examples)
        )
        
        self.results.append(result)
        return result
    
    def get_statistics(self) -> Dict[str, Any]:
        """Get learning statistics."""
        return {
            "name": self.name,
            "tasks_learned": len(self.learned_tasks),
            "total_executions": len(self.results),
            "tasks": {name: len(task.examples) for name, task in self.learned_tasks.items()}
        }


class FewShotLearningPattern:
    """
    Few-Shot Learning Pattern - Learn tasks from small number of examples.
    
    Enables LLMs to quickly adapt to new tasks by providing a few
    demonstration examples in the prompt context.
    """
    
    def __init__(self, model_name: str = "gpt-4"):
        self.model_name = model_name
        self.learners: Dict[str, FewShotLearner] = {}
        self.task_library: Dict[str, FewShotTask] = {}
    
    def create_learner(self, name: str) -> FewShotLearner:
        """Create a few-shot learner."""
        learner = FewShotLearner(name, self.model_name)
        self.learners[name] = learner
        return learner
    
    def register_task(self, task: FewShotTask):
        """Register a task in the library."""
        self.task_library[task.task_name] = task
        print(f"šŸ“‹ Task registered: {task.task_name} ({len(task.examples)} examples)")
    
    def create_task(self, task_name: str, description: str, 
                   examples: List[Example], example_format: ExampleFormat,
                   instruction: Optional[str] = None) -> FewShotTask:
        """Create and register a task."""
        task = FewShotTask(
            task_name=task_name,
            description=description,
            examples=examples,
            example_format=example_format,
            instruction=instruction
        )
        self.register_task(task)
        return task
    
    def teach_learner(self, learner_name: str, task_name: str):
        """Teach a task to a learner."""
        if learner_name not in self.learners:
            raise ValueError(f"Learner '{learner_name}' not found")
        if task_name not in self.task_library:
            raise ValueError(f"Task '{task_name}' not in library")
        
        learner = self.learners[learner_name]
        task = self.task_library[task_name]
        learner.learn_task(task)
    
    def get_statistics(self) -> Dict[str, Any]:
        """Get pattern statistics."""
        return {
            "total_learners": len(self.learners),
            "tasks_in_library": len(self.task_library),
            "learners": {name: learner.get_statistics() for name, learner in self.learners.items()}
        }


# Example usage
if __name__ == "__main__":
    print("=== Few-Shot Learning Pattern Demo ===\n")
    
    # Create pattern
    print("1. Creating few-shot learning pattern...")
    pattern = FewShotLearningPattern()
    
    # Create learner
    learner = pattern.create_learner("QuickLearner")
    
    # Task 1: Sentiment Analysis
    print(f"\n{'='*70}")
    print("šŸ“š Task 1: Sentiment Analysis")
    print(f"{'='*70}\n")
    
    sentiment_examples = [
        Example(
            input="I love this product! It's amazing!",
            output="Positive",
            explanation="Enthusiastic language with positive words"
        ),
        Example(
            input="Terrible experience. Very disappointed.",
            output="Negative",
            explanation="Strong negative words expressing dissatisfaction"
        ),
        Example(
            input="It's okay, nothing special.",
            output="Neutral",
            explanation="Lukewarm response without strong emotion"
        )
    ]
    
    sentiment_task = pattern.create_task(
        task_name="sentiment_analysis",
        description="Classify the sentiment of text as Positive, Negative, or Neutral",
        examples=sentiment_examples,
        example_format=ExampleFormat.QA_PAIRS,
        instruction="Analyze the emotional tone and classify accordingly"
    )
    
    pattern.teach_learner("QuickLearner", "sentiment_analysis")
    
    # Test sentiment analysis
    test_inputs = [
        "This is the best thing ever!",
        "I'm not impressed at all.",
        "It works as expected."
    ]
    
    print("Testing learned task:\n")
    for test_input in test_inputs:
        result = learner.execute_task("sentiment_analysis", test_input)
        print(f"Input: {result.input}")
        print(f"Output: {result.output}")
        print(f"Examples used: {result.examples_used}\n")
    
    # Task 2: Code Documentation
    print(f"\n{'='*70}")
    print("šŸ“š Task 2: Code Documentation")
    print(f"{'='*70}\n")
    
    doc_examples = [
        Example(
            input="def add(a, b): return a + b",
            output="Adds two numbers and returns their sum.",
            label="math_function"
        ),
        Example(
            input="def is_even(n): return n % 2 == 0",
            output="Checks if a number is even, returns True if divisible by 2.",
            label="boolean_function"
        )
    ]
    
    doc_task = pattern.create_task(
        task_name="code_documentation",
        description="Generate concise documentation for Python functions",
        examples=doc_examples,
        example_format=ExampleFormat.LABELED,
        instruction="Describe what the function does in one clear sentence"
    )
    
    pattern.teach_learner("QuickLearner", "code_documentation")
    
    # Test code documentation
    code_inputs = [
        "def factorial(n): return 1 if n == 0 else n * factorial(n-1)",
        "def reverse_string(s): return s[::-1]"
    ]
    
    print("Testing learned task:\n")
    for code_input in code_inputs:
        result = learner.execute_task("code_documentation", code_input)
        print(f"Code: {result.input}")
        print(f"Doc: {result.output}\n")
    
    # Statistics
    print(f"\n{'='*70}")
    print("šŸ“Š Learning Statistics")
    print(f"{'='*70}")
    
    stats = pattern.get_statistics()
    
    print(f"   Total learners: {stats['total_learners']}")
    print(f"   Tasks in library: {stats['tasks_in_library']}")
    
    for learner_name, learner_stats in stats['learners'].items():
        print(f"\n   Learner: {learner_name}")
        print(f"   - Tasks learned: {learner_stats['tasks_learned']}")
        print(f"   - Total executions: {learner_stats['total_executions']}")
        print(f"   - Task details:")
        for task_name, num_examples in learner_stats['tasks'].items():
            print(f"     * {task_name}: {num_examples} examples")
    
    print("\nāœ“ Few-shot learning enabled rapid task adaptation!")

    

Agentic Architecture Pattern: Few Shot Learning

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

Overview

Pattern 192: Few-Shot Learning Pattern

LLM learns to perform tasks from a small number of examples provided in the prompt. Demonstrates in-context learning where the model adapts based on examples.


Code Structure Analysis

File Information

  • Pattern Number: 192
  • Pattern Name: 192 Few Shot Learning Pattern
  • File Path: patterns\llm_specific\192_few_shot_learning_pattern.py
  • Total Lines: 333

Detailed Code Explanation

Module Docstring

"""
Pattern 192: Few-Shot Learning Pattern

LLM learns to perform tasks from a small number of examples provided in the prompt.
Demonstrates in-context learning where the model adapts based on examples.
"""

Explanation: This module docstring describes the purpose and key features of the 192 Few Shot Learning Pattern pattern.


Imports Section

from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from langchain_core.prompts import ChatPromptTemplate, FewShotPromptTemplate, PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI  # First 20 imports shown

Explanation: The module imports necessary dependencies: – from typing import Dict, Any, List, Optional, Callable: Type hints for better code documentation – from dataclasses import dataclass, field: Data class decorators for clean data structures – from datetime import datetime: Date and time utilities – from enum import Enum: Enumeration support for fixed sets of values – from langchain_core.prompts import ChatPromptTemplate, FewShotPromptTemplate, PromptTemplate: LangChain framework integration – from langchain_core.output_parsers import StrOutputParser: LangChain framework integration – from langchain_openai import ChatOpenAI: LangChain framework integration


Enumerations

ExampleFormat (Line 17)

class ExampleFormat(Enum):
    QA_PAIRS
    INPUT_OUTPUT
    DEMONSTRATION
    LABELED

Purpose: Format for few-shot examples.

Values: – QA_PAIRS: Represents qa pairs – INPUT_OUTPUT: Represents input output – DEMONSTRATION: Represents demonstration – LABELED: Represents labeled


Classes

ExampleFormat (Line 17)

Description: Format for few-shot examples.

Example (Line 26)

Description: A single few-shot example.

FewShotTask (Line 36)

Description: A task to be performed using few-shot learning.

FewShotResult (Line 46)

Description: Result from few-shot learning.

FewShotLearner (Line 56)

Description: Agent that learns from few examples.

Methods:

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

Purpose: No method docstring.

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

learn_task (Line 65)
def learn_task(self, task):
    """Learn a new task from examples."""

Purpose: Learn a new task from examples.

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

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

Purpose: Create prompt with few-shot examples.

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

execute_task (Line 121)
def execute_task(self, task_name, input_text):
    """Execute learned task on new input."""

Purpose: Execute learned task on new input.

Parameters: – self: Instance reference – task_name: Parameter for task_name – input_text: Parameter for input_text

get_statistics (Line 148)
def get_statistics(self):
    """Get learning statistics."""

Purpose: Get learning statistics.

Parameters: – self: Instance reference

FewShotLearningPattern (Line 158)

Description: Few-Shot Learning Pattern – Learn tasks from small number of examples.

Enables LLMs to quickly adapt to new tasks by providing a few demonstration examples in the prompt context.

Methods:

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

Purpose: No method docstring.

Parameters: – self: Instance reference – model_name: LLM model to use (e.g., “gpt-4”)

create_learner (Line 171)
def create_learner(self, name):
    """Create a few-shot learner."""

Purpose: Create a few-shot learner.

Parameters: – self: Instance reference – name: Identifier or label

register_task (Line 177)
def register_task(self, task):
    """Register a task in the library."""

Purpose: Register a task in the library.

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

create_task (Line 182)
def create_task(self, task_name, description, examples, example_format, instruction):
    """Create and register a task."""

Purpose: Create and register a task.

Parameters: – self: Instance reference – task_name: Parameter for task_name – description: Parameter for description – examples: Parameter for examples – example_format: Parameter for example_format – instruction: Parameter for instruction

teach_learner (Line 196)
def teach_learner(self, learner_name, task_name):
    """Teach a task to a learner."""

Purpose: Teach a task to a learner.

Parameters: – self: Instance reference – learner_name: Parameter for learner_name – task_name: Parameter for task_name

get_statistics (Line 207)
def get_statistics(self):
    """Get pattern statistics."""

Purpose: Get pattern statistics.

Parameters: – self: Instance reference


Design Patterns Used

  • Strategy Pattern: Different execution strategies for various scenarios
  • State Pattern: Managing different states in the workflow
  • Chain of Responsibility: Sequential processing through workflow nodes
  • Observer Pattern: Tracking and monitoring pattern execution
  • Factory Pattern: Creating instances with proper configuration

Usage Example

# Initialize the pattern
pattern = ExampleFormat(name="example", model_name="gpt-4")

# Configure and execute
result = pattern.execute(data={"key": "value"})

# Check results
print(result)

Key Concepts

  • LLM Integration: Uses LangChain/OpenAI for intelligent decision-making
  • Workflow Orchestration: LangGraph manages execution flow through nodes
  • State Management: TypedDict defines workflow state structure
  • Error Handling: Comprehensive error handling and fallback mechanisms
  • Extensibility: Designed for easy customization and extension

Extension Points

This pattern can be extended by: 1. Adding custom workflow nodes 2. Implementing additional validation logic 3. Integrating with external services 4. Customizing LLM prompts and responses 5. Adding monitoring and logging capabilities

Comments

Leave a Reply

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