"""
Pattern 52: Supervised Learning Agent
Agent learns from labeled training data to make predictions on new inputs.
Implements training, validation, evaluation, and prediction using LLM-based learning.
"""
from typing import Dict, Any, List, Optional, Tuple
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
import random
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
class LearningStrategy(Enum):
"""Strategies for learning from examples."""
FEW_SHOT = "few_shot" # Use examples in prompt
FINE_TUNING = "fine_tuning" # Simulate fine-tuning
PATTERN_MATCHING = "pattern_matching" # Match patterns
@dataclass
class TrainingExample:
"""Labeled training example."""
input_data: str
label: str
weight: float = 1.0
metadata: Dict[str, Any] = field(default_factory=dict)
@dataclass
class ValidationResult:
"""Validation metrics."""
accuracy: float
precision: float
recall: float
f1_score: float
confusion_matrix: Dict[str, int]
@dataclass
class Prediction:
"""Model prediction with confidence."""
input_data: str
predicted_label: str
confidence: float
reasoning: Optional[str] = None
actual_label: Optional[str] = None
correct: Optional[bool] = None
timestamp: datetime = field(default_factory=datetime.now)
class SupervisedLearningAgent:
"""Agent that learns from labeled examples."""
def __init__(self, name: str, task_description: str,
model_name: str = "gpt-4", strategy: LearningStrategy = LearningStrategy.FEW_SHOT):
self.name = name
self.task_description = task_description
self.llm = ChatOpenAI(model=model_name, temperature=0.3)
self.strategy = strategy
self.training_examples: List[TrainingExample] = []
self.validation_examples: List[TrainingExample] = []
self.predictions: List[Prediction] = []
self.is_trained = False
def train(self, examples: List[TrainingExample], validation_split: float = 0.2):
"""Train on labeled examples."""
print(f"\n๐ {self.name}: Training on {len(examples)} examples...")
# Split into training and validation
shuffled = examples.copy()
random.shuffle(shuffled)
split_idx = int(len(shuffled) * (1 - validation_split))
self.training_examples = shuffled[:split_idx]
self.validation_examples = shuffled[split_idx:]
self.is_trained = True
print(f" Training examples: {len(self.training_examples)}")
print(f" Validation examples: {len(self.validation_examples)}")
def _create_few_shot_prompt(self, input_data: str, num_examples: int = 5) -> str:
"""Create few-shot prompt with training examples."""
prompt_parts = [f"Task: {self.task_description}\n"]
prompt_parts.append("Learn from these labeled examples:\n")
# Sample random training examples
sample_examples = random.sample(
self.training_examples,
min(num_examples, len(self.training_examples))
)
for i, ex in enumerate(sample_examples, 1):
prompt_parts.append(f"\nExample {i}:")
prompt_parts.append(f"Input: {ex.input_data}")
prompt_parts.append(f"Label: {ex.label}")
prompt_parts.append(f"\n\nNow predict the label for this input:")
prompt_parts.append(f"Input: {input_data}")
prompt_parts.append("Label:")
return "\n".join(prompt_parts)
def predict(self, input_data: str, return_reasoning: bool = False) -> Prediction:
"""Make prediction using learned patterns."""
if not self.is_trained:
raise ValueError(f"{self.name} has not been trained yet")
# Create prompt based on strategy
if self.strategy == LearningStrategy.FEW_SHOT:
prompt_text = self._create_few_shot_prompt(input_data)
else:
prompt_text = f"Task: {self.task_description}\n\nInput: {input_data}\n\nLabel:"
# Get prediction from LLM
prompt = ChatPromptTemplate.from_messages([
("system", f"You are {self.name}, a supervised learning model. "
f"Predict labels based on learned patterns. "
f"{'Provide brief reasoning.' if return_reasoning else 'Provide only the label.'}"),
("human", "{prompt}")
])
chain = prompt | self.llm | StrOutputParser()
response = chain.invoke({"prompt": prompt_text})
# Parse response
lines = response.strip().split('\n')
predicted_label = lines[0].strip()
reasoning = '\n'.join(lines[1:]).strip() if len(lines) > 1 and return_reasoning else None
# Estimate confidence (simplified)
confidence = 0.85 if len(self.training_examples) > 10 else 0.70
prediction = Prediction(
input_data=input_data,
predicted_label=predicted_label,
confidence=confidence,
reasoning=reasoning
)
self.predictions.append(prediction)
return prediction
def evaluate(self, test_examples: List[TrainingExample]) -> ValidationResult:
"""Evaluate model on test set."""
print(f"\n๐งช Evaluating {self.name} on {len(test_examples)} test examples...")
correct = 0
predictions_dict: Dict[str, List[Prediction]] = {}
confusion = {}
for ex in test_examples:
pred = self.predict(ex.input_data)
pred.actual_label = ex.label
pred.correct = (pred.predicted_label.lower().strip() == ex.label.lower().strip())
if pred.correct:
correct += 1
# Track predictions by label
if ex.label not in predictions_dict:
predictions_dict[ex.label] = []
predictions_dict[ex.label].append(pred)
# Confusion matrix
key = f"{ex.label}->{pred.predicted_label}"
confusion[key] = confusion.get(key, 0) + 1
accuracy = correct / len(test_examples) if test_examples else 0
# Calculate precision, recall, F1 per class (simplified)
precision = accuracy # Simplified
recall = accuracy
f1_score = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
return ValidationResult(
accuracy=accuracy,
precision=precision,
recall=recall,
f1_score=f1_score,
confusion_matrix=confusion
)
def get_statistics(self) -> Dict[str, Any]:
"""Get learning statistics."""
correct_predictions = sum(1 for p in self.predictions if p.correct)
total_predictions = len([p for p in self.predictions if p.actual_label is not None])
return {
"name": self.name,
"is_trained": self.is_trained,
"training_examples": len(self.training_examples),
"validation_examples": len(self.validation_examples),
"total_predictions": len(self.predictions),
"accuracy": correct_predictions / total_predictions if total_predictions > 0 else 0,
"strategy": self.strategy.value
}
class SupervisedLearningPattern:
"""
Supervised Learning Agent Pattern - Learn from labeled data.
Trains agents on labeled examples to make predictions on new inputs.
Supports training, validation, evaluation, and prediction workflows.
"""
def __init__(self, model_name: str = "gpt-4"):
self.model_name = model_name
self.agents: Dict[str, SupervisedLearningAgent] = {}
def create_agent(self, name: str, task_description: str,
strategy: LearningStrategy = LearningStrategy.FEW_SHOT) -> SupervisedLearningAgent:
"""Create a supervised learning agent."""
agent = SupervisedLearningAgent(name, task_description, self.model_name, strategy)
self.agents[name] = agent
return agent
def train_test_split(self, examples: List[TrainingExample],
test_size: float = 0.2) -> Tuple[List[TrainingExample], List[TrainingExample]]:
"""Split examples into training and test sets."""
shuffled = examples.copy()
random.shuffle(shuffled)
split_idx = int(len(shuffled) * (1 - test_size))
return shuffled[:split_idx], shuffled[split_idx:]
def get_statistics(self) -> Dict[str, Any]:
"""Get pattern statistics."""
return {
"total_agents": len(self.agents),
"agents": {name: agent.get_statistics() for name, agent in self.agents.items()}
}
# Example usage
if __name__ == "__main__":
print("=== Supervised Learning Agent Demo ===\n")
# Create pattern
print("1. Creating supervised learning pattern...")
pattern = SupervisedLearningPattern()
# Task: Sentiment Analysis
print(f"\n{'='*70}")
print("๐ Task: Sentiment Analysis")
print(f"{'='*70}")
agent = pattern.create_agent(
name="SentimentClassifier",
task_description="Classify text sentiment as Positive, Negative, or Neutral"
)
# Create training data
training_data = [
TrainingExample("I love this product! Amazing quality!", "Positive"),
TrainingExample("Best purchase ever! Highly recommend!", "Positive"),
TrainingExample("Fantastic experience, will buy again", "Positive"),
TrainingExample("Really impressed with the service", "Positive"),
TrainingExample("Excellent quality and fast shipping", "Positive"),
TrainingExample("Terrible experience, very disappointed", "Negative"),
TrainingExample("Waste of money, doesn't work at all", "Negative"),
TrainingExample("Poor quality, broke after one use", "Negative"),
TrainingExample("Worst product I've ever bought", "Negative"),
TrainingExample("Not worth it, total ripoff", "Negative"),
TrainingExample("It's okay, nothing special", "Neutral"),
TrainingExample("Average product, does the job", "Neutral"),
TrainingExample("Not bad, not great either", "Neutral"),
TrainingExample("Acceptable quality for the price", "Neutral"),
TrainingExample("Standard product, meets expectations", "Neutral"),
]
# Split data
train_data, test_data = pattern.train_test_split(training_data, test_size=0.3)
# Train agent
print("\n2. Training agent...")
agent.train(train_data, validation_split=0.2)
# Make predictions
print(f"\n{'='*70}")
print("๐ฎ Making Predictions")
print(f"{'='*70}\n")
test_inputs = [
"This is absolutely wonderful!",
"Completely useless and broken",
"It works as expected, nothing more"
]
for test_input in test_inputs:
pred = agent.predict(test_input, return_reasoning=False)
print(f"Input: {pred.input_data}")
print(f"Prediction: {pred.predicted_label}")
print(f"Confidence: {pred.confidence:.2%}\n")
# Evaluate on test set
print(f"\n{'='*70}")
print("๐ Model Evaluation")
print(f"{'='*70}\n")
results = agent.evaluate(test_data)
print(f"Accuracy: {results.accuracy:.2%}")
print(f"Precision: {results.precision:.2%}")
print(f"Recall: {results.recall:.2%}")
print(f"F1 Score: {results.f1_score:.2%}")
print(f"\nConfusion Matrix:")
for key, count in sorted(results.confusion_matrix.items()):
print(f" {key}: {count}")
# Statistics
print(f"\n{'='*70}")
print("๐ Learning Statistics")
print(f"{'='*70}")
stats = pattern.get_statistics()
for agent_name, agent_stats in stats['agents'].items():
print(f"\nAgent: {agent_name}")
print(f" Trained: {agent_stats['is_trained']}")
print(f" Training examples: {agent_stats['training_examples']}")
print(f" Validation examples: {agent_stats['validation_examples']}")
print(f" Total predictions: {agent_stats['total_predictions']}")
print(f" Accuracy: {agent_stats['accuracy']:.2%}")
print(f" Strategy: {agent_stats['strategy']}")
print("\nโ Supervised learning enabled prediction from labeled data!")
Agentic Architecture Pattern: Supervised Learning
Pattern 52: 52 Supervised Learning – Line-by-Line Explanation
Overview
Pattern 52: Supervised Learning Agent
Agent learns from labeled training data to make predictions on new inputs. Implements training, validation, evaluation, and prediction using LLM-based learning.
Code Structure Analysis
File Information
- Pattern Number: 52
- Pattern Name: 52 Supervised Learning
- File Path:
patterns\learning_adaptation\52_supervised_learning.py - Total Lines: 336
Detailed Code Explanation
Module Docstring
"""
Pattern 52: Supervised Learning Agent
Agent learns from labeled training data to make predictions on new inputs.
Implements training, validation, evaluation, and prediction using LLM-based learning.
"""
Explanation: This module docstring describes the purpose and key features of the 52 Supervised Learning pattern.
Imports Section
from typing import Dict, Any, List, Optional, Tuple
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
import random
from langchain_core.prompts import ChatPromptTemplate
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, Tuple: Type hints for better code documentation
– from dataclasses import dataclass, field: Data class decorators for clean data structures
– from datetime import datetime: Date and time utilities
– from enum import Enum: Enumeration support for fixed sets of values
– from langchain_core.prompts import ChatPromptTemplate: LangChain framework integration
– from langchain_core.output_parsers import StrOutputParser: LangChain framework integration
– from langchain_openai import ChatOpenAI: LangChain framework integration
Enumerations
LearningStrategy (Line 18)
class LearningStrategy(Enum):
FEW_SHOT
FINE_TUNING
PATTERN_MATCHING
Purpose: Strategies for learning from examples.
Values:
– FEW_SHOT: Represents few shot
– FINE_TUNING: Represents fine tuning
– PATTERN_MATCHING: Represents pattern matching
Classes
LearningStrategy (Line 18)
Description: Strategies for learning from examples.
TrainingExample (Line 26)
Description: Labeled training example.
ValidationResult (Line 35)
Description: Validation metrics.
Prediction (Line 45)
Description: Model prediction with confidence.
SupervisedLearningAgent (Line 56)
Description: Agent that learns from labeled examples.
Methods:
__init__ (Line 59)
def __init__(self, name, task_description, model_name, strategy):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
– name: Identifier or label
– task_description: Parameter for task_description
– model_name: LLM model to use (e.g., “gpt-4”)
– strategy: Parameter for strategy
train (Line 70)
def train(self, examples, validation_split):
"""Train on labeled examples."""
Purpose: Train on labeled examples.
Parameters:
– self: Instance reference
– examples: Parameter for examples
– validation_split: Parameter for validation_split
_create_few_shot_prompt (Line 86)
def _create_few_shot_prompt(self, input_data, num_examples):
"""Create few-shot prompt with training examples."""
Purpose: Create few-shot prompt with training examples.
Parameters:
– self: Instance reference
– input_data: Parameter for input_data
– num_examples: Parameter for num_examples
predict (Line 108)
def predict(self, input_data, return_reasoning):
"""Make prediction using learned patterns."""
Purpose: Make prediction using learned patterns.
Parameters:
– self: Instance reference
– input_data: Parameter for input_data
– return_reasoning: Parameter for return_reasoning
evaluate (Line 148)
def evaluate(self, test_examples):
"""Evaluate model on test set."""
Purpose: Evaluate model on test set.
Parameters:
– self: Instance reference
– test_examples: Parameter for test_examples
get_statistics (Line 188)
def get_statistics(self):
"""Get learning statistics."""
Purpose: Get learning statistics.
Parameters:
– self: Instance reference
SupervisedLearningPattern (Line 204)
Description: Supervised Learning Agent Pattern – Learn from labeled data.
Trains agents on labeled examples to make predictions on new inputs. Supports training, validation, evaluation, and prediction workflows.
Methods:
__init__ (Line 212)
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_agent (Line 216)
def create_agent(self, name, task_description, strategy):
"""Create a supervised learning agent."""
Purpose: Create a supervised learning agent.
Parameters:
– self: Instance reference
– name: Identifier or label
– task_description: Parameter for task_description
– strategy: Parameter for strategy
train_test_split (Line 223)
def train_test_split(self, examples, test_size):
"""Split examples into training and test sets."""
Purpose: Split examples into training and test sets.
Parameters:
– self: Instance reference
– examples: Parameter for examples
– test_size: Parameter for test_size
get_statistics (Line 232)
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 = LearningStrategy(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
Leave a Reply