Router
TLiteLLMRouter provides multi-deployment routing with load balancing, automatic failover, rate limiting, and fallback chains. Use it when you have multiple API keys, endpoints, or want automatic failover between providers.
Basic Setup
var
LLM: TLiteLLM;
D: TLLMDeployment;
begin
LLM := TLiteLLM.Create;
// Deployment 1: primary OpenAI endpoint
FillCharFast(D, SizeOf(D), 0);
D.ModelName := 'gpt-4o'; // logical name for routing
D.ModelId := 'gpt4o-key1'; // unique deployment ID
D.Provider := 'openai';
D.ApiKey := 'sk-key-1';
D.ApiBase := 'https://api.openai.com/v1';
D.Model := 'gpt-4o'; // actual model name for API
D.Rpm := 100; // requests per minute limit
D.Weight := 2; // higher weight = more traffic
LLM.AddDeployment(D);
// Deployment 2: secondary OpenAI endpoint (different key)
D.ModelId := 'gpt4o-key2';
D.ApiKey := 'sk-key-2';
D.Weight := 1;
LLM.AddDeployment(D);
// Route: picks best healthy deployment
Response := LLM.RouterChat('gpt-4o', Messages, Tools);
end;
TLLMDeployment Record
TLLMDeployment = packed record
// --- Configuration (set by you) ---
ModelName: RawUtf8; // logical model name (used for routing lookup)
ModelId: RawUtf8; // unique deployment identifier
Provider: RawUtf8; // 'openai', 'anthropic', 'gemini'
ApiKey: RawUtf8; // API key for this deployment
ApiBase: RawUtf8; // base URL (e.g. 'https://api.openai.com/v1')
Model: RawUtf8; // actual model name sent to the API
Tpm: Integer; // tokens per minute limit (0 = unlimited)
Rpm: Integer; // requests per minute limit (0 = unlimited)
Weight: Integer; // weight for shuffle strategy (default 1)
// --- Runtime state (managed by router) ---
CooldownUntil: Int64; // UnixTimeUtc when cooldown expires
FailCount: Integer; // consecutive failures
TotalLatencyMs: Int64; // total latency across all requests
RequestCount: Int64; // total request count
end;
Runtime fields are automatically managed by the router. Initialize them to 0 or use FillCharFast.
Routing Strategies
Set the strategy via LLM.Router.Strategy:
rsSimpleShuffle (default)
Weighted random selection. Each deployment's Weight determines its probability of being chosen. With weights 2 and 1, the first deployment gets ~67% of traffic.
rsLowestLatency
Selects the deployment with the lowest average latency (TotalLatencyMs / RequestCount). Only deployments with RequestCount > 0 are compared; if all deployments have zero requests, the first one is selected.
rsLowestCost
Selects the deployment whose model has the lowest InputCostPerToken (from TLiteLLMCostTracker). Useful when mixing expensive and cheap models under the same logical name.
rsLeastBusy
Selects the deployment with the lowest RequestCount. Distributes load evenly.
rsUsageBased
Selects the deployment with the lowest RequestCount among those with Tpm > 0. Useful for preferring deployments that have defined token limits. Note: this strategy does not perform actual TPM accounting — it uses RequestCount as a proxy for usage.
LLM.Router.Strategy := rsLowestLatency;
Cooldown
When a deployment fails with any ELiteLLM error, the router applies a cooldown (via MarkFailed). Only retryable errors (429, 500+) proceed to try the next deployment; non-retryable errors (400, 401, 404) are re-raised immediately after cooldown is applied:
LLM.Router.CooldownSeconds := 60; // default
During cooldown, the deployment is excluded from selection. After cooldown expires, it becomes eligible again. The FailCount is reset to 0 on the next successful request.
Rate Limiting
The router tracks per-minute request counts and enforces RPM limits:
D.Rpm := 60; // max 60 requests per minute for this deployment
The rate counter uses a fixed minute bucket (UnixTimeUtc div 60). Deployments that have reached their RPM limit are excluded from the healthy pool.
TPM (tokens per minute) limits are defined but only used as a filter for rsUsageBased strategy (deployments with Tpm > 0 are preferred). TPM is not actively tracked or enforced — only RPM is tracked per-minute.
Fallback Chains
Define fallback models to try when the primary model has no healthy deployments:
// If gpt-4o has no healthy deployments, try gpt-4o-mini, then claude
LLM.Router.SetFallbacks('gpt-4o',
TRawUtf8DynArray.Create('gpt-4o-mini', 'claude-sonnet'));
The router tries models in order: primary first, then each fallback. For each model, it selects a healthy deployment and attempts the request. If all deployments for a model are in cooldown or rate-limited, it moves to the next fallback model.
Retry Logic
LLM.Router.MaxRetries := 3; // default: 3 attempts per model
Within each model, the router retries up to MaxRetries times across different healthy deployments. A failed deployment is removed from the healthy pool for that request (and put on cooldown for future requests).
Non-retryable errors (400, 401, 404) are raised immediately without trying other deployments.
Full Example
var
LLM: TLiteLLM;
D: TLLMDeployment;
Response: TLLMResponse;
begin
LLM := TLiteLLM.Create;
try
// OpenAI deployments
FillCharFast(D, SizeOf(D), 0);
D.ModelName := 'smart-model';
D.Provider := 'openai';
D.ApiBase := 'https://api.openai.com/v1';
D.Rpm := 60;
D.ModelId := 'openai-1';
D.ApiKey := 'sk-key1';
D.Model := 'gpt-4o';
D.Weight := 3;
LLM.AddDeployment(D);
D.ModelId := 'openai-2';
D.ApiKey := 'sk-key2';
D.Model := 'gpt-4o';
D.Weight := 1;
LLM.AddDeployment(D);
// Gemini fallback
D.ModelName := 'smart-model-fallback';
D.ModelId := 'gemini-fb';
D.Provider := 'gemini';
D.ApiBase := 'https://generativelanguage.googleapis.com/v1beta';
D.ApiKey := 'AIza...';
D.Model := 'gemini-2.5-flash';
D.Rpm := 100;
D.Weight := 1;
LLM.AddDeployment(D);
// Fallback chain
LLM.Router.SetFallbacks('smart-model',
TRawUtf8DynArray.Create('smart-model-fallback'));
// Configure
LLM.Router.Strategy := rsLowestLatency;
LLM.Router.CooldownSeconds := 30;
LLM.Router.MaxRetries := 2;
// Use
Response := LLM.RouterChat('smart-model', Messages, Tools);
WriteLn('Served by: ', Response.Model);
WriteLn('Cost: $', FormatFloat('0.000000', Response.Cost));
finally
LLM.Free;
end;
end;
Thread Safety
The router uses TLightLock for all deployment and rate counter operations. Multiple threads can safely call RouterChat concurrently. However, AddDeployment, RemoveDeployments, and SetFallbacks should be called during initialization, before concurrent access begins.
Router vs Direct Chat
| Feature | LLM.Chat(...) |
LLM.RouterChat(...) |
|---|---|---|
| Provider resolution | From "provider/model" string |
From deployment registry |
| API key | From .env or parameter |
From TLLMDeployment.ApiKey |
| Retry | Within single endpoint (2 retries) | Across multiple deployments |
| Load balancing | None | 5 strategies |
| Fallback | None | Cross-model fallback chains |
| Rate limiting | None | Per-deployment RPM tracking |
| Cooldown | None | Automatic on failure |
| Cost tracking | Yes | Yes |