Enable users to add custom router implementations without modifying the core codebase.
New File: llmrouter/plugin_system.py
Features:
- π Automatic discovery of custom routers
- β Validation of router implementations
- π¦ Registration into the system
- π§ Support for multiple discovery strategies
Key Classes:
class PluginRegistry:
- discover_plugins(plugin_dir, verbose) # Discover plugins
- _load_router_from_directory() # Load router
- _validate_router_class() # Validate interface
- register_to_dict() # Register to dictionaryModified Files:
llmrouter/cli/router_inference.py(inference)llmrouter/cli/router_train.py(training)
Modifications: Added plugin discovery and registration code
# ============================================================================
# Plugin System Integration
# ============================================================================
from llmrouter.plugin_system import discover_and_register_plugins
plugin_registry = discover_and_register_plugins(verbose=False)
for router_name, router_class in plugin_registry.discovered_routers.items():
ROUTER_REGISTRY[router_name] = router_class
# ============================================================================- π
custom_routers/randomrouter/ - Function: Randomly select LLM
- Use: Baseline comparison
- π
custom_routers/thresholdrouter/ - Function: Route based on difficulty estimation
- Features: Complete training pipeline
- π
custom_routers/README.md- Quick start guide
LLMRouter/
β
βββ llmrouter/
β βββ plugin_system.py β NEW - Plugin system core
β βββ cli/
β β βββ router_inference.py π§ MODIFIED - Integrated plugins
β β βββ router_train.py π§ MODIFIED - Integrated plugins
β βββ models/
β βββ meta_router.py Existing base class
β
βββ custom_routers/ β NEW - Custom router directory
β βββ __init__.py
β βββ README.md β NEW - Usage guide
β β
β βββ randomrouter/ β NEW - Example 1
β β βββ __init__.py
β β βββ router.py Random routing implementation
β β βββ trainer.py Trainer (no-op)
β β βββ config.yaml Config example
β β
β βββ thresholdrouter/ β NEW - Example 2
β βββ __init__.py
β βββ router.py Difficulty estimation router
β βββ trainer.py Complete trainer
β βββ config.yaml (optional)
β
βββ tests/test_plugin_system.py β NEW - Test script
Automatic Search Paths:
1. ./custom_routers/ (project directory, recommended)
2. ~/.llmrouter/plugins/ (user directory)
3. $LLMROUTER_PLUGINS (environment variable)
Discovery Strategy:
- Scan subdirectories
- Look for
router.pyormodel.py - Find classes ending with
Router - Optionally load
Trainerclass fromtrainer.py
Must Implement:
class YourRouter(MetaRouter):
def __init__(self, yaml_path: str):
super().__init__(model=..., yaml_path=yaml_path)
def route_single(self, query_input: dict) -> dict:
# Return dict containing 'model_name'
pass
def route_batch(self, batch: list) -> list:
# Return list of results
passOptional (for training support):
class YourRouterTrainer(BaseTrainer):
def train(self) -> None:
# Training logic
passPrinciple:
- Use Python's dynamic imports
- Register to existing
ROUTER_REGISTRYat runtime - Zero modifications to existing code (only integration code added)
# custom_routers/my_router/router.py
from llmrouter.models.meta_router import MetaRouter
import torch.nn as nn
class MyRouter(MetaRouter):
def __init__(self, yaml_path: str):
model = nn.Identity()
super().__init__(model=model, yaml_path=yaml_path)
self.llm_names = list(self.llm_data.keys())
def route_single(self, query_input: dict) -> dict:
# Simple example: route based on query length
query = query_input['query']
if len(query) < 50:
selected = self.llm_names[0] # Short query -> small model
else:
selected = self.llm_names[-1] # Long query -> large model
return {
"query": query,
"model_name": selected,
"predicted_llm": selected,
}
def route_batch(self, batch: list) -> list:
return [self.route_single(q) for q in batch]# Inference
llmrouter infer --router my_router \
--config custom_routers/my_router/config.yaml \
--query "What is machine learning?"
# Training (if has trainer)
llmrouter train --router my_router \
--config custom_routers/my_router/config.yaml
# List all routers
llmrouter list-routersdef route_single(self, query_input):
query = query_input['query'].lower()
if 'code' in query:
return {"model_name": "code-specialist"}
elif len(query) < 50:
return {"model_name": "small-fast-model"}
else:
return {"model_name": "large-model"}from llmrouter.utils import get_longformer_embedding
def route_single(self, query_input):
embedding = get_longformer_embedding(query_input['query'])
similarity = self._compute_similarity(embedding)
best_model = max(similarity, key=similarity.get)
return {"model_name": best_model}def route_single(self, query_input):
difficulty = self._estimate_difficulty(query_input)
# Select cheapest model that can handle the difficulty
for model in sorted(self.llm_data.items(), key=lambda x: x[1]['cost']):
if model[1]['capability'] >= difficulty:
return {"model_name": model[0]}def route_single(self, query_input):
# Get predictions from multiple sub-routers
votes = [r.route_single(query_input) for r in self.sub_routers]
# Majority voting
from collections import Counter
model_counts = Counter(v['model_name'] for v in votes)
best_model = model_counts.most_common(1)[0][0]
return {"model_name": best_model}from custom_routers.my_router import MyRouter
router = MyRouter("custom_routers/my_router/config.yaml")
result = router.route_single({"query": "test"})
assert "model_name" in result# Route-only test
llmrouter infer --router my_router \
--config config.yaml \
--query "test" \
--route-only
# Complete test (including API call)
llmrouter infer --router my_router \
--config config.yaml \
--query "test" \
--verbosefrom llmrouter.plugin_system import discover_and_register_plugins
registry = discover_and_register_plugins(
plugin_dirs=['custom_routers'],
verbose=True # Show detailed discovery process
)- β No core code modifications
- β Only integration code added (5-10 lines)
- β Existing functionality completely unaffected
- β Automatic discovery
- β Automatic validation
- β Automatic registration
- β Multiple discovery paths supported
- β Both training and inference supported
- β Complex router implementations supported
- β Same usage as built-in routers
- β Rich examples and documentation
- β Clear error messages
llmrouter/plugin_system.py: ~400 lines- CLI integration code: ~30 lines (total)
- Example routers: ~600 lines
- Documentation: ~1000 lines
router_inference.py: +15 linesrouter_train.py: +15 lines
- New: ~2000 lines
- Modified: ~30 lines
- Invasiveness: Very Low
# Step 1: Create router directory
mkdir -p custom_routers/awesome_router
# Step 2: Implement router
cat > custom_routers/awesome_router/router.py << 'EOF'
from llmrouter.models.meta_router import MetaRouter
import torch.nn as nn
class AwesomeRouter(MetaRouter):
def __init__(self, yaml_path: str):
super().__init__(model=nn.Identity(), yaml_path=yaml_path)
self.llm_names = list(self.llm_data.keys())
def route_single(self, query_input: dict) -> dict:
# Your routing logic
return {
"query": query_input['query'],
"model_name": self.llm_names[0],
"predicted_llm": self.llm_names[0],
}
def route_batch(self, batch: list) -> list:
return [self.route_single(q) for q in batch]
EOF
# Step 3: Create configuration
cat > custom_routers/awesome_router/config.yaml << 'EOF'
data_path:
llm_data: 'data/example_data/llm_candidates/default_llm.json'
api_endpoint: 'https://integrate.api.nvidia.com/v1'
EOF
# Step 4: Use it!
llmrouter infer --router awesome_router \
--config custom_routers/awesome_router/config.yaml \
--query "Hello, world!"- Quick Start:
custom_routers/README.md - API Documentation: Inline documentation in
llmrouter/plugin_system.py
- π Read
custom_routers/README.md - π Check
RandomRouterexample (simplest) - π‘ Understand
ThresholdRouterexample (trainable) - π οΈ Create your own simple router
- π Gradually add complex features
- π Share with the community
- Plugin system core implementation
- CLI integration
- Simple example router (RandomRouter)
- Advanced example router (ThresholdRouter)
- Complete documentation
- Usage guide
- Test script
- Zero-invasive verification
With this plugin system, users can now:
- β Easy Extension - Create custom routers in minutes
- β Seamless Integration - Usage identical to built-in routers
- β Flexible Deployment - Multiple discovery paths and configuration
- β Rapid Iteration - No core code changes, quick experimentation
Core Value: Making LLMRouter a truly extensible framework! π
- GitHub Issues: https://github.com/ulab-uiuc/LLMRouter/issues
- Example Code:
custom_routers/ - Detailed Docs:
docs/CUSTOM_ROUTERS.md