"""
Pattern 122: Service Mesh Pattern
Description:
Infrastructure layer for agent-to-agent communication with service
discovery, load balancing, and observability.
Components:
- Service registry
- Load balancer
- Circuit breaker
- Observability layer
Use Cases:
- Large-scale distributed agents
- Microservices architecture
- Reliable communication
LangChain Implementation:
Implements service mesh concepts for agent communication management.
"""
import os
from typing import List, Dict, Any, Optional
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
import random
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 ServiceStatus(Enum):
"""Service health status."""
HEALTHY = "healthy"
DEGRADED = "degraded"
UNHEALTHY = "unhealthy"
@dataclass
class ServiceInstance:
"""Represents a service instance."""
id: str
name: str
host: str
port: int
status: ServiceStatus = ServiceStatus.HEALTHY
load: int = 0
max_capacity: int = 100
response_times: List[float] = None
def __post_init__(self):
if self.response_times is None:
self.response_times = []
class ServiceRegistry:
"""Service discovery and registration."""
def __init__(self):
self.services: Dict[str, List[ServiceInstance]] = {}
def register(self, service_name: str, instance: ServiceInstance):
"""Register a service instance."""
if service_name not in self.services:
self.services[service_name] = []
self.services[service_name].append(instance)
print(f"ā Registered {service_name} instance: {instance.id}")
def deregister(self, service_name: str, instance_id: str):
"""Deregister a service instance."""
if service_name in self.services:
self.services[service_name] = [
i for i in self.services[service_name] if i.id != instance_id
]
print(f"ā Deregistered {service_name} instance: {instance_id}")
def discover(self, service_name: str) -> List[ServiceInstance]:
"""Discover healthy instances of a service."""
instances = self.services.get(service_name, [])
return [i for i in instances if i.status == ServiceStatus.HEALTHY]
def get_all_services(self) -> List[str]:
"""Get list of all registered services."""
return list(self.services.keys())
class LoadBalancer:
"""Load balancing for service requests."""
def __init__(self, strategy: str = "least_loaded"):
self.strategy = strategy
def select_instance(self, instances: List[ServiceInstance]) -> Optional[ServiceInstance]:
"""Select an instance based on load balancing strategy."""
if not instances:
return None
if self.strategy == "round_robin":
return random.choice(instances)
elif self.strategy == "least_loaded":
return min(instances, key=lambda i: i.load)
elif self.strategy == "best_performance":
# Choose instance with best average response time
instances_with_times = [
i for i in instances if i.response_times
]
if instances_with_times:
return min(
instances_with_times,
key=lambda i: sum(i.response_times) / len(i.response_times)
)
return instances[0]
return instances[0]
class CircuitBreaker:
"""Circuit breaker for fault tolerance."""
def __init__(self, failure_threshold: int = 3, timeout: int = 60):
self.failure_threshold = failure_threshold
self.timeout = timeout
self.failures: Dict[str, int] = {}
self.open_circuits: Dict[str, datetime] = {}
def record_failure(self, service_id: str):
"""Record a service failure."""
self.failures[service_id] = self.failures.get(service_id, 0) + 1
if self.failures[service_id] >= self.failure_threshold:
self.open_circuits[service_id] = datetime.now()
print(f"ā Circuit opened for {service_id}")
def record_success(self, service_id: str):
"""Record a successful call."""
self.failures[service_id] = 0
if service_id in self.open_circuits:
del self.open_circuits[service_id]
print(f"ā Circuit closed for {service_id}")
def is_open(self, service_id: str) -> bool:
"""Check if circuit is open."""
if service_id in self.open_circuits:
# Check if timeout has passed
elapsed = (datetime.now() - self.open_circuits[service_id]).seconds
if elapsed > self.timeout:
del self.open_circuits[service_id]
return False
return True
return False
class ServiceMesh:
"""Service mesh for agent communication."""
def __init__(self, model_name: str = "gpt-4"):
self.registry = ServiceRegistry()
self.load_balancer = LoadBalancer(strategy="least_loaded")
self.circuit_breaker = CircuitBreaker()
self.llm = ChatOpenAI(model=model_name, temperature=0.3)
self.request_log: List[Dict[str, Any]] = []
def call_service(self, service_name: str, request_data: Dict[str, Any]) -> Dict[str, Any]:
"""Make a service call through the mesh."""
print(f"\nš Calling service: {service_name}")
# Discover instances
instances = self.registry.discover(service_name)
if not instances:
print(f" ā No healthy instances found")
return {"error": "ServiceUnavailable"}
# Select instance via load balancer
instance = self.load_balancer.select_instance(instances)
if not instance:
return {"error": "NoInstanceAvailable"}
# Check circuit breaker
if self.circuit_breaker.is_open(instance.id):
print(f" ā Circuit open for {instance.id}, trying another instance")
# Try another instance
instances.remove(instance)
if instances:
instance = self.load_balancer.select_instance(instances)
else:
return {"error": "AllCircuitsOpen"}
print(f" ā Routing to instance: {instance.id} (load: {instance.load})")
# Simulate service call
try:
start_time = datetime.now()
# Simulate processing
instance.load += 10
response_time = random.uniform(0.1, 0.5)
instance.response_times.append(response_time)
# Simulate occasional failures
if random.random() str:
"""Generate observability report."""
report_prompt = ChatPromptTemplate.from_messages([
("system", "Analyze service mesh metrics and provide insights."),
("user", """Request Log:
{log}
Service Registry:
{registry}
Provide:
1. Service health summary
2. Performance metrics
3. Bottlenecks identified
4. Recommendations""")
])
log_summary = "\n".join([
f"{r['service']}: {r['status']} ({r.get('response_time', 'N/A')}s)"
for r in self.request_log[-20:]
])
registry_summary = "\n".join([
f"{name}: {len(instances)} instances"
for name, instances in self.registry.services.items()
])
chain = report_prompt | self.llm | StrOutputParser()
return chain.invoke({
"log": log_summary,
"registry": registry_summary
})
def demonstrate_service_mesh():
"""Demonstrate service mesh pattern."""
print("=== Service Mesh Pattern ===\n")
mesh = ServiceMesh()
# Register services
print("1. Registering Service Instances")
print("-" * 50)
# Data processing service
mesh.registry.register("data-processor", ServiceInstance(
id="dp-1", name="data-processor", host="10.0.1.1", port=8001
))
mesh.registry.register("data-processor", ServiceInstance(
id="dp-2", name="data-processor", host="10.0.1.2", port=8001
))
mesh.registry.register("data-processor", ServiceInstance(
id="dp-3", name="data-processor", host="10.0.1.3", port=8001
))
# Analytics service
mesh.registry.register("analytics", ServiceInstance(
id="an-1", name="analytics", host="10.0.2.1", port=8002
))
mesh.registry.register("analytics", ServiceInstance(
id="an-2", name="analytics", host="10.0.2.2", port=8002
))
print()
# Make service calls
print("2. Making Service Calls Through Mesh")
print("-" * 50)
for i in range(10):
result = mesh.call_service("data-processor", {"data": f"request_{i}"})
for i in range(5):
result = mesh.call_service("analytics", {"query": f"query_{i}"})
# Observability
print("\n3. Service Mesh Observability")
print("-" * 50)
print(f"Total requests: {len(mesh.request_log)}")
successful = sum(1 for r in mesh.request_log if r['status'] == 'success')
print(f"Successful: {successful}")
print(f"Failed: {len(mesh.request_log) - successful}")
print(f"Success rate: {successful/len(mesh.request_log)*100:.1f}%")
# Generate report
print("\n4. Detailed Observability Report")
print("-" * 50)
report = mesh.get_observability_report()
print(report)
print("\n=== Summary ===")
print("Service mesh demonstrated with:")
print("- Service discovery and registration")
print("- Load balancing (least loaded strategy)")
print("- Circuit breaker pattern")
print("- Request routing")
print("- Health monitoring")
print("- Observability and metrics")
if __name__ == "__main__":
demonstrate_service_mesh()
Agentic Design Pattern: Service Mesh Pattern
Pattern 122: Service Mesh Pattern – Line-by-Line Explanation
Overview
This document provides a detailed line-by-line explanation of the Service Mesh Pattern pattern implementation.
Pattern Description
Pattern 122: Service Mesh Pattern
Description: Infrastructure layer for agent-to-agent communication with service discovery, load balancing, and observability.
Components: – Service registry – Load balancer – Circuit breaker – Observability layer
Use Cases: – Large-scale distributed agents – Microservices architecture – Reliable communication
LangChain Implementation: Implements service mesh concepts for agent communication management.
File Statistics
- Total Lines: 355
- Classes: 6
- Functions: 1
- Constants: 0
Module Documentation
"""
Pattern 122: Service Mesh Pattern
Description:
Infrastructure layer for agent-to-agent communication with service
discovery, load balancing, and observability.
Components:
- Service registry
- Load balancer
- Circuit breaker
- Observability layer
Use Cases:
- Large-scale distributed agents
- Microservices architecture
- Reliable communication
LangChain Implementation:
Implements service mesh concepts for agent communication management.
"""
Purpose: This module implements the Service Mesh Pattern pattern, providing a structured approach to agent design and implementation.
Import Statements
Standard Library Imports
import dataclasses.dataclass
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
Purpose: Core Python functionality:
– dataclasses.dataclass: 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)
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: ServiceStatus
Lines 38-42
Inherits from: Enum
Purpose:
Service health status.
Class: ServiceInstance
Lines 46-59
Purpose:
Represents a service instance.
Methods:
__post_init__(self)
Lines 57-59
Purpose: Post Init operation.
Parameters:
Class: ServiceRegistry
Lines 62-90
Purpose:
Service discovery and registration.
Methods:
__init__(self)
Lines 65-66
Purpose: Initialize the class instance with required parameters.
Parameters:
register(self, service_name, instance)
Lines 68-73
Purpose:
Register a service instance.
Parameters:
– service_name: Service name
– instance: Instance
deregister(self, service_name, instance_id)
Lines 75-81
Purpose:
Deregister a service instance.
Parameters:
– service_name: Service name
– instance_id: Instance id
discover(self, service_name)
Lines 83-86
Purpose:
Discover healthy instances of a service.
Parameters:
– service_name: Service name
Returns: <ast.Subscript object at 0x000001A06D718710>
get_all_services(self)
Lines 88-90
Purpose:
Get list of all registered services.
Parameters:
Returns: <ast.Subscript object at 0x000001A06D71B2D0>
Class: LoadBalancer
Lines 93-122
Purpose:
Load balancing for service requests.
Methods:
__init__(self, strategy)
Lines 96-97
Purpose: Initialize the class instance with required parameters.
Parameters:
– strategy: Strategy
select_instance(self, instances)
Lines 99-122
Purpose:
Select an instance based on load balancing strategy.
Parameters:
– instances: Instances
Returns: <ast.Subscript object at 0x000001A06D8271D0>
Class: CircuitBreaker
Lines 125-158
Purpose:
Circuit breaker for fault tolerance.
Methods:
__init__(self, failure_threshold, timeout)
Lines 128-132
Purpose: Initialize the class instance with required parameters.
Parameters:
– failure_threshold: Failure threshold
– timeout: Timeout
record_failure(self, service_id)
Lines 134-140
Purpose:
Record a service failure.
Parameters:
– service_id: Service id
record_success(self, service_id)
Lines 142-147
Purpose:
Record a successful call.
Parameters:
– service_id: Service id
is_open(self, service_id)
Lines 149-158
Purpose:
Check if circuit is open.
Parameters:
– service_id: Service id
Returns: bool
Class: ServiceMesh
Lines 161-283
Purpose:
Service mesh for agent communication.
Methods:
__init__(self, model_name)
Lines 164-169
Purpose: Initialize the class instance with required parameters.
Parameters:
– model_name: Language model instance
call_service(self, service_name, request_data)
Lines 171-250
Purpose:
Make a service call through the mesh.
Parameters:
– service_name: Service name
– request_data: Request data
Returns: <ast.Subscript object at 0x000001A06D64B650>
get_observability_report(self)
Lines 252-283
Purpose:
Generate observability report.
Parameters:
Returns: str
Functions
demonstrate_service_mesh()
Lines 286-350
Purpose:
Demonstrate service mesh pattern.
Key Concepts Summary
Pattern Overview
The Service Mesh Pattern 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 121
- Pattern 123
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 Service Mesh Pattern 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: 122_service_mesh_pattern.py
Total Lines: 355
Pattern Category: AI Agent Design Pattern #122
Generated from actual implementation code
For educational and reference purposes
Leave a Reply