"""
Pattern 034: Active Learning
Description:
Active Learning enables agents to strategically request human input for the most
informative or uncertain cases. Rather than passively learning from all data,
the agent actively selects examples that will maximize learning efficiency,
focusing human effort on cases where it matters most.
Components:
- Uncertainty Estimator: Measures confidence in predictions
- Query Strategy: Selects most informative examples
- Oracle: Human expert providing labels/feedback
- Learning Loop: Incorporates feedback to improve
- Sample Selector: Chooses examples for annotation
Use Cases:
- Training data collection with limited budget
- Model improvement in production
- Handling ambiguous or edge cases
- Domain adaptation
- Quality assurance and verification
LangChain Implementation:
Uses confidence estimation and strategic sampling to identify cases where
human feedback will be most valuable, optimizing the learning process.
"""
import os
from typing import List, Dict, Any, Optional, Tuple
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
import random
from collections import defaultdict
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 QueryStrategy(Enum):
"""Strategies for selecting samples for human annotation."""
UNCERTAINTY_SAMPLING = "uncertainty_sampling" # Least confident examples
MARGIN_SAMPLING = "margin_sampling" # Smallest margin between top predictions
ENTROPY_SAMPLING = "entropy_sampling" # Highest entropy
QUERY_BY_COMMITTEE = "query_by_committee" # Maximum disagreement
DIVERSITY_SAMPLING = "diversity_sampling" # Representative diversity
EXPECTED_ERROR_REDUCTION = "expected_error_reduction" # Max expected improvement
@dataclass
class Prediction:
"""A prediction with confidence information."""
input: str
output: str
confidence: float
alternatives: List[Tuple[str, float]] = field(default_factory=list) # (output, confidence)
metadata: Dict[str, Any] = field(default_factory=dict)
@dataclass
class AnnotationRequest:
"""Request for human annotation."""
id: str
input: str
predicted_output: str
confidence: float
query_strategy: QueryStrategy
timestamp: datetime = field(default_factory=datetime.now)
# Human response
human_label: Optional[str] = None
feedback: Optional[str] = None
annotation_time: Optional[datetime] = None
@dataclass
class TrainingExample:
"""Labeled training example."""
input: str
output: str
source: str # "human", "synthetic", "model"
confidence: float = 1.0
created_at: datetime = field(default_factory=datetime.now)
class Oracle:
"""
Simulates human expert for annotation (in production, would be real human).
"""
def __init__(self, auto_annotate: bool = True):
self.auto_annotate = auto_annotate
self.annotation_count = 0
def annotate(self, request: AnnotationRequest) -> AnnotationRequest:
"""
Provide annotation for the request.
In simulation mode, provides realistic labels.
In production, would wait for human annotation.
"""
self.annotation_count += 1
if self.auto_annotate:
# Simulate human annotation
# In practice, this would involve actual human judgment
request.human_label = f"[HUMAN ANNOTATED] {request.predicted_output}"
request.feedback = "Annotation provided"
request.annotation_time = datetime.now()
return request
class ActiveLearningAgent:
"""
Agent that uses active learning to improve through strategic human feedback.
Features:
- Multiple query strategies
- Confidence estimation
- Strategic sample selection
- Learning from feedback
"""
def __init__(
self,
query_strategy: QueryStrategy = QueryStrategy.UNCERTAINTY_SAMPLING,
oracle: Optional[Oracle] = None,
temperature: float = 0.7
):
self.llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=temperature)
self.query_strategy = query_strategy
self.oracle = oracle or Oracle()
# Training data
self.training_examples: List[TrainingExample] = []
self.unlabeled_pool: List[str] = []
self.annotation_history: List[AnnotationRequest] = []
self._next_request_id = 1
# Prompt for making predictions with confidence
self.prediction_prompt = ChatPromptTemplate.from_messages([
("system", """You are an AI assistant that provides predictions with confidence scores.
Previous examples (for reference):
{examples}
Task: {input}
Provide your answer and estimate your confidence (0.0-1.0).
Format:
ANSWER: [your answer]
CONFIDENCE: [0.0-1.0]
ALTERNATIVES: [alternative answer 1] (confidence), [alternative answer 2] (confidence)"""),
("user", "{input}")
])
def predict_with_confidence(self, input_text: str) -> Prediction:
"""
Make a prediction with confidence estimation.
"""
# Format examples from training data
examples_text = self._format_examples(self.training_examples[:5])
# Generate prediction
chain = self.prediction_prompt | self.llm | StrOutputParser()
result = chain.invoke({
"input": input_text,
"examples": examples_text
})
# Parse result
answer, confidence, alternatives = self._parse_prediction(result)
return Prediction(
input=input_text,
output=answer,
confidence=confidence,
alternatives=alternatives
)
def select_for_annotation(
self,
predictions: List[Prediction],
budget: int = 5
) -> List[Prediction]:
"""
Select most informative examples for human annotation.
Args:
predictions: List of predictions to choose from
budget: Number of examples to select
Returns:
Selected predictions for annotation
"""
if not predictions:
return []
# Apply query strategy
if self.query_strategy == QueryStrategy.UNCERTAINTY_SAMPLING:
# Select examples with lowest confidence
selected = sorted(predictions, key=lambda p: p.confidence)[:budget]
elif self.query_strategy == QueryStrategy.MARGIN_SAMPLING:
# Select examples with smallest margin between top 2 predictions
selected = []
for pred in predictions:
if len(pred.alternatives) >= 2:
margin = abs(pred.alternatives[0][1] - pred.alternatives[1][1])
selected.append((margin, pred))
else:
selected.append((0.0, pred))
selected = [p for _, p in sorted(selected, key=lambda x: x[0])[:budget]]
elif self.query_strategy == QueryStrategy.DIVERSITY_SAMPLING:
# Select diverse examples (simple: random sampling)
selected = random.sample(predictions, min(budget, len(predictions)))
else:
# Default: uncertainty sampling
selected = sorted(predictions, key=lambda p: p.confidence)[:budget]
return selected
def request_annotations(
self,
predictions: List[Prediction]
) -> List[AnnotationRequest]:
"""
Request human annotations for selected predictions.
"""
requests = []
for pred in predictions:
request = AnnotationRequest(
id=f"ann_{self._next_request_id:04d}",
input=pred.input,
predicted_output=pred.output,
confidence=pred.confidence,
query_strategy=self.query_strategy
)
self._next_request_id += 1
# Get annotation from oracle
request = self.oracle.annotate(request)
requests.append(request)
self.annotation_history.append(request)
return requests
def incorporate_feedback(
self,
annotations: List[AnnotationRequest]
) -> int:
"""
Incorporate human annotations into training data.
Returns number of examples added.
"""
added = 0
for annotation in annotations:
if annotation.human_label:
example = TrainingExample(
input=annotation.input,
output=annotation.human_label,
source="human",
confidence=1.0
)
self.training_examples.append(example)
added += 1
return added
def active_learning_cycle(
self,
unlabeled_data: List[str],
annotation_budget: int = 5
) -> Dict[str, Any]:
"""
Perform one cycle of active learning.
Steps:
1. Make predictions on unlabeled data
2. Select most informative examples
3. Request human annotations
4. Incorporate feedback into training data
Returns:
Statistics about the cycle
"""
# Step 1: Predict on unlabeled data
predictions = []
for input_text in unlabeled_data:
pred = self.predict_with_confidence(input_text)
predictions.append(pred)
# Step 2: Select for annotation
selected = self.select_for_annotation(predictions, annotation_budget)
# Step 3: Request annotations
annotations = self.request_annotations(selected)
# Step 4: Incorporate feedback
added = self.incorporate_feedback(annotations)
return {
"cycle_complete": True,
"predictions_made": len(predictions),
"selected_for_annotation": len(selected),
"annotations_received": len(annotations),
"examples_added": added,
"total_training_examples": len(self.training_examples),
"avg_confidence": sum(p.confidence for p in predictions) / len(predictions) if predictions else 0
}
def _format_examples(self, examples: List[TrainingExample]) -> str:
"""Format training examples for prompt."""
if not examples:
return "No examples yet."
lines = []
for i, ex in enumerate(examples, 1):
lines.append(f"Example {i}:")
lines.append(f" Input: {ex.input}")
lines.append(f" Output: {ex.output}")
return "\n".join(lines)
def _parse_prediction(self, result: str) -> Tuple[str, float, List[Tuple[str, float]]]:
"""Parse prediction result."""
lines = result.strip().split('\n')
answer = ""
confidence = 0.5
alternatives = []
for line in lines:
if line.startswith("ANSWER:"):
answer = line.replace("ANSWER:", "").strip()
elif line.startswith("CONFIDENCE:"):
try:
conf_str = line.replace("CONFIDENCE:", "").strip()
confidence = float(conf_str)
except ValueError:
pass
elif line.startswith("ALTERNATIVES:"):
# Parse alternatives (simple parsing)
alt_str = line.replace("ALTERNATIVES:", "").strip()
# This is simplified - in practice, would need better parsing
if not answer:
answer = result
return answer, confidence, alternatives
def get_statistics(self) -> Dict[str, Any]:
"""Get active learning statistics."""
if not self.annotation_history:
return {
"total_annotations": 0,
"training_examples": len(self.training_examples),
"avg_confidence_at_annotation": 0.0
}
avg_conf = sum(a.confidence for a in self.annotation_history) / len(self.annotation_history)
return {
"total_annotations": len(self.annotation_history),
"training_examples": len(self.training_examples),
"avg_confidence_at_annotation": avg_conf,
"oracle_calls": self.oracle.annotation_count,
"query_strategy": self.query_strategy.value
}
def demonstrate_active_learning():
"""
Demonstrates active learning with strategic sample selection
and human feedback integration.
"""
print("=" * 80)
print("ACTIVE LEARNING DEMONSTRATION")
print("=" * 80)
# Create oracle (simulated human expert)
oracle = Oracle(auto_annotate=True)
# Test 1: Uncertainty Sampling
print("\n" + "=" * 80)
print("Test 1: Uncertainty Sampling Strategy")
print("=" * 80)
agent1 = ActiveLearningAgent(
query_strategy=QueryStrategy.UNCERTAINTY_SAMPLING,
oracle=oracle
)
# Simulated unlabeled data
unlabeled_data = [
"What is machine learning?",
"Explain neural networks",
"How does backpropagation work?",
"What is deep learning?",
"Describe convolutional neural networks",
"What is transfer learning?",
"Explain reinforcement learning",
"What are transformers in AI?"
]
print(f"\nUnlabeled data pool: {len(unlabeled_data)} examples")
print("\nStarting active learning cycle...")
result1 = agent1.active_learning_cycle(unlabeled_data, annotation_budget=3)
print(f"\nCycle Results:")
print(f" Predictions made: {result1['predictions_made']}")
print(f" Selected for annotation: {result1['selected_for_annotation']}")
print(f" Annotations received: {result1['annotations_received']}")
print(f" Examples added to training: {result1['examples_added']}")
print(f" Total training examples: {result1['total_training_examples']}")
print(f" Average confidence: {result1['avg_confidence']:.2f}")
# Show which examples were selected
print(f"\nSelected examples (lowest confidence):")
for i, annotation in enumerate(agent1.annotation_history[:3], 1):
print(f" {i}. \"{annotation.input}\" (confidence: {annotation.confidence:.2f})")
# Test 2: Multiple cycles
print("\n" + "=" * 80)
print("Test 2: Multiple Active Learning Cycles")
print("=" * 80)
agent2 = ActiveLearningAgent(
query_strategy=QueryStrategy.UNCERTAINTY_SAMPLING,
oracle=oracle
)
# Run 3 cycles
for cycle in range(1, 4):
print(f"\n--- Cycle {cycle} ---")
result = agent2.active_learning_cycle(unlabeled_data, annotation_budget=2)
print(f"Training examples: {result['total_training_examples']}")
print(f"Average confidence: {result['avg_confidence']:.2f}")
# Test 3: Compare strategies
print("\n" + "=" * 80)
print("Test 3: Comparing Query Strategies")
print("=" * 80)
strategies = [
QueryStrategy.UNCERTAINTY_SAMPLING,
QueryStrategy.MARGIN_SAMPLING,
QueryStrategy.DIVERSITY_SAMPLING
]
for strategy in strategies:
agent = ActiveLearningAgent(
query_strategy=strategy,
oracle=Oracle(auto_annotate=True)
)
result = agent.active_learning_cycle(unlabeled_data[:5], annotation_budget=2)
print(f"\n{strategy.value}:")
print(f" Examples added: {result['examples_added']}")
print(f" Avg confidence: {result['avg_confidence']:.2f}")
# Show final statistics
print("\n" + "=" * 80)
print("Final Statistics")
print("=" * 80)
stats = agent1.get_statistics()
print(f"\nAgent 1 (Uncertainty Sampling):")
print(f" Total annotations: {stats['total_annotations']}")
print(f" Training examples: {stats['training_examples']}")
print(f" Avg confidence at annotation: {stats['avg_confidence_at_annotation']:.2f}")
print(f" Oracle calls: {stats['oracle_calls']}")
# Summary
print("\n" + "=" * 80)
print("SUMMARY")
print("=" * 80)
print("""
Active Learning provides:
✓ Strategic sample selection for annotation
✓ Confidence-based uncertainty estimation
✓ Multiple query strategies
✓ Efficient use of human expertise
✓ Continuous improvement through feedback
✓ Cost-effective training data collection
This pattern excels at:
- Maximizing learning from limited annotation budget
- Focusing human effort on most informative examples
- Handling ambiguous or edge cases
- Improving model performance efficiently
- Domain adaptation with minimal labels
Query strategies:
1. UNCERTAINTY_SAMPLING: Select least confident predictions
2. MARGIN_SAMPLING: Smallest margin between top predictions
3. ENTROPY_SAMPLING: Highest prediction entropy
4. QUERY_BY_COMMITTEE: Maximum disagreement among models
5. DIVERSITY_SAMPLING: Representative sample diversity
6. EXPECTED_ERROR_REDUCTION: Maximum expected improvement
Active learning cycle:
1. Make predictions on unlabeled data
2. Estimate confidence for each prediction
3. Select most informative examples using query strategy
4. Request human annotations for selected examples
5. Incorporate feedback into training data
6. Repeat until budget exhausted or performance satisfactory
Benefits:
- Efficiency: Fewer labels needed for same performance
- Focus: Human effort on valuable examples
- Adaptability: Continuously improves with feedback
- Cost-effective: Reduces annotation costs
- Quality: Better than random sampling
Use active learning when you need:
- Limited annotation budget
- Efficient model training
- Production model improvement
- Domain adaptation
- Edge case handling
- Cost-effective data collection
""")
if __name__ == "__main__":
demonstrate_active_learning()
Agentic Design Pattern: Active Learning
Pattern 034: Active Learning – Line-by-Line Explanation
Overview
This document provides a detailed line-by-line explanation of the Active Learning pattern implementation.
Pattern Description
Pattern 034: Active Learning
Description: Active Learning enables agents to strategically request human input for the most informative or uncertain cases. Rather than passively learning from all data, the agent actively selects examples that will maximize learning efficiency, focusing human effort on cases where it matters most.
Components: – Uncertainty Estimator: Measures confidence in predictions – Query Strategy: Selects most informative examples – Oracle: Human expert providing labels/feedback – Learning Loop: Incorporates feedback to improve – Sample Selector: Chooses examples for annotation
Use Cases: – Training data collection with limited budget – Model improvement in production – Handling ambiguous or edge cases – Domain adaptation – Quality assurance and verification
LangChain Implementation: Uses confidence estimation and strategic sampling to identify cases where human feedback will be most valuable, optimizing the learning process.
File Statistics
- Total Lines: 546
- Classes: 6
- Functions: 1
- Constants: 0
Module Documentation
"""
Pattern 034: Active Learning
Description:
Active Learning enables agents to strategically request human input for the most
informative or uncertain cases. Rather than passively learning from all data,
the agent actively selects examples that will maximize learning efficiency,
focusing human effort on cases where it matters most.
Components:
- Uncertainty Estimator: Measures confidence in predictions
- Query Strategy: Selects most informative examples
- Oracle: Human expert providing labels/feedback
- Learning Loop: Incorporates feedback to improve
- Sample Selector: Chooses examples for annotation
Use Cases:
- Training data collection with limited budget
- Model improvement in production
- Handling ambiguous or edge cases
- Domain adaptation
- Quality assurance and verification
LangChain Implementation:
Uses confidence estimation and strategic sampling to identify cases where
human feedback will be most valuable, optimizing the learning process.
"""
Purpose: This module implements the Active Learning pattern, providing a structured approach to agent design and implementation.
Import Statements
Standard Library Imports
import collections.defaultdict
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 random
import typing.Any
import typing.Dict
import typing.List
import typing.Optional
import typing.Tuple
Purpose: Core Python functionality:
– collections.defaultdict: Specialized container datatypes
– 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
– random: Random number generation
– 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: QueryStrategy
Lines 45-52
Inherits from: Enum
Purpose:
Strategies for selecting samples for human annotation.
Class: Prediction
Lines 56-62
Purpose:
A prediction with confidence information.
Class: AnnotationRequest
Lines 66-78
Purpose:
Request for human annotation.
Class: TrainingExample
Lines 82-88
Purpose:
Labeled training example.
Class: Oracle
Lines 91-116
Purpose:
Simulates human expert for annotation (in production, would be real human).
Methods:
__init__(self, auto_annotate)
Lines 96-98
Purpose: Initialize the class instance with required parameters.
Parameters:
– auto_annotate: Auto annotate
annotate(self, request)
Lines 100-116
Purpose:
Provide annotation for the request.
In simulation mode, provides realistic labels.
In production, would wait for human annotation.
Parameters:
– request: Request
Returns: AnnotationRequest
Class: ActiveLearningAgent
Lines 119-384
Purpose:
Agent that uses active learning to improve through strategic human feedback.
Features:
- Multiple query strategies
- Confidence estimation
- Strategic sample selection
- Learning from feedback
Methods:
__init__(self, query_strategy, oracle, temperature)
Lines 130-163
Purpose: Initialize the class instance with required parameters.
Parameters:
– query_strategy: Input query or question
– oracle: Oracle
– temperature: Sampling temperature (0-1)
predict_with_confidence(self, input_text)
Lines 165-187
Purpose:
Make a prediction with confidence estimation.
Parameters:
– input_text: Input data
Returns: Prediction
select_for_annotation(self, predictions, budget)
Lines 189-232
Purpose:
Select most informative examples for human annotation.
Args:
predictions: List of predictions to choose from
budget: Number of examples to select
Returns:
Selected predictions for annotation
Parameters:
– predictions: Predictions
– budget: Budget
Returns: <ast.Subscript object at 0x000001A06D179A90>
request_annotations(self, predictions)
Lines 234-259
Purpose:
Request human annotations for selected predictions.
Parameters:
– predictions: Predictions
Returns: <ast.Subscript object at 0x000001A06D75B090>
incorporate_feedback(self, annotations)
Lines 261-283
Purpose:
Incorporate human annotations into training data.
Returns number of examples added.
Parameters:
– annotations: Annotations
Returns: int
active_learning_cycle(self, unlabeled_data, annotation_budget)
Lines 285-325
Purpose:
Perform one cycle of active learning.
Steps:
1. Make predictions on unlabeled data
2. Select most informative examples
3. Request human annotations
4. Incorporate feedback into training data
Returns:
Statistics about the cycle
Parameters:
– unlabeled_data: Unlabeled data
– annotation_budget: Annotation budget
Returns: <ast.Subscript object at 0x000001A06D6AA490>
_format_examples(self, examples)
Lines 327-338
Purpose:
Format training examples for prompt.
Parameters:
– examples: Examples
Returns: str
_parse_prediction(self, result)
Lines 340-365
Purpose:
Parse prediction result.
Parameters:
– result: Result
Returns: <ast.Subscript object at 0x000001A06D681C10>
get_statistics(self)
Lines 367-384
Purpose:
Get active learning statistics.
Parameters:
Returns: <ast.Subscript object at 0x000001A06D625450>
Functions
demonstrate_active_learning()
Lines 387-541
Purpose:
Demonstrates active learning with strategic sample selection
and human feedback integration.
Key Concepts Summary
Pattern Overview
The Active 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
- Agent Class: Main implementation of the pattern logic
- Prompt Engineering: Carefully crafted prompts to guide LLM behavior
- Tool Integration: Optional tools for extended functionality
- Memory Management: State handling across interactions
- 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
.envfiles 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
- Prompt Optimization: Minimize tokens while maintaining clarity
- Caching: Cache repeated queries/responses
- Model Selection: Use smaller models when appropriate
- Batch Processing: Group similar requests
- 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
- Monitoring: Add logging, metrics, tracing
- Validation: Input/output schema validation
- Rate Limiting: Implement request throttling
- Caching: Redis or in-memory cache for responses
- Async Support: Non-blocking operations for scalability
Feature Extensions
- Multi-Model Support: Switch between providers
- Fallback Models: Graceful degradation strategy
- Custom Tools: Domain-specific function calling
- Advanced Memory: Vector stores for long-term memory
- Evaluation: Automated testing and benchmarking
Code Quality
- Testing: Unit tests, integration tests
- Documentation: API docs, usage examples
- Type Safety: Stricter type hints
- Configuration: Externalized config files
Related Patterns
- Pattern 033
- Pattern 035
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 Active 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: 034_active_learning.py
Total Lines: 546
Pattern Category: AI Agent Design Pattern #034
Generated from actual implementation code
For educational and reference purposes
Leave a Reply