Repository navigation
🚀 Get started
New to AISIX? Get the gateway running and route your first LLM request in minutes:
- 📖 Documentation — https://docs.api7.ai/ai-gateway/
- ⚡ Gateway quickstart (one container, declarative
resources.yaml) — https://docs.api7.ai/ai-gateway/getting-started/gateway-quickstart
📦 Download
Pull the container image from the GitHub Container Registry:
docker pull ghcr.io/api7/aisix:1.7.1The rolling latest tag and the docker.io/api7/aisix mirror for private/offline deployments are listed on the package page.
AISIX 1.7.1 is a patch release. The gateway now handles every request field by what the target platform documents: a parameter the target can carry is sent as written and the upstream's own error comes back, a parameter it cannot carry is dropped, and a value that is illegal in the caller's own protocol is a 400 naming the field. Answers come back in full, including every choice, logprobs, refusal and annotations.
- Request parameters follow the target platform's contract (#1352, #1353): Bedrock, Vertex Gemini and Claude receive the fields they document, in the slot they document, and the upstream's rejection reaches the caller.
- Answers come back in full (#1353, #1354, #1356): every choice,
logprobs,refusal,annotationsand legacyfunction_call, and answers whose content is an array of parts work end to end. - Legacy function calling works on every provider (#1353), including Claude, Vertex Gemini and Amazon Bedrock.
- Streamed chat usage follows
stream_options.include_usageon every upstream (#1351). - Exporters accept plaintext
http://endpoints on any host (#1346). - Vertex AI
global,usandeulocations reach Google's endpoints, and transcription usage and latency are recorded more completely (#1357, #1359, #1360).
⚠️ Behavior changes
See Upgrade notes for what to update.
- Streamed
/v1/chat/completionsusage followsstream_options.include_usageon every upstream (#1351). Withinclude_usage: true, usage is sent exactly once, on its own chunk (choices: []) after every other chunk. Without it, no chunk carries usage, as with OpenAI. Before, Claude (any platform), Vertex Gemini and OpenAI-compatible upstreams that report usage on the finish chunk showed it there even withoutinclude_usage. Usage events and TPM limits are unchanged. Clients that read usage from a stream must requestinclude_usage. - Parameters the gateway used to drop now reach the upstream (#1352, #1353). Fields the target defines go out as the caller wrote them, and the upstream's rejection reaches the caller with its status and message; the gateway no longer drops, rewrites or pre-validates them. On Amazon Bedrock this means
stopto Grok or GPT 5.6 and later,temperature/top_p/logprobsto a reasoning GPT, the penalties andn, and a tool'sstrictfor a model that does not take it can now get AWS's400; on Vertex Gemini 2.5, so can a/v1/messagesthinking.budget_tokensabove the model's ceiling. Details are under Providers and endpoints. - Values that are illegal in the caller's own protocol answer
400naming the field (#1351, #1353). This covers a body that is valid JSON but does not fit the request (for examplemax_tokens: invalid value: integer -1, expected u32ormissing field messages, instead ofinvalid JSON request body), a messagecontentthat is a number, boolean or object, and, on the Claude, Converse and Vertex Gemini bridges, a wrong-typedstop,max_tokens,max_completion_tokens,temperature,top_p,tool_choice,reasoning_effortorservice_tier, a malformed tool, or a replayed tool call withoutidorfunction.name. These used to be dropped silently, forwarded raw or read as empty. On Bedrock Converse, astopthat is not a non-empty string or string array, and amax_completion_tokensthat is not a non-negative integer, are refused the same way. A lone empty-stringstopis still skipped andnullis still treated as absent. anthropic-betais forwarded to Anthropic by default (#1353). On/v1/messagesand/v1/messages/count_tokensto Anthropic or an Anthropic-compatible endpoint, the caller'santhropic-betaheader now reaches the upstream without being listed in the provider key'sforward_client_headers. A value the provider key sets throughdefault_headersorforward_client_headersstill wins.anthropic-versionstays pinned, and Claude on Bedrock and Vertex AI keeps its platform's beta filtering.- An answer the upstream already served is not run again (#1353). A
2xxthe gateway cannot decode now returns502directly. It used to be retried, fail over to the next Model Group target and count toward cooldown, so the request was billed twice. This includes/v1/images/edits. A Decisions Model Group no longer fails over an incomplete converted answer either; the caller gets502(unexpected decision response) and the target is not cooled down. Credential token exchanges (Azure AAD, Vertex service account) keep their retry behavior. - Claude stop reasons map to OpenAI values on chat (#1353).
refusalis nowcontent_filter,model_context_window_exceededislengthandpause_turnisstop; they used to appear as raw finish reasons. On/v1/messagesfrom a chat upstream, a content filter or an OpenAIrefusalends asrefusalinstead ofstop_sequence, with the refusal text as a text block. - Anthropic server tools are not offered to chat upstreams (#1353). On
/v1/messagesconverted to chat,web_search_*,web_fetch_*,code_execution_*andtool_search_tool_*are no longer sent as parameterless functions. Client tools (bash_*,text_editor_*,computer_*) are unchanged. - Error messages from Anthropic carry Anthropic's own text (#1353). On
/v1/messagesandcount_tokensto Anthropic, an upstream error'serror.messageis Anthropic's message instead of the whole raw body as a string. An OpenAI-shape upstream error with a numericcodeorparamkeeps itsmessageas well.
🔌 Providers and endpoints
- Amazon Bedrock Chat Completions route (Grok, GPT 5.6 and later) (#1352).
n,stop,frequency_penalty,presence_penalty, Grok'sreasoning_effort: "none", and GPT'stemperature/top_p/logprobs/top_logprobswhile it reasons are now sent as given. They used to be dropped. On Converse,stopis sent asstopSequencesto every model, including Grok and GPT 5.6 and later. Where AWS refuses one, the caller now gets AWS's400. - Amazon Bedrock Converse (#1353). OpenAI models (gpt-oss, GPT, Grok) receive
seed, the penalties,user,safety_identifier,logit_bias,parallel_tool_calls,metadataand ajson_objectresponse_formatthroughadditionalModelRequestFields, as AWS documents. Cohere Command R receivesseedand the penalties, Jamba the penalties, and Z.AI GLM and Kimi K3reasoning_effort. Nova 2 mapsreasoning_effort: "none"to disabled reasoning. Titan Multimodal embeddings mapdimensions. A function'sstrictreaches Converse astoolSpec.strict; a model that does not takestrict(for example Nova Lite) now answers with Bedrock's400where the request used to succeed without it. The output cap for GPT, Grok and Kimi K3 is no longer raised to 16. A request with no user or assistant turn goes to Bedrock and returns Bedrock's error instead of a gateway400. Conversetemperature/top_pkeep their exact decimal value. - Vertex Gemini (#1353).
generationConfignow carriesmax_completion_tokens,stop,seed, the penalties,n(ascandidateCount),logprobs/top_logprobsand a/v1/messagestop_k.reasoning_effortmaps tothinkingLevelon Gemini 3 and later and to a thinking budget on Gemini 2.5. A/v1/messagesthinking.budget_tokensgoes to Gemini 2.5 as sent, so a budget above the model's ceiling now gets Vertex's400where the request used to succeed without thinking.service_tierflex/priorityis sent as Vertex's Flex / Priority PayGo header. Functionparametersgo out unchanged asparametersJsonSchemaon Gemini 2.5 and later, soadditionalPropertiesis kept. Every candidate comes back as a choice with itslogprobs, and a prompt Gemini blocks finishes ascontent_filter. - Claude on chat (Anthropic, Vertex AI, Bedrock InvokeModel) (#1353). OpenAI-only fields such as
seed,n,logprobs,logit_bias, the penalties,storeandprompt_cache_keyare dropped instead of reaching Anthropic and causing a400.userandsafety_identifierbecomemetadata.user_id, and a function tool'sstrictis copied to the Claude tool. - Fields reach the upstream as written (#1353). A caller's own
strictjson_schema goes out unchanged; the gateway closes a schema only when it setstrictitself while translating/v1/messagesoutput_format. An assistantcontent: nullis sent asnull, andtemperature/top_pkeep the caller's decimal (0.7, not0.699999988). Themax_tokens→max_completion_tokensrename for OpenAI reasoning models applies only on OpenAI's own API; an OpenRouter key servingopenai/o3-mini, for example, now receivesmax_tokens, the only field OpenRouter documents. - Legacy function calling works on every provider (#1353).
functions/function_callandrole: "function"turns are accepted on every target, andnullvalues are treated as absent. OpenAI-wire targets receive them as sent. Claude (Anthropic, Vertex AI), Vertex Gemini and Bedrock InvokeModel and Converse used to answer400; they now receive them as tools, and the answer comes back asmessage.function_call/delta.function_callwithfinish_reason: "function_call". Only one call per turn fits the legacy shape. - Answers come back in full (#1353). Responses from OpenAI-compatible providers, Azure OpenAI, the Vertex AI OpenAI-compatible endpoint and Bedrock Chat Completions now keep every choice (streamed deltas keep their
index), choicelogprobs,refusal,annotationsand legacyfunction_call. Only the first choice was kept before./v1/messagesand/v1/responsesread the first choice. The response cache stores the whole response. - Answers whose content is an array of parts work end to end (#1353, #1354, #1356). OpenAI-compatible upstreams such as Mistral and Databricks that answer with
contentas an array of parts now work, streamed or not. Their text reaches/v1/messages,/v1/responsesand content capture, and their reasoning parts are relayed asreasoning_contenton chat, athinkingblock on/v1/messagesand areasoningitem on/v1/responses, counted in estimated completion tokens and captured for exporters. On a/v1/responsesstream, reasoning that follows text now opens a new item in order instead of being appended to the earlier one. /v1/embeddingsforwardsuserand other fields to OpenAI-wire targets and accepts token-id input (#1353) ([1, 2],[[1, 2]]), which used to be a400. Token ids carry no text, so input guardrails let such a request through. Bedrock and Vertex AI embeddings refuse token ids with a400.- Claude below 4.5 on Vertex AI or Bedrock with structured output stays on the native Messages route (#1353), so Anthropic-only fields are no longer lost. Reasoning that streams while a tool call is open is now kept as its own thinking block.
/v1/messagestop_kand the exactthinking.budget_tokensreach targets that have a slot for them. - Vertex AI location
globaland the multi-region locationsus/eureach Google's endpoints (#1357). With no API base on the provider key,globalnow goes tohttps://aiplatform.googleapis.comandus/eutohttps://aiplatform.{us,eu}.rep.googleapis.com, on every Vertex AI route (Gemini, embeddings, Claude, partner models, the OpenAI-compatible endpoint). They used to go toglobal-aiplatform.googleapis.comandus-aiplatform.googleapis.com, which do not exist. Regional locations such asus-central1are unchanged. - Bedrock Converse request bodies are byte-identical for identical requests (#1348). JSON keys, including those inside tool schemas, are now sent in a stable order.
- A Vertex AI provider key with a mistyped secret field gets an error naming the field (#1351), for example
service_account_json must be a JSON object (the contents of the service-account key file), got a string, instead of "must be valid JSON".
🛡️ Guardrails
- Input guardrails scan reasoning replayed as a content part (#1355). Mistral
thinking, Databricksreasoningand Anthropic-shapedthinkingparts in chat content are now judged likereasoning_content, so a block rule that matches them returns422where the request used to pass. Mask rules rewrite unsigned parts. A part with a non-emptysignatureis scan-only, like a signed thinking block on/v1/messages: block rules still fire, but a mask hit is forwarded unchanged. The gateway does not verify signatures, so use a block action where such text must not reach the upstream. On passthrough routes, a Mistralthinkingpart no longer makes the body unscannable. - Output guardrails scan every choice (#1353). Output guardrails and masking now cover every choice, the
refusaltext and legacyfunction_callarguments. Masking does not rewritelogprobs, so a caller that requestslogprobsreceives the upstream's token text unmasked.
📊 Observability and usage events
- Exporters accept plaintext
http://endpoints on any host (#1346). Theotlp_httpandobject_storeexporterendpointnow acceptshttp://with any host, for example an intranet collector athttp://otel-collector-dev:4318/v1/traces. It used to be limited to a fixed set of test hosts. Aliyun SLSendpointand Datadogsitekeep their restrictions. - Response-cache hits export the same output as the answer they replay (#1357). A cache hit's usage event now carries the stored response's
finish_reasoninstead of an empty one, and its OTLP / Datadog span gainsgen_ai.response.finish_reasonsand the structuredgen_ai.output.messages(reasoning included) that a fresh answer exports. - Latencies under 1 ms are reported as 1 ms (#1359).
upstream_latency_ms,downstream_latency_ms,upstream_ttft_ms, per-attempt latency and embedding-call latency used to be reported as not measured when they were under a millisecond, as the caller latency of an exact-match cache hit usually is. A latency that was never measured is still0or absent.
🐛 Fixes
- A streamed ensemble request with
stream_optionsno longer fails with502(#1351). Panel members no longer receivestream_options; the caller still gets its usage chunk. - Claude chat streams that stop early are recorded with the real input and cache tokens (#1351). A stream to Anthropic or Claude on Vertex AI that ends before its final event (client disconnect or an in-stream upstream error) now records the input, cache-read and cache-write counts Claude reported, instead of an estimated prompt and no cache tokens. A stream that stops before its first content is still estimated.
- Passthrough streams are metered from server-labelled usage frames (#1351) when the protocol parser read no usage, so a server that reports tokens only on
event: token_usageframes is no longer recorded with zero tokens. - Transcription and translation usage reported as
prompt_tokens/completion_tokensis recorded (#1357). An upstream that reports chat-style counts instead ofinput_tokens/output_tokens(Z.AIglm-asr-2512, for example) now gets token counts and token-priced cost on its usage events, for/v1/audio/transcriptions(streamed or not) and/v1/audio/translations. Upstreams that report the transcription names or a duration are unaffected. - Duration-billed transcriptions record the right length (#1359). A streamed
/v1/audio/transcriptionsnow records the duration the upstream reports on its final event, and falls back to the uploaded file's length only when there is none, as non-streamed requests already did; it used to price on the file length alone. WAV and FLAC files written as a stream (as OpenAI's/v1/audio/speechandffmpegto a pipe produce them) are now measured instead of recorded with no duration. A duration too large to store is recorded as unmeasured with a warning in the gateway log. After the upgrade, these requests record a different duration and cost, and streamed WAV and FLAC uploads that used to be recorded with no duration start to carry a cost. - Requests that reached no upstream no longer report an upstream latency (#1360). On a response-cache hit, or a request refused before its first upstream attempt (an input guardrail block, an unknown model, a rate-limit or budget refusal, and similar),
upstream_latency_msandupstream_ttft_msare now0(not measured) instead of the gateway's own handling time, on usage events, exporters and per-attempt rows, so statistics computed fromupstream_latency_mschange for these rows.downstream_latency_msstill reports what the caller waited.
⬆️ Upgrade notes
These notes apply when you upgrade from 1.7.0 or earlier.
- Request
include_usageto read usage from a chat stream. Clients that read usage from the finish chunk of a/v1/chat/completionsstream withoutstream_options.include_usage: truereceive none after the upgrade. - Requests that relied on the gateway dropping parameters can now get the upstream's
400. On Bedrock,stopto Grok or GPT 5.6 and later,temperature/top_p/logprobsto a reasoning GPT, the penalties andn, andstricton a tool for a model that does not take it. On Vertex Gemini 2.5, athinking.budget_tokensabove the model's ceiling. Stop sending them for those models. anthropic-betanow reaches Anthropic. Provider keys that did not list it inforward_client_headersstart forwarding the caller's value. Set the header indefault_headersif callers must not choose it.- Gateways of different versions sharing a response cache. During a rolling upgrade or a rollback, a response-cache entry with more than one choice or with
logprobs, written by a 1.7.1 gateway, is a cache error for a 1.7.0 or earlier gateway sharing the cache. Other entries are unaffected.
Known issues
- An ensemble whose judge is a reasoning GPT 5.6 or later on Amazon Bedrock gets a
400. The judge always sendstemperature: 0.2, which AWS refuses while the model reasons. Use a different judge model.
What's Changed
- feat(obs): accept plain http:// exporter endpoints on any host by @jarvis9443 in #1346
- ci(image): build the gateway binary on the runner, package it with a thin Dockerfile by @jarvis9443 in #1347
- ci: delete expired ci-test-* branch images from ghcr daily by @jarvis9443 in #1349
- refactor(bedrock): send Converse request bodies with a stable key order by @tc3oliver in #1348
- ci: ghcr retention for main builds, orphans and their cosign signatures by @jarvis9443 in #1350
- fix: chat stream usage contract, Claude early-stop accounting, Bedrock Converse stop/max validation, and other 1.7.0 QA fixes by @jarvis9443 in #1351
- fix(bedrock): forward parameters AWS refuses instead of silently dropping them by @jarvis9443 in #1352
- fix: handle request parameters by the target platform's contract by @jarvis9443 in #1353
- fix: render the text and reasoning of an array-content chat answer on /v1/messages, /v1/responses and content capture by @jarvis9443 in #1354
- fix: treat replayed reasoning content parts like reasoning_content in input guardrails by @jarvis9443 in #1355
- fix: relay the reasoning parts of a streamed array-content delta on every endpoint by @jarvis9443 in #1356
- fix: 1.7.1 release-surfaced data-plane fixes by @jarvis9443 in #1357
- fix: 1.7.1 release-surfaced data-plane fixes (QA round 2) by @jarvis9443 in #1359
- fix(obs): report no upstream latency on rows that reached no upstream by @jarvis9443 in #1360
New Contributors
- @tc3oliver made their first contribution in #1348
Full Changelog: v1.7.0...v1.7.1