Getting Started
Configuration
Advanced configuration options for LLM providers, retrieval systems, and MCP services
Configuration
MRRA provides flexible configuration options for LLM providers, retrieval systems, caching, and MCP services. This guide covers all configuration aspects in detail.
LLM Provider Configuration
Supported Providers
MRRA supports multiple LLM providers through a unified interface:
# OpenAI Configuration
openai_cfg = dict(
provider='openai',
model='gpt-4o-mini', # or gpt-4, gpt-3.5-turbo
api_key='your-openai-api-key',
temperature=0.2,
max_tokens=1000,
timeout=60
)
# With custom base URL (for proxies)
openai_proxy_cfg = dict(
provider='openai',
model='gpt-4o-mini',
api_key='your-api-key',
base_url='https://your-proxy.com/v1',
temperature=0.2
)# Qwen Configuration (Alibaba DashScope)
qwen_cfg = dict(
provider='openai-compatible', # Use OpenAI-compatible interface
model='qwen-plus', # or qwen-turbo, qwen-max
base_url='https://dashscope.aliyuncs.com/compatible-mode/v1',
api_key='your-dashscope-api-key',
temperature=0.2,
max_tokens=2000
)
# Alternative direct configuration
qwen_direct_cfg = dict(
provider='qwen',
model='qwen-plus',
api_key='your-dashscope-api-key',
temperature=0.2
)# SiliconFlow Configuration
siliconflow_cfg = dict(
provider='openai-compatible',
model='deepseek-chat', # or other available models
base_url='https://api.siliconflow.cn/v1',
api_key='your-siliconflow-api-key',
temperature=0.2,
max_tokens=1500
)# DeepInfra Configuration
deepinfra_cfg = dict(
provider='openai-compatible',
model='meta-llama/Meta-Llama-3.1-8B-Instruct',
base_url='https://api.deepinfra.com/v1/openai',
api_key='your-deepinfra-api-key',
temperature=0.2,
max_tokens=2000
)# Custom Provider Configuration
custom_cfg = dict(
provider='openai-compatible', # Use OpenAI-compatible interface
model='your-model-name',
base_url='https://your-api-endpoint.com/v1',
api_key='your-api-key',
headers={'Custom-Header': 'value'}, # Optional custom headers
temperature=0.2,
max_tokens=1000,
timeout=120
)Environment Variable Configuration
Set up environment variables for secure configuration:
# OpenAI
export MRRA_OPENAI_API_KEY="your-openai-key"
export MRRA_OPENAI_MODEL="gpt-4o-mini"
# Qwen
export MRRA_QWEN_API_KEY="your-dashscope-key"
export MRRA_QWEN_MODEL="qwen-plus"
# SiliconFlow
export MRRA_SILICONFLOW_API_KEY="your-siliconflow-key"
# Default provider
export MRRA_DEFAULT_PROVIDER="openai"
export MRRA_DEFAULT_MODEL="gpt-4o-mini"Use environment variables in configuration:
import os
def create_llm_config_from_env():
"""Create LLM configuration from environment variables"""
provider = os.getenv('MRRA_DEFAULT_PROVIDER', 'openai')
if provider == 'openai':
return dict(
provider='openai',
model=os.getenv('MRRA_OPENAI_MODEL', 'gpt-4o-mini'),
api_key=os.getenv('MRRA_OPENAI_API_KEY'),
temperature=float(os.getenv('MRRA_TEMPERATURE', '0.2'))
)
elif provider == 'qwen':
return dict(
provider='openai-compatible',
model=os.getenv('MRRA_QWEN_MODEL', 'qwen-plus'),
base_url='https://dashscope.aliyuncs.com/compatible-mode/v1',
api_key=os.getenv('MRRA_QWEN_API_KEY'),
temperature=float(os.getenv('MRRA_TEMPERATURE', '0.2'))
)
else:
raise ValueError(f"Unsupported provider: {provider}")
# Usage
llm_cfg = create_llm_config_from_env()Activity Extraction Configuration
Parameter Guidelines
Configure activity extraction based on your data characteristics:
# Default configuration for urban mobility
default_cfg = dict(
method="radius", # 'radius' or 'grid'
radius_m=300, # Detection radius in meters
min_dwell_minutes=30, # Minimum stay time
max_gap_minutes=90, # Max gap between points
grid_size_m=200 # Grid cell size (for grid method)
)
# Configuration for different scenarios
scenarios = {
'urban_detailed': dict(
method="radius",
radius_m=200, # Smaller radius for dense urban areas
min_dwell_minutes=20, # Shorter minimum dwell
max_gap_minutes=60, # Tighter gap tolerance
grid_size_m=150
),
'suburban': dict(
method="radius",
radius_m=500, # Larger radius for suburban areas
min_dwell_minutes=45, # Longer dwell times
max_gap_minutes=120, # More tolerance for gaps
grid_size_m=300
),
'sparse_data': dict(
method="grid", # Grid method more robust for sparse data
radius_m=800,
min_dwell_minutes=15, # Lower threshold for sparse data
max_gap_minutes=180, # Higher tolerance
grid_size_m=500
),
'high_frequency': dict(
method="radius",
radius_m=100, # Very fine-grained for high-frequency data
min_dwell_minutes=10, # Short dwells for frequent sampling
max_gap_minutes=30, # Tight gaps
grid_size_m=100
)
}
# Select based on your data type
data_type = 'urban_detailed' # Change as needed
ext_cfg = scenarios[data_type]
acts = ActivityExtractor(tb, **ext_cfg).extract()Adaptive Configuration
Automatically configure based on data analysis:
def auto_configure_extraction(tb):
"""Automatically configure extraction based on trajectory characteristics"""
df = tb.df
# Analyze data characteristics
avg_points_per_user = len(df) / df['user_id'].nunique()
time_span = (df['timestamp_local'].max() - df['timestamp_local'].min()).total_seconds() / 3600 # hours
# Calculate typical sampling frequency
sampling_freq_minutes = time_span * 60 / len(df) if len(df) > 0 else 60
# Estimate typical movement distances
distances = []
for user_id in df['user_id'].unique()[:5]: # Sample first 5 users
user_df = df[df['user_id'] == user_id].sort_values('timestamp_local')
for i in range(1, min(100, len(user_df))): # Sample up to 100 points
prev = user_df.iloc[i-1]
curr = user_df.iloc[i]
lat_diff = curr['latitude'] - prev['latitude']
lon_diff = curr['longitude'] - prev['longitude']
distance = ((lat_diff**2 + lon_diff**2)**0.5) * 111000 # Approximate meters
distances.append(distance)
median_distance = sorted(distances)[len(distances)//2] if distances else 300
# Configure based on analysis
if avg_points_per_user > 2000 and sampling_freq_minutes < 5:
# High-frequency data
config = dict(
method="radius",
radius_m=max(100, median_distance * 0.5),
min_dwell_minutes=max(5, sampling_freq_minutes * 2),
max_gap_minutes=max(30, sampling_freq_minutes * 10),
grid_size_m=max(100, median_distance * 0.3)
)
elif avg_points_per_user < 200:
# Sparse data
config = dict(
method="grid",
radius_m=max(500, median_distance * 2),
min_dwell_minutes=max(15, sampling_freq_minutes * 0.5),
max_gap_minutes=max(120, sampling_freq_minutes * 5),
grid_size_m=max(300, median_distance * 1.5)
)
else:
# Standard data
config = dict(
method="radius",
radius_m=max(200, median_distance),
min_dwell_minutes=max(20, sampling_freq_minutes),
max_gap_minutes=max(60, sampling_freq_minutes * 3),
grid_size_m=max(150, median_distance * 0.7)
)
print(f"Auto-configured extraction parameters: {config}")
print(f"Based on: {avg_points_per_user:.0f} avg points/user, {sampling_freq_minutes:.1f}min sampling, {median_distance:.0f}m median distance")
return config
# Use adaptive configuration
ext_cfg = auto_configure_extraction(tb)
acts = ActivityExtractor(tb, **ext_cfg).extract()Graph Configuration
Graph Construction Options
from mrra.graph.mobility_graph import GraphConfig
# Basic configuration
basic_cfg = GraphConfig(
grid_size_m=200, # Grid cell size
min_dwell_minutes=5, # Minimum dwell for graph nodes
use_activities=True # Use activity-based construction
)
# Advanced configuration
advanced_cfg = GraphConfig(
grid_size_m=200,
min_dwell_minutes=5,
use_activities=True,
include_transitions=True, # Include location-to-location edges
purpose_transitions=True, # Include purpose-to-purpose edges
temporal_granularity='both', # 'hour', 'timebin', or 'both'
weight_by_duration=True, # Weight edges by time spent
max_edge_weight=1000, # Cap edge weights
normalize_weights=True # Normalize edge weights
)
# Memory-optimized configuration for large datasets
memory_optimized_cfg = GraphConfig(
grid_size_m=500, # Larger grid reduces node count
min_dwell_minutes=10, # Higher threshold reduces edges
use_activities=True,
include_transitions=False, # Skip transition edges to save memory
purpose_transitions=False,
temporal_granularity='hour', # Use only hour nodes, not time bins
max_nodes=10000 # Limit total nodes
)Retrieval Configuration
Configure GraphRAG retrieval weights and parameters:
from mrra.retriever.graph_rag import GraphRAGGenerate
# Create retriever with custom weights
retriever = GraphRAGGenerate(tb=tb, mobility_graph=mg)
# Configure retrieval weights
retriever.purpose_weight = 0.6 # How much to weight purpose context
retriever.hour_weight = 0.5 # How much to weight hour context
retriever.dow_weight = 0.3 # How much to weight day-of-week
retriever.recent_weight = 0.2 # How much to weight recent locations
retriever.user_weight = 1.0 # How much to weight user context
# Configure retrieval parameters
retriever.max_results = 50 # Maximum locations to consider
retriever.min_score_threshold = 0.01 # Minimum relevance score
retriever.diversification_factor = 0.3 # Diversify results (0=no diversification, 1=maximum)
# Task-specific configurations
task_configs = {
'next_position': {
'purpose_weight': 0.4,
'hour_weight': 0.6,
'dow_weight': 0.4,
'recent_weight': 0.8, # High weight on recent context
},
'future_position': {
'purpose_weight': 0.6,
'hour_weight': 0.5,
'dow_weight': 0.3,
'recent_weight': 0.3, # Lower weight on recent context
},
'full_day_traj': {
'purpose_weight': 0.7, # High weight on purpose patterns
'hour_weight': 0.4,
'dow_weight': 0.5,
'recent_weight': 0.2,
}
}
def configure_retriever_for_task(retriever, task):
"""Configure retriever weights based on prediction task"""
if task in task_configs:
config = task_configs[task]
for param, value in config.items():
setattr(retriever, param, value)
return retrieverCache Configuration
Cache Directory and Settings
from mrra.persist.cache import CacheManager
# Default cache configuration
default_cache = CacheManager() # Uses .mrra_cache/
# Custom cache directory
custom_cache = CacheManager(base_dir='/path/to/custom/cache')
# Environment-based cache configuration
import os
cache_dir = os.getenv('MRRA_CACHE_DIR', '.mrra_cache')
cache_manager = CacheManager(base_dir=cache_dir)Cache Settings and Policies
class ConfigurableCacheManager(CacheManager):
def __init__(self, base_dir=None, settings=None):
super().__init__(base_dir)
# Default settings
self.settings = {
'max_cache_size_gb': 5.0, # Maximum cache size
'default_ttl_hours': 24, # Time-to-live for cached items
'cleanup_interval_hours': 6, # How often to run cleanup
'compression_level': 6, # Compression level (0-9)
'enable_compression': True, # Enable cache compression
'max_activities_per_cache': 10000, # Limit activities per cache file
'auto_cleanup_expired': True, # Automatically clean expired items
}
if settings:
self.settings.update(settings)
def save_activities(self, tb_hash, key, activities):
"""Save activities with size limiting"""
# Limit activities if too many
if len(activities) > self.settings['max_activities_per_cache']:
print(f"Limiting activities to {self.settings['max_activities_per_cache']}")
activities = activities[:self.settings['max_activities_per_cache']]
# Check cache size before saving
if self._get_cache_size_gb() > self.settings['max_cache_size_gb']:
print("Cache size limit exceeded, cleaning up...")
self._cleanup_old_files()
# Save with compression if enabled
if self.settings['enable_compression']:
self._save_activities_compressed(tb_hash, key, activities)
else:
super().save_activities(tb_hash, key, activities)
def _get_cache_size_gb(self):
"""Calculate total cache size in GB"""
import os
total_size = 0
for root, dirs, files in os.walk(self.base_dir):
for file in files:
file_path = os.path.join(root, file)
if os.path.exists(file_path):
total_size += os.path.getsize(file_path)
return total_size / (1024**3) # Convert to GB
# Use configurable cache
cache_settings = {
'max_cache_size_gb': 10.0,
'default_ttl_hours': 48,
'enable_compression': True
}
cache_manager = ConfigurableCacheManager(settings=cache_settings)Multi-Agent Reflection Configuration
Agent Configuration Templates
# Template configurations for different use cases
agent_templates = {
'basic': dict(
max_round=1,
subAgents=[
{"name": "temporal", "prompt": "Focus on time patterns and select from Options."},
{"name": "spatial", "prompt": "Focus on location patterns and select from Options."},
],
aggregator="confidence_weighted_voting"
),
'comprehensive': dict(
max_round=2,
subAgents=[
{"name": "temporal", "prompt": "Analyze time patterns including hour-of-day and day-of-week preferences."},
{"name": "spatial", "prompt": "Analyze spatial patterns including clustering and accessibility."},
{"name": "purpose", "prompt": "Analyze activity purposes and sequential logic."},
{"name": "routing", "prompt": "Analyze movement efficiency and transition patterns."},
],
aggregator="confidence_weighted_voting",
consensus_threshold=0.6
),
'mcp_enhanced': dict(
max_round=1,
subAgents=[
{
"name": "context_aware",
"prompt": "Use external context (weather, POIs, traffic) for location selection.",
"mcp": {
"weather": {},
"maps": {},
}
},
{
"name": "pattern_based",
"prompt": "Focus on historical patterns and user preferences."
}
],
aggregator="confidence_weighted_voting"
),
'fast': dict(
max_round=1,
subAgents=[
{"name": "combined", "prompt": "Consider all factors quickly and select from Options."}
],
aggregator="simple_selection"
)
}
def get_agent_config(template_name, custom_overrides=None):
"""Get agent configuration from template with optional overrides"""
if template_name not in agent_templates:
raise ValueError(f"Unknown template: {template_name}")
config = agent_templates[template_name].copy()
if custom_overrides:
config.update(custom_overrides)
return config
# Usage
config = get_agent_config('comprehensive', {
'max_round': 1, # Override to speed up
'consensus_threshold': 0.8 # Require higher consensus
})Configuration Validation
def validate_mrra_config(config):
"""Validate MRRA configuration and suggest improvements"""
issues = []
suggestions = []
# Check LLM configuration
if 'llm' in config:
llm_cfg = config['llm']
if not llm_cfg.get('api_key'):
issues.append("LLM API key not provided")
if llm_cfg.get('temperature', 0.2) > 0.8:
suggestions.append("High temperature may cause inconsistent results")
if llm_cfg.get('max_tokens', 1000) > 4000:
suggestions.append("High max_tokens may increase costs and latency")
# Check extraction configuration
if 'extraction' in config:
ext_cfg = config['extraction']
if ext_cfg.get('radius_m', 300) < 50:
suggestions.append("Very small radius may miss activities")
if ext_cfg.get('min_dwell_minutes', 30) > 120:
suggestions.append("High minimum dwell may miss short activities")
# Check agent configuration
if 'reflection' in config:
refl_cfg = config['reflection']
if len(refl_cfg.get('subAgents', [])) > 5:
suggestions.append("Many sub-agents may increase latency and costs")
if refl_cfg.get('max_round', 1) > 3:
suggestions.append("Many reflection rounds may be slow and expensive")
return {
'valid': len(issues) == 0,
'issues': issues,
'suggestions': suggestions
}
# Example complete configuration
complete_config = {
'llm': {
'provider': 'openai',
'model': 'gpt-4o-mini',
'temperature': 0.2,
'max_tokens': 1000
},
'extraction': {
'method': 'radius',
'radius_m': 300,
'min_dwell_minutes': 30
},
'graph': {
'grid_size_m': 200,
'use_activities': True
},
'retrieval': {
'purpose_weight': 0.6,
'hour_weight': 0.5
},
'reflection': {
'max_round': 1,
'subAgents': [
{"name": "temporal", "prompt": "Focus on time patterns."},
{"name": "spatial", "prompt": "Focus on location patterns."}
]
},
'cache': {
'base_dir': '.mrra_cache',
'max_size_gb': 5.0
}
}
validation = validate_mrra_config(complete_config)
print("Configuration validation:", validation)Configuration Best Practices:
- Start with default configurations and adjust based on your data characteristics
- Use environment variables for sensitive information like API keys
- Validate configurations before running expensive operations
- Monitor performance and adjust parameters accordingly
- Use caching extensively to avoid recomputation
Production Configuration
Scalable Configuration Management
import yaml
import os
from pathlib import Path
class MRRAConfigManager:
"""Production-ready configuration management"""
def __init__(self, config_file=None):
self.config_file = config_file or os.getenv('MRRA_CONFIG_FILE', 'mrra_config.yaml')
self.config = self._load_config()
def _load_config(self):
"""Load configuration from file with environment variable substitution"""
if not Path(self.config_file).exists():
return self._create_default_config()
with open(self.config_file, 'r') as f:
config = yaml.safe_load(f)
# Substitute environment variables
return self._substitute_env_vars(config)
def _substitute_env_vars(self, config):
"""Recursively substitute environment variables in configuration"""
if isinstance(config, dict):
return {k: self._substitute_env_vars(v) for k, v in config.items()}
elif isinstance(config, list):
return [self._substitute_env_vars(item) for item in config]
elif isinstance(config, str) and config.startswith('${') and config.endswith('}'):
env_var = config[2:-1] # Remove ${ and }
default_value = None
if ':' in env_var:
env_var, default_value = env_var.split(':', 1)
return os.getenv(env_var, default_value)
else:
return config
def _create_default_config(self):
"""Create default configuration"""
default_config = {
'llm': {
'provider': '${MRRA_LLM_PROVIDER:openai}',
'model': '${MRRA_LLM_MODEL:gpt-4o-mini}',
'api_key': '${MRRA_API_KEY}',
'temperature': 0.2,
'max_tokens': 1000,
'timeout': 60
},
'extraction': {
'method': 'radius',
'radius_m': 300,
'min_dwell_minutes': 30,
'max_gap_minutes': 90
},
'graph': {
'grid_size_m': 200,
'min_dwell_minutes': 5,
'use_activities': True
},
'retrieval': {
'purpose_weight': 0.6,
'hour_weight': 0.5,
'dow_weight': 0.3,
'recent_weight': 0.2
},
'cache': {
'base_dir': '${MRRA_CACHE_DIR:.mrra_cache}',
'max_size_gb': 5.0,
'default_ttl_hours': 24
}
}
# Save default config
with open(self.config_file, 'w') as f:
yaml.dump(default_config, f, default_flow_style=False)
return self._substitute_env_vars(default_config)
def get(self, key, default=None):
"""Get configuration value with dot notation"""
keys = key.split('.')
value = self.config
for k in keys:
if isinstance(value, dict) and k in value:
value = value[k]
else:
return default
return value
def get_llm_config(self):
"""Get LLM configuration"""
return self.config.get('llm', {})
def get_extraction_config(self):
"""Get extraction configuration"""
return self.config.get('extraction', {})
# Usage
config_manager = MRRAConfigManager('production_config.yaml')
# Get configurations
llm_cfg = config_manager.get_llm_config()
ext_cfg = config_manager.get_extraction_config()
cache_dir = config_manager.get('cache.base_dir', '.mrra_cache')Example production configuration file (mrra_config.yaml):
# MRRA Production Configuration
llm:
provider: ${MRRA_LLM_PROVIDER:openai}
model: ${MRRA_LLM_MODEL:gpt-4o-mini}
api_key: ${MRRA_API_KEY}
temperature: 0.2
max_tokens: 1000
timeout: 120
extraction:
method: radius
radius_m: 300
min_dwell_minutes: 30
max_gap_minutes: 90
grid_size_m: 200
graph:
grid_size_m: 200
min_dwell_minutes: 5
use_activities: true
include_transitions: true
purpose_transitions: true
retrieval:
purpose_weight: 0.6
hour_weight: 0.5
dow_weight: 0.3
recent_weight: 0.2
max_results: 50
reflection:
max_round: 1
aggregator: confidence_weighted_voting
subAgents:
- name: temporal
prompt: "Focus on temporal patterns and select from Options."
temperature: 0.1
- name: spatial
prompt: "Focus on spatial patterns and select from Options."
temperature: 0.1
cache:
base_dir: ${MRRA_CACHE_DIR:.mrra_cache}
max_size_gb: 10.0
default_ttl_hours: 48
enable_compression: true
auto_cleanup: true
logging:
level: ${MRRA_LOG_LEVEL:INFO}
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"Security Considerations:
- Never commit API keys or sensitive data to version control
- Use environment variables for all secrets
- Implement proper access controls for configuration files
- Regularly rotate API keys and update configurations
Next Steps
- Explore Examples for real-world configuration usage
- Learn about Development for advanced configuration options
- Check Troubleshooting for configuration-related issues