发布说明
本页汇总 AISIX 网关、控制面、控制台和部署包中面向用户的变更,按版本从新到旧排列。
如果一次升级跳过了若干版本,其间每个版本的升级说明依然适用。请按从旧到新的顺序阅读——从你当前版本的下一个版本开始,一直读到目标版本。支持的升级路径和升级顺序参见升级 AISIX。
发布产物包括 docker.io/api7/aisix 网关镜像、docker.io/api7/aisix-cp-* 下的控制面镜像、aisix-cp Helm Chart 和离线安装包。
1.5.0
发布日期: 2026 年 9 月 29 日
模型组现在适用于所有单次请求接口——Completions、Embeddings、重排、图像生成与编辑、音频和视频提交——并具备 Chat 已有的故障转移、重试、逐次尝试用量记录以及 least_latency / least_busy 负载均衡。OIDC 服务提供方可以用共享的 HMAC 密钥验证入站 JWT。Responses 到 Chat 的桥接现在会生成完整的 Response 对象、response.failed 事件以及重放的推理内容,这些正是 Codex CLI 等 Agent 客户端所期望的;/v1/chat/completions 也开始接受 developer 消息。控制面按上游 报告的原样记录 Token 用量,包括上游自己给出的总数,并按该上游的计数方式为推理内容计价。流式输出护栏按生成内容计算缓冲区大小,在 /v1/messages 上扣住所有具备拦截能力的护栏链,并在 window 模式下遵循该配置行自己的缓冲设置。每个模型服务请求现在都会留下一条用量记录,响应头发出后才失败的流会以失败的状态码记录,而不再是 200。网关会发布内存指标并自行采集堆 profile,且在等待上游期间持有大请求体所占的内存减少约三分之一。
行为变化
-
响应头
200发出后才失败的流,现在以失败的状态码记录。 流中途的上游错误、传输错误、解码错误或超时、上游的带内错误事件,以及 Responses 桥接的空流失败,会被记录为502、504或上游自己的4xx(例如 Anthropic 带内的rate_limit_error记为429),并填入error_class和error_message。调用方中途离开时,在所有流式接口上都记为499。此前这些记录都是200,错误字段为空。日志页的状态列、控制台的成功率和延迟分位数(只统计 2xx)、访问日志以及aisix_usage_events_emitted_total的status标签都会随之变化。成本、预算和限流不受影响。/v1/audio/speech现在在音频结束时写入用量事件,因此其延迟覆盖整个流。 -
每个模型服务请求现在都会留下一条用量记录。 Cohere 重排(它上报的是搜索单元而非 Token 数)、 模型服务提供方在 Completions、Embeddings、图像生成和视频提交上缺少对应能力时网关自己返回的
501,以及网关无法读回结果的 MCP 工具调用(502),此前都不会写入用量事件。现在它们会以零 Token 记录出现在日志中。轮询视频任务和下载视频内容仍是仅有的不写记录的调用。 -
单次请求接口上每一次失败的上游尝试都有自己的用量记录。 在 Completions、Embeddings、重排、图像生成与编辑、三个音频接口、视频提交以及
/v1/messages/count_tokens上,每一次失败的尝试——无论是故障转移还是对同一目标的重试——现在都会写入一条零 Token、不计费的记录,带上它的attempt_kind和错误,与 Chat 已有的行为一致。这同样适用于直连模型:重试预算重放了5xx的直连模型,现在每次尝试都会留下一条记录。所有尝试都失败时,最后一次尝试的记录就是该请求的最终记录。 -
用量事件的
occurred_at精确到毫秒(2026-09-24T12:42:25.123Z),控制面、SLS、Datadog 和对象存储都是如此。OTLP 把它作为 span 的结束时间携带,而不是字符串。只接受…:SSZ的解析器必须能接受小数秒。Admin API 和控制台仍然把occurred_at显示到秒。 -
日志列表及其导出改为按
occurred_at、再按 ID 排序,而不再按插入顺序。环境中有多个网关时,较晚的请求不会再排在较早的请求之下。 -
经 Vertex AI 记录的 Gemini 用量现在就是 Gemini 报告的用量。 这适用于经 Vertex AI 的思考型调用(无论是否流式),前提是 Gemini 报告的总数等于提示、补全和思考内容三者之和。此时用 量记录中的
completion_tokens不含思考内容,reasoning_tokens为思考内容,并新增total_tokens。没有这样的总数时,记录仍把思考内容计入completion_tokens。SLS 和对象存储导出携带同样的原始取值,因此对导出数据的completion_tokens求和时,这些记录不再包含思考内容。成本、限流、预算、Prometheus Token 指标、访问日志、OTLP/Datadog 的gen_ai.usage.output_tokens以及客户端收到的用量均不变。 -
推理内容按上游自己的计数方式计价。 当上游给出的总数表明推理内容是在补全之外单独计数的(
prompt + completion + reasoning == total)时,全部completion_tokens按补全单价计费,全部reasoning_tokens按推理单价计费。其他所有记录,包括没有总数的记录,仍沿用此前的公式。对于在completion_tokens之外上报推理内容的 OpenAI 兼容上游,这会为此前公式漏计的补全 Token 计费。/v1/messages和/v1/completions现在与/v1/chat/completions一样记录推理 Token,因此如果模型设置了单独的推理单价,这两个接口上的推理内容也会按该单价计费。 -
推理 Token 超过补全 Token、或缓存命中的提示 Token 超过提示 Token 的用量记录,现在会被存储。 此前控制面会丢弃这类记录,同时把整个批次应答为已接受,于是该请求从日志中消失,也从未被计费。现在它会按上报的原样存储这些计数。
-
流式输出护栏的
max_buffer_bytes按生成内容计算。 流因输出护栏而被扣住期间,该上限在所有路由上统计助手文本、推理内容和工具调用参数,从不统计 SSE 封装。JSON 封装同样不计入,只有透传路由中继网关无法解析的请求体时例外,此时整个data:载荷都计入。纯文本的 Chat 流触发位置与此前完全相同。推理内容或工具调用参数较多的 Chat 流,现在会在合计内容达到上限(默认 256 KiB)时触发,此前推理内容不被计入。在原生/v1/messages和/v1/responses、Responses 桥接以及透传路由上,此前统计的是线上字节,现在该上限会更晚触发。每个被扣住的流还有一个以原始字节计、等于max_buffer_bytes128 倍的上限,几乎不含内容的帧组成的流可能达到它;越过该上限同样是缓冲区超限事件,按on_buffer_exceeded处理。 -
在具备拦截能力的输出护栏下,流式
/v1/messages响应在扫描完成后才下发。window模式的输出护栏——Azure 和阿里云文本审核、custom以及aliyun_ai_guardrail——此前会让流式/v1/messages响应逐 Token 通过,因此拦截只能在内容已经发出后追加一条错误,custom脚本看到的文本也是空的。现在响应会被扣住,扫描通过后整体放行,因此调用方收到第一个字节的时间会推迟。只监控的护栏链仍然实时流式输出。 -
在整条流被扣住的场景下,
window模式护栏遵循自己的缓冲设置。 在/v1/responses上(原生和桥接均是),window护栏链此前以固定的 256 KiB 上限扣住,并且总是失败即拦截;在/v1/messages上它此前根本不会被扣住,见上一条。现在这两个接口上被扣住的window护栏链都使用该配置行的max_buffer_bytes和on_buffer_exceeded;有多个window配置行时取最小的上限,并且除非每 一行都设置为失败放行,否则流会失败即拦截。含有任何buffer_full配置行的护栏链不受影响。在全部为window的护栏链下,/v1/chat/completions上流式工具调用参数现在也受同一个合并后上限约束,此前扫描会在固定的 256 KiB 处停止。 -
/v1/messages和/v1/responses现在遵循on_buffer_exceeded: fail_open。 此前这两个接口不论该设置如何都会失败即拦截。现在已扣住的内容会不经扫描放行,与 Chat 一致,并且请求会记录guardrail_bypassed_reason: output_buffer_exceeded。 -
keyword和pii护栏对每个值分别判定。 在/v1/chat/completions、/v1/completions、/v1/messages、/v1/messages/count_tokens、/v1/responses和 MCPtools/call上,此前它们对每个请求扫描一整段拼接后的文本,而脱敏却按值分别进行,因此拦截规则、监控模式下的would_mask和实际执行的脱敏可能给出不一致的结果。现在每条消息、每个内容块、每个工具调用参数、调用方发送的每个工具结果,以及 MCPtools/call结果和structuredContent中的每个值都会被单独判定,工具载荷中的对象键和 JSON 数字也各自算作一个值。锚定整个值的规则(^…$)现在会触发拦截。只在跨越两个值时才能匹配的规则——跨两条消息、同一条 Chat 消息的两个文本块、键和它的值、工具名称和它的参数——将不再匹配。匹配对象键或数字的keyword或pii规则现在会触发拦截。请复查那些依赖跨值匹配的规则。透传路由仍把提取出的文本作为一整段扫描。在/v1/responses上,请求中重放的条目——mcp_call的参数和输出、mcp_approval_response.reason以及数组形式的function_call_output.output——现在不仅会被扫描,还会被脱敏。在响应侧,只有mcp_call的arguments会被扫描和脱敏,托管工具的output不会。 -
透传路由上的护栏读取的内容与类型化接口一致。 此前经透传路由中继的 Anthropic Messages 流不会被扫描,工具调用参数(双向)、系统提示词以及调用方发送的工具结果也不会被读取。现在这些都会被读取,因此此前未经扫描就通过的请求和响应现在可能被拦截。推理和思考内容与类型化接口一样不被扫描。
-
无法改写内容的路由上的
pii脱敏规则命中现在会被记录。 在透传路由、/a2a、任务类接口、/v1/realtime和/v1/videos上,脱敏命中此前会静默放行。内容仍然原样通过,但该记录现在会带有一条执行命中,动作为新增的mask_unsupported;监控模式下的命中则为would_mask_unsupported,而不再是would_mask。 -
被扣留上限拒绝或放行的流现在会说明原因。 失败即拦截的触发现在会记录一条执行命中,动作为新增的
blocked_buffer_exceeded,并指明当时生效的是哪一行的上限。失败放行的触发现在会记录guardrail_bypassed_reason: output_buffer_exceeded,并计入aisix_guardrail_bypasses_total。 -
按护栏拆分的阶段序列只统计护栏实际运行过的阶段。 此前仅作用于输入的护栏会在每个请求上记录一个接近零的
aisix_guardrail_latency_seconds{phase="output"}样本 ,仅作用于输出的护栏则记录对应的输入样本。对于单阶段护栏,这些序列将不再出现。hook_point: both的配置行不受影响。 -
首 Token 时间指标新增
side标签。aisix_request_ttft_seconds和aisix_llm_time_to_first_token_seconds原有的观测保留为side="upstream",并新增side="downstream":从网关收到请求到客户端收到第一个帧,包括输入护栏、重试和输出扣留。不按side过滤的查询现在会混合两者,其_count也会翻倍;加上side!="downstream"即可保持原有含义,滚动升级期间它也能匹配 1.4.0 网关的序列。side总是会输出,且不会被observability.metrics.labels移除。 -
aisix_request_e2e_latency_seconds也新增side标签,但默认含义相反。 它原有的观测,即客户端感受到的整个请求耗时,变为side="downstream"。新增的side="upstream"表示产生该响应的那次尝试中上游所花的时间,与该尝试的upstream_latency_ms是同一个数值:每个请求最多一个,缓存命中、到达上游之前就失败的请求、/a2a以及集成模型则没有。不按side过滤的查询现在会混合两者。加上side!="upstream"即可保持原有含义,它也能匹配 1.4.0 网关的序列;这与 TTFT 的过滤条件正好相反。side总是会输出,且不会被observability.metrics.labels移除。 -
阿里云配额限流和阿里云侧超时现在会被单独归类。 阿里云以 HTTP 200 加响应体中的
Code 588/Code 581报告这两种情 况;两种阿里云护栏现在把它们报告为aliyun_throttled和aliyun_timeout,而不再是aliyun_5xx,体现在guardrail_bypassed_reason和aisix_guardrail_bypasses_total{reason}中。 -
对象存储导出器在首次尝试即被存储服务明确拒绝时,会直接丢弃该批次。 当 S3、Google Cloud Storage 或 Azure Blob 以不可重试的
4xx应答一次上传时,该批次会被立即丢弃,计入aisix_otlp_fanout_drops_total{reason="permanent_error"},记录一次日志,并立即体现在导出器的健康状态中。401、403和404此前就会被立即丢弃;其他4xx此前会在完整的 5 分钟预算内反复重试,其后的记录则不断排队,最终以queue_full被丢弃。408、429、5xx以及 S3 的RequestTimeout和OperationAborted仍会重试。Datadog 导出器现在会重试408,而不再丢弃。 -
接收端持续失败的导出器,从第一次失败的尝试起就显示为失败。 此前,对正在限流、超时、返回
5xx或不可达的接收端进行重试的导出器,会一直报告自己健康,直到某个批次在重试预算耗尽时被丢弃。现在每一次失败的尝试都会上报其最近的错误,因此控制台会立即显示它处于失败状态,并在下一次成功投递后恢复。失败批次数仍然只统计被丢弃的批次。既未投递也未丢弃过任何批次的导出器,现在显示为「no batches delivered yet」,而不再是「delivery healthy — 0 batches shipped」。 -
流式护栏拒绝现在带有
error.code。 在/v1/messages和count_tokens上,护栏拒绝保留error.type: invalid_request_error,并新增error.code(策略拦截为content_filter,失败即拦截的配置行为guardrail_unavailable)。/v1/chat/completions上的流式拒绝帧现在携带与缓冲模式下422相同的错误码。在中继 Anthropic 流的透传路由上,拒绝帧现在采用 Anthropic 的格式,因此其error.type从content_filter变为invalid_request_error;请改为读取error.code。 -
所配置 URL 中的用户信息(
user:pass@host)会被接受并按原样使用。 它既不会被校验,也不会被脱敏。控制面现在在模型服务提供方凭证的api_base和apis.<name>.base,以及环境的mcp_resource_url上接受它,并按原样存储和返回。网关现在在 Azure OpenAI 和 Vertex AI 的api_base、Azure AD 的authority_host、OIDC 的issuer和jwks_uri、MCP OAuth 的resource_url(按配置原样发布在受保护资源元数据端点上),以及managed.cp_base_url/managed.cp_etcd_endpoint上接受它;此前这些位置都会拒绝它。回环地址的http://OTLP 和对象存储导出器端点也可以携带它:OTLP 会把它作为 Basic 认证发送,对象存储服务则会忽略它并自行签名请求。只要环境中注册的某个网关早于 1.5.0,这样的导出器端点就会被以422 DP_INCOMPATIBLE拒绝。日志、错误和调试输出会按原样显示所配置的 URL,包括其中的用户信息;凭证类查询参数仍会被脱敏。 -
访问日志在响应体结束时写出。 它现在排在该请求的
provider call completed日志之后。如果慢速客户端仍在读取非流式响应时关闭宽限期已经耗尽,该请求的日志会丢失,这与流式请求此前的情况相同。对于由网关代理的视频,GET /v1/videos/{id}/content现在在转发结束时才结束duration_ms。 -
从日志页和审计页下载的文件使用查看者所在的时区。 控制台会请求浏览器所在的时区,因此在首尔下载的日志或审计导出文件,会显示
2026-09-12T13:03:01+09:00,而此前显示的是2026-09-12T04:03:01Z。按%Y-%m-%dT%H:%M:%SZ解析这些文件的脚本需要改用能识别时区偏移的解析器。Admin API 用量事件导出的调用方如果不传新增的timezone参数,仍然得到 UTC。 -
任何网关都无法加载的护栏配置现在会被以
400拒绝。pii/presidio的action、default_action、operator或language为空字符串,pii或presidio的max_buffer_bytes为0,任一阿里云护栏的max_buffer_bytes为负数,以及pii自定义模式名称超过 64 个字符——此前这些配置可以保存,随后被每个网关丢弃,导致该护栏什么都不检查。pii或presidio上的负数此前就会被拒绝,阿里云护栏上的0仍表示使用默认值。省略某个字段仍表示使用其默认值。 -
新建的预算在其花费首次被计算之前显示「no spend data yet」,而不再是
$0.00 (0%)。这一状态在预算创建后,以及升级后到第一次聚合之前,持续一个聚合周期,约 5 秒。 -
从控制台保存护栏时,会保留表单中未显示的配置。 此前控制台只发送表单渲染出来的字段,而 API 会整体替换
config,因此通过 API 设置的取值会在第一次从控制台保存时被重置为默认值。现在从控制台保存的custom或 Azure 文本审核的window模式配置行,以及任意模式下的任一阿里云护栏配置行,会显式写入max_buffer_bytes和on_buffer_exceeded,阿里云的window配置行还会写入window_size/window_overlap_size,除非有修改,否则都取网关的默认值。 -
MCP 护栏拒绝在日志中显示为「tool error」。 网关以带内方式报告该拒绝,即 HTTP 200 上一个
isError: true的 JSON-RPC 结果;日志中的徽标和概览页的最近尝试卡片现在显示「tool error」,并把 HTTP 状态码移到记录详情中。存储和导出的status_code不变。 -
Playground 不再在未设置时发送
temperature,向 OpenAI 和 Azure OpenAI 推理模型发送max_completion_tokens而不是max_tokens,并应用模型服务提供方凭证的request.param_renames。
新功能
-
共享密钥(HMAC)JWT 验证。 OIDC 服务提供方可以携带
hmac_secret来代替 JWKS。设置了它即选择 HMAC 验证:HS256、HS384和HS512Token 会按原样以该密钥的 UTF-8 字节进行验证,不会发起任何获取请求,issuer和audiences也变为可选。iss与某个服务提供方的issuer匹配的 Token 只由该服务提供方验证;否则会按名称顺序依次尝试所有 已启用且未设置 issuer 的共享密钥服务提供方。密钥至少为 32 字节,在 Admin API 中只写(读取时返回hmac_secret_set),静态加密存储,并且从不出现在审计事件或数据导出中。JWKS 服务提供方不受影响。只要环境中有任何已注册网关早于 1.5.0,控制面就会以422 DP_INCOMPATIBLE拒绝保存携带密钥的服务提供方,因为更早的网关会改用 issuer 发布的密钥来验证该服务提供方。 -
模型组适用于所有单次请求接口。
/v1/completions、/v1/embeddings、/v1/rerank、/v1/images/generations、/v1/images/edits、/v1/audio/transcriptions、/v1/audio/translations、/v1/audio/speech和视频提交此前对模型组返回400。现在它们会按与 Chat 相同的策略顺序、健康过滤、重试预算和故障转移遍历模型组的目标。用量记录归属于实际服务该请求的目标,部署和回退指标以及访问日志中的路由摘要都会被填写,least_latency和least_busy模型组也会在这些接口上跨目标均衡负载。每个目标都必须支持其所在的接口。/v1/realtime和任务类接口按设计仍拒绝模型组。 -
/v1/chat/completions支持developer消息。 OpenAI 推理模型以及 Pi 等客户端会发送带有role: "developer"的请求,此前这类请求会被以400拒绝。现在对 OpenAI 原样保留;对不接受该角色的 OpenAI 兼容模型服务提供方,以system发送;在 Anthropic、Gemini 和 Bedrock 上映射到原生的指令位置。护栏把它们当作系统消息处理:input_messages: latest_turn不包含它们,all包含它们。 -
用量记录保存上游报告的
total_tokens。 每条用量记录按原样保存上游报告的总数,未报告或报告为0时为null。用量日志 API 以及 JSON 和 CSV 导出会返回它,日志详情中显示为「Total tokens (reported by upstream)」。usage_summary会对它求和,没有该值的记录改用计算得出的总数。/usage 页面的合计现在累加每条记录自己的总数。 -
区分策略拦截和失败即拦截。 用量记录新增
guardrail_blocked_fail_closed,当护栏因为无法评估内容(例如其服务提供方宕机,或流超出了缓冲区)而非策略命中而拒绝时为 true。护栏拦截标签页新增拦截类型过滤器,每一行显示 Policy / Fail-closed 徽标,列表和导出也接受同样的过滤条件。升级前记录的行读取为false。 -
按指定时区导出时间戳。 日志导出(
GET /environments/{env_id}/usage_events/export)接受可选的 IANAtimezone,并以该时区及其偏移显示所有时间戳。控制台下载的日志和审计文件使用查看者所在的时区。 -
Google Cloud Storage 导出器支持
endpoint:即上传所用的 Cloud Storage XML API 基础 URL,例如私有端点。上传使用 XML API,因此该端点必须提供 XML API。控制台的导出器表单现在为 GCS 和 Azure Blob 提供端点字段。只要环境中有任何已注册网关早于 1.5.0,控制面就会以422 DP_INCOMPATIBLE拒绝保存携带端点的 GCS 导出器,因为更早的网关会忽略它并上传到 Google 的公共主机。 -
网关内存诊断。 Prometheus 监听器现在会发布内存分配器的字节统计(
aisix_allocator_bytes)、cgroup 内存上限(aisix_memory_limit_bytes)、标准的process_*指标、按运行时的任务数 Gauge,以及进程内各存储的条目数和字节数 Gauge(aisix_component_entries、aisix_component_bytes)——其中包括排队中的用量事件和导出器批次、各类缓存、输出护栏扣留的内容以及处理中的请求体。堆采样默认开启。新增的监听器observability.debug(默认127.0.0.1:9091,默认开启)在GET /debug/pprof/heap上提供堆 profile。它默认监听回环地址;配置非回环地址也会被接受,但会输出一条告警。启用observability.heap_profiling.auto_dump(默认开启,阈值为内存上限的 80% 和 90%,目录为/var/lib/aisix/heap,每台主机保留 5 个文件)后,网关会在内存越过每个阈值时自行写出一份 profile,因此即使发生内存不足被杀,磁盘上也会留有一份。这两个配置块都在网关的配置文件中设置。分配器指标、堆采样和堆 profile 需要官方镜像所用的基于 GNU C 库的 Linux 构建,进程指标仅在 Linux 上发布。实测采样开销在多次运行间的正常波动范围内。 -
访问日志记录消息体大小。
proxy request completed日志新增request_body_bytes,即从客户端读取的字节数,以及response_body_bytes,即发送给客户端的字节数,包括 SSE 封装和保活帧。无法得到最终值时对应字段会被省略:请求体未读到结尾时(例如Content-Length检查返回的413)省略request_body_bytes,未写出响应头时省略response_body_bytes;/v1/realtime上两者都不出现。 -
被拒绝的用量事件会被计数。 当控制面接受一个用量批次、但拒绝其中部分事件时,网关会输出一条告警日志,并把它们计入新增的
aisix_usage_events_rejected_total计数器。此前这类事件会无声无息地消失。 -
控制台提供更多护栏设置。 Lakera、Presidio(包括按实体设置的动作和分数阈值)、OpenAI Moderation(按类别的阈值)以及两种阿里云护栏,现在会展示网关读取的全部配置字段,
window模式的护栏也会显示其流缓冲设置。 -
入门教程包含部署网关。 教程现在在创建环境与添加模型服务提供方凭证之间新增一步「Deploy your data plane」,在有网关完成注册后即算完成。
改进
-
Responses 到 Chat 的桥接行为符合 Agent 客户端的预期。 它发出的每个 Response 都携带 Responses API 定义的完整字段集。中途失败的流会在已有的
error事件之后以response.failed结束:护栏中止时为invalid_prompt,上下文长度、配额、速率限制和过载则使用上游自己的错误码(context_length_exceeded、insufficient_quota、rate_limit_exceeded、server_is_overloaded或slow_down),因此 Codex CLI 不会再把这样的轮次当作连接中断而重试五次。首个事件就是失败的流会以response.created和response.in_progress开头,这是 OpenAI SDK 的要求。不含任何内容的上游流现在会以可重试的upstream_error失败,而不再以空输出完成;在结束之后才断开的连接会正常完成。重放的reasoning条目会以reasoning_content发送给上游,因此这类请 求会发送更多输入 Token。助手消息及其后的工具调用会作为一条消息发送给上游,namespace工具(Codex 的multi_agent_v1)会以<namespace>__<tool>的形式提供给模型。 -
发往 OpenAI 和 Azure OpenAI 推理模型的
max_tokens会以max_completion_tokens发送,在 Chat、/v1/messages桥接和 Responses 桥接上均是如此,因此这些请求不会再被上游以400拒绝。模型服务提供方凭证的request.param_renames仍具有最终决定权。 -
透传路由会为重排和 DashScope 原生调用计量。 经透传路由中继的 Cohere 风格重排请求体或 DashScope 原生信封,其非流式 JSON 响应现在会记录上游的 Token 数和调用方的模型,此前记录的是零 Token 且没有模型。流式响应的计量方式不变,这些记录仍然不产生费用。
-
自定义护栏脚本在 Chat、Responses 和 Messages 上可以读取
ctx.model。 在这些接口上,输入钩子的ctx.model此前始终为空,因此以模型为键的策略从不生效。现在它是调用方所指定的模型。 -
所有上游事件流都由同一个符合规范的解析器读取。 以单独回车符分帧的流在所有路由上都能被正确分帧、重新打时间戳、扫描和计费,以字节顺序标记开头的流会保留其第一个事件,把一个 JSON-RPC 事件拆成多行
data:的 A2A Agent 会被正常中继而不再中断流。模型服务提供方的流中单个帧未结束就增长超过 16 MiB 时,现在会失败,而不再无限增长。 -
流式集成模型只报告一次用量,放在一个最终的用量块中,而不再在每个携带用量的评审帧 上重复报告整个评审组的用量。仅当客户端请求了
stream_options.include_usage时才会发送该块。 -
删除或禁用导出器会停止其投递流水线,并将其从网关上报的导出器健康状态中移除。重新启用会启动一条全新的流水线。
-
routing target attempt failed告警日志在所有日志级别下都携带request_id,包括log_level: warn。 -
控制台更易阅读。 文字采用更易读的字号层级和更高的对比度,每个页面的页头都是一句话,细节收在折叠的「How it works」说明中。
-
部分故障期间,/usage 页面会显示部分数据。 数据加载失败的环境会被标记为「Data unavailable」并在横幅中列出,其他环境仍正常显示。
-
预算会报告其花费最近一次被计算的时间(
state.aggregated_at),/budgets 页面上的数据新鲜度说明也以该时间为准。 -
导出组织数据的速度不再随共享配置存储的规模变慢。 此前在大型部署上,即使是很小的组织,
GET /data_export也要花几分钟;导出内容不变。 -
控制面会压缩其配置存储的历史。 dp-manager 每 5 分钟从控制面 PostgreSQL 数据库中的配置存储里删除已被取代的修订版本,以及比最新 1000 个修订版本更早的删除记录。在 1.4.0 中没有任何机制清理它们,因此该表只增不减。间隔和保留数量都是固定的。0.12.0 及以后的网关在 watch 读到已被压缩的历史时会重新读取配置。
-
控制面只输出结构化 JSON 日志。 cp-api 和 dp-manager 此前会在 JSON 日志中混入带颜色 的纯文本行。一次性的启动迁移和回填现在各写一行 JSON:成功的汇总为 INFO,数量作为字段;运维人员仍需修复的配置行,以及迁移重新使之生效的护栏,保持为 WARN。数据库错误是
error级别的 JSON 记录,超过 200 毫秒的查询以slow sql记为warn。「record not found」查询不再记录日志,API 已经应答的约束冲突以debug级别记录。panic 和第三方库的输出也都是 JSON 记录。
修复
- 修复了依赖先前配置的配置(例如护栏和紧接着创建的护栏挂载)偶尔以错误顺序到达网关、导致网关跳过该挂载的问题。
- 修复了 Cohere 模型服务提供方凭证在以裸主机作为
api_base时,Chat 和 Embeddings 请求发往错误 URL,以及在使用/compatibility/v1基础地址时重排请求发往错误 URL 的问题。 - 修复了已存储裸主机地址的 Jina 模型服务提供方凭证在 Embeddings 上返回
404的问题;一次性迁移会把它们改为带版本号的基础地址并重新发布。 - 修复了响应体为空或错误消息为空白的上游错误以空的
error.message返回给调用方的问题;现在会显示例如upstream returned 404 Not Found。 - 修复了在响应或流式块中省略
model的 OpenAI 兼容上游以upstream_decode_error失败的问题。 - 修复了用量记录缺少
applied_guardrails的问题。/v1/completions、/v1/embeddings、/v1/rerank、图像、音频、视频、count_tokens、透传路由和任务类接口上的错误记录和护栏拒绝记录缺少该字段;/v1/responses、透传路由、/v1/realtime和任务类接口上的成功记录也缺少该字段。 - 修复了监控模式的输出护栏漏掉流式响应前 256 KiB 之后出现的匹配的问题。
- 修复了
/v1/messages/count_tokens在请求发生重试或故障转移时只记录成功那次尝试的问题。 - 修复了启用网关磁盘快照缓存时,重启前刚删除的资源在重启后重新出现的问题。
- 修复了共用同一张网关证书的多个副本互相覆盖被拒绝资源报告的问题;现在只有当每个拒绝该资源的副本都仍在使用先前的取值时,才会出现
stale_serving_since。 - 修复了 Google Cloud Storage 导出器忽略
endpoint的问题。 - 修复了在由资源文件配置的网关中,两类未设置
api_base的模型服务提供方凭证返回400的问题:anthropic凭证在/v1/messages和count_tokens上失败;provider为空的旧式adapter: openai凭证在自行构建上游 URL 的路由(音频、图像编辑、任务类接口、Realtime 和/v1/responses)上失败。 - 修复了输出
keyword和pii护栏对流式原生/v1/responses回复中的原始推理文本进行脱敏或拦截的问题,这类回复来自 gpt-oss 等以response.content_part.done结束推理内容的上游。生成的推理内容不在输出护栏的范围内,这与非流式路径一直以来的行为一致。 - 修复了创建、重命名或删除环境后,控制台的环境切换器在下一次导航前一直显示旧状态的问题。
- 修复了中文控制台中护栏
endpoint的帮助信息显示为英 文的问题。 - 修复了网关在等待上游应答期间持有请求体约三份拷贝(某些路由上更多)的问题,该问题可能在并发的大型 base64 图像请求下导致网关内存耗尽。现在请求在等待期间最多持有两份请求体,集成模型每多一个处理中的成员再加一份。
- 修复了
content为文本块数组的 Chat 消息中,redacted_entity_counts把每个实体计数两次的问题。 - 修复了网关在配置 watch 因压缩以外的原因被取消后静默停止应用配置变更、而
/status/config仍报告已连接的问题。现在它会重新读取配置并重新开始 watch。经过一段健康期之后的重连也会重新从 1 秒的等待开始,而不再沿用先前失败累积下来的最长 60 秒的延迟。 - 修复了经 Vertex AI Gemini 的流式
/v1/chat/completions在第一个内容块上发送全零usage对象的问题;现在用量只出现在最后一个块上。 - 修复了导出器投递错误在网关日志和控制台的导出器健康状态中暴露导出器上所配置密钥的问题:API Key、请求头凭证和对象存储密钥现在显示为
***。接收端自己的错误文本其余部分保持不变。 - 修复了所有网关都会丢弃的导出器端点仍可被保存的问题——大写的 scheme(例如
HTTPS://),以及紧跟在回环http://主机之后的空端口、查询参数或片段;现在它们会被以400拒绝。
API 变化
1.4.0 与 1.5.0 的 Cloud Admin API 文档结构对比显示,没有新增或移除任何操作或结构定义:两份文档都是 129 个 操作、240 个结构定义。变化包括新增的字段和参数、OIDC 服务提供方上变为可选的响应属性、护栏命中上新增的枚举取值,以及模型服务提供方凭证上现在允许用户信息的 api_base 模式。有几处变化的含义无法通过结构对比识别,列在表格之后。
| 端点 | 变化 |
|---|---|
POST /environments/{env_id}/oidc_providers | 新增可选的只写请求字段 hmac_secret(至少 32 个 UTF-8 字节)。请求中的 issuer 和 audiences 不再是必填项;除非设置了 hmac_secret,否则它们仍然必填。以下情况返回 400 INVALID_REQUEST:hmac_secret 与 jwks_uri 同时设置、未设置 hmac_secret 的服务提供方缺少 issuer 或 audiences,以及密钥不足 32 字节。只要环境中注册的某个网关早于 1.5.0,保存携带密钥的服务提供方就会返回 422 DP_INCOMPATIBLE。 |
PATCH /environments/{env_id}/oidc_providers/{oidc_provider_id} | 新增可选的 hmac_secret:省略表示保留已存储的密钥,null 表示移除它。issuer 和 audiences 接受 null,仅当更新后的服务提供方带有密钥时才合法。上述三条 400 规则针对更新后的服务提供方进行检查。422 DP_INCOMPATIBLE 闸门相同,适用于对携带密钥的服务提供方的任何更新。 |
GET /environments/{env_id}/oidc_providers、GET …/{oidc_provider_id} 以及 POST / PATCH 的响应 | 新增必有字段 hmac_secret_set(布尔值)。对于共享密钥服务提供方,issuer 可能缺失,audiences 可能为空;无条件读取 issuer 的客户端必须能容忍它缺失。JWKS 服务提供方的返回与此前完全相同。 |
GET /environments/{env_id}/usage_events | 新增查询参数 guardrail_blocked_fail_closed。每行新增 guardrail_blocked_fail_closed(布尔值,升级前记录的行为 false)和 total_tokens(上游报告的值,未报告时为 null)。guardrail_enforced_hits[].action 新增 blocked_buffer_exceeded 和 mask_unsupported;guardrail_monitor_hits[].action 新增 would_mask_unsupported。 |
GET /environments/{env_id}/usage_events/export | 新增查询参数 guardrail_blocked_fail_closed 和 timezone(IANA 名称;省略时与此前一样为 UTC;为空、Local 或未知取值返回 400 INVALID_REQUEST)。各行新增与列表相同的两个字段和枚举取值;CSV 新增 guardrail_blocked_fail_closed 和 total_tokens 两列。 |
GET /environments/{env_id}/usage_summary | 每个分桶新增 total_tokens:有上游报告的总数时累加该值,否则累加计算得出的总数。 |
GET /budgets、GET /budgets/{budget_id} | 新增 state.aggregated_at(可为 null 的日期时间):花费最近一次被计算的时间;预算创建后首次计算之前为 null。 |
POST /provider_keys、PATCH /provider_keys/{provider_key_id} 以及 GET / PATCH 的响应 | api_base 模式现在允许用户信息(https://user:pass@host/...);此前接受的所有取值仍然接受。apis.<name>.base 同样如此。取值按原样存储和返回。 |
结构对比无法体现 的变化:
- 护栏的
POST/PATCH(/environments/{env_id}/guardrails…)现在对所有网关在加载时都会拒绝的取值返回400:pii/presidio上为空字符串的action、default_action、operator或language,pii或presidio上为0的max_buffer_bytes,任一阿里云护栏上为负数的max_buffer_bytes,以及超过 64 个字符的pii自定义模式名称。这些调用此前会成功,并保存一个任何网关都不会加载的护栏。pii或presidio上的负数此前就返回400,阿里云护栏上的0仍被接受并表示默认值。 - 导出器的创建和更新 会以
400拒绝以下otlp_http或object_store的endpoint:大写 scheme(HTTPS://),以及紧跟在回环http://主机之后的空端口、查询参数或片段;所有网关都会丢弃这样的配置行。回环http://端点现在可以携带用户信息,但只要环境中注册的某个网关早于 1.5.0,就会以422 DP_INCOMPATIBLE拒绝。 - 环境的创建和更新 在
mcp_resource_url中接受用户信息(此前会被拒绝),并按原样返回。 - 导出器的创建和更新 现在在
gcs类型的object_store导出器上接受endpoint,此前这会返回400。它是 Cloud Storage XML API 的基础 URL,必须为https(或指向允许列表中回环主机的http),并且仍然不能与auth_mode: cloud_identity同时使用。只要环境中注册的某个网关早 于 1.5.0,保存携带它的导出器就会返回422 DP_INCOMPATIBLE。 GET /environments/{env_id}/usage_events及其导出 按occurred_at、再按 ID 排序,而不再按插入顺序。导出的分页遵循同样的顺序。- 用量记录上的
cost_usd按行根据上游的总数计算:当prompt + completion + reasoning == total_tokens时,补全和推理分别全额计费。已存储的记录中,reasoning_tokens现在可能超过completion_tokens,cached_prompt_tokens也可能超过prompt_tokens。 GET /environments/{env_id}/rejected_resources:只有当每个拒绝该资源的副本都仍在使用先前的取值时,才会出现stale_serving_since。GET /environments/{env_id}/dp_nodes:在每个节点的导出器健康状态中,last_error现在在批次重试期间也会被设置,并在下一次成功投递后清除;failed_batches和last_failure_unix仍然只统计在重试耗尽后或因永久性错误而被丢弃的批次。字段说明已相应更新,结构不变。guardrail_monitor_hits[].action的取值would_block和would_mask是新补充到文档中的枚举取值,并非新增;input_messages的说明提到了developer消息,并改为描述消息窗口而非所读取的文本。这些只是说明文字的变化。
网关与控制面之间的协议(/dp/*)不属于 Cloud Admin API。POST /dp/telemetry 中的每个事件新增了可选的 total_tokens,网关现在也会读取 2xx 应答中的 rejected 计数。
升级说明
从早于 1.5.0 的版本升级时,均需遵循本节说明,包括跳过 1.5.0 升级到更新版本的情况。
- 控制面和网关都运行 1.5.0 后,报告的成本可能上升。 有三类流量的计费比 1.4.0 更完整。在
completion_tokens之外单独计算推理内容的 OpenAI 兼容上游此前被少计费,因为 1.4.0 会从补全中减去推理部分;现在其补全 Token 会全额计费。推理 Token 超过补全 Token、或缓存命中的提示 Token 超过提示 Token 的请求,此前被 1.4.0 丢弃、从未计费;现在它们会被存储并计费。/v1/messages和/v1/completions上的推理内容现在按模型的推理单价计费,与/v1/chat/completions此前的行为一致。在 Gemini 报告了总数的情况下,经 Vertex AI 的 Gemini 思考型记录的计数会变化——completion_tokens不再包含思考内容,思考内容计入reasoning_tokens,SLS 和对象存储导出中也是如此——但成本不变。 - 在首 Token 时间的查询和告警中加上
side!="downstream"。 否则,针对aisix_request_ttft_seconds或aisix_llm_time_to_first_token_seconds的查询会把新增的网关侧观测混入上游观测,其_count也会翻倍。滚动升级期间,side!="downstream"同样能匹配 1.4.0 网关。 - 在端到端延迟的查询和告警中加上
side!="upstream"。 否则,针对aisix_request_e2e_latency_seconds的查询会把新增的上游观测混入客户端感受到的延迟。这与 TTFT 指标的过滤条件正好相反,它同样能在滚动升级期 间匹配 1.4.0 网关。 - 对于响应头发出后才失败的流式流量,成功率、延迟分位数和状态码分布会发生变化。 这些请求现在记为
502、504、上游的4xx或499,而不再是200,体现在日志、控制台的成功率和延迟分位数,以及aisix_usage_events_emitted_total的status标签中。 - SLS、Datadog 或对象存储导出中
occurred_at的解析器必须能接受小数秒。 只接受…:SSZ的解析器会拒绝新的取值。 - 复查那些依赖跨两条消息、同一条 Chat 消息的两个文本块、键和值或工具名称和参数进行匹配的
keyword和pii规则。 这类规则将不再匹配,而锚定整个值的规则,以及匹配工具载荷中对象键或数字的规则,现在会触发拦截。 - 透传路由上的护栏现在可能拦截此前未经扫描就通过的流量,因为它们会读取工具调用、系统提示词、调用方发送的工具结果以及 Anthropic 流。
- 推理内容或工具调用参数较多的流,会更早在
/v1/chat/completions上触发max_buffer_bytes,因为该上限现在会统计它们。如果这类流现在会触发on_buffer_exceeded,请提高扣住它们的护栏的上限。 - 根据
guardrail_enforced_hits[].action或guardrail_monitor_hits[].action分支处理的消费方会看到新的取值:blocked_buffer_exceeded、mask_unsupported和would_mask_unsupported。 - 读取经透传路由中继、来自 Anthropic 上游的流式护栏拒绝的客户端,应根据
error.code而不是error.type进行分支处理。 - 1.4.0 和 1.5.0 网关共用一个 Redis 响应缓存期间,1.4.0 网关会把 1.5.0 写入的部分条目视为未命中,直到这些条目过期。这些条目的用量中带有上游报告的总数,或被折叠进补全的 Gemini 思考内容。响应和计费不受影响。
- 写在 Redis URL 中的密码(
redis://user:pass@host)现在会出现在网关的 Redis 连接告警和降级告警中。 这些告警按原样显示所配置的 URL,而 1.4.0 只输出host:port。任何所配置 URL 中的用户信息现在都会按原样出现在网关日志和错误中。对于单节点和集群 Redis,请把凭证移到单独的username和password字段;Sentinel 的认证信息仍然写在 sentinel URL 中。 - 解析从控制台下载的日志或审计文件的脚本必须能接受数字形式的 UTC 偏移,例如
+09:00。省略timezone的 Admin API 用量事件导出调用方仍然收到 UTC。 - dp-manager 首次在 1.5.0 上启动约 5 分钟后,会一次性压缩从未压缩过的配置存储的全部历史。 该过程运行期间,配置写入会变慢,变更到达网关也会更久。该过程中重启 dp-manager 会从中断处继续。之后的压缩规模很小。
- 升级后,每个网关都会监听
127.0.0.1:9091、对堆分配进行采样,并在内存接近上限时把堆 profile 写入/var/lib/aisix/heap。 无需修改任何配置。如需关闭,可以设置observability.debug.enabled: false(释放该端口)、observability.heap_profiling.auto_dump.enabled: false(不写 profile 文件),或在网关环境中设置_RJEM_MALLOC_CONF=prof_active:false(不采样)。端口已被占用时只会记录日志,不 会阻止网关启动。在公开的 Helm Chart 中,/var/lib/aisix是一个emptyDir,因此这些 profile(每台主机最多 5 个)会占用节点的临时存储。
已知问题
- 在
google(AI Studio)模型服务提供方凭证上,思考型 Gemini 模型的思考 Token 会被少计。 网关对这类凭证调用 Gemini 的 OpenAI 兼容接口,该接口只在total_tokens中体现思考 Token。它们不会被计为推理内容,因此报告的成本、基于 Token 的限流和预算都会少计这部分。 - 如果在一次压缩过程中 PostgreSQL 停顿数秒,dp-manager 会重启。 当某个压缩批次错过其 5 秒超时、随后又提交失败时(例如 PostgreSQL 故障切换或长时间的锁等待期间),dp-manager 会退出。它会重启,并从中断处继续压缩。
1.4.0
发布日期: 2026 年 9 月 22 日
网关现在会重发控制面未能应答的用量批次,因此控制面故障只会延迟用量数据,而不再丢失它们。启动时连不上 Redis 的网关不再让监听端口一直关闭;etcd 的连接始终无法完成时,网关也不再卡在启动阶段——它会正常启动,有快照缓存就按快照缓存提供服务,并在后台持续重试。网关不认识的资源类型现在被视为向前兼容,而不再算作一次失败的重新加载。日志写出、配置下发、Prometheus 抓取和上游 DNS 解析都不再与请求处理争抢资源。控制台只生成最基础的网 关部署模板,更高级的网关配置改为由文档说明。离线安装包现在会透传 CORS 允许列表,Origin 允许列表也接受浏览器实际发送的写法。
行为变化
-
启动时限流 Redis 不可用,不再导致网关无法启动。 此前,配置了
ratelimit.backend: redis的网关在该 Redis 只接收或丢弃数据包而不应答时(容器停止、主机宕机、网络分区),完全不会绑定任何监听端口,几分钟后进程退出;在此期间它不响应任何请求,/livez和/metrics也不例外。现在网关会绑定监听端口并开始服务,按副本计数,并输出一条 WARN 日志,点明后端、Redis 的主机和端口,以及本次连接所花掉的预算;日志永远不会输出所配置的 URL,因为其中带有密码。该降级状态每 5 分钟重述一次。后台任务会在 Redis 恢复应答后立即接入共享后端。这是临时降级,网关不会永久切换到memory后端;降级期间不执行集群级限流。 -
启动时缓存 Redis 不可用,同样不再导致网关无法启动。 网关会绑定监听端口,并在 Redis 恢复应答之前把每条
backend: redis缓存策略都当作未命中处理,告警、5 分钟重述和后台接入的机制完全相同。是否支持向量检索只在服务端真正应答探测时才判定,因此不会有任何东西被贸然启用:探测尚未通过时,语义策略只记录一次日志并退化为仅精确匹配,期间每个请求既不触发向量化调用,也不产生 Redis 往返。原本希望缓存 Redis 不可达时启动失败的运维人员,将不再得到该行为。 -
etcd.dial_timeout_ms现在默认为 5000 毫秒,此前该连接过程完全没有上限。 只有设置了etcd.user的部署受影响,因为没有凭据时该连接不产生任何 I/O。该取值约束单次连接尝试,整次连接按每个已配置端点各获得一份,即dial_timeout_ms × max(1, 端点数)。超时到期会被报告为 etcd 不可达,并走既有路径:输出警告、绑定监听端口、按快照缓存提供服务、后台重试。该快照缓存是在连接之后才读取的,因此无上限的连接过程也让这个专为控制面故障而存在的机制一直没被用上。写dial_timeout_ms: 0可保持此前无上限的行为。request_timeout_ms未作改动,仍然默认无上限。 -
Redis 缓存故障期间,每次中断只报告一次,而不再每个请求报告一次。
cache lookup failed、cache write failed、cache backfill write failed及其两个语义缓存对应项,会把一次中断中的首次失败记为 WARN,其余记为 DEBUG,并在下一次成功后重新置位,因此后续再次中断仍会被报告。aisix_redis_failures_total{operation}未作改动,仍然统计每一次失败的操作。 -
Redis 明确应答并拒绝连接配置的情况,现在与「连不上」区分开,并且不再导致启动失败。 凭据被拒绝、服务端返回
NOAUTH或DENIED、服务端没有所配置的database,此前一律按「连不上」上报,于是告警把一台毫秒级就已应答的服务端归咎于网络。现在这类失败以自己的名义走降级路径:启动告警带reason=refused和驱动返回的错误,每 5 分钟的重述也带同一个词,因此一个过滤条件就能同时找到两者;真正连不上时仍然是reason=unreachable。网关随后以降级方式提供服务——限流器按副本计数,缓存一律未命中——并持续尝试重新接入。因此在 Redis 一侧修好凭据后,网关无需重启即可采用它。错误信息的具体程度取决于驱动:被拒绝的database会带上服务端自己的原文,而被拒绝的凭据只会得到一条固定的认证失败信息。 -
仍会导致启动失败的,是网关在任何网络交互之前就拒绝的配置。 驱动无法解析的 Redis
url和无法读取的 TLS 材料,对限流器和缓存都是如此;该配置块自身的校验同样如此:所选模式缺少url、nodes、sentinels或master_name,以及timeout_secs: 0。这样配置写错时仍会在启动阶段立即暴露。 -
共享 Redis 的
username、password和database字段现在在所有模式下都生效。 作为默认模式的single此前会解析这三个字段、然后直接丢弃:通过password提供的凭据从未进入握手,因此网关在启动时记录connected,之后在整个进程生命周期内每一次 Redis 操作都失败。这些显式字段现在还会覆盖内嵌在url中的凭据——否则通过环境变量注入的取值会被 URL 里遗留的旧凭据压过,失去意义。凭据按「一对」处理,设置其中任意一半都会同时替换两半。database在single和sentinel模式下生效;Redis Cluster 只有 DB 0。两处同时配置了凭据时,启动阶段会有一条 WARN 日志点明这一情况。 -
无法识别的资源类型不再被读作一次失败的重新加载。 网关读到
kind不在其构建版本认识范围内的文档时,现在上报aisix_config_last_reload_successful 1和state: "synced",此前上报的是0和"degraded"。该配置行在GET /status/config上从rejected[]移到新增的unknown_kinds[],指标上从aisix_config_rejected_resources移到新增的aisix_config_unknown_kind_resources{kind};两组序列互不重叠。真正的拒绝——类型错误、缺少必填字段、未知枚举取值、没有任何oneOf匹配——仍会翻转该 Gauge,并由保留的最后一次失败记录点名。未知类型的配置行还有自己独立的保留额度,因此大量此类配置行不会再把真正被拒绝的记录挤出/status/config和心跳。不需要修改任何配置。此前把aisix_config_rejected_resources跨所有 kind 求和、用来表示「有东西加载不了」的告警,现在不再包含未知资源类型。 -
部署网关页面上的 Metric labels 编辑器已移除。 控制台现在只生成最基础的网关部署模板:mTLS 证书包、
AISIX_CONFIG_PATH、dp-manager 端点和代理端口。observability.metrics.labels仍然是受支持的网关启动配置项,只是改为按文档配置,而不再通过控制台表单配置。该面板没有任何服务端状态,因此已按此前生成的片段运行的网关不受影响。 -
发送失败的用量批次现在会被重发,而不是丢弃。 面向 1.4.0 控制面时,网关会以相同的批次 ID 原样重发同一批次,直到该批次被接受,或直到批次中最早的事件已超过 30 分钟。连续 8 次收到响应的失败之后,网关也会放弃。因此控制面故障只会延迟用量数据,而不再丢失它们,用量可能在控制台上晚几分钟出现。后续批次的投递会排在正在重发的批次之后。
aisix_usage_event_drops_total新增两个reason取值:send_failed(未经重发即放弃)和retry_budget_exhausted。面向不声明批次去重能力的控制面时行为不变,该批次仍按此前的方式被丢弃。 -
日志消费方卡住时,代价是丢日志行,而不是网关整体卡住。 日志事件进入一个容量为 32768 的有界队列,由专用线程消费。容器运行时停止读取网关的 stderr 时——一次日志轮转就足以造成这种情况——新的事件会被丢弃并计入
aisix_log_lines_dropped_total,待写出端恢复后输出一条汇总 WARN。此前请求工作线程会阻塞在write上,整个网关随之卡住,/livez也不例外。队列未写满时不会有任何丢失。 -
遥测导出器可以扛过更长的中断,并遵循
Retry-After。 暂时失败的导出器会把一个批次保留最多 5 分钟,退避区间从 200 毫秒增长到 30 秒上限;此前它在约 3 秒内尝试 4 次后即放弃。这覆盖 OTLP、Datadog、SLS 和对象存储。429或503响应上的Retry-After两种写法都会被遵循,上限同为 30 秒。每个 Sink 背后的队列容量从 1024 提升到 8192。队列写满时会丢弃最新的一条记录并计为queue_full,此前这类记录会在更上游以retries_exhausted丢失。全量采集的导出器持有自己的记录,因此长时间中断会占用更多内存。永久性错误仍然在第一次尝试后即丢弃。 -
中断期间不再有请求为探测 Redis 是否恢复付出代价。 Redis 熔断器打开后,30 秒窗口到期时改由后台探测任务验证恢复情况,而不再让下一个业务请求充当探测者。响应缓存和共享限流计数器共用这个熔断器。恢复速度 不变,只是不再由调用方买单。由于
PING的说服力不如此前探测所用的真实命令,一台能应答PING、但该子系统自身的操作仍然超时的服务端会让熔断器关闭;此时熔断器后面的命令会各付一次超时预算,直到第一次失败重新打开它。 -
GET /metrics改为分块响应。 指标文本按 256 KiB 分块流式输出,不再在内存中整体构造;文本内容本身不变,分块边界总是落在完整的序列之间。在高基数场景下,一次抓取带来的内存峰值从数百 MB 降到几 MB。这带来两个后果:渲染在第一个分块之后失败时,响应体会以一个错误结束,而不是返回500,因此被截断的抓取不会被当作完整数据摄入;读取方停止读取却不关闭连接时,它会在有限等待后失去自己这次抓取,而不再阻塞之后的每一次抓取。两次重叠的抓取不再共用同一次渲染,第二次会等待一次渲染并得到属于自己的当前指标文本。 -
上游主机名现在通过一个短生命周期的共享缓存解析。 请求路径上的每个出向客户端都经由同一个进程级缓存解析:对同一名称的并发查询会合并为一次,成功结果复用 30 秒,失败结果复用 1 秒,缓存最多保存 1024 个名称。因此上游地址发生变化时,网关最多会在 30 秒内仍然连向旧地址。Bedrock 和
/v1/realtime的连接自建传输层,不在覆盖范围内。模型服务提供方凭证的resolve_addresses固定地址仍然在其之上生效,且从不经过该缓存。 -
无法读取吊销列表时,控制面返回
503而不是401。 网关调用的每个/dp路由现在都区分两种情况:吊销列表读取失败返回503 MTLS_UNAVAILABLE,网关会重试;证书本身不被接受返回401。涉及的路由包括心跳、证书轮换、额度检查和用量上报。两种情况都不会放行。此前,最常见的这类控制面瞬时故障会以最终拒绝的形式到达网关。 -
Origin 允许列表现在接受浏览器实际发送的写法。
AISIX_CLOUD_CORS_ALLOWED_ORIGINS和AISIX_TRUSTED_ORIGINS现在接受十六进制形式的 IPv4 映射地址(例如https://[::ffff:c0a8:1]),这正是Origin头携带的形式。Helm Chart 现在接受显式写出零段的规范地址(例如https://[1::1:0]),而不再拒绝安装。Chart 还会在渲染阶段拒绝那些此前能渲染通过、随后导致 cp-api 反复崩溃重启的非法 IPv6 条目,并拒绝带有多个前导分隔符的通配符后缀——后者 cp-api 一直都是拒绝的。cp-api 此前接受的条目,现在没有任何一项会被拒绝。
新功能
-
用量上报按批次幂等。 网关为每个用量批次生成一个 ID,通过
X-Aisix-Usage-Batch-Id发送;dp-manager 在插入这些记录的同一个事务中登记该 ID,因此已提交的批次会得到与首次投递完全相同的响应,并且不会重复写入任何内容。每个/dp/telemetry响应都携带X-Aisix-Usage-Batch-Dedup: 1,网关据此判断重发是安全的;该能力逐响应判定、从不缓存,因此 dp-manager 副本版本混杂和回滚都是安全的。控制面永远无法存储的批次会返回422,网关立即丢弃而不重发。登记记录至少保留 24 小时,并由既有的清理守护任务回收。 -
离线安装包可以配置 CORS。 打包的
docker-compose.yaml现在会透传AISIX_CLOUD_CORS_ALLOWED_ORIGINS,.env.example中以注释形式提供该项,README 中也在AISIX_TRUSTED_ORIGINS旁作了说明。此前,控制台与 cp-api 不同源的部署只能手工修改 compose 文件,而下一次解包又会覆盖它。源码树中的 compose 环境也获得了同样的配置项,外加通知、MCP 规范的开关和 CA 引导覆盖项。 -
新增网关指标。 新增
aisix_config_unknown_kind_resources{kind}、aisix_config_apply_duration_seconds{trigger}、aisix_config_apply_batch_events{trigger}和aisix_log_lines_dropped_total。trigger标签取watch表示一批合并后的 watch 事件,取full表示一次全量同步。四者都已登记到指标标签目录中,因此observability.metrics.labels可以对它们做选择,trigger是新增的标签变量。
改进
- 后台计算不再与请求处理争抢资源:配置下发、Prometheus 指标渲染和快照回收都运行在降低了优先级的线程上,而请求工作线程、
/livez与/readyz监听器以及日志写出线程保持原有优先级。 - 配置摘要改为在被读取时计算,而不是每次下发都计算。在约 70000 个资源的配置上,一次下发的 CPU 开销从 0.165 核秒降到 0.0275 核秒,摘要逐字节一致,
apply_seq和applied_at也保持文档所述的规则。 - 按调用方的额度判定缓存改为常数时间淘汰,而不再在每次 未命中时扫描全部 10000 个条目。
- 代理与用量发送器之间的队列容量从 1024 提升到 16384,可以吸收此前会以
sink_full丢弃事件的数秒级控制面停顿。定时刷新现在会从就绪队列补齐,而不再在仍有积压时发送一个偏小的批次。 - 环境级额度汇总改由新增的部分覆盖索引应答,不再扫描其他环境的计费用量。该索引在启动时于既有的迁移锁下并发创建,中断的创建过程会被修复。
- 用量上报解析一个批次的定价时改为两次查询,而不是每个模型一次、每次未命中再加一次:一个包含 100 个模型、其中 50 个未命中的批次,现在只需两次读取,此前需要 150 次。
- 公开的
aisix-cpChart 的配置项表格现在覆盖全部 117 个配置项,包括安装时必须提供的那 4 个。PostgreSQL 密码仍为占位值时的渲染期提示改为openssl rand -hex 24,因为 base64 字符(+、/、=)会破坏内嵌该密码的postgres://DSN。
修复
- 大量网关同时申请证书时,cp-api 不再耗尽连接池。
POST /api/environments/{env_id}/gateway_certificates此前会在持有一条池化连接的同时再取最多三条,因此 16 个网关副本的一次滚动发布就可能把连接池卡住,直到调用方放弃。现在证书、其凭据身份和审计记录会一起提交或一起回滚,因此回滚掉的签发不会再留下一条调用方从未拿到私钥的、仍然有效的 mTLS 凭据。 DELETE /api/environments/{env_id}现在会原子地吊销证书并删除环境。此前中途失败可能导致证 书已被吊销、而环境仍然存在,从而把一整批网关踢出一个仍在正常工作的环境。- 读取已注册网关列表时发生的瞬时数据库故障,不再让一次资源保存变成
500且什么都没存下。网关列表读不出来时不再对任何操作设限,与 1.3.0 之前一致;网关列表可以读出时,兼容性闸门自身的判定(422 DP_INCOMPATIBLE)没有变化。 - 在 dp-manager 从未运行过的控制面上,
GET /api/data_export现在返回409 DATA_EXPORT_UNAVAILABLE并点名需要启动 dp-manager,而不再返回带有原始 SQL 错误的500。 - 数据导出和导入的审计记录,现在对失败的以及下载中途被放弃的尝试也会写入,记录中的
outcome取completed、failed或client_disconnected;导出还会记录在响应写出端统计的bytes_delivered。此前,取走了组织部分数据后消失的客户端不会留下任何记录。 - dp-manager 不再因为一个长生命周期的 watch 而无限停留在 gRPC 优雅关闭状态;排空过程被限制在既有的 5 秒关闭预算内,启动失败时也会取消并回收它已创建的工作任务。
- cp-api 和 dp-manager 不再以 Gin 的 debug 模式运行:每次启动 187 行、逐条点名内部处理函数的路由清单,已从生产日志中消失。
GIN_MODE=debug仍然可以打开该清单。 - 控制台不再在启动时对从未配置过的 Google 和 GitHub OAuth 提供方输出告警;只配置了 client id 的提供方也不再以空 secret 注册。
- 在额度聚合任务执行期间删除额度,不再产生来自聚合任务或告警通知器的告警日志。
- 用量事件的四个有长度上限的字段中出现超长取值时,现在在上报时被截断,并按批 次输出一条告警,而不再让整个批次失败、连带影响其中所有其他计费记录。这四个字段是
cache_status、inbound_protocol、operation和guardrail_bypassed_reason。
API 变化
API 结构对比显示本版本没有新增、移除或变更任何操作:两份文档都是 129 个操作,没有新增或移除结构定义,也没有任何破坏性变化。唯一的结构性差异是 GET /data_export 的描述。另有一处变化,其含义无法通过结构对比识别。
| 端点 | 变化 |
|---|---|
GET /data_export | 在 dp-manager 从未启动过的控制面上,该调用现在返回 409,error.code 为 DATA_EXPORT_UNAVAILABLE,此前返回的是带有原始 SQL 错误的 500 EXPORT_FAILED。该前置条件——dp-manager 首次启动才会创建保存投影配置的表,而每个导出包都包含这部分数据——现在写入了端点说明,409 的描述也列出了两个错误码。EXPORT_IN_PROGRESS 行为不变,只是现在有了文档:它同时覆盖该组织已有导出在进行中,以及部署级的并发导出上限。 |
网关与控制面之间的协议(/dp/*)不属于 Cloud Admin API。它新增了 POST /dp/telemetry 上的 X-Aisix-Usage-Batch-Id、每个 /dp 响应上的 X-Aisix-Usage-Batch-Dedup: 1、永远无法存储的批次所返回的 422,以及无法读取吊销列表时返回的 503 MTLS_UNAVAILABLE。
升级说明
从早于 1.4.0 的版本升级至本版本或后续版本时,均需遵循本节说明,包括跳过 1.4.0 的升级。
- 在环境内所有网关都升级到 1.4.0 之前,不要把新增的指标族写进
observability.metrics.labels。 网关在启动时会拒绝该配置中无法识别的指标族,因此一段写有aisix_config_unknown_kind_resources、aisix_config_apply_duration_seconds、aisix_config_apply_batch_events或aisix_log_lines_dropped_total的配置,会让 1.3.0 的网关无法启动。 - 基于
aisix_config_rejected_resources的告警现在不再包含未知资源类型。 如需保留此前「有东西加载不了」的更宽口径,请把aisix_config_unknown_kind_resources一并纳入。 - 升级后 cp-api 首次启动会在
dpmgr_usage_events上创建第二个部分索引,在既有的迁移锁下并发创建。用量表较大时,启动会一次性多做一些工作,此后还会持续付出该索引的存储和写入维护开销。 - 带凭据的 etcd,如果其连接过程本来就需要超过 5 秒,现在必须显式设置
etcd.dial_timeout_ms。 该字段现在默认为 5000 毫秒,此前该过程没有上限;写0可恢复原有行为。没有配置etcd.user的部署不受影响,因为其连接过程不产生任何 I/O。 - 升级前请移除或修正遗留的
redis.password(或redis.username)字段。 在 1.4.0 之前,single模式下这两个字段完全不生效,因此在可用的 URL 凭据旁遗留了旧取值的部署,升级后会改用字段中的取 值。此时共享后端会以reason=refused降级,而此前该字段是被忽略的。 - 指向需要认证、但未配置任何凭据的 Redis 时,启动阶段会出现该 WARN 日志,这是预期结果。 这类部署本来就每一次 Redis 操作都失败。现在它会在启动时报告
reason=refused并以降级方式提供服务,而不再是先记录connected、再逐请求失败。 - 用量重发需要控制面和网关都是 1.4.0。 1.4.0 的网关面向更早版本的控制面时,发送失败的批次仍按此前的方式丢弃;没有任何配置项可以开启或关闭该能力。
1.3.0
发布日期: 2026 年 9 月 18 日
模型、MCP Server 和定价现在按资源 ID 被引用,而不再依赖它们当前使用的名称,因此重命名其中任何一个都不会再改写所有指向它的文档。结构化输出现在在 Anthropic、Gemini 和 Bedrock 上游上均可用;Responses 到 Chat 的桥接会按调用方的请求和预期返回推理内容、图片、工具参数和用量。调用方中途放弃的请求现在会记入用量日志;流式请求改为在流结束时写一条访问日志,而不是在流开始时写。网关和控制面镜像除 linux/amd64 外还发布 linux/arm64,控制面 Helm Chart 允许 OpenShift 自行分配 UID。模型服务提供方凭证可以为通过私有链路访问的端点指定固定地址;一个网关可以提供多个各带独立 TLS 的代理监听器;一个组织的全部配置可以导出为单个文件并加载到另一套部署上。