Skip to main content

ai-proxy-multi

Proxies requests to several LLM providers with balancing and fallback.

Category AIAdd it to Route, Service, Consumer, Consumer group, Global rule, Plugin configEngine plugin ai-proxy-multiPriority 1041

What it does​

ai-proxy-multi sends each chat request a route takes to one of several language models, listed under Instances. Each instance carries its own provider, key, model and weight. The Balancer picks one instance per request, by round robin unless you choose another Algorithm.

Without a Fallback strategy, a failure of the chosen instance reaches the client. With one, http_429 or http_5xx for example, a request whose instance answers with such a status moves on to another instance.

When to use it​

  • Two providers behind one assistant, most requests to one and a share to the other, for example 80 to 20 by weight.
  • A second provider that takes over when the first answers that it is overloaded or failing.
  • Each partner kept on one instance, with the consistent hash algorithm hashing on the consumer.
  • Prompts sent by what they ask, translations to one model and poems to another, with the semantic algorithm and a few examples per instance.
  • A token budget for each instance, counted by ai-rate-limiting under the instance's name.

Not for one model at one provider — see ai-proxy (Proxies requests to an LLM provider with a unified API), balancing requests over your own backend instances — see Upstream (Upstreams are the backends that routes and services send traffic to) or splitting traffic between ordinary upstreams — see traffic-split (Splits traffic between upstreams by weight and match rules).

Set it up​

Split chat requests between two providers by weight​

Each Authorization value is sent to its provider as written, so write it as Bearer, a space and that provider's key.

Under Basics fill Instances as in the JSON below.

ai-proxy-multi · as the console saves it
{
"instances": [
{
"name": "primary",
"provider": "openai",
"weight": 80,
"auth": {
"header": {
"Authorization": "<secret>"
}
},
"options": {
"model": "gpt-4o"
}
},
{
"name": "secondary",
"provider": "deepseek",
"weight": 20,
"auth": {
"header": {
"Authorization": "<secret>"
}
},
"options": {
"model": "deepseek-chat"
}
}
]
}

Things to know​

  • name — ai-rate-limiting on the same route counts the tokens of the instance that answered under its name. An instance named primary gives the answer X-Ai-Ratelimit-Limit-Primary.
  • name — Two instances with one name are refused when you save.
  • endpoint — An endpoint that is not an address with a scheme and a host is refused when you save.
  • Algorithm — Semantic takes no part in health checks, fallback or retries. It falls back only when no instance clears its threshold or the embedding fails.
  • Hash on — Read only with the Chash algorithm, where a Key is required unless Hash on is Consumer. Under any other algorithm a value here is stored and ignored.
  • Key — Read only with the Chash algorithm, where a Key is required unless Hash on is Consumer. Under any other algorithm a value here is stored and ignored.
  • Fallback strategy — Instance health and rate limiting works only as the single choice, and Rate limiting only inside a list. The engine refuses either word in the other shape.
  • Fallback retry limit — Empty, a failed request keeps trying until one instance succeeds or all have been tried.
  • Retry failures within — A failure slower than this window is returned to the client instead of moving on.
  • Semantic options — Read only while the balancer algorithm is Semantic, and under any other algorithm even an invalid embedding endpoint is stored and ignored.
  • examples — Under the semantic algorithm, an instance without examples is refused when you save.
  • Timeout — Every request waits for the embedding call.
  • Fallback — A name that no instance carries is refused.
  • Fallback — Empty, the first instance answers.
  • Threshold — The debugging header rounds scores to four places, so 1.0000 can still fall short of 1.
  • Response size limit — A non-streamed answer over the cap reaches the client as 502 with max_response_bytes exceeded.

Settings​

The fields as the console shows them, section by section.

Basics​

Instancesinstancesarray of objectsRequired

The AI services to balance across, one object each with a name, provider, weight, auth and options, as in the example. Other keys are stored as written.

at least 1 item · example [{"name":"primary","provider":"openai","weight":80,"auth":{"header":{"Authorization":"Bearer YOUR_API_KEY"}},"options":{"model":"gpt-4o"}},{"name":"fallback","provider":"deepseek","weight":20,"auth":{"header":{"Authorization":"Bearer YOUR_API_KEY"}},"options":{"model":"deepseek-chat"}}]
Each item:
authinstances[].authobjectRequired
awsinstances[].auth.awsobject

Other keys are stored as written.

access_key_idinstances[].auth.aws.access_key_idstringRequired
at least 1 character
secret_access_keyinstances[].auth.aws.secret_access_keystringRequired

Stored on the engine and shown only to roles that manage this object.

at least 1 character
session_tokeninstances[].auth.aws.session_tokenstring

Stored on the engine and shown only to roles that manage this object.

at least 1 character
gcpinstances[].auth.gcpobject

Other keys are stored as written.

expire_early_secsinstances[].auth.gcp.expire_early_secsintegerdefault 60
at least 0
max_ttlinstances[].auth.gcp.max_ttlinteger
at least 1
service_account_jsoninstances[].auth.gcp.service_account_jsonstring

Stored on the engine and shown only to roles that manage this object.

headerinstances[].auth.headerobject

Stored on the engine and shown only to roles that manage this object. An object whose keys are letters, digits, dots, underscores and hyphens, each with a string as its value.

queryinstances[].auth.queryobject

Stored on the engine and shown only to roles that manage this object. An object whose keys are letters, digits, dots, underscores and hyphens, each with a string as its value.

nameinstances[].namestringRequired
1 to 100 characters
providerinstances[].providerstringRequired
one of aimlapi, anthropic, azure-openai, bedrock, deepseek, gemini, openai, openai-compatible, openrouter, vertex-ai
weightinstances[].weightintegerRequired
at least 0
checksinstances[].checksobject

Other keys are stored as written.

activeinstances[].checks.activeobjectRequired

Other keys are stored as written.

concurrencyinstances[].checks.active.concurrencyintegerdefault 10
healthyinstances[].checks.active.healthyobject

Other keys are stored as written.

http_statusesinstances[].checks.active.healthy.http_statusesarray of integersdefault [200,302]
at least 1 item; each 200 to 599
intervalinstances[].checks.active.healthy.intervalintegerdefault 1
at least 1 · in seconds
successesinstances[].checks.active.healthy.successesintegerdefault 2
1 to 254
hostinstances[].checks.active.hoststring
a host name, with an optional leading wildcard, or * alone
pattern^\*$|^\*?[0-9a-zA-Z-._\[\]:]+$
http_methodinstances[].checks.active.http_methodstringdefault GET
one of CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PURGE, PUT, TRACE
http_pathinstances[].checks.active.http_pathstringdefault /
http_req_bodyinstances[].checks.active.http_req_bodystringdefault
https_verify_certificateinstances[].checks.active.https_verify_certificatebooleandefault true
portinstances[].checks.active.portinteger
1 to 65535
req_headersinstances[].checks.active.req_headersarray of strings
at least 1 item
timeoutinstances[].checks.active.timeoutnumberdefault 1
in seconds
typeinstances[].checks.active.typestringdefault http
one of http, https, tcp
unhealthyinstances[].checks.active.unhealthyobject

Other keys are stored as written.

http_failuresinstances[].checks.active.unhealthy.http_failuresintegerdefault 5
1 to 254
http_statusesinstances[].checks.active.unhealthy.http_statusesarray of integersdefault [429,404,500,501,502,503,504,505]
at least 1 item; each 200 to 599
intervalinstances[].checks.active.unhealthy.intervalintegerdefault 1
at least 1 · in seconds
tcp_failuresinstances[].checks.active.unhealthy.tcp_failuresintegerdefault 2
1 to 254
timeoutsinstances[].checks.active.unhealthy.timeoutsintegerdefault 3
1 to 254
examplesinstances[].examplesarray of strings
1 to 64 items; each at least 1 character
optionsinstances[].optionsobject

Other keys are stored as written.

modelinstances[].options.modelstring
overrideinstances[].overrideobject

Other keys are stored as written.

endpointinstances[].override.endpointstring
at least 1 character ·
pattern^https?://[^:/]+
llm_optionsinstances[].override.llm_optionsobject
max_tokensinstances[].override.llm_options.max_tokensinteger
at least 1
request_bodyinstances[].override.request_bodyobject
anthropic-messagesinstances[].override.request_body.anthropic-messagesobject
bedrock-converseinstances[].override.request_body.bedrock-converseobject
openai-chatinstances[].override.request_body.openai-chatobject
openai-embeddingsinstances[].override.request_body.openai-embeddingsobject
openai-responsesinstances[].override.request_body.openai-responsesobject
passthroughinstances[].override.request_body.passthroughobject
request_body_force_overrideinstances[].override.request_body_force_overridebooleandefault false
priorityinstances[].priorityintegerdefault 0
provider_confinstances[].provider_confobject

Other keys are stored as written.

project_idinstances[].provider_conf.project_idstring
regioninstances[].provider_conf.regionstring
at least 1 character
thresholdinstances[].thresholdnumber
-1 to 1

Behavior​

Balancerbalancerobjectdefault {"algorithm":"roundrobin"}
Algorithmbalancer.algorithmstring

How an instance is picked for each request: round robin, consistent hash, or semantic by prompt similarity. Semantic takes no part in health checks, fallback or retries. It falls back only when no instance clears its threshold or the embedding fails.

one of chash, roundrobin, semantic
Hash onbalancer.hash_onstringdefault vars
one of consumer, cookie, header, vars, vars_combinations
Keybalancer.keystring

The request value the Chash balancer hashes, such as remote_addr or a header name, read according to Hash on.

Fallback strategyfallback_strategystring or array of strings
one of http_429, http_5xx, instance_health_and_rate_limiting, rate_limiting as a string
Fallback status codesfallback_http_statusesarray of integers

Upstream status codes that also send the request to another instance, beside the ones the strategy names.

at least 1 item; each 400 to 599
Loggingloggingobject
Payloadslogging.payloadsbooleandefault false

Adds the request and response bodies to the record that a logger plugin on this route writes. Nothing is written unless a logger plugin runs on the route.

Summarieslogging.summariesbooleandefault false

Adds the model, the duration and the token counts to the record that a logger plugin on this route writes. Nothing is written unless a logger plugin runs on the route.

Fallback retry limitmax_retriesinteger

How many more instances a failed request may try, used only with a fallback strategy. Empty keeps trying until one succeeds or all have been tried.

at least 0
Retry failures withinretry_on_failure_within_msinteger

A failed request moves to another instance only when it failed within this window. A slower failure is returned to the client.

at least 1 · in milliseconds
Semantic optionssemantic_optsobject
Embeddingssemantic_opts.embeddingsobjectRequired
Authsemantic_opts.embeddings.authobjectRequired
Headersemantic_opts.embeddings.auth.headerobject

Stored on the engine and shown only to roles that manage this object. An object whose keys are any name, each with a string as its value.

Querysemantic_opts.embeddings.auth.queryobject

Stored on the engine and shown only to roles that manage this object. An object whose keys are any name, each with a string as its value.

Modelsemantic_opts.embeddings.modelstringRequired

The embedding model that turns the prompt into a vector for the similarity match.

at least 1 character
Providersemantic_opts.embeddings.providerstringRequired

The service that computes the embeddings for the semantic match.

one of azure-openai, openai
Endpointsemantic_opts.embeddings.endpointstring

The embedding service address, which OpenAI may leave empty and Azure OpenAI needs as the full deployment URL with its API version.

pattern^https?://[^:/]+
SSL verifysemantic_opts.embeddings.ssl_verifybooleandefault true
Timeoutsemantic_opts.embeddings.timeoutintegerdefault 3000

How long the embedding call may take before the request falls back. Every request waits for this call.

at least 1 · in milliseconds
Debuggingsemantic_opts.debuggingbooleandefault false

Adds the per-instance scores and the chosen instance to the response headers.

Fallbacksemantic_opts.fallbackstring

The name of the instance that answers when no instance clears its threshold or the embedding fails. Empty uses the first instance.

at least 1 character
Thresholdsemantic_opts.thresholdnumberdefault 0

The similarity score an instance must reach to be chosen. Below it the request goes to the fallback instance, or to the first instance when none is named. The debugging header rounds scores to four places, so 1.0000 can still fall short of 1.

-1 to 1
Timeouttimeoutintegerdefault 30000

How long the gateway waits for the model to answer one call.

1 to 600000 · in milliseconds
SSL verifyssl_verifybooleandefault true
Response size limitmax_response_bytesinteger

The largest model response in bytes, streamed or not, where empty sets no cap. A non-streamed answer over the cap reaches the client as 502 'max_response_bytes exceeded'.

at least 1
Stream duration limitmax_stream_duration_msinteger

The longest a streamed answer may run before it is cut off, and unset means no limit.

at least 1 · in milliseconds
Streaming flush intervalstreaming_flush_interval_msintegerdefault 10

How often buffered streamed output is sent on to the client, where zero sends each chunk as it arrives.

at least 0 · in milliseconds

Advanced​

Request body limitmax_req_body_sizeintegerdefault 67108864

The largest request body in bytes the gateway reads, and a larger one is refused with 413.

at least 1
Keepalivekeepalivebooleandefault true
Keepalive poolkeepalive_poolintegerdefault 30
at least 1
Keepalive timeoutkeepalive_timeoutintegerdefault 60000

How long an idle connection to the provider is kept open for reuse.

at least 1000 · in milliseconds

Every plugin also has Enabled, Priority, Filter, Error response and Pre-function: see Plugin execution settings.

G8 dev · Apache APISIX® 3.19.0
Apache, Apache APISIX and APISIX are trademarks of The Apache Software Foundation.
Facts
Category
AI
Add it to
Route, Service, Consumer, Consumer group, Global rule, Plugin config
Engine plugin
ai-proxy-multi
Priority
1041