Request routing between LLM providers: LLM Router

When a single provider can't handle peak load, failures hit the product and reputation. We design and implement turnkey request routing between models: we distribute traffic by quality, cost, and availability. The result is predictable service operation and fewer failures during peak hours.
Frequently Asked Questions

LLM Router: why a single provider can't handle the workload

Hard-wiring to a single LLM provider breaks down predictably: the application hits request limits at peak load, and some requests start failing with an error even before the response is generated.

Then a second effect kicks in — the provider under load starts responding more slowly, and response quality drops: the model switches to a stripped-down mode, and you get quality degradation where there used to be a stable result.

To the user, this looks like "the service froze" or "it got dumber," even though the application code hasn't changed.

This is exactly the problem that LLM Router solves — a layer that routes LLM requests across multiple providers.

It maintains a single entry point, distributes traffic across available models, monitors provider limits, and switches the flow to a backup channel when the primary one has exhausted its quota or is responding too slowly.

LLM fault tolerance no longer depends on a single vendor: a failure or degradation on one route doesn't bring down the entire product.

LLM request routing is built not "round-robin," but by rules: task class, required quality, acceptable latency, and processing cost.

Simple requests go to fast and cheap models, complex ones go to strong models, and when the priority route is unavailable, the request automatically goes to the backup route while preserving context.

This way, provider limits stop being a ceiling for the product, and response quality degradation is localized to a single route instead of the entire service.

Let's break down how this is solved in practice: which routing rules make sense, how failover switching is configured, and what's needed so that switching between providers doesn't break the application's logic.

What request routing between models provides

A router is a layer between the application and the models that decides, for each request, where to send it: to which provider, to which model, with what time limit, and what to do if a response does not arrive.

Without it, the application is tightly bound to a single vendor, and any failure, latency spike, or quality degradation directly affects the user.

The routing layer decouples these dependencies: model selection rules, timeout thresholds, fallback order, and retry conditions live in configuration rather than in the product code.

The first measurable effect is a reduction in the failure rate. When each request type has a chain consisting of a primary and a backup provider, and retries are performed only for idempotent operations, a single provider failure no longer turns into a user-facing error.

In practice, the share of unsuccessful calls drops from percent-level to tenths of a percent — with the same application code.

The second effect is stable latency. The router tracks response time for each destination and switches traffic when a provider exceeds a given threshold, instead of waiting for a timeout.

This removes the "tails" in the response time distribution: the median barely changes, but long waits that spoil the product experience are reduced severalfold.

The third effect is controllable response quality. Complex requests can be routed to a stronger model, simple and high-volume ones to a fast and inexpensive one, and response validation can be moved into a separate step.

Quality stops being an averaged compromise: you define it with rules for a specific scenario and change it without rewriting the product.

Finally, it is load management. Per-destination limits, a queue during peaks, and priorities for critical operations prevent a single heavy scenario from consuming the overall throughput. A traffic spike is spread across available capacity instead of turning into a cascade of failures.

Routing Modes: Comparing Approaches

A router does not "pick the best model" — it applies a rule to each request. The modes differ in which signal serves as the basis for the choice: a rigid sequence, predefined shares, token cost, or an assessment of response quality. Below is how this looks in configuration and where each mode breaks down.

Mode When it fits Limitations
Priority route One primary provider, the rest on standby in case of failure Keeps a cold reserve: switching increases time to first token
Weighted distribution Need to spread the load and compare providers on live traffic Shares are fixed; when one leg degrades, the skew does not self-correct
By cost High-volume, uniform requests without high demands on the response A cheap model more often falls into re-querying — savings are eaten up by retries
By quality Tasks where an error costs more than latency: document parsing, analytics Quality assessment lags behind the request; you need your own signal
Fallback route A mandatory layer on top of any of the modes Without a health-check it produces false triggers and unnecessary switches

In practice, modes are combined: a priority route with a weighted reserve and a per-request cost limit. Then a provider failure does not bring down the service, and a traffic spike does not turn into a token bill.

All modes share a common limitation — the quality of the input signal. If the health-check only verifies availability rather than the correctness of the response, the router will dutifully send requests to a degraded leg. That is why we always tie routing rules to response metrics, not just to the status code.

How we implement a router: stages of work

Implementing a router begins not with configuring rules, but with taking inventory of what is already happening in production.

We collect call logs, group them by task type, context length, and required accuracy — and only after that does it become clear where the route "always to the strongest model" overpays in time and cost, and where a cheap model produces an unacceptable error rate.

Stages of work

  1. LLM call audit. We analyze the request history: which scenarios dominate, how prompt lengths are distributed, where retries and caching kick in, which responses go back for rework. The output is a map of real workloads, not assumptions.
  2. Route scheme design. We define task classes and, for each one, a chain of models with switching conditions: by request type, context volume, and response format requirements. We fix fallback rules in case the primary provider is unavailable.
  3. Configuring rules and thresholds. We set priorities, context length limits, and behavior on errors and timeouts. Separately, we configure what to do with requests that matched no rule — they must not fail silently.
  4. Load testing. We run traffic close to production: we check how the router behaves under peak load, when one of the providers fails, and when responses degrade. We look at the share of successful switches and the response time.
  5. Quality comparison on real data. We run the same set of tasks through different routes and compare the result against a reference — this shows where savings are not worth the loss of accuracy.
  6. Handover to operations. We hand over the configuration, the route scheme, monitoring rules, and instructions for changing thresholds. The client's team can edit routes without us.
  7. Post-launch support. For the first weeks we monitor metrics and adjust thresholds based on actual traffic behavior.

Each stage ends with an artifact that can be verified: a workload map, a route scheme, a load testing report. This makes it possible to change rules deliberately rather than at random — and to understand what effect each change produced.

Configuration, access policies, and operational regulations as deliverables

The project ends not with a demonstration of a working router, but with the handover of a package your team can use to operate it, extend it, and pass knowledge on. Below is what exactly remains in your hands.

  • Route configuration — rules for selecting a provider and model by task type, priorities, limits, timeouts, and failure behavior. Documented as versioned files, not as settings "in the interface on an engineer's machine."
  • Access policies — roles, keys, quotas by team and scenario, restrictions on sensitive data, and a log of who changed what.
  • Integration scheme — how the router is embedded in your services: entry points, request and response formats, error handling, fallback paths when a provider is unavailable.
  • Documentation — architecture description, configuration parameter reference, instructions for typical changes, and analysis of common failures.
  • Operational regulations — the procedure for adding a new provider, rules for updating models, cost and response quality control, and the procedure for rolling back to a previous configuration.
  • Monitoring and alerts — a set of metrics for latency, error rate, and request cost with configured trigger thresholds.
  • Development plan — what has been deliberately deferred beyond the first stage and in what order to return to it.

We review each artifact with your engineers during handover so that the configuration and regulations don't remain a formality. Describe your task — we'll come back with an estimate and a plan.

Case study: how routing eliminated a class of failures under peak load

The client is a service with a conversational interface and a flow of requests in the tens of thousands per day.

Requests went directly to a single model provider: as long as it responded reliably, everything worked, but during the evening peak the error rate reached 9%, and during the provider's scheduled maintenance the service was completely down — recovery took up to 40 minutes with manual switchovers.

We deployed LLM Router as a separate layer between the application and the providers.

The router maintains a pool of several models, checks their availability with short probe requests, and distributes traffic according to rules: a priority provider, a backup one, and a separate branch for long responses.

If the error rate or latency exceeds a threshold, traffic automatically moves to the backup model, and the application doesn't even know about it.

What changed in numbers

Metric Before After
Failure rate at peak up to 9% 0.4%
Response latency at peak 3x increase 1.3x increase
Recovery time after provider failure up to 40 minutes 20-30 seconds
Manual switchovers during an incident every one none

The "provider unavailable" class of failures is gone from operations: switchover takes seconds and happens without an on-call engineer.

We also set up rollback separately — if a new model on the backup branch delivers unstable quality, a rule returns traffic to the previous one with a single configuration edit, without a rebuild or release.

We measured not only availability but also quality: routing logs show what share of requests went to the backup and why. This made it possible to revisit the thresholds — some switchovers were unnecessary and created load on the backup provider.

How quality-based routing differs from failover

These are two different mechanisms that are often confused because both live in the same layer — the LLM Router.

Failover solves the availability problem: the primary provider returned an error, timed out, or hit a limit — the router retries the request with the next one on the list. There is only one criterion here: liveness.

The request goes to wherever the service responds, not to wherever the response will be better. Quality-based routing solves a different problem — it selects a model for a specific request before sending it, relying on its content.

The difference shows up at the moment of model selection. With failover, there is a single default model, and it changes only as a result of a failure — that is, response quality remains a side effect of an incident.

With quality-based routing, the router first classifies the request: a short factual question, a long document analysis, code generation, image handling. Then the selection criteria come into play — task type, required context length, acceptable latency, token cost.

Only after that does the request go to the appropriate model, while failover remains a safety net on top of that decision.

In practice it looks like this: provider substitution happens at the transport level and does not know what the request was about.

Quality-based routing works at the level of meaning and does not protect against failure — if the selected provider is unavailable, without a separate retry mechanism the request will simply fail.

That is why in a working configuration they do not compete but complement each other: first model selection by criteria, then a chain of backup providers in case of failure.

The mistake is to build only failover and call it routing. Then a simple request goes to an expensive model, and a complex one goes to a cheap one, and response quality fluctuates from request to request.

The opposite mistake is to route by quality without a fallback: any provider unavailability brings down the entire service, because no substitution is provided for.

Technical doubts before implementation

Before a pilot, the same four questions almost always come up: how the router will fit into the current stack, whether latency will increase, who will maintain it, and what to do if the provider goes down. Below are short answers to each, without marketing.

Do I need to rewrite application code for the router?

No. The router runs as a separate service and provides an OpenAI-compatible HTTP interface — the same request and response format as direct calls to the provider. In the application, the base_url and key change; the call logic, prompts, and response parsing stay the same. If the stack already has an SDK client, it continues to work without changes.

How much will response latency increase?

One network hop is added between the application and the provider — a few milliseconds for routing, which is unnoticeable against the backdrop of the model generating a response. The main time goes into inference itself, not into provider selection.

If retries on error are enabled, latency increases only at the moment of failure — and that is better than showing the user an error.

How difficult is it to maintain the router?

Configuration is a declarative file: routing rules, limits, provider priorities, keys. It changes without rebuilding the service. The main maintenance work is updating the model list and monitoring quotas, not fixing code. Metrics for each provider (error rate, response time, token usage) are collected automatically.

What happens if a provider is unavailable or returns an error?

The router switches the request to a backup provider according to a defined rule — by error code, timeout, or quota exhaustion. The application receives a response and does not know about the failure.

If all are unavailable, a clear error is returned indicating the cause, rather than a "hanging" request.

Are there limitations worth knowing about in advance?

Providers differ in feature support: not all can do tool calls, streaming, or image handling. Routing rules need to be built taking these differences into account, otherwise some requests will go to a place where the required feature is not supported.

This is solved at the configuration stage, but it requires an explicit description of requirements for each model.

Let's discuss your routing task

To come back with an estimate and a plan rather than generalities, we need to understand your current routing scheme and the constraints it lives within. Describe the task in free form — then we'll ask clarifying questions and gather the source data. The more specific the inputs, the more accurate the estimate of timelines and scope of work.

What's useful to include with the task description:

  • the current model invocation scheme: which providers are involved, and by what criterion a model is selected for a request;
  • how failures and limit overruns are currently handled — whether there are retries, failover to a backup provider, a queue;
  • latency and cost requirements: what matters more for each class of requests, where it's acceptable to wait;
  • data rules: which requests must not be sent to external providers, whether there are storage and logging requirements;
  • the expected load profile: peak requests per minute, the share of heavy and light calls, seasonality;
  • integration points: where requests come from, which services and teams are affected;
  • infrastructure and access constraints: where the router is deployed, who owns the configuration.

Based on this data, we assess the scope: whether a separate routing layer is needed or whether it's enough to extend the existing one, which fault-tolerance rules we build in, and how we'll set up observability and rollback.

We come back with a phased plan, timelines, and what will be required on your side. The next step is a short, focused conversation: describe the task, and we'll come back with an estimate and a plan.

AI Development Areas

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1394
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1369
  • B2B Advance company logo design
    B2B Advance company logo design
    816
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1141
  • AIDER company logo development
    AIDER company logo development
    1057
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1153