gpt-5.4” into an HTTP call to somebody’s API. It makes that call itself, from the application processes, using a route table that names which upstream serves each model id.
There is no gateway mode to choose. Ragen used to route every call through a LiteLLM proxy, selected by an
LLM_GATEWAY variable. That path and that variable are gone — Portkey, vLLM, Ollama, LiteLLM and anything else speaking OpenAI’s API are attached per model, as a route with provider: openai-compatible. See Attaching an external gateway.Calling providers directly
Ragen reads a route table naming which upstream serves each model id, and takes credentials from the environment.infra/llm-gateway/routes.yaml
LLM_ROUTES_PATH at your own file to serve a different set. The shipped table is Ragen’s own installation — a default, not a law.
A route carries no credentials and no display name. Credentials come from the environment; display names and capability flags are a separate concern.
Credentials per provider
Vertex may need no credential variable at all.
VERTEX_CREDENTIALS accepts either the service-account JSON itself or a path to it — both work. Leave it unset on a workload that has its own identity (Cloud Run, GKE Workload Identity, GCE) and Google’s application default credentials apply, with no key to rotate or leak. This is the one provider where “no credentials configured” is routinely correct.A route’s own location beats VERTEX_LOCATION, which matters because some models are served from the global endpoint only and 404 in a region.Attaching an external gateway
Ragen deliberately does not build spend dashboards, provider fallback, cross-vendor retries or response caching. Those are what a gateway is for, and anything speaking OpenAI’s/v1/chat/completions and /v1/embeddings can serve some or all of your models.
Portkey
Run it yourself — one container, no account:infra/llm-gateway/routes.yaml
.env.local
LLM_PORTKEY_API_KEY is the upstream key — your OpenAI or Anthropic key — because the self-hosted gateway forwards it rather than holding credentials of its own. x-portkey-provider tells Portkey which upstream that key belongs to.
Chat and embeddings both route this way; there is nothing extra to configure for the embedding side.
Using Portkey’s hosted service
With a saved Portkey config — which is where its fallbacks, retries and caching are defined — name the config instead of the provider:.env.local
Header names are Portkey’s, not Ragen’s. Check their documentation for the version you run —
LLM_PORTKEY_HEADERS passes through whatever JSON object you give it, so a header change on their side needs no change here.Check it before you rely on it
Anything else OpenAI-compatible
vLLM, Ollama, Text Generation Inference, a hosted API, or LiteLLM itself — a proxy Ragen no longer has a mode for is still a perfectly goodopenai-compatible upstream. The pattern is identical; only the connection name changes.
Per model, not per deployment
connection is a property of the route, so different models can come from different places at once: a local vLLM for the cheap ones, a hosted API for the hard ones, a gateway in front of a third. Ragen does not care that they differ.
Before you rely on it
Misconfiguration does not fail at boot. It fails at the first model call, as a 5xx, because that is the first moment anything checks whether a credential works.--probe makes one real call per configured model. It exists because “configured” and “works” turned out to be different questions — a provider can have every variable set and still fail to authenticate, and a role-based deployment (Bedrock’s default credential chain, Vertex’s application default credentials) has no variable to inspect in the first place.
If a provider stops working
There is no mode to switch back to, so the fix is per model rather than global: point the affected route at something else and leave every other route alone. Which shape the replacement takes depends on what you are pointing at, and the two are not interchangeable:
Only the second is “two variables and done”; the first needs whatever credentials that provider family requires, which is why Credentials per provider is the table to check before assuming a swap is free.
Either way it is the same mechanism as attaching a gateway, which is why there is no separate rollback procedure: routing is configuration, and it always was.