Once more than one team calls more than one model, direct-to-provider calls become ungovernable: no unified spend view, no fallback when a provider degrades, and every app hard-codes model names.
Tier: Advanced · Workflow area: Serving & LLMOps
A model gateway — the pattern Uber's GenAI Gateway made canonical — puts one OpenAI-compatible endpoint in front of all providers and centralizes routing, budgets, fallbacks, and caching. This playbook stands up a LiteLLM-style gateway with three specific policies: cheap-model-first cascades, per-team budgets, and a semantic cache, then measures what each saves.
claude-x for a self-hosted vLLM model (pb-46) without touching app code.A single script calling a single model does not need a gateway — adopt it at the second consumer or the first budget question, whichever comes first.
pip install 'litellm[proxy]' and Docker (for Redis).Stand up the proxy with a model list. config.yaml maps public model names to backends; apps then call the gateway with an OpenAI client and a gateway-issued key:
model_list:
- model_name: fast # cheap tier
litellm_params: {model: "anthropic/claude-haiku-4-5", api_key: os.environ/ANTHROPIC_API_KEY}
- model_name: smart # quality tier
litellm_params: {model: "anthropic/claude-opus-4-8", api_key: os.environ/ANTHROPIC_API_KEY}
- model_name: local # your vLLM box
litellm_params: {model: "openai/qwen2.5-7b", api_base: "http://vllm:8000/v1", api_key: "none"}
Run litellm --config config.yaml, verify a completion through the proxy.
Add provider fallback. Configure fallbacks so smart → fast → local on provider errors/timeouts (LiteLLM fallbacks router setting). Test by pointing smart at a wrong API key and confirming requests still succeed via the fallback, with the reroute visible in gateway logs.
Implement the cascade. Cheap-model-first with escalation: route each request to fast; escalate to smart when a checkable condition fails — schema validation error, a self-reported confidence below threshold, or a task-type classifier flag. Implement as a thin client-side wrapper or gateway hook. The cascade needs a deterministic escalation trigger — "answer looks bad" is not one; "JSON failed to validate" is.
Set per-team budgets. Issue each team (or app) its own virtual key with a monthly budget and rate limits via the gateway's key-management API. Set one team's budget deliberately low and verify the 429-on-exhaustion behavior — discovering budget semantics in production is the expensive way.
Add semantic caching. Wire Redis as a semantic cache (embedding-similarity match above a threshold returns the cached response). Start conservative (similarity ≥0.97, cache only deterministic/low-temperature routes); paraphrase-level cache hits returning subtly wrong answers are worse than misses.
Measure on the 200-request replay. Report: % served by fast without escalation, escalation rate, cache hit rate, fallback activations, and blended cost per request vs the all-smart baseline. Cascades on mixed workloads routinely cut spend 40–70%; your number depends on your escalation trigger's strictness.
The gateway's leverage is that policy lives in one place: a routing change, a budget cut, or a new provider is a config edit applied to every consumer at once — the same reason MCP centralizes tools (pb-43), applied to model access.
Run the gateway and Redis inside the private network with only self-hosted backends (vLLM endpoints) — you keep unified budgets, routing, and caching with zero external calls. For client work, per-client virtual keys give you clean per-engagement cost attribution, which billing will thank you for.
Log route, cache-hit, tokens, and cost per request from day one — this exact log stream becomes the input to your cost dashboard (pb-49) and turns every future "why is spend up?" into a groupby.