Intelligent LLM routing with weighted least-outstanding selection, 429 cooldown, and request class isolation
Project description
llm-route
Intelligent LLM routing library for Python. Drop-in replacement for direct Azure OpenAI calls with automatic load balancing, 429 failover, and request class isolation.
Built as a minimal-dependency alternative to LiteLLM Router, focused on security and transparency.
Features
- Weighted least-outstanding routing — routes to the deployment with the lowest load relative to its capacity
- 429-aware cooldown — respects
Retry-Afterheaders, automatically fails over to the next backend - Request class isolation — separate concurrency budgets for light/medium/heavy requests prevent expensive operations from starving fast ones
- Token-aware capacity tracking — tracks actual token usage per deployment per minute window
- Request deadline — enforces a total timeout across all retry attempts
- Health reporting — exposes deployment health, inflight counts, 429 rates, and TPM usage
Install
pip install llm-route
Or with uv:
uv add llm-route
Quick Start
import asyncio
from llm_route import SmartRouter, RequestClass, RouterConfig
from llm_route.config import DeploymentConfig
config = RouterConfig(
deployments=[
DeploymentConfig(
name="eastus-1",
endpoint="https://my-resource.openai.azure.com/",
api_key="your-key",
deployment_name="gpt-4o",
tpm_quota=120_000,
),
],
)
router = SmartRouter(config=config)
async def main():
response = await router.complete(
messages=[{"role": "user", "content": "Hello"}],
request_class=RequestClass.LIGHT,
)
print(response.choices[0].message.content)
asyncio.run(main())
Configuration
JSON config file
{
"deployments": [
{
"name": "eastus-1",
"endpoint": "https://my-eastus-1.openai.azure.com/",
"api_key": "your-api-key",
"deployment_name": "gpt-4o",
"tpm_quota": 120000
},
{
"name": "eastus-2",
"endpoint": "https://my-eastus-2.openai.azure.com/",
"api_key": "your-api-key",
"deployment_name": "gpt-4o",
"tpm_quota": 60000
}
],
"default_timeout": 60.0,
"max_retries": 3,
"cooldown_seconds": 10.0,
"concurrency": {
"light": 20,
"medium": 10,
"heavy": 3
}
}
Load it:
config = RouterConfig.from_file("config.json")
router = SmartRouter(config=config)
Environment variables
All settings can be set via env vars with LLM_ROUTE_ prefix:
LLM_ROUTE_DEFAULT_TIMEOUT=60.0
LLM_ROUTE_MAX_RETRIES=3
LLM_ROUTE_COOLDOWN_SECONDS=10.0
Request Classes
Request classes provide concurrency isolation per deployment. Heavy requests (full document review) won't starve light ones (quick text search).
| Class | Default concurrency / deployment | Use case |
|---|---|---|
LIGHT |
20 | Short extraction, find-text, quick Q&A |
MEDIUM |
10 | Clause analysis, section review |
HEAVY |
3 | Full document review, redline, long synthesis |
await router.complete(
messages=[...],
request_class=RequestClass.HEAVY, # uses the heavy concurrency budget
)
How Routing Works
- Filter — remove disabled, cooled-down, and already-tried deployments
- Filter — remove deployments with no available concurrency for the request class
- Score —
inflight / weightwhereweight = tpm_quota / min_tpm. Lower is better. - Select — pick lowest score; break ties by remaining TPM headroom
- Execute — acquire semaphore, call Azure OpenAI with remaining deadline
- Failover — on 429 or 5xx, mark cooldown, try next deployment
- Deadline — if total timeout expires, raise
RouterExhaustedError
Health Monitoring
health = router.health()
for dep in health.deployments:
print(f"{dep.name}: healthy={dep.healthy}, inflight={dep.inflight}, "
f"tpm={dep.tpm_used}/{dep.tpm_quota}, 429s={dep.total_429s}")
Expose as a FastAPI endpoint:
@app.get("/health/llm")
async def llm_health():
return router.health().model_dump()
Dependencies
Minimal by design:
openai— Azure OpenAI SDKpydantic— data validationpydantic-settings— configuration management
Optional:
redis— shared state for multi-replica deployments (pip install llm-route[redis])
Security
This library was built in response to the LiteLLM supply chain attack (March 2026). Design principles:
- Minimal dependencies — 3 required packages, all well-maintained
- No build-time code execution — pure Python, no compiled extensions
uv.lockcommitted — exact dependency tree is auditable- OIDC publishing — no stored PyPI tokens in CI
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file llm_route-0.3.2.tar.gz.
File metadata
- Download URL: llm_route-0.3.2.tar.gz
- Upload date:
- Size: 31.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07532ca42acbc2e2653a4777f6a4d2987f14a933aa9cb834f31f3a6ea4843c66
|
|
| MD5 |
85a84751ff0615fbee67a907fe0b3ead
|
|
| BLAKE2b-256 |
1c2538959accd81422c7d648ccb21c9ed67c5be3f47297c453bd6ed0ff369cd0
|
Provenance
The following attestation bundles were made for llm_route-0.3.2.tar.gz:
Publisher:
publish.yml on aipro99/llm-route
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llm_route-0.3.2.tar.gz -
Subject digest:
07532ca42acbc2e2653a4777f6a4d2987f14a933aa9cb834f31f3a6ea4843c66 - Sigstore transparency entry: 1211000934
- Sigstore integration time:
-
Permalink:
aipro99/llm-route@eab5f71d939c13444cf242831dc26bf224984f1f -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/aipro99
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@eab5f71d939c13444cf242831dc26bf224984f1f -
Trigger Event:
release
-
Statement type:
File details
Details for the file llm_route-0.3.2-py3-none-any.whl.
File metadata
- Download URL: llm_route-0.3.2-py3-none-any.whl
- Upload date:
- Size: 19.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5bf262cf1670cc6666314c3de58908c63f6c08909b9f8526fec06832dccfa38
|
|
| MD5 |
ac96af72191149cb0a39c67d71b72001
|
|
| BLAKE2b-256 |
77a1b838c48db00740b8e43d4c368b6345c4d405df8c1f7cdcf1f1d5259f9c2d
|
Provenance
The following attestation bundles were made for llm_route-0.3.2-py3-none-any.whl:
Publisher:
publish.yml on aipro99/llm-route
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llm_route-0.3.2-py3-none-any.whl -
Subject digest:
d5bf262cf1670cc6666314c3de58908c63f6c08909b9f8526fec06832dccfa38 - Sigstore transparency entry: 1211001001
- Sigstore integration time:
-
Permalink:
aipro99/llm-route@eab5f71d939c13444cf242831dc26bf224984f1f -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/aipro99
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@eab5f71d939c13444cf242831dc26bf224984f1f -
Trigger Event:
release
-
Statement type: