跳到主要内容
版本:1.5.0

发布说明

本页汇总 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_bytes 128 倍的上限,几乎不含内容的帧组成的流可能达到它;越过该上限同样是缓冲区超限事件,按 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 和 MCP tools/call 上,此前它们对每个请求扫描一整段拼接后的文本,而脱敏却按值分别进行,因此拦截规则、监控模式下的 would_mask 和实际执行的脱敏可能给出不一致的结果。现在每条消息、每个内容块、每个工具调用参数、调用方发送的每个工具结果,以及 MCP tools/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 和 HS512 Token 会按原样以该密钥的 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)接受可选的 IANA timezone,并以该时区及其偏移显示所有时间戳。控制台下载的日志和审计文件使用查看者所在的时区。

  • 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-cp Chart 的配置项表格现在覆盖全部 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 的代理监听器;一个组织的全部配置可以导出为单个文件并加载到另一套部署上。

行为变化​

  • 调用方中途放弃的请求现在会记录一条用量数据。 此前,客户端在响应头写出前断开连接时,只会留下一条访问日志,用量日志中没有任何记录,所有计量端点均如此。现在这类请求会记录一条终态事件:状态码 499、error_class = "client_disconnected"、Token 数为零、费用为零;此外,此前已失败的每次尝试各记录一条事件。正在进行中的那次尝试会被记录下来,因此 499 记录可以说明请求当时已选定哪个目标。流式响应在传输过程中被放弃,或在首字节之前被断开,都会以各自的消息记录同样的数据。/mcp、/a2a、透传命名空间、/v1/realtime 的升级前阶段,以及文件、批处理和微调相关接口,会记录一条模型字段为空、并带有各自归属信息的数据。上传被放弃时同样会记录一条。

    这些记录此前并不存在,因此环境的请求数会上升、成功率会下降——控制面的这两项指标都由用量事件推导得出。延迟分位数不受影响,它们本来就只统计成功的记录。花费也不受影响:这些记录的费用为零。

  • 网关的磁盘配置缓存现在改为显式开启。 新增的 managed.snapshot_cache_enabled 在托管模式和自建 etcd 模式下均默认为 false;仅配置 snapshot_cache_path 不再启用持久化:只配置路径时,网关完全不会写快照文件。关闭时,网关会跳过缓存读取、编码、全量状态拷贝和后台写入。内存中保留最后一份可用配置并继续服务的行为不变。不启用缓存时重启会发生什么,参见升级说明。

  • 流式请求改为在流结束时写访问日志。 此前有六类接口在响应头生成时就立刻写日志,往往提前数分钟:被放弃的流会写一条 200 的访问日志,同时另有一条 499 的用量事件;正常完成的流所写的日志既没有 Token 计数,也没有模型服务提供方的响应 ID。现在该日志与请求的终态用量事件一同写出,因此两者在状态码、错误类别和错误消息上必然一致;流式请求的日志也会包含 Token 计数、provider_request_id、upstream_model 和 provider_key_id。三种结束方式下,每个请求都只写一条日志。

  • 每条访问日志新增 duration_ms,表示请求从到达网关到最后一个字节发出所占用的时间。latency_ms 含义不变,仍表示调用方的等待时间,流式请求为首 Token 时间;因此两者在流式请求上相差整个流的时长,在非流式请求上相等。日志还新增 upstream_model 和 provider_key_id,表示实际选中的目标,而 model 表示调用方请求的入口。

  • 缓存命中现在会上报缓存信息,并且不会再上报未实际分发到的目标。 日志新增 cache_status,命中时还会带 cache_hit_layer。路由型或语义型模型组命中缓存时,provider、provider_key_id 和 upstream_model——以及由它们构造的 Prometheus 标签——现在会上报 unknown 或不上报,而不再上报策略恰好排在首位的那个候选。因此,按模型服务提供方统计请求的面板不会再把模型组的缓存命中计到并未提供服务的提供方上,而按凭证标签过滤日志页时这些记录会被排除。直连模型的缓存命中行为不变;命中时的用量事件现在会在 provider_model_version 中记录生成被缓存内容的模型。缓存命中的费用本来就为零。

  • 上游未返回用量时,非流式 /v1/chat/completions 现在会返回网关自己的估算值,而不是零。 用量记录中本来就保存了该估算值,因此调用方无法把读到的数据与控制台的计费对上。按计数项处理:上游返回的计数保持原值,为零的计数用估算值填充,与被填充的零并列的总数会重新计算。缓存命中同样这样返回。计费结果不变;流式 /v1/chat/completions 仍然转发上游自己的用量帧。

  • 协议转换后没有工具留存时,tool_choice 会被丢弃。 OpenAI 兼容上游和 Anthropic 上游都会拒绝只有 tool_choice 而没有 tools 的请求,因此提交空工具列表的调用方——Agent 类 CLI 在上下文压缩调用时就是这个形状——会收到上游返回的 400。现在三个转换器都只在转换后的工具列表非空时才带上 tool_choice,包括强制调用工具的取值,并按普通的无工具请求处理。直接向 OpenAI 形状上游的 /v1/chat/completions 提交这一组合的调用方,仍按原样转发。

  • /v1/responses 上的输入护栏现在会读取重放的工具调用的名称和参数。 该 API 把模型轮次表示为不带 role 的类型化条目,因此此前扫描会把 Agent 的整个工具循环当作用户文本,并完全丢弃 function_call 条目——在 /v1/chat/completions 上会命中的拦截规则(该接口一直会扫描同样的重放调用),只要把内容移入这个接口的工具调用就可以绕过。如果拦截规则的匹配模式会出现在重放的工具调用参数中,运维人员会看到此前放行的请求开始被拒绝。这是在补上该缺口,不是回归。

  • 两类护栏不再扫描 /v1/responses 上重放的工具结果。 semantic 和 azure_content_safety_text_moderation 在默认 text_source 下只读取 user 角色的消息。此前 function_call_output 被错误地标记为 user 消息,因此它们恰好会扫描到;现在它被正确地识别为工具结果,因此不再扫描——这与 role: "tool" 消息一直不在它们于 /v1/chat/completions 上的读取范围内是一致的。这是两个接口行为对齐,但对配置未变的既有规则来说是覆盖范围的缩小:把 text_source 设为读取全部消息的取值即可继续扫描工具结果。

  • URL 改写规则现在也会在按 Host 匹配的透传分发之前执行。 改写是所有路由族在入口阶段的操作,因此不带 hosts 列表的既有规则,现在也会改写按 Host 分发的请求。为规则添加 hosts 可以把作用范围收回。

  • Bedrock、对象存储遥测导出器和 Realtime 连接现在遵循所配置的 upstream 连接参数。 Bedrock 和对象存储的连接池现在按 upstream.pool_idle_timeout_secs(默认 30 秒)回收空闲连接,而不再固定为 90 秒;这正是在会提前回收空闲连接的负载均衡器后面,调低该参数能够生效的原因。护栏访问 Bedrock 时使用 upstream.connect_timeout_ms(默认 5 秒),而不再使用 SDK 内置的 3.1 秒;/v1/realtime 的升级请求卡住时,也会在该预算内失败,而不再等待内核的 SYN 重试耗尽。Realtime 会话无法建立上游连接时,现在还会向请求指标贡献一个 status="502" 的样本,此前这种情况只出现在日志中、不计入任何指标。

  • 出向请求会带上构建版本号。 此前无论运行哪个版本,上游请求都携带 aisix/0.1;现在默认 User-Agent 为 aisix/<build version>,与 aisix --version 和 Server 响应头取自同一来源。基于旧字符串配置的上游允许列表需要更新。

  • 无法识别的 AISIX_* 环境变量不再导致启动失败。 此前加载器会把所有此类变量都当作配置覆盖项,而根配置会拒绝未知字段,因此命名空间中只要有一个名为 aisix-* 的 Kubernetes Service,就会让同命名空间内所有网关 Pod 反复崩溃重启。现在只有首段能对应到顶层配置项的变量才会被保留,其余会被丢弃,并输出一条点名该变量的 WARN 日志。真实配置段下拼错的键名仍然会像此前一样导致启动失败。直接运行二进制时,AISIX_CONFIG 现在可以生效。

  • 不带 scheme 的控制面地址会被接受,格式错误的地址会导致启动失败。 managed.cp_base_url 在加载时会统一归一化,因此 dpm.example.com:7944 会被读作 https://dpm.example.com:7944。此前这样的取值可以连上 etcd,但随后会以 429 budget_exceeded 拒绝所有被代理的请求,而控制台仍显示网关健康。managed.cp_etcd_endpoint 保持相反的约定,现在会剥离 scheme 从而容忍带 scheme 的取值,此前这种取值会拼成无法连接的地址。两种形状都不符合的取值现在会导致启动失败,并点名对应的变量。控制面对自己的同类配置(AISIX_CLOUD_DPMGR_BASE_URL、AISIX_DPMGR_BASE_URL)应用完全相同的规则,因此不带 scheme 的取值现在会带着 scheme 出现在控制台的安装指令和 dp-manager 的服务端证书中。

  • 删除被限流策略指定为作用对象的模型会被拒绝,返回 409 MODEL_IN_USE。 此前删除会成功,并在 PostgreSQL 和 etcd 中都留下一条悬空的策略,按一个解析不到任何资源的 ID 统计请求。请先删除或改指该策略。仅携带 model 或 model_name 条件的条件型策略不构成阻塞——该条件只是不再匹配。

  • 缓存策略的 model: 作用域现在可以在重命名后保持有效,但删除后不再恢复。 该选择器按所选模型的资源 ID 生效。删除该模型后,策略将永久不再覆盖任何请求:之后创建的同名模型是另一个资源。在重新保存之前,策略仍会列出且处于启用状态,但不匹配任何请求;重新保存会按当前使用该名称的资源重新解析选择器。

  • MCP Server 重命名现在会带上环境的匿名访问上限配置。 此前该上限会保留旧名称、不再匹配,从而在没有任何提示的情况下关闭匿名访问。删除 MCP Server 现在也会改写并重新投影引用它的配置行;运维人员观察到的结果是没有变化——引用仍然可见且不生效——但这些配置行会在删除时被写入,而此前删除完全不会触及它们。

  • 控制面 Helm Chart 不再固定 UID。 三个组件的 podSecurityContext 中都移除了 runAsUser、runAsGroup 和 fsGroup;runAsNonRoot: true 和 RuntimeDefault seccomp 配置保留。在会自行分配 UID 的集群上(例如 OpenShift 的 restricted-v2 SCC),Pod 以该命名空间分配的 UID 运行;在其他环境中以镜像自带用户运行,该 UID 与 Chart 此前固定的值相同。镜像的 USER 也因此改为数字形式(cp-api 和 dp-manager 为 10001,控制台为 1001,网关为 10001):Chart 不再提供 runAsUser 后,kubelet 无法确认以名称指定的用户是否为 root,会拒绝启动这类容器。

  • PUT /model_pricing 更新时现在会写入所有费率列。 此前更新路径漏掉了 duration_cents_per_1m_seconds,因此从第二次保存起,按音频时长计价的模型会一直保留第一次写入的费率,而控制台显示的是修改后的值,遥测链路则按已存储的值计费。该端点的审计事件存在同样的问题:修改四项费率中的任意一项,记录下的 before 和 after 都逐字节相同。

  • 删除包含环境内部相互引用的环境现在可以成功。 此前,只要路由型模型组的目标、Ensemble 的评审模型、语义路由的模型、缓存策略的向量化模型或透传路由的匿名 API Key 位于待删除的环境内,DELETE /api/environments/{id} 就会返回 500 并报出外键错误,该环境只能手工逐项解除引用后才能删除。

  • 由 Go 列表渲染出的 CHECK 约束在该列表变化后会重建自身,升级后的数据库和新建数据库都是如此。此前,升级后的数据库可能保留一条会拒绝合法 kind=custom 护栏的约束,表现为 500。同一套判定的另一面:运维人员手工删除的约束不会再被下次启动重新加回。

  • AISIX_TRUSTED_ORIGINS 的取值现在按 cp-api 对自身允许列表所用的 Origin 语法校验。 无法匹配浏览器 Origin 头的取值——*、通配符形式、大写的 scheme 或主机名、结尾的点或斜杠、显式写出的默认端口——会被丢弃并在服务端日志中记录错误,而不再被信任,来自该来源的登录会被拒绝。部署自身的 Origin 及其 loopback 形式仍然受信任。

新功能​

  • Anthropic、Gemini 和 Bedrock 上游支持结构化输出。 此前,/v1/chat/completions 调用方要求返回 JSON 时(以及 /v1/responses 调用方通过 text.format 要求时),这三类上游都会返回普通文本,因为它们的协议都没有顶层的 response_format。现在每类上游都会收到其自身 API 定义的形状:Claude 4.5 及更新版本使用 output_config.format,Gemini 使用 generationConfig.responseJsonSchema(2.x 及更新版本)或 responseSchema(1.x,并做旧方言的转换),Bedrock 在 Messages 路径使用 output_config.format、在 Converse 路径使用 outputConfig.textFormat。其余情况——较早的 Claude 系列、Anthropic 兼容的第三方、支持工具调用的 Converse 厂商——会把 Schema 挂在一个合成的强制工具上,并把回复转换回普通的 JSON 内容。Schema 会被收窄到各提供方文档所支持的关键字子集,每个被移除的约束都会折叠进对应属性的描述中,并以 additionalProperties: false 封闭,而 required 完全保留调用方的原始写法。调用方自己的工具和显式指定的 tool_choice 始终优先于合成工具。工具路径的上游请求以非流式发出,再以伪流式返回结果,因此这类请求会付出本来不会有的首字节延迟。

  • Responses 到 Chat 的桥接达到与原生路径一致的能力。 该桥接用于服务模型没有原生 Responses 端点的 /v1/responses 调用方。现在它会把模型的推理内容作为 reasoning 输出条目返回,并带上对应的流式事件序列;转发 input_image、input_file 和 input_audio 部分而不再丢弃;把 text.format 转换为 response_format;转发 parallel_tool_calls;转换 custom(自由形式)工具,使模型能够调用它;把各种 tool_choice 形式归一化为与提供方无关的形状;并把 function_call_output 序列化为 JSON,而不再向模型发送空字符串。经桥接的自由形式工具调用会作为携带自由形式 input 的 custom_tool_call 条目返回,并通过其专用的事件对流式输出;重放这类调用时也会正确回传上游,因此多轮对话可以正常工作。经桥接的调用方读到的用量现在与实际记录的用量一致。在 Anthropic 转换器上,parallel_tool_calls: false 会被改写为 tool_choice.disable_parallel_tool_use,而不再被平铺到一个会拒绝未知字段的请求体上。

  • 护栏可以只读取最新一轮对话。 所有护栏类型新增 input_messages 配置项(all,默认值;或 latest_turn)。IDE 和 Agent 客户端每次调用都会重放整段对话,因此一条命中过某条消息的规则会在该会话的后续请求中持续拒绝,即使新的提示词本身没有问题。latest_turn 只读取最后一条 assistant 消息之后的消息(不含 system 消息)——即本轮的 user 消息和回应它们的工具结果——因此结尾处的 assistant 预填内容仍属于当前轮次。该配置只作用于输入钩子;hook_point: output 与 latest_turn 同时配置会被拒绝,而不是被接受后忽略。在 latest_turn 下,脱敏类护栏会完整保留调用方发送的对话历史。控制台的护栏表单提供“输入扫描范围”选择器,并在列表中显示对应标记。

  • 重命名不再破坏指向模型、MCP Server 或定价的引用。 控制面投影的每一处引用,现在都会在一直携带的展示名称之外带上被引用资源的 ID,网关在每个请求中都按 ID 到实时的资源表中解析。覆盖范围包括:调用方 API Key 的模型允许列表,路由型模型组的目标,Ensemble 的候选模型和评审模型,语义路由的向量化模型、默认模型、各条路由和失败兜底目标,缓存策略的作用域及其相似度向量化模型,语义护栏的向量化模型,MCP 工具的授权与拒绝项,按 MCP Server 的限流策略,以及环境的 MCP 匿名访问上限。重命名资源会在下一个请求生效,不需要修改引用它的文档,也不会在配置中产生改写扇出。运维人员已有的配置都不需要调整;名称仍然写在 ID 旁边,因此早于本版本的网关仍按原有方式读取这些引用。

  • 定价改为独立的配置文档。 模型的按 Token 价格现在取自共享的定价文档——依次为环境自身的覆盖项、部署级的目录、模型自带的 cost 字段——而不再内联保存价格。调整价格现在只需写入定价本身,而不必改写所有按该价格计费的模型;向量化模型也第一次带上了网关可以解析的价格。该目录发布在一个新的部署级 etcd 前缀下,网关可读但不可写。

  • 模型服务提供方凭证可以为其端点指定固定地址。 通过私有链路访问的上游往往没有 DNS 记录,而其后的厂商仍然会对不携带自身主机名的请求返回 404——并且 Host 不是可转发的请求头。模型服务提供方凭证新增可选字段 resolve_addresses,接受一组有序的 IPv4 或 IPv6 字面量地址,并在连接凭证 api_base 所指主机名时使用这些地址。只有连接目标发生变化:Host 请求头、HTTP/2 的 :authority、TLS 的服务器名称和证书校验都仍使用该主机名,scheme 和端口仍取自 base URL。地址按书写顺序依次尝试,与解析器返回的结果一样,因此当私有链路在每个可用区各终结于一个地址时,其中一个不可用仍然可达。该字段的作用范围是 api_base 的主机,因此从同一主机提供第二种协议的 apis 条目也被覆盖,而指向其他主机的条目按正常方式解析。省略该字段即按此前方式通过 DNS 解析,null 会清除已有配置。所有通过该凭证分发请求的接口都遵循该字段;Bedrock 和 /v1/realtime 不遵循,因为它们自行构建传输层,同样也不遵循该凭证的 tls 配置。网关通过正向代理访问上游时该字段无效,因为主机名会交给代理、由代理自行解析。控制台在端点 URL 旁提供“端点地址”字段。

  • 直连模型的 effort_mapping 支持保留键。 此前该映射只回答一个问题——“调用方要求 X,就发送 Y”——对运维人员实际遇到的两种情况没有表达方式。现在空字符串键匹配完全没有设置推理档位的请求(字段缺失、为 null 或为空),并为其补上一个档位;* 键匹配其他所有没有独立条目的已有取值;而 null 值表示从出向请求中移除该档位,从而使用提供方自己的默认值。在 Anthropic 的 messages 和 Token 计数端点上只读取 output_config.effort:对本映射而言 thinking 块不算推理档位设置,因此只发送 thinking 而不设置推理档位的客户端会命中空字符串条目。通过 thinking.type: disabled 关闭推理的请求永远不会被赋予档位。控制台把规则两侧都渲染为选择器,因为保留键和移除操作都无法手工键入。

  • 可自定义 Webhook 请求体、请求头,并记录响应内容。 此前 Webhook 通知渠道只能发送一种固定的载荷形状和一个固定的请求头,因此期望其他格式的接收方根本无法接入;投递被拒绝时也只记录 webhook returned 400。现在渠道可以配置可选的 Go text/template 请求体(可使用告警事件变量、单行的 message 变量和 json 函数,保存时即渲染并校验),以及最多 16 个额外请求头,其取值与渠道 URL 一样是只写的。投递失败时会记录目标返回的状态码和响应体,并从其中脱敏掉渠道自身的 URL 和请求头取值;列表中保留前 8192 字节,新增的单条投递查询端点返回完整内容。测试按钮会展示实际发送的请求体和收到的响应。

  • 组织数据的导出与导入。 GET /api/data_export 会把一个组织拥有的全部数据——环境、模型、凭证、各类策略、团队、成员、网关读取的投影配置,以及一段时间窗口内的审计记录——以单个 gzip 压缩的 SQL 文件流式导出;POST /api/data_import 则在一个事务内把它应用到另一套同版本控制面的部署上。默认行为是备份:凭证仍以该部署自身的主密钥加密保存,未脱敏的文件还会额外携带证书颁发机构,从而使恢复后仍保留原有网关,该模式需要 owner 角色。redact=true 则生成支持包:所有凭证被替换为已知的合成值,所有账号使用一个公开的固定口令登录,因此不应接触真实密钥的人员也可以复现该配置。恢复到已经签发过证书的部署时,会保留该部署自身的颁发机构并在响应中说明。控制台提供导出卡片。

  • URL 改写规则可以按入站 Host 限定作用范围。 新增可选的 hosts 列表,把规则限定到指定的主机——大小写不敏感的精确名称,或单段通配符,端口忽略。Host 和路径都必须匹配,且只应用第一条匹配的规则。

  • /mcp 访问日志会说明请求内容。 所有 MCP 操作都通过同一个 POST 传输,因此握手、工具调用和被 ACL 清空的 tools/list 此前在日志中完全一样。现在日志会带上 mcp_method,tools/call 时带 mcp_tool,tools/list 时带 tools_total 和 tools_returned。上游返回了工具但 tools/list 结果为空时,会输出一条 WARN,点明是两种配置错误中的哪一种。

  • MCP 匿名访问允许列表,以及所有 API Key 和策略,都可以按资源 ID 指定 MCP Server,这正是上面的重命名保持有效在网关侧得以成立的原因。

  • 控制面提供可选的 Prometheus 指标,使用独立的监听地址,未设置 AISIX_CLOUD_METRICS_LISTEN 时不启用(Helm Chart 中为 api.metrics.enabled,同时会渲染指标 Service 和可选的 ServiceMonitor)。这些指标以 aisix_cp_ 为前缀,上报写入量和配置扇出的基数,因此一套 Prometheus 可以同时覆盖两个平面。

  • 多个代理监听器,各带独立的 TLS。 此前 proxy.addr 加 proxy.tls 描述的是唯一的那个监听器,因此配置证书会让这个唯一端口变成仅 HTTPS,而同时还需要明文 HTTP 的部署没有任何办法实现。新增的 proxy.listeners 配置块接受代理监听器的完整集合,每一项包含一个地址和各自可选的 TLS,因此一个网关可以同时提供 HTTPS 和明文 HTTP。所有监听器共用一个路由表和一份应用状态,TLS 与 ALPN 协商按监听器各自进行,每个监听器都像此前唯一的那个监听器一样参与优雅关闭和连接排空。listeners 缺失或为空时,proxy.addr 和 proxy.tls 仍是单监听器的简写形式且行为不变;listeners 已设置时,proxy.addr 不会被绑定,网关会输出一条 INFO 日志说明这一点,而 proxy.tls 与非空的 listeners 并存属于配置错误,而不是一个不作用于任何监听器的证书。重复的地址会在启动时被拒绝,并点名两个条目,因为否则 SO_REUSEPORT 会让两个条目共同绑定同一端口,在部分连接上按 TLS 应答、在其他连接上按明文应答。仅使用环境变量的部署可以通过 AISIX_PROXY__LISTENERS 以单个 JSON 数组配置整个集合。aisix Chart 1.3.0 提供对应的 listeners 配置项,每个端口一项,各自带有独立的容器端口、Service 端口、可选的 NodePort 和可选的 TLS Secret。

  • 网关和控制面镜像发布 linux/arm64。 流水线发布的每个 tag——dev、sha-*、发布候选版本和正式版本——现在都是同时包含 linux/amd64 和 linux/arm64 的 manifest list,网关和 aisix-cp-api、aisix-cp-dpm、aisix-cp-ui 都是如此。每个架构都在其自身的 runner 上原生构建并做冒烟测试,两个架构都就绪后才发布 tag。离线安装包按架构分别构建并在文件名中体现(aisix-self-hosted-offline-<version>-linux-{amd64,arm64}.tar.gz);run.sh 会拒绝为其他架构构建的安装包,而不是加载无法执行的镜像。不带架构后缀的文件名仍然提供 amd64 安装包。

  • cp-api 可以为部署在其他 Origin 上的控制台提供服务。 AISIX_CLOUD_CORS_ALLOWED_ORIGINS(Helm Chart 中为 api.corsAllowedOrigins)列出允许跨源调用 /api/* 的浏览器 Origin。默认为空,此时完全不写 CORS 响应头,这也是私有化部署的控制面所需要的行为:它从同一个 Origin 提供 API 和控制台,因此不存在跨源请求。配置后,它允许跨源调用 /api/*,包括 /api/auth/* 下的 Better Auth 路由,并按具体取值而不是 * 回显 Origin;控制台代理不在范围内。Chart 会在渲染时校验取值,cp-api 也会在启动时再次校验。此版本的 Docker Compose 软件包不会将 .env 中的环境变量传递给 cp-api;需要跨源访问时,请使用 Helm chart。Chart 与镜像对浏览器规范化的 IPv4 映射 IPv6 Origin 存在差异,因此请使用 DNS 主机名或 IPv4 地址,而不要使用这种形式。

  • 控制台的 Deployment 可以挂载私有数据库 CA。 ui.extraVolumes 和 ui.extraVolumeMounts 接受 ConfigMap 或 Secret,并通过 ui.extraEnvVars 把 NODE_EXTRA_CA_CERTS 指向它,因此基于数据库的认证可以信任私有 PostgreSQL 证书链。

改进​

  • 批量修改配置不再与请求处理路径争抢资源。 watch 事件现在按时间窗口合并,而不再按恰好积压的数量合并,窗口大小会根据上一次应用的开销自适应调整;配置应用移出异步 I/O 工作线程,因此无关的连接不再排在它后面等待;配置摘要从检查点续算,而不再重新哈希所有配置行;资源索引在多个快照之间共享字符串;被替换的配置由一个共享的后台线程回收,而不再由恰好持有最后一个引用的请求线程同步回收。在 7 万行配置的场景下,仅最后一项就把请求线程的析构开销从 7 到 8 ms 的 p99 降到 1 微秒以内。1507 行的突发写入现在只需 12 次全量配置遍历,此前为 131 次。

    代价是单次孤立的配置写入会延后一个静默周期才可见:以本地 etcd 实测,从写入到 applied_revision 变化的中位耗时从 21 ms 变为 42 ms。这不需要调整任何配置,被服务的配置内容也没有任何变化。

  • 高基数指标抓取的开销大幅降低。 指标记录器改为按序列存储并使用无锁样本缓冲,按指标类型缓存转义后的标签和排序后的序列目录,按上一次渲染结果预分配输出缓冲,并在阻塞型工作线程上渲染,重叠的抓取共享同一次渲染。在 53260 条序列、723 MB 输出的场景下,预热后的渲染 CPU 耗时从约 6.8 秒降到 0.57 秒,空闲维护开销从 1.11 秒降到 0.011 秒。指标名称、类型、默认标签、直方图分桶边界和滚动分位数均保持不变。标签取值中包含原始反斜杠、引号或换行符时,现在会被正确转义,不会再把不同的序列混为一条。

  • 限流判定和 JWT 认证不再扫描无关的配置行。 限流策略候选项按其所需条件建立索引,JWT 与 API Key 的绑定按 API Key 表的 generation 建立索引,两者都由其所读取的表触发失效,而不再由任何配置写入触发。

  • 控制面 outbox 的投递速度提升。 事务改为在进程内直达内嵌的 Kine,而不再经过其自身的 gRPC 监听地址;最多四个互不相关的键可以并发投递,同一个键的顺序仍然保持;水位线读取不再列出整个资源范围;较大的 etcd Range 和 Watch 响应在编码时不再使用临时缓冲;遥测刷写改为每条语句最多持久化 100 个事件,此前为 1 个(内嵌的 Kine 同时升级到 v0.16.3,修正了资源类型名称中包含下划线时的前缀读取)。预算检查不再扫描零费用的用量记录,为此在启动迁移之后并发创建了一个新增的部分索引;配置写入时的网关兼容性查询改为复用同一个事务,而不再从可能已经耗尽的连接池中再取一条连接。

  • 控制台采用 API7 Console 的颜色 Token。 所有背景、文字、边框、状态和操作的颜色都改为 Console 的取值,卡片边缘改用阴影表现。仅涉及视觉:字体、间距、控件尺寸和布局均未改变。

修复​

  • 被反复剔除的路由目标可能导致请求工作线程长时间阻塞。 60 秒日志限流窗口过期后的第一次剔除会在持有读锁的同时获取同一分片的写锁,因此请求既不会走到上游超时,故障期间被阻塞的工作线程还会不断累积。

  • 有效密钥正在拉取时,并发的 JWT 请求可能失败。 此前刷新间隔在结果产生之前就被记录,因此缓存为空时的调用方会被拒绝,而使用刚轮换密钥的请求可能错过已在进行的刷新。现在按 JWKS URL 或 issuer 合并拉取请求,并在刷新期间或上游故障期间继续使用已过期的信任材料。

  • 修复了一个连接池死锁,它可能在并发访问下使环境的模型列表和成员列表卡住。

  • 网关可能在关闭时挂住。 此前,未配置 etcd 请求超时时,一直得不到响应的初始配置读取或 watch 创建不会被关闭信号取消。

  • GET /api/config/public 和控制台的安装指令会带上 scheme。 参见行为变化中关于控制面地址的说明;此前从控制台复制的不带 scheme 的取值,会产生一个拒绝所有被代理请求的网关。

  • 网关可以读取共享的定价目录。 etcd 授权拦截器此前把每张网关证书的作用范围限定在其所属环境的前缀内,因此新增的部署级前缀会返回 PermissionDenied——网关可以容忍,但每次启动都会告警。现在 /aisix/global/ 下的读取被授权,写入仍不被授权,网关也仍然无法访问其他环境的键空间。

  • 语义路由可能被投影成错误的向量化失败兜底目标。 通过 API 无法触发,API 会从三个方面拒绝这种形状;现在投影会拒绝该文档并说明原因,而不再填入恰好位于该位置的模型。

  • 控制台的脱敏开关不再在角色信息加载期间显示为选中状态,此前这会让没有动过该开关的 owner 静默下载到未脱敏的备份。快速切换页面时,上一个页面的迟到响应也不会再覆盖当前 URL 所对应页面的内容。

API 变化​

API 结构对比显示本版本共 42 处变化:新增 3 个操作,未移除操作;新增 6 个结构定义,未移除结构定义(DataImportResponse、GuardrailInputMessages、NotificationDeliveryResponse、ProviderKeyResolveAddresses、WebhookBodyTemplate、WebhookHeaders)。42 处中有 6 处被标记为影响调用方,全部集中在 effort_mapping 一个字段上:其映射取值在 4 个模型操作上现在可以为 null,取值的最小长度在 2 个操作上从 0 提升为 1。其余均为新增。

端点变化
GET /data_export新增。 把一个组织的全部配置以 gzip 压缩的 SQL 文件流式导出。查询参数为 redact(默认 false)、audit_since(默认为 30 天前)、include_usage_events(默认 false)和 usage_since(默认为 7 天前)。200 的响应类型为 application/gzip,带 Content-Disposition 和 X-Aisix-Export-Redacted;该组织已有导出在进行中时返回 409。需要新增的 data_export 读权限;未脱敏的导出还需要 owner 角色——管理员 Token 仅在其所属用户具有该角色且 Token 带 write 作用域时才被接受。
POST /data_import新增。 以请求体接收该 gzip 文件,并在一个事务内应用。控制面尚无任何用户时无需认证;此后调用方必须是已登录的自然人,个人访问 Token 一律不被接受。200 返回 DataImportResponse(imported、redacted、rows、ca 取值为 unchanged、replaced 或 kept_target、warnings、owner_user_id)。409 的错误码为 MIGRATION_VERSION_MISMATCH、ORG_EXISTS、USER_EXISTS、OUT_OF_SCOPE_ROWS、PROJECTION_TABLE_MISSING、MASTER_KEY_MISMATCH 或 MASTER_KEY_UNAVAILABLE。ca 为 replaced 时,cp-api 和 dp-manager 必须重启。
GET /notification_deliveries/{delivery_id}新增。 返回单条投递记录,包含目标返回的完整响应体,上限为所记录的 1 MiB。按组织隔离,访问其他组织的投递记录返回 404。
/environments/{env_id}/guardrails[/{guardrail_id}] 的 POST 和 PATCH,以及护栏的读取响应新增可选的 input_messages(all 或 latest_turn,默认 all)。省略该字段时行为不变。hook_point: output 与 input_messages: latest_turn 同时提交会被拒绝,返回 400 INVALID_REQUEST 并点名这两项设置;创建和 PATCH 的任一侧均适用。
/environments/{env_id}/models[/{model_id}] 的 POST 和 PATCH,以及模型的读取响应变更。 effort_mapping 的取值现在可以为 null——表示移除项,含义是“不向上游发送推理档位”——且取值的 minLength 从 0 提升为 1。把该映射反序列化为不可空字符串的调用方必须接受 null。此前被接受的两种形状现在返回 400:空字符串键映射到 null,以及任何映射到 "" 的条目。生成该映射的自动化程序不得把缺失的取值序列化为 ""。
同上两个模型操作目标环境中已注册的网关早于支持这些取值的版本时,保留键 "" 和 * 以及 null 值还会被拒绝,返回 422 DP_INCOMPATIBLE。该 422 及其错误信封与 1.2.0 相同,变化的是可能触发它的配置集合。
/notification_channels[/{channel_id}] 的 POST 和 PATCH新增可选的 body_template(Go text/template,渲染结果不超过 64 KiB,保存时必须能对样例事件渲染出合法 JSON,拒绝 range、template 和 block)和 headers(不超过 16 项,名称为不超过 128 个字符的 RFC 7230 token,取值不超过 4096 个字符且不含控制字符;拒绝 Content-Type、Content-Length、Host、Transfer-Encoding 和 Connection)。在 slack 渠道上这两个字段都会被拒绝,返回 400,包括把携带这两个字段的 Webhook 渠道改为 slack 的更新请求。更新时回传打码的 *** 请求头取值会保留已存储的值;对没有存储值的名称回传打码取值则返回 400。提交空对象会移除所有请求头。
GET /notification_channels 和 GET /notification_channels/{channel_id}新增: 渠道响应带上 body_template(渠道发送固定载荷时为空字符串)和 headers(仅名称,取值为 ***,没有时为 null)。两个字段始终返回。对读取方是新增字段;由严格 Schema 生成的客户端需要重新生成。
POST /notification_channels/{channel_id}/test新增可选的 request_body、response_status 和 response_body。只要收到了响应就会返回 response_body,包括成功的响应,其中渠道自身的 URL 和请求头取值会被打码。在允许访问私有目标地址的部署上,这会把目标返回的响应体交给调用方。
GET /notification_deliveries新增: 投递记录带上 last_response_status、last_response_body(前 8192 字节,按 UTF-8 边界截断)和 last_response_body_truncated;三者始终返回,未失败或从未收到响应的记录取值为 null 或 false。对读取方是新增字段;由严格 Schema 生成的客户端需要重新生成。
POST /provider_keys、PATCH /provider_keys/{provider_key_id} 和 GET /provider_keys/{provider_key_id}新增可选的 resolve_addresses:IPv4 和 IPv6 字面量地址数组(minItems: 1,不含端口,不带方括号);缺失或为 null 表示 api_base 的主机通过 DNS 解析。PATCH 整体替换该列表,null 清除它;详情响应会回显该字段,因为它属于网络拓扑而不是凭据。以下情况会被拒绝,返回 400 INVALID_REQUEST:某一项不是裸 IP 字面量(主机名、带方括号的地址、CIDR 网段、host:port 形式、超出范围的字节、带 IPv6 zone);api_base 本身已经是字面量地址或没有可读取的主机——这项校验针对最终的组合结果,因此只改动 api_base 的 PATCH 也会被拦住,且错误会点名两个字段;以及 Bedrock 适配类型的凭证,因为它通过自己的传输层分发请求。目标环境中只要有已注册的网关早于 1.3.0,就会被拒绝并返回 422 DP_INCOMPATIBLE:这类版本会忽略该字段并通过公共 DNS 解析主机,从而把该凭证的凭据交给任何应答方。
POST /roles 和 PATCH /roles/{role_name}读权限的 resource 枚举新增 data_export。该资源没有对应的写权限。

另有六处变化,其含义无法通过结构对比识别:

  • DELETE /environments/{env_id}/models/{model_id} 在多一种情况下返回 409 MODEL_IN_USE:存在 scope 为 model 且 scope_ref 指向该模型的限流策略。状态码和错误信封不变,变化的是此前返回 200 的一种情况。携带 model 或 model_name 条件的条件型策略有意不构成阻塞。
  • 缓存策略的 applies_to: "model:<name>" 现在按所选模型的资源 ID 生效。类型和取值都不变,但绑定方式变了:重命名后策略仍作用于该模型,而删除后策略将永久不再覆盖任何请求,之后重新创建同名模型也不例外。以未改动的选择器重新保存该策略会重新解析它。
  • MCP 工具的授权项、拒绝项、按 Server 的限流策略或匿名访问上限条目,其 Server 段落是某个已注册 Server 的精确名称时,现在会绑定到该 Server,并在重命名后按新名称读回。携带 * 的条目,或未指向任何已注册 Server 的条目,仍按名称匹配。这四种载体的数据结构都没有变化。
  • PUT /model_pricing 现在会在更新时写入 duration_cents_per_1m_seconds。该端点的文档说明它是整体替换,且其响应会回显已存储的记录,因此试图修改音频价格的组织收到的响应与它刚刚发出的请求相矛盾。
  • PATCH /environments/{env_id}/models/{model_id} 不再承诺所有引用都会跟随重命名:限流策略的 model_name 条件会保留旧名称并不再匹配。这一点此前即已如此,现在明确写出。
  • DELETE /environments/{env_id} 不再对资源相互引用的环境返回 500。数据结构没有变化;此前失败的调用现在会成功。

升级说明​

从早于 1.3.0 的版本升级至本版本或后续版本时,均需遵循本节说明,包括跳过 1.3.0 的升级。

  • 请先升级控制面,再升级网关。 这是唯一受支持的顺序。
  • 如果依赖跨重启的磁盘恢复能力,请设置 managed.snapshot_cache_enabled: true。 该配置项是新增的,默认为 false;仅配置 snapshot_cache_path 不再启用持久化——只配置路径时,1.3.0 完全不会写快照文件。因此,dp-manager 不可达时重启的网关会输出 waiting for the first configuration before binding the proxy listener,并且在控制面恢复可达之前完全不提供服务;1.2.0 会从磁盘恢复并继续提供服务(snapshot restored from on-disk cache)。处理方式是设置 managed.snapshot_cache_enabled: true,Helm Chart 或容器部署可使用 AISIX_MANAGED__SNAPSHOT_CACHE_ENABLED=true;路径保持默认值 /var/lib/aisix/config_cache.json。内存中保留最后一份可用配置并继续服务的行为不变。
  • 环境的请求数会上升、成功率会下降,这是预期结果。 调用方放弃的请求现在会记录用量数据,此前不记录。这些记录的 Token 数和费用均为零,可按 error_class = "client_disconnected" 过滤,也不改变任何花费。延迟分位数不受影响。
  • 请把日志处理改为读取流结束时的那条访问日志。 流式请求只写一条日志,写在流结束时,携带最终状态码和 Token 计数;此前写在响应头生成时,携带 200 且没有计数。所有日志还会新增 duration_ms(与 latency_ms 并列),非流式 /v1/chat/completions 的日志新增 cache_status。
  • 请检查为网关或控制面配置的各个地址是否带 scheme。 不是 http 或 https URL 的取值现在会导致启动失败,而不再在运行期才出问题:网关的 managed.cp_base_url 和 managed.cp_etcd_endpoint,cp-api 的 AISIX_CLOUD_DPMGR_BASE_URL,以及 dp-manager 的 AISIX_DPMGR_BASE_URL。不带 scheme 的 host:port 现在会被接受并读作 https://;已有的小写 http:// 或 https:// 取值不受影响。
  • 如果此前依赖固定的 UID,请重新配置。 控制面 Helm Chart 不再为任何组件设置 runAsUser、runAsGroup 或 fsGroup。按 UID 匹配的 PodSecurityPolicy 或 Gatekeeper 规则,以及已预先 chown 的外部挂载卷,需要通过 values 重新设置这三个键。内置的 PostgreSQL 子 Chart 保留自己的 UID,在 OpenShift 上需要单独关闭——--set postgresql.primary.podSecurityContext.enabled=false --set postgresql.primary.containerSecurityContext.enabled=false。
  • 请下载与自身架构匹配的离线安装包。 安装包现在按架构分别构建,文件名为 aisix-self-hosted-offline-<version>-linux-{amd64,arm64}.tar.gz;run.sh 会拒绝为其他架构构建的安装包。不带架构后缀的文件名仍然提供 amd64 安装包。
  • 升级窗口期间,早于 1.3.0 的网关会上报一条被拒绝的定价配置,这是预期结果。 只要还有早于 1.3.0 的网关处于已注册状态,1.3.0 控制面对 Model Pricing 覆盖项的投影(已有的覆盖项在升级时重新投影,新的覆盖项在保存时投影)就会使该网关上报 aisix_config_rejected_resources{kind="pricing"} 1 和 aisix_config_last_reload_successful 0。流量、就绪状态和后续的配置更新都不受影响,控制面的「被拒绝的资源」视图也仍然为空,因为对该网关而言这是一个未知的资源类型。网关升级到 1.3.0 后,这两条序列会立即恢复。请在升级控制面后尽快升级网关,并在此窗口期间不要对早于 1.3.0 的网关的 aisix_config_last_reload_successful 配置告警。
  • 请重新保存所有带音频时长费率的组织定价覆盖项。 第一次保存之后的任何一次保存所设置的 duration_cents_per_1m_seconds 都被丢弃了,因此已存储的值是最早写入的那个。重新保存该定价即可写入当前费率。
  • 请重新保存 applies_to 所选模型已被删除并重新创建过的缓存策略。 该选择器现在在保存时解析为资源 ID,而重新创建的模型是另一个资源。
  • 请修正或清除携带 {"": null} 或映射到 "" 的条目的 effort_mapping。 这两种形状现在都返回 400。已存储此类配置的模型仍然可以正常服务,但其编辑表单会把该规则显示为不完整,并且重新提交未改动映射的 PATCH 会被拒绝。这两种形状此前都无法通过控制台配置出来。
  • 请更新所有基于网关出向 User-Agent 做匹配的配置。 它现在上报 aisix/<build version>,而不再是固定的 aisix/0.1。
  • 如果使用 Bedrock、对象存储遥测导出或 /v1/realtime,请检查 upstream.pool_idle_timeout_secs 和 upstream.connect_timeout_ms。 这三条链路现在遵循所配置的取值(默认分别为 30 秒和 5 秒),此前它们使用的是 90 秒、3.1 秒,或完全不设超时。

1.2.0​

发布日期: 2026 年 9 月 8 日

本版本明确了最低支持版本,并加强了网关配置兼容性校验:控制面会在保存前拒绝已注册网关无法加载的配置。网关优化了配置变更处理,避免每次 watch 事件都产生与完整配置规模成正比的开销,解决批量修改配置导致请求处理阻塞的问题。此外,运维人员可以按指标选择标签集合;OpenAI 上游返回的原始缓存写入计数也会完整保留在网关响应、用量日志及其导出结果中。

行为变化​

  • Token 用量恰好达到窗口上限时,网关现在会拒绝新请求。 此前,当已提交的 Token 计数恰好达到上限时,tpm 和 tpd 仍会额外放行一个请求,只有超过上限后才会拒绝。内存和共享 Redis 两种后端现在使用相同的上限判断规则,切换后端不会改变实际限流行为。此变更适用于所有 Token 窗口,包括由策略派生的窗口和 API Key 级窗口。窗口上限显式配置为 0 时,现在会拒绝所有请求,与上限为 0 的请求计数窗口(例如 rpm)保持一致。请求计数采用预扣方式,此前已能准确执行上限,因此行为不变。

  • 控制面现在会拒绝保存已注册网关无法加载的配置。 控制面会根据目标环境中各已注册网关版本的配置读取规则,校验每份投影文档;只要某个受支持版本无法加载该文档,就返回 422 DP_INCOMPATIBLE。此前,写入会成功,响应中仅包含一条 row_rejected 告警,此时资源可能已在部分网关上停止生效。error.message 会完整说明网关版本、受影响的网关及配置中存在问题的部分;error.dp_compat 则以结构化字段提供相同信息。row_rejected 告警码已移除。新增的 below_floor 告警用于报告低于控制面最低支持版本的网关;控制面不对这些旧版本网关执行兼容性校验。

    网关停止上报后,其注册信息仍会保留 5 分钟。因此,集群升级后的一段时间内,拒绝信息仍可能列出集群中已不再运行的旧版本。这是预期的保守校验行为:旧注册信息过期前,控制面仍会将其纳入检查。拒绝信息包含 last_heartbeat_age_seconds,可在过期注册信息被清理后重试。

  • 数据库记录的上一次控制面版本低于 0.12.0 时,控制面会拒绝启动。 控制面 API 服务(cp-api)会在启动迁移时记录自身版本。如果数据库中记录的版本低于最低支持版本,服务会停止启动,并提示已记录的版本及处理方式。离线安装包的 run.sh 也会在启动任何容器前拒绝此类升级。请先升级到受支持的版本,或在完成备份后设置 AISIX_ALLOW_UNSUPPORTED_UPGRADE=1。API 服务和安装脚本均支持该环境变量,Helm Chart 中可通过 api.extraEnvVars 设置。全新安装不受此限制;上一次使用该数据库的控制面版本尚未引入版本记录机制时,也不受此限制。

  • 显式为空的 ignore_statuses 列表现在会被保留。 此前,创建或修改模型时提交的空列表会被接受,但随后会被替换为 [408, 429],并以该默认值存储、返回和投影。这导致后台健康探测仍会忽略 408 和 429,未按用户配置将其视为失败,且没有提示输入已被覆盖。现在,空列表在存储、GET 返回结果和网关配置中均保持为空列表。省略该字段的行为不变,仍使用默认值 [408, 429]。本版本之前保存的模型会保留已被替换的默认值,需显式设置为空列表后重新保存。

  • 使用非 Anthropic 上游时,系统提示词中的 Anthropic 计费归属行会被移除。 Anthropic 原生客户端会在系统提示词开头添加一行 x-anthropic-billing-header;在某些部署中,该行的部分内容会随请求变化,导致其他模型服务提供方收到的提示词前缀每轮都不同,无法命中提示词缓存。对于 POST /v1/messages 和 POST /v1/messages/count_tokens,如果解析出的目标并非目录中的第一方 anthropic 提供方,网关会在构建上游请求前移除该行:对于数组形式的 system,移除计费归属块;对于字符串形式的 system,移除第一行。提示词其余部分(包括 cache_control 标记)逐字节保留,messages 不会被修改。判断依据是目录中的厂商 ID:指向区域性或经代理的 Anthropic 端点的第一方凭据会保留该行;OpenAI Chat 桥接、第三方 Anthropic 兼容透传,以及 Bedrock、Vertex、Azure 平台适配均会移除该行。此变更无需调整配置,未发送该行的调用方不受影响。

新功能​

  • 按指标选择标签。 新增 observability.metrics.labels 配置块,用于声明每个指标族的完整标签列表;也可通过环境变量 AISIX_OBSERVABILITY__METRICS__LABELS 以 JSON 对象形式配置。未配置的指标族保留原有默认标签,因此升级后无需调整现有指标配置。标签选择在观测值累加前生效,移除 counter 或 histogram 的标签会聚合对应的观测值,不会丢弃观测数据;gauge 会保留用于标识序列的必需标签。未知的指标名称、不支持的标签变量或重复标签会导致启动失败,配置变更需重启后生效。首 Token 时间和请求延迟指标现在支持在原生和桥接请求路径上添加模型服务提供方凭证及调用方归属标签,这些标签默认不启用。

  • 控制台的网关安装页面支持选择指标标签。 运维人员可以添加受支持的标签、移除默认标签或恢复默认配置。Docker、Compose、Helm 和 systemd 安装指令都会通过启动环境变量包含完整的标签配置。这是网关进程级设置,不新增资源字段,也不改变资源投影。

  • 完整保留 OpenAI 上游返回的原始缓存写入计数。 cache_write_tokens 现在会保留在网关响应的 usage.prompt_tokens_details.cache_write_tokens 中,并传递至用量事件、Admin API 的用量日志列表与导出结果,以及控制台的日志详情。此功能覆盖原生 OpenAI 请求、各协议桥接、旧版非流式 Completions 及可识别的透传用量。显式返回的 0 与字段缺失保持区分,上游未提供该字段时不会补值。该字段保存原始计数,与 Anthropic 可累加的 cache_creation_tokens 分开存储,不改变 Token 总数,也不影响计费。历史用量记录中的该字段不会补填。

改进​

  • 批量修改配置不再阻塞网关请求处理。 此前,每次配置写入成功后,网关都会深拷贝完整快照,重新解析所有存储文档并进行规范化序列化,以重新计算两个哈希值,随后递增全局版本号。所有派生缓存均使用该版本号判断是否失效,因此每次写入的处理开销都与完整配置规模成正比。各工作线程收到下一个请求时,还会同步重建完整的护栏索引:为每个启用的挂载创建运行时和 HTTP 客户端,并分别重新加载 CA 存储。如果构建期间快照发生变化,构建会反复重试,且没有重试次数上限。该线程上的 /livez 请求也需等待这些操作完成。

    派生缓存现在根据其读取的表判断是否失效。每个已配置的护栏仅构建一个实例,并在各挂载间共享;只要对应配置行未变化,索引重建时就会复用该实例。并发触发的索引构建会合并执行,原有的重试循环已移除。快照克隆改为结构共享,每个条目版本的摘要仅计算一次,排队的配置事件在同一个写时复制周期内批量应用。聚合式 /mcp 端点也会按配置行缓存各 MCP Server 的工具集,无需在每次调用时重新遍历所有已注册的 OpenAPI 文档。

    配置、协议结构和上报值保持不变:config_hash 和 source_hash 逐字节一致,请求所应用的护栏及被拒绝配置行的上报行为均不变。新增 info 级别日志 guardrail index rebuilt,记录各类配置行数及构建、复用的实例数量。

  • 修复三个指标族未输出的问题。 aisix_redis_failures_total、aisix_otlp_fanout_failures_total 和 aisix_otlp_fanout_drops_total 此前虽已定义输出方法,但未被调用,因此查询结果始终为空。这些指标用于观察采用失败放行策略的子系统是否发生降级。Redis 失败现在按限流存储、响应缓存和语义缓存分别计数,并通过包含子系统信息的操作标签(如 ratelimit_acquire、cache_get、semantic_lookup)区分来源,便于在共用 Redis 时识别发生降级的子系统。OTLP 扇出会统计每次失败的导出尝试,包括重试;丢弃记录按 queue_full、worker_stopped、retries_exhausted 和 permanent_error 分类计数。批次被丢弃时,按批次中的记录条数计入。

  • 控制台页面在数据加载失败时会显示明确的错误提示。 此前,列表数据为 null 同时表示“仍在加载”和“加载失败”,导致错误卡片下方持续显示加载动画,部分页面甚至没有错误提示。现在,列表页会在加载成功或失败后结束加载状态。此变更覆盖团队及团队详情、预算、A2A Agent、管理员 Token、MCP Server、模型服务提供方凭据、定价、审计、通知渠道及投递记录,以及三个用量列表;也覆盖环境内的模型、API Key、限流策略、缓存策略、Claim 映射、OIDC 提供方、透传路由、可观测性、日志和 MCP 策略页面。组织设置卡片及团队 MCP 授权卡片采用相同处理方式。设置页和通知页在组织列表加载失败时会显示标准提示条。刷新或重试时,页面会重新进入加载状态,避免在请求进行期间持续显示上一次失败的提示。

修复​

  • Redis 不可达时,不再让每一个用到它的请求挂起。 当 ratelimit.backend 为 redis,或某条缓存策略使用 Redis 后端时,运行期出故障的 Redis 此前会让这些请求等上数分钟,而不是降级;aisix_redis_failures_total 会记下这次失败,却没有任何请求结果随之而来。现在每一次 Redis 往返和连接尝试都由各 redis: 块下新增的 timeout_secs 约束,默认 5 秒。在这个预算之内,既有的失败即放行路径会接管:限流回落到进程本地计数器,缓存则记为未命中。一次失败之后,该子系统会短路 30 秒,因此中断期间大约每 30 秒只有一个探测请求会付出完整预算。熔断器按子系统共享:缓存的精确连接和向量连接算作一个,限流器是另一个。Redis 恢复之后,网关最多在 30 秒内察觉,在此之前限流按副本各自计数、缓存记为未命中;上游环节耗时超过 30 秒的请求,仍可能在缓存写入时再付出一份预算。之后共享计数会自动恢复,既不需要重启,也不需要改配置。

  • 控制面无法提交的写入,不再返回 2xx。 每请求的事务此前是在处理函数的响应已经发出之后才提交的。读取状态行后就断开的调用方会取消上下文,随后提交失败、插入被回滚,而这个调用方手里却留着一个 201,对应的记录已经不存在。现在写操作的响应会一直挂起到提交成功为止:一个事务没能保住的 2xx 会被丢弃,改为以标准错误信封返回 500,记录照旧回滚。只有 2xx 会被扣住,409、400 或 499 与此前完全一样地送达。保持连接的调用方感受不到任何差别。

  • 多行 data: 流式帧现在会正确返回调用方使用的模型别名。 事件流格式允许单个帧的负载分布在多行 data: 中,并以换行符连接。此前,模型 ID 改写逻辑只读取第一行,导致这类帧无法解析为 JSON,进而被原样转发,调用方收到的是上游模型 ID,而非请求中使用的模型别名。受影响的帧包括 /v1/messages 的 message_start 帧和 /v1/responses 的快照帧。现在,网关会读取拼接后的完整负载,改写模型 ID,并将各行写回原位置,保留原有分帧结构和换行格式。

  • 控制台不再无限重试失败的 Token 签发。 此前,控制台未记录签发失败状态。当认证服务不可达时,预算提示条的轮询会使每个打开的标签页每 30 秒启动一轮新的签发,每轮尝试 3 次。现在,签发失败后会保存错误,并进入指数退避窗口:初始为 30 秒,逐次翻倍,最长为 5 分钟。窗口内的请求直接返回已保存的错误,不再发起签发尝试。下一次签发成功或退出登录时会重置退避状态。若刷新失败时旧 Token 仍有效,则继续使用旧 Token,与此前行为一致。

  • 路由模型的审计记录不再包含未设置字段的 null 值。 此前,路由模型未设置 hash_on 和 fallback_on_statuses 时,审计事件会将其记录为 JSON null,但 API 既不接受也不返回该值。现在,未设置时会省略这些字段,与网关配置文档保持一致。历史记录不会被改写。

API 变化​

API 结构对比显示,本版本未新增或移除操作,未改变请求结构,新增了响应结构定义 DataPlaneIncompatibleError。破坏性变更检查未报告错误,报告的 36 条告警均为响应枚举新增取值。以下响应及行为变化仍需调用方适配。

端点变化
32 个会向网关投影配置的写操作,包括:模型、API Key(含 /rotate)、护栏及护栏挂载的 POST 和 PATCH;限流策略、缓存策略(含 /purge)、Claim 映射及透传路由的 POST 和 PATCH;可观测性导出器、OIDC 提供方、MCP Server(含 /approve)及 MCP Server 提交的 POST 和 PATCH;模型服务提供方凭证及 A2A Agent 的 POST 和 PATCH;以及 PATCH /environments/{env_id}、PUT /environments/{env_id}/mcp_policy 和 PUT /model_pricing。新增 422 响应 DataPlaneIncompatibleError,在目标环境中已注册的受支持网关无法加载待保存配置时返回。error.code 为 DP_INCOMPATIBLE,error.message 提供可直接展示给运维人员的完整错误说明。error.dp_compat 包含 kind、dp_version、path、reason、affected_dp_count、affected_dp_nodes、affected_dp_versions 和 last_heartbeat_age_seconds。调用方需在所有向网关投影配置的写操作中处理 422,并根据错误提示升级受影响的网关或移除不兼容的设置。
上述操作中会返回 warnings 的 27 个创建与更新操作,以及获取单个模型、API Key、护栏、限流策略、缓存策略、Claim 映射、透传路由、MCP Server、模型服务提供方凭证或 A2A Agent 的 GET 操作。warnings[].code 枚举移除 row_rejected,新增 below_floor。此前返回 row_rejected 告警的情况,现在改为返回 422 DP_INCOMPATIBLE。below_floor 用于报告低于控制面最低支持版本的网关,其 field 为空,因为告警针对网关版本而非具体配置字段。依赖 row_rejected 告警码进行分支处理的自动化程序需相应更新。
  • GET /environments/{env_id}/usage_events
  • GET /environments/{env_id}/usage_events/export
用量事件响应新增可选字段 cache_write_tokens。对于本版本之前的历史记录,以及上游未上报缓存写入计数的记录,该字段不返回。显式的 0 与字段缺失保持区分。该字段保存原始计数,不与提示词 Token 数相加。

另有三处行为或语义变化,无法通过结构对比识别:

  • CompatibilityWarning.min_dp_version 的类型和 unreleased 哨兵值保持不变,但含义改为能够读取该字段的最低受支持网关版本;对于 below_floor,则表示控制面支持的最低网关版本。此前,该字段表示能够完整执行字段功能的最低网关版本,取值来自手工维护的映射表。affected_dp_count 的含义也从“运行版本低于 min_dp_version 的已注册网关数量”改为“此告警适用的已注册网关数量”。数据结构不变,但部分集群返回的数量可能变化。
  • background_model_check.ignore_statuses 此前接受 [],但实际存储为 [408, 429];现在会按空列表存储、返回和投影。请求结构不变,但调用方提交 [] 后读回的值已改变。字段描述也明确了空数组的含义,以及创建和 PATCH 操作中省略 background_model_check 时各自的行为。
  • 租户作用域下的每一个写操作,在此前会返回一个记录已被回滚的 2xx 的场景中,现在返回 500。这只有在调用方写入过程中断开时才可能触发,而那种情况下它什么也收不到。形状没有变化,对保持连接的调用方也没有变化。

升级说明​

从早于 1.2.0 的版本升级至本版本或后续版本时,均需遵循本节说明,包括跳过 1.2.0 的升级。

  • 如果当前版本低于 0.12.0,请先升级到 0.12.0 或更高的受支持版本,再升级到本版本。数据库记录的上一次控制面版本低于 0.12.0 时,控制面 API 服务和离线安装包均会拒绝升级。完成备份后,可设置 AISIX_ALLOW_UNSUPPORTED_UPGRADE=1 绕过该限制;Helm Chart 中可通过 api.extraEnvVars 设置。本控制面支持 0.12.0 及更新版本的网关。
  • 请更新依赖 row_rejected 告警码进行分支处理的自动化程序。此前返回该告警的情况,现在改为返回 422 DP_INCOMPATIBLE,所有向网关投影配置的写操作都可能返回此错误。同一告警枚举新增 below_floor,用于报告低于最低支持版本的网关。
  • 对于本版本之前曾将 background_model_check.ignore_statuses 显式设为空列表的模型,请将该字段重新设置为 [] 后保存。旧版本实际存储的是默认值 [408, 429];仅升级不会修正该值,原样保存默认值也不会恢复空列表配置。

1.1.0​

发布日期: 2026 年 9 月 7 日

这个版本加固了控制面到网关之间的这条路径。网关现在只有在拿到可服务的配置之后才打开代理端口,能够自行从 etcd 中断、etcd Token 过期或 watch 始终未被确认中恢复,并且可以加载此前会超出内部消息大小上限的配置集。A2A Agent 补齐了调用方请求头转发契约;On-Premises 控制面 Chart 支持固定 NodePort,也不再等待一个已经被告知不使用的内置数据库。

行为变化​

  • 网关只有在应用过一次配置之后,才绑定代理监听器。 在 etcd 模式下,冷启动的实例会保持代理端口关闭,直到第一次配置读取成功;此前它会立即接受连接,并因为还不知道任何 API Key 而对每个请求返回 401 invalid_api_key。把"端口可连接"当作"该实例已就绪"的编排系统,不会再把流量路由到一个无内容可服务的实例上。这没有配置开关,也无法关闭;启动顺序现在就是如此。这段等待只会发生在从未应用过配置的实例上。文件模式会立即通过这道闸门;重启后发现磁盘快照缓存的实例同样如此——它会恢复快照并在远不到一秒内完成绑定,即使此时配置源不可达,因此已经运行过的 Pod 在控制面故障期间也能直接恢复服务。只有没有快照缓存的首次启动会等待,而在控制面可达时,这段等待在真实配置规模下是数十毫秒量级。由于 /livez 和 /readyz 由代理监听器提供,在这个窗口内针对它们的探针会收到连接被拒绝而不是响应;指标监听器上的 /status/ready 和 /status/config 全程可用。使用 Helm 的用户请在升级镜像的同时采用 1.1.0 Chart:Chart 的启动预算已经相应放宽。

  • etcd.dial_timeout_ms 和 etcd.request_timeout_ms 现在开始生效。 此前的版本会解析这两个键,但没有任何代码读取它们,所以无论配置文件里写了什么,每个部署实际上都没有 etcd 超时。两个键都是可选的,不设置即表示无上限,不存在隐式的 5000。request_timeout_ms 约束每一次单请求单响应的 etcd 调用——启动时以及每次 watch 重连时的配置范围读取、创建 watch,以及 Admin API 的读取——不会约束已建立的 watch 流。dial_timeout_ms 约束整个拨号过程,包括 TLS 握手和认证交换。从上一版本自带示例复制而来的配置文件已经带着这两个键的 5000 取值,升级前请先检查,详见升级说明。

  • 配置了 etcd 凭据的网关,在 etcd 启动时不可达的情况下不再退出。 此前设置 etcd.user 和 etcd.password_env 会让不可达的 etcd 成为致命错误:进程会在大约 20 到 25 秒后退出,此时还没有任何重试或监听器。这样的实例现在与未认证的实例行为一致——它会启动、保持代理监听器关闭、按已有的退避策略重试,并在配置到达后立即绑定。etcd 主动拒绝的凭据——用户名或密码错误、用户缺少所需权限,或者向未开启认证的集群发送了凭据——仍然是致命错误,并且现在会在 etcd 的第一次应答上就中止启动,而不是走完一整轮固定的重试阶梯。此前依赖进程退出来判断"etcd 挂了"的做法,应改为读取 /status/ready。

新功能​

  • A2A Agent 可以把入站的调用方请求头转发到上游。 A2A Agent 新增 forward_client_headers 列表,用于点名网关转发给该 Agent 的调用方请求头,写法是最多含一个 * 的 glob 模式,匹配不区分大小写。它作用于 /a2a/<name> 上提供的每一个 JSON-RPC 方法——message/send、message/stream 以及所有任务操作——也作用于 /a2a/<name>/.well-known/agent-card.json 上的 Agent Card 获取。至此,这份转发契约在四个代理面上全部补齐:模型服务提供方凭证、透传路由、MCP Server 和 A2A Agent。默认为空且不转发任何内容,因此现有 Agent 的行为不会改变。

    点名该 Agent auth_type 所填充的凭据槽位——bearer 对应 authorization,api_key 对应 x-api-key——会把调用方自己的凭据替换网关的凭据交给 Agent,而不是同时给出两份;这让原本就按最终用户身份做鉴权的内部 Agent 可以继续这样做。凭据槽位以及 traceparent 和 tracestate 只有在模式精确写出名称时才会转发,* 或 x-* 这类宽泛 glob 永远不会把它们扫进来。转发后会破坏这次交互的请求头,无论模式多宽泛都会被拒绝:host、逐跳请求头、x-aisix-* 命名空间、描述由网关重新序列化的请求体的那些请求头,以及 a2a-version——后者是网关自己对 protocol_version 所固定版本的声明。

    转发 cookie 之前有一个限制值得了解。网关会终结入站的 HTTP/2,并且不做 cookie 重组,因此如果 HTTP/2 调用方的客户端把 cookie 拆成多个请求头字段(这是 HPACK 的一种压缩手段,并非每个客户端都会这么做),只有其中第一个会被转发。A2A Agent、MCP Server 和模型服务提供方凭证都是如此;透传路由则会转发每一个取值。

    该配置可以在控制台的 A2A Agent 创建与编辑表单的"高级"区域中设置,也可以通过 Admin API 设置。如果在保存非空列表时,作用范围内仍有网关运行着不支持该字段的版本,保存会返回一条兼容性告警;这些网关在升级前不会转发任何内容,方向上是失败即拒绝。

改进​

  • 网关可以加载大于 4 MiB 的配置集。 网关会在单次 etcd 范围响应中读取自己的整个前缀,而 4 MiB 的 gRPC 解码上限意味着规模超过该值的环境永远无法加载——触及这条上限的是环境中资源的数量,而不是某个资源本身很大。它也不会自愈:运行中的实例会静默地不再看到配置变更,重启或新调度的实例则根本不会应用任何配置。配置读取路径和 Admin 读取面上的这条上限都已解除。低于旧上限的部署不受影响。

  • 控制面不再限制它写往网关的单个资源的大小。 控制面自身写入路径上的两条消息大小上限——outbox 客户端 2 MiB 的发送上限和内嵌存储 4 MiB 的接收上限——会让某个过大的投影资源在每一轮轮询中都被拒绝,且永远如此。由于按键隔离,队列中其余部分仍在正常排空,所以外部看到的现象是:某一个资源的配置始终没有到达网关,而保存它的人得不到任何提示。这两条上限都不是为这条路径选择的,现已移除。触及其中任何一条都需要异常大的投影值,例如一个授权了数千个模型的 API Key。

  • 等待配置源的网关现在会明确说明。 在第一次配置读取尚未完成期间,网关会在等待开始时记录日志,并每十秒重复一条告警。此前,一个能接受 TCP 连接却不作应答的端点,会让进程既没有端口、也没有任何日志。

  • On-Premises 控制面 Chart 支持为 API 和控制台服务指定固定 NodePort。 api.service.nodePort 和 ui.service.nodePort 加入了已有的 dpm.service.nodePort,各自只在对应 Service 类型为 NodePort 且已设置取值时才渲染;两者默认都为空,因此没有设置它们的安装保持动态分配。这让运维方可以在安装前就把 api.publicBaseURL 设为一个已知的地址。通过 NodePort 访问 API 和控制台走的是明文 HTTP:控制台的 NodePort 并不是一个独立入口,而是一个同源代理的上游,该代理会把 /api/* 路由到 API;除非部署在受信任的私有网络中,否则应由该代理终结 TLS。

修复​

  • etcd 认证 Token 过期或失效后,不再需要重启网关。 etcd 客户端只在连接建立时认证一次、之后不再认证,因此当 Token 在连接空闲期间到期(配置稳定的网关正处于这种状态),或因 etcd 认证存储发生变更而失效时,后续所有调用都会被拒绝,直到进程重启为止。网关现在会丢弃该连接、重新认证并把这次调用重试一次,配置读取路径和 Admin 读取面上都是如此。etcd 确实拒绝的凭据仍会按原样上报,不会被循环重试。

  • 网关在一次更新后不久被停止时,不再丢失最后一份配置快照。 快照缓存的写入此前是分离派发的,没有任何环节等待它完成,因此在应用变更后不久被停止的实例可能在写入尚未完成时就退出,重启后失去最后一份已知良好快照。现在关闭时会排空进行中的写入,上限为五秒。快照写入也按应用顺序提交:较旧修订版本的写入不会再覆盖较新的,因此在一连串更新之后重启的网关,不会回到一份它早已越过的快照上。优雅排空流程、排空窗口和 preStop 行为均保持不变。

  • 始终未被确认的配置 watch 现在能够被发现。 如果 etcd 能应答范围读取、却始终不确认 watch,网关会永远停留在自己的第一份快照上,对之后的每一次变更都视而不见,而 /status/config 仍然报告连接正常。设置了 request_timeout_ms 时,未被确认的 watch 创建会被中止,并按已有的退避策略重试。

  • MCP 访问控制的重投影现在覆盖每一条受影响的记录。 升级时刷新 MCP 访问控制的重投影,其分页方式可能跳过部分记录,让这些记录保留着已被淘汰的投影,兼容性告警也因此一直存在。现在它会显式遍历每一个 API Key 和每一条 MCP 策略。升级控制面时,每个现有 API Key 和每条 MCP 策略会多出一次投影写入。API、配置和资源形状都没有变化,也不需要运维方做任何操作。

  • 配置了外部数据库时,On-Premises 控制面 Chart 不再等待内置的 PostgreSQL。 设置 postgresql.builtin=false 会关闭内置的 PostgreSQL 服务,但 API 和数据面管理器仍会运行一个由 postgresql.image.* 构建的 PostgreSQL 就绪 init 容器,因此在私有网络中,即使外部数据库健康,拉不到 PostgreSQL 镜像也可能阻塞启动。该就绪 init 容器现在只在 postgresql.builtin=true 时渲染。内置部署不受影响,仍然是默认方式。使用外部数据库的运维方需要自行确保它在控制面启动前已经就绪。

API 变化​

OpenAPI 结构对比没有发现破坏性变化。所有新增内容都是可选的,且都集中在 A2A Agent 这一面。

端点变化
  • GET /a2a_agents
  • GET /a2a_agents/{a2a_agent_id}
A2A Agent 表示新增可选字段 forward_client_headers。
  • POST /a2a_agents
  • PATCH /a2a_agents/{a2a_agent_id}
接受可选的 forward_client_headers,取值是一个请求头名称 glob 模式数组;传 [] 会清除已有列表。条目按与其他转发面相同的规则校验——RFC 7230 token 语法、每个条目最多一个 *、最多 64 个条目——如果某个模式只可能点名这一面永远不会转发的请求头,则以 400 拒绝。只携带 forward_client_headers 的 PATCH 是一次有效更新。
  • POST /a2a_agents
  • PATCH /a2a_agents/{a2a_agent_id}
当该 Agent 所暴露环境中的网关运行着不会执行所保存 forward_client_headers 的版本时,保存成功的响应可能包含 warnings。告警形状沿用已有的 CompatibilityWarning;这是 A2A 保存首次可能携带它的版本。

有一处描述在形状不变的前提下收窄了。截至 1.0.0,A2A 的 auth_type 字段声明网关自身的凭据绝不会被转发给调用方、也不会向调用方暴露。这一保证现在只在 forward_client_headers 没有点名 auth_type 所填充的槽位时成立;一旦点名,Agent 收到的就是调用方的凭据而不是网关的。该字段的形状和枚举取值均未改变。

升级说明​

从任何早于 1.1.0 的版本升级时,本节说明都适用,包括那些途中越过 1.1.0 直接升到更新版本的升级。

  • 升级前请检查你的 etcd: 配置块。etcd.dial_timeout_ms 和 etcd.request_timeout_ms 在本版本中首次生效,而上一版本在 config.example.yaml 和 config.managed.yaml 中把这两个键都写成了生效的 5000。因此从其中任一文件复制而来的配置文件,会在配置范围读取上获得一个真实生效的 5 秒上限。如果某个部署的配置集无法在该上限内完成加载,这次读取会失败并重试;而由于网关现在只有在成功应用配置之后才绑定代理监听器,它将无法开始提供服务。除非你确实希望缓慢的 etcd 快速失败,否则请移除 request_timeout_ms;如果保留,请按你自己的配置集规模来设定取值,而不是沿用示例中原有的数字。dial_timeout_ms: 5000 没有可比的风险。现在两个键在自带示例中都处于未启用状态,不设置即表示无上限。
  • 如果你的控制面 Helm values 文件中已经写了 api.service.nodePort 或 ui.service.nodePort,升级前请检查它们。这两个键在本版本之前是被忽略的,现在会被渲染,因此升级 Chart 可能改变一个原本由 Kubernetes 动态分配的端口。想保持动态分配,请删除该键。

1.0.0​

发布日期: 2026 年 9 月 4 日

这个版本让安全护栏的行为在需要调优的地方变得可见、可配置。语义护栏会报告实际测得的相似度,控制台可以在规则挂到生产流量之前对已保存的规则做测试,失败后放行的决定也会在整个网关中得到一致记录。本次发布还为模型路由、MCP 服务器、透传路由和 Realtime 统一了调用方请求头转发契约,完善了不同模型服务提供方协议之间的推理控制,并让路由与配置失败更容易诊断。

行为变化​

  • 模型冷却现在需要显式开启。 直接模型没有 cooldown 配置块,或配置块中省略 enabled 时,请求失败后不再进入冷却。需要保留此前行为的,请设置 cooldown.enabled: true;开启后,默认超时时间与触发条件不变。此前依赖隐式冷却的现有模型会受到这一破坏性行为变化的影响。

  • 安全护栏不再把 Files API 当成一个不透明的整体扫描。 /v1/files 下的上传请求体、上传响应和文件下载现在不做输入或输出护栏评估。此前的整文件扫描既不能逐条评估 JSONL 记录,也无法把掩码后的内容写回 multipart 请求体,还会用替换字符解码二进制文件。/v1/batches 和 /v1/fine_tuning/jobs 的请求信封仍受护栏保护;本版本不包含逐条文件记录筛查。

  • 网关无法扫描的请求体现在遵循实际管辖该方向的护栏策略。 只有至少一条作用域内的护栏会读取这个方向、并且对它采用失败即拒绝时,网关才拒绝不可读内容。不会读取这个方向的护栏不会导致拒绝;所有相关护栏都采用失败后放行时,请求会继续,并记录 unscannable_body。fail_open 现在同样适用于 keyword 和 pii 护栏,而不只适用于远程护栏。已缓冲的流式输出在无法恢复出任何可扫描内容时仍然失败即拒绝,因为放行就意味着释放从未经过护栏评估的字节。

  • 无法解码的音频转写与翻译响应现在遵循输出失败策略。 输出护栏采用失败即拒绝时,这类纯文本转写返回 422 content_filter,错误码为 guardrail_unavailable;采用失败后放行时,原始字节会被转发,并记录这次绕过。能够解码的转写内容仍会接受扫描。

  • 不支持的流式请求会在到达模型服务提供方之前失败。 对 /v1/completions 或 /v1/images/generations 发送 stream: true 现在返回 400 invalid_request_error。这两个端点不转发流式响应;此前请求会被发往上游,可能在重试预算内重复产生可计费工作,最终返回与解码有关的 502。

  • 安全护栏现在按推理内容的提供者确定作用域。 调用方重放的推理内容属于输入,会在 Chat Completions、Responses 和 Anthropic Messages 上接受扫描;模型生成的推理内容不属于输出扫描范围。Anthropic 已签名的 thinking 块会接受拦截动作检查,但不会被掩码动作改写,因为客户端重放时必须保持这些已签名字节不变。

  • 流式错误事件现在采用各端点的原生信封。 /v1/messages 流中的护栏错误使用 Anthropic 的 invalid_request_error 类型;/v1/responses 发出扁平的 Responses API 错误事件,code、message、param 和 sequence_number 位于顶层。HTTP 错误信封不变。

  • 新发布的镜像只使用不可变的完整版本标签。 稳定版本发布 :X.Y.Z、:latest 和 :sha-*;候选版本发布完整 RC 标签与 SHA 标签。此后不再创建新的 :X.Y 和 :X 缩写标签。注册表中已经存在的缩写标签会保留,但本版本及后续版本都不会再推进它们。

新功能​

  • 语义护栏在部署前后都可以测量。 编辑表单新增试运行面板,可以为探测文本生成向量嵌入,并展示拒绝或允许分数、配置阈值、最接近的样例以及最终判定。经过语义护栏评估的请求会在用量事件中新增 guardrail_scores,通过的请求也会记录。日志会显示分数、阈值、方向、最接近样例的索引和向量嵌入模型;用量 API 与 CSV 导出携带同一份记录。持久化用量数据只保存样例索引,不保存样例或被筛查的文本。

  • 调用方请求头转发现在覆盖模型服务提供方凭证、MCP Server、透传路由和 Realtime。 MCP Server 与透传路由新增 forward_client_headers;模型服务提供方凭证已有的配置现在也作用于 Realtime 和所有经过协议翻译的模型服务提供方路径。在 MCP 与标准模型端点上,它是一份允许列表;在透传路由上,它恢复一条原本会被路由剥离的请求头。由于该字段可能传递调用方凭据与链路上下文,包括 AWS SigV4 请求身份头在内的凭据槽位,以及 traceparent / tracestate,都必须精确写出名称,不能由 glob 选中。被精确转发的凭据会替换网关或 default_headers 原本放入该槽位的凭据,不会追加第二个值。Amazon Bedrock 是例外:其签名器拥有 authorization 和 SigV4 请求头,签名前会丢弃调用方提供的这些值。

  • 直接模型可以为上游规范化推理力度。 新增的 effort_mapping 对象会在最终直接目标选定后,执行一次区分大小写的精确字符串映射。没有列出的值或缺失值原样透传;映射不会补充调用方没有提供的值,映射结果也不会再次进入映射。它覆盖 Chat Completions、Responses、Anthropic Messages 与 Token 计数请求,包括原生及跨模型服务提供方路径、流式请求、Bedrock 两种调用方式,以及由路由、语义或 Ensemble 模型选出的直接目标。该配置只允许用于直接模型,并可在控制台编辑。

改进​

  • 语义护栏要求使用为其向量嵌入模型选定的阈值。 非空的 deny_examples 必须同时配置 deny_threshold,非空的 allow_examples 必须同时配置 allow_threshold;没有样例的方向不要求阈值。此前省略阈值的现有数据会填入 0.75,保持原有执行效果。控制台测试面板与每次请求的分数可用于测量并调整替代值。

  • 所有受保护的代理面都能看到失败后放行结果。 成功和失败的用量事件都会携带 guardrail_bypassed_reason,包括在任何单条护栏运行之前发生的绕过。aisix_guardrail_bypasses_total 指标新增 reason="unscannable_body";aisix_guardrail_blocks_total 也会计入在某条可计时护栏运行前发生的失败即拒绝。A2A、原本不产生用量的 rerank,以及不支持能力的路径,会在需要保留护栏归因时发出零 Token 用量事件。

  • 护栏配置失败现在会作为配置状态上报。 能反序列化、但运行时无法构建的记录会出现在 /status/config、拒绝指标和托管心跳状态中,修复后自动消失。PII、Presidio、关键词和语义护栏配置中,原本可能导致整条护栏被丢弃的 JSON null 现在会被拒绝。升级迁移只会用安全默认值修复已存储的 null 与缺失值,再校验完整投影记录;其他格式错误的记录保持不变。

  • 缓冲式输出护栏覆盖完整 SSE 帧。 Messages 与 Responses 路径现在可以处理 CRLF 分帧、多行 data: 载荷、缺失的最终终止符,以及流式请求返回的非 SSE JSON 响应。无法在保持结构的前提下掩码的内容会被移除或拒绝,而不会未经读取就释放;可以掩码的多行帧会保留完整载荷。

  • 推理控制可以跨协议翻译。 Anthropic 的 output_config.effort 和自适应/禁用 thinking 会映射到相应的 OpenAI reasoning_effort;OpenAI 的 effort 值会映射到 Anthropic 当前使用的 output_config.effort 形式。Anthropic 的结构化输出声明也会转换成带严格 JSON schema 的 OpenAI response_format,而不再被丢弃。

  • 路由和指标会展示网关实际完成的更多工作。 因冷却或后台健康检查而被移除的路由目标会产生一条限频告警,写明目标与原因;失败尝试告警在 Chat Completions、Messages、Token 计数和 Responses 之间保持一致。原生与翻译后的 Responses 流现在都会报告两组 TTFT 指标;Ensemble 请求在配额、用量事件和 Token 指标中使用同一份用量估算。

  • 控制台会保留资源引用,不再要求运营方重新输入。 已有资源字段使用可搜索选择器;允许合法新值的字段继续提供可编辑建议;过期引用仍然可见,不会因一次无关编辑而被静默清空。在日志中,手工输入的请求模型筛选仍然是大小写不敏感的子串搜索;从已知模型中选择则会在数据流与 CSV 导出中执行大小写敏感的精确匹配。

修复​

  • Rerank 与 Realtime 的响应模型名保持一致。 Jina 形状的 /v1/rerank 响应以及 Realtime 的 session.created / session.updated 事件现在报告调用方寻址的网关模型名,而不是模型服务提供方的模型 ID。把完整 Realtime session 对象发回 session.update 时,模型名会再次转换为上游 ID,同时不会改动单独配置的转写模型。

  • 模型服务提供方不支持的能力不再消耗重试预算。 缺失的 completions、embeddings 或图像生成能力会被明确分类,并直接返回已有的 501,不再重试一次不会随尝试变化的 adapter 能力。

  • 通配符模型引用会在失效或扩大访问范围之前得到校验。 当模型被精确名称引用,或重命名会把 API Key 的单模型授权静默扩成命名空间授权时,不允许把该模型重命名成通配符别名。语义护栏不能新选择通配符别名作为 embedding 模型。缓存策略可以选择由通配符别名服务的具体模型名,但不能选择通配符模式本身。已有引用只在其值发生变化时重新校验。

API 变化​

OpenAPI 结构对比没有发现破坏性的形状变化。不过,下列若干校验变化属于语义上的破坏性变化:此前会被接受的请求现在可能返回 400。调用方需要同时检查这些变化和新增字段。

端点变化
  • GET /environments/{env_id}/models
  • GET /environments/{env_id}/models/{model_id}
模型表示新增可选字段 effort_mapping,并注明 cooldown.enabled 默认为 false。
  • POST /environments/{env_id}/models
  • PATCH /environments/{env_id}/models/{model_id}
直接模型接受可选的 effort_mapping,配置后成功响应会返回它;更新时传 null 或 {} 会清除它,非直接模型会拒绝该字段。省略 cooldown 配置块或 enabled 表示关闭冷却。当精确名称引用或 API Key 授权会被破坏时,PATCH 拒绝把模型重命名成通配符别名。
  • POST /environments/{env_id}/guardrails
  • PATCH /environments/{env_id}/guardrails/{guardrail_id}
语义样例列表要求配套阈值;语义向量嵌入模型不能新引用通配符别名;受影响的语义、PII、Presidio 和关键词配置字段拒绝 JSON null。PATCH 完整替换 config 时,必须包含其样例列表要求的每个阈值。
  • POST /environments/{env_id}/cache_policies
  • PATCH /environments/{env_id}/cache_policies/{cache_policy_id}
model:<name> 选择器可以写由通配符别名服务的具体地址,但选择器本身不能是通配符模式。已有值只在发生变更时重新校验。
  • POST /provider_keys
  • PATCH /provider_keys/{provider_key_id}
已有的 request.forward_client_headers 与 request.default_headers 校验现在接受凭据槽位、拒绝会破坏传输的请求头和 x-aisix-* 名称,并应用上文所述的精确匹配与冲突规则。部分此前被接受但不生效的请求头条目,必须先删除才能再次保存完整请求覆盖配置。
  • GET /environments/{env_id}/passthrough_routes
  • POST /environments/{env_id}/passthrough_routes
  • GET /environments/{env_id}/passthrough_routes/{passthrough_route_id}
  • PATCH /environments/{env_id}/passthrough_routes/{passthrough_route_id}
请求与响应新增可选字段 forward_client_headers;更新时传 null 会清除它。
  • GET /mcp_servers
  • POST /mcp_servers
  • GET /mcp_servers/{mcp_server_id}
  • PATCH /mcp_servers/{mcp_server_id}
  • POST /mcp_server_submissions
  • PATCH /mcp_server_submissions/{mcp_server_id}
请求与响应新增可选字段 forward_client_headers。POST /mcp_servers/{mcp_server_id}/approve 与 /reject 返回的 MCP Server 表示中也包含该字段。
  • GET /environments/{env_id}/usage_events
新增可选布尔查询参数 requested_model_exact;响应项可能包含 guardrail_scores。
  • GET /environments/{env_id}/usage_events/export
新增可选布尔查询参数 requested_model_exact;导出项新增 guardrail_scores。

升级说明​

从任何早于 1.0.0 的版本升级时,本节说明都适用,包括那些途中越过 1.0.0 直接升到更新版本的升级。

  • 冷却改为显式开启属于破坏性行为变化。升级前,请为每个需要保留 1.0.0 之前隐式冷却行为的直接模型设置 cooldown.enabled: true。
  • 本版本中 /v1/files 不在安全护栏覆盖范围内。不要依赖上传或下载的整文件关键词、PII 或远程护栏判定。
  • 检查每条护栏的 hook 与失败策略。AISIX 无法扫描、且由相关失败即拒绝护栏管辖的请求体仍会被拒绝;没有相关失败即拒绝护栏时则可能继续。特别是 fail_open: true 现在会对 keyword 和 pii 护栏生效,可能新放行 AISIX 无法扫描的请求或响应。
  • 客户端重放的推理内容现在可能被输入护栏拦截。模型生成的推理内容不再由输出护栏评估,掩码动作也不会改写 Anthropic 已签名的 thinking 块。
  • 当音频转写或翻译响应字节无法解码、且输出护栏采用失败即拒绝时,客户端需要处理 422 content_filter。采用失败后放行时,原始字节现在可能在未经内容评估的情况下被转发。
  • 对 /v1/completions 或 /v1/images/generations 发送 stream: true 现在不会联系模型服务提供方,而是返回 400 invalid_request_error,不再最终返回与解码有关的 502。请更新状态码处理和重试策略。
  • 请更新自定义流解析器以适配原生护栏错误信封:Messages 流使用 Anthropic 的 invalid_request_error,Responses 流把 code、message、param 和 sequence_number 放在顶层。
  • 升级前检查包含 JSON null 的已有护栏。上一版本跳过、且能够安全修复的记录在迁移后可能开始执行;只缺少语义阈值的记录会保持已有的 0.75 行为。
  • 创建或完整替换语义护栏配置的 API 客户端,必须为每个非空样例列表提供对应阈值。即使 OpenAPI 形状没有结构性破坏,阈值与 null 校验仍属于 Cloud Admin API 的语义破坏性变化。
  • 检查重命名模型或写入模型引用的自动化。当精确引用会被破坏或 API Key 授权会扩大时,不允许把模型重命名成通配符别名;语义护栏不能新使用通配符别名作为向量嵌入模型;缓存策略可以写由别名服务的具体模型,但不能写通配符模式本身。
  • 检查 Realtime 使用的模型服务提供方凭证 forward_client_headers 模式:1.0.0 开始在该代理面上执行这份配置。凭据槽位与 traceparent / tracestate 必须精确写名,宽泛 glob 不会选中它们。再次保存完整覆盖配置前,请删除被拒绝的传输头、x-stainless-*、anthropic-version 或 x-aisix-* 条目。在 Bedrock 兼容端点上,转发的调用方值现在会在 x-api-key、api-key、x-goog-api-key、proxy-authorization 和 cookie 槽位中覆盖 default_headers。Bedrock 签名器仍然拥有 authorization 与 AWS SigV4 请求头,并丢弃调用方提供的值。
  • 原本期望新发布的 :X.Y 或 :X 镜像别名继续推进的自动化,需要改用完整版本或 :latest。
  • 如果告警基于 aisix_guardrail_bypasses_total,请考虑新增的 reason="unscannable_body" 序列,以及现在被纳入总数的其他事件。

0.13.0​

发布日期: 2026 年 9 月 1 日

这个版本围绕两件事:把流量区分开,以及按上游自己的方式访问它。模型服务提供方凭证现在可以声明该端点原生提供哪些 API 面、每一个面在哪个地址上,因此一份凭证就能同时访问一个上游的 OpenAI 兼容路径和 Anthropic 兼容路径,不必再建第二份凭证和第二个模型。每条用量记录现在都写明了这次请求要网关做的是什么,图像生成和视频提交在导出器和日志里不再和文本对话混成同一股 OpenAI 流量。被网关限流的调用方,也终于能从响应里读到上限是多少、什么时候可以再来。此外,凡是会返回模型名的端点,响应里现在报的都是调用方寻址时用的网关模型名,而不再是其中一部分端点报服务提供方自己的 ID。

行为变化​

  • 升级后,现有的 DeepSeek 模型服务提供方凭证会直达 DeepSeek 自己的路由,而不再被翻译。 AISIX 现在内置了一份经过实测的声明,写明 DeepSeek 原生提供 /v1/responses 和 Anthropic 兼容的 /anthropic/v1/messages,并在升级时一次性应用到符合条件的凭证上:自身没有任何声明、使用 deepseek 提供方、且 api_base 仍指向 https://api.deepseek.com。这些凭证的 apis_source 会标记为 catalog。对流量的影响是:Responses API 请求会被转发到 DeepSeek 自己的 /v1/responses 而不再翻译成 chat completions,推理输出项因此得以保留;Anthropic 协议的请求会走到 Anthropic 兼容路径,提示缓存断点和思考块因此得以保留。你自己声明过的凭证不会被改动。
  • 客户端从响应里读到的 model 字段,现在是它请求时用的网关模型名。 涉及 /v1/messages、/v1/responses、/v1/completions、/v1/embeddings(流式与非流式同样适用)以及 /v1/videos 的轮询。这几条路径此前返回的是服务提供方自己的模型 ID——一个别名为 gpt4o-mini 的模型会回来 gpt-4o-mini-2024-07-18,而 /v1/chat/completions 早就返回别名了。透传路由不受影响,仍然原样转发服务提供方的响应。
  • 网关自己产生的限流拒绝现在带响应头。 网关拒绝一个请求时,429 会描述拒绝它的那一条上限:x-ratelimit-limit、x-ratelimit-remaining、x-ratelimit-reset、x-ratelimit-scope 和 Retry-After。x-ratelimit-reset 与 Retry-After 都是以秒为单位的相对值。并发维度的拒绝此前完全没有重试提示,现在也有了。这些响应头只在网关自己拒绝时添加;上游返回的 429 仍按上游原样透传。成功响应上原有的 x-ratelimit-limit-requests / -tokens / -concurrent 这组按维度命名的响应头保持不变。
  • 键已经消失的 Prometheus gauge 不再继续上报最后一个值。 aisix_budget_limit_usd / _spent_usd / _remaining_usd / _reset_seconds / _details_present 以及 aisix_ratelimit_remaining_{requests,tokens} 只在请求路径上被写入,因此删掉一个 API Key 会把它的时间序列冻结在最后读到的值上——一条针对预算耗尽的告警,会为一个已经不存在的凭证持续触发。这类序列现在会退休为 NaN,Prometheus 将其视为"没有值"而不是零。比较这些 gauge 的告警不会再匹配到已删除的 Key。如果你的仪表盘面板直接读原始值,Key 删除之后看到的会是一段空缺,而不是一条水平线。

新功能​

  • 模型服务提供方凭证可以声明原生 API 面。 同一个上游账号常常在同一个主机的不同路径上提供多种协议,共用一份凭证——DeepSeek、智谱和 Kimi 都同时提供 OpenAI 兼容路径和 Anthropic 兼容路径。api_base 只能指出其中一个,于是其余请求一律被翻译,丢掉目标协议携带而标准 chat 形状没有的东西。凭证现在支持一个 apis 块,写明每个面以及它所在的 base URL:

    {
    "apis": {
    "responses": {},
    "messages": { "base": "https://api.deepseek.com/anthropic" }
    }
    }

    两个面的判定规则不同,因为它们各自的依据不同。messages 是附加的:adapter 本来就是 anthropic 的凭证,无论这个块怎么写都继续原生提供 /v1/messages,在这里列出它是为了给 adapter 是别的值的凭证补上这条路由。responses 是权威的:一旦这个块存在,/v1/responses 只有被列出才会原生提供——运营方正是用"不列出"来表达"这个端点没有 Responses 路由",从而让请求被翻译成 chat completions,而不是打到上游收一个 404。完全没有这个块时,两者都回退到此前的推断方式:/v1/messages 依据提供方 ID 或 anthropic adapter,/v1/responses 仅依据提供方 ID。这个块没有涉及的面——embeddings、音频、图像、视频、files、batches、微调、rerank——一律照旧使用 api_base。把它设为 {} 表示该端点除自身 adapter 的面之外不提供任何其他面,设为 null 则清除声明。可在控制台的 Provider Keys 页面配置,也可通过 Cloud Admin API 的 POST 与 PATCH /provider_keys 配置。

  • 用量记录写明了请求要网关做的是什么。 每条用量记录现在都带 operation 字段,取值由请求命中的路由决定、绝不取自调用方文本:chat、completions、messages、count_tokens、responses、embeddings、rerank、realtime、image_generation、image_edit、transcription、translation、speech、video_generation、files、batches、batch_completion、fine_tuning、mcp、a2a、passthrough。inbound_protocol 对每一条 OpenAI 形状的路由都报同一个 openai,因此此前要区分文本对话、图像生成和视频提交,只能对捕获到的 prompt 做正则——而 metadata_only 的导出器根本没有 prompt,零 Token 的视频提交更是无从判断。这个字段会进入你自己的导出器(OTLP、Datadog、SLS),也会进入控制台:Logs 页可以按它筛选,并为每个请求标注——对话类端点(chat、messages、responses、completions)作为常见情形不做标注;GET /usage_events 与 GET /usage_events/export 新增 operation 查询参数,返回的每一项也带这个字段。

改进​

  • 用量记录与预算指标现在写出成员名字,不只是 ID。 aisix_usage_events_emitted_total、aisix_usage_event_drops_total 和五个 aisix_budget_* gauge 现在都在 user_id 旁边带上 user_name,与 aisix_proxy_requests_total 及 aisix_llm_* 系列保持一致。一条用量记录告警或一块预算看板,不必再去 Prometheus 之外查表才能说出它讲的是谁。

修复​

  • aisix_budget_remaining_usd 现在真的会发出来了。 网关只有在控制面的预算决定里写明剩余金额时才能发出这个 gauge,而那份决定从来没带过它——所以指标参考文档里描述的这条时间序列,在 0.12.0 及更早的任何部署里都不存在,基于它做的看板面板或告警匹配不到任何东西。它现在会与 aisix_budget_limit_usd、aisix_budget_spent_usd 一同出现,标签相同、出现时机也相同。只需升级控制面即可,网关不用改、也不用配置。
  • 因来源被拒的登录错误提示不再误述服务端信任的来源,也不再指错要重启的组件。 它此前说服务端只信任它被配置的那一个地址;实际上它同时信任该地址的 localhost/127.0.0.1 对应形式,以及 AISIX_TRUSTED_ORIGINS 中列出的每一个来源,提示现在给出了后一种解法。它此前还让运营方去重启 cp-api,而拒绝这次登录的检查其实运行在控制台里。
  • Helm Chart 的安装后提示不再给出一个它让你执行的 port-forward 并不服务的地址,那段提示里同样存在的、关于可信来源的不准确说法也一并修正。

API 变化​

没有破坏性变化,全部新增项都是可选的。

路由变化
  • POST /provider_keys
新增可选请求属性 apis。当作用范围内有数据面运行的网关版本过旧、无法执行所声明的某个面时,201 响应会带上 warnings
  • PATCH /provider_keys/{provider_key_id}
新增可选请求属性 apis;null 清除声明,{} 表示该端点除自身 adapter 的面之外不提供任何其他面。响应新增 apis、apis_source 和 warnings
  • GET /provider_keys/{provider_key_id}
响应新增 apis、apis_source(catalog 或 operator)和 warnings
  • GET /environments/{env_id}/usage_events
新增可选查询参数 operation;每一项新增 operation 字段
  • GET /environments/{env_id}/usage_events/export
新增可选查询参数 operation;导出的每一项新增 operation 字段

注意 apis 不会在创建响应中回显,与 api_base 一致——用 GET /provider_keys/{provider_key_id} 读回,其中的 apis_source 会说明这份声明是 AISIX 提供的还是你自己写的。

升级说明​

从任何早于 0.13.0 的版本升级时,本节说明都适用,包括那些途中越过 0.13.0 直接升到更新版本的升级。

  • 控制面会在升级后的第一次启动时,一次性把内置的 API 面声明应用到「行为变化」中描述的那些凭证上。这个动作是尽力而为且幂等的:某次启动没能完成,下一次启动会重试;已经带有声明的凭证永远不会被改动。如果某个端点你不希望被原生访问,自己给它写上 apis。
  • 如果你对 aisix_budget_* 或 aisix_ratelimit_remaining_* 配了告警,升级前请对照上面的 gauge 退休变化检查一遍表达式。
  • 仍运行 0.13.0 之前版本的网关不会记录 operation,因为这个取值是由网关根据匹配到的路由推导的。只要机群中还有这样的网关,按 operation 过滤——无论是在 Logs 中、在 GET /usage_events 上,还是在导出中——都会把它的流量排除在结果之外。这些请求照常被代理和记录,只是 operation 过滤看不到它们。升级该网关后,此后的流量即可正常过滤;已经记录下来、没有 operation 的行仍然在过滤范围之外。

0.12.0​

发布日期: 2026 年 8 月 30 日

这个版本让两份契约开始名副其实。Cloud Admin API 现在覆盖控制台能做的全部操作,每个版本发布一份不可变的文档,并且对它所声明的内容做校验。安全护栏则只在你挂载它的地方生效——"没有挂载就等于处处生效"这条规则,已经从网关、控制台和升级回填三处一并移除,而现有护栏实际拦截的范围不受影响。除此之外,Token 计数改为按调用方自己的协议上报,Gemini 模型的思考 Token 终于被计入,用量记录会指出凭证背后的那个人,还有几处删除操作可能留下悬空引用的路径被堵上了。

行为变化​

  • 安全护栏的作用域现在就是它的挂载关系;没有任何挂载的护栏不筛查任何流量。 此前一条没有挂载记录的护栏会以最低优先级作用于整个环境。以"没有记录"作为判据正是危险所在,因为收窄作用域恰恰是通过删除环境级挂载来表达的:一条只作用于某个模型的护栏,会在该模型被删除的那一刻,悄无声息地扩大到环境里的每一个请求。升级不会改变你现有护栏实际拦截的范围——控制面会在升级过程中,把原来隐含的环境级作用域写成一条显式的环境级挂载,且发生在网关不再认可隐含作用域之前;同时它还会把此前某次启动错误放大到环境级的护栏,恢复成你配置的窄作用域。从此之后有变化的是:新建的护栏在你挂载之前不作用于任何流量。声明一条没有挂载的护栏仍然不算错误:它的作用对象可能只是被删掉了。控制台中这类护栏现在显示为 Not attached——"没有挂载到任何对象,因此不筛查任何流量",此前显示的是 Global/"作用于所有模型";网关也会为每条已启用但没有挂载的护栏打一条 WARN。与此相关:在控制台打开一条窄作用域护栏、只改了个无关的地方就点 Save,不会再写出一条环境级挂载——编辑器现在把"没有挂载"表示成一个独立状态,而不是默认回退到环境级。
  • 控制台一直在调用的二十一条控制面路由现在进入了 Admin API 契约,并且会对请求做校验。 这些路由此前用 Admin Token 就能访问,只是没有公开的 schema;现在它们出现在 API 参考中。把一条在线路由纳入契约同时也为它打开了请求校验,因此请求体中携带了 schema 未声明的字段时会返回 400,而不再是被接受后忽略——POST /teams 带一个多余字段,在上个版本返回 201,现在返回 400 additional properties not allowed。如果你有程序在调用用量数据流、用量导出、用量汇总或请求级指标、团队与团队成员、模型价格覆盖、邀请、成员移除或通知投递日志,请确认它只发送已文档化的字段。完整路由清单见「API 变化」。
  • 响应中的 Token 计数现在按调用方自己的协议口径上报。 两种协议只在一件事上有分歧:提示缓存的计数是包含在输入计数之内,还是与之并列。OpenAI 协议下 prompt_tokens 是包含缓存命中在内的完整输入;Anthropic 协议下输入计数不含缓存,cache_creation_input_tokens / cache_read_input_tokens 与之并列。网关此前会把上游报什么形状就原样透传,因此当客户端用的协议与上游的协议不一致时,它拿到的是另一种口径的账:用 OpenAI 协议访问 Anthropic 上游的客户端会看到 prompt_tokens: 40 与 total_tokens: 2104 并存——既对不上账,缓存命中也无处体现。同一个请求现在上报 2088 与 2104,命中部分出现在 prompt_tokens_details.cached_tokens 中。在发生口径转换的情况下,total_tokens 会由投影后的输入与输出计数重新算出,而不是照抄一个按另一种口径算出来的总数;不需要转换时,仍然原样透传上游给出的总数。流式、非流式与 /v1/responses 均已覆盖。记录下来的用量事件不变,因此计费与历史费用不受影响——变的只是回给调用方的计数。
  • OpenAI 协议的响应现在可能带上缓存写入计数。 prompt_tokens_details.cache_creation_tokens(/v1/responses 上是 input_tokens_details 下的同名字段)表示本轮被上游写入缓存的 prompt Token 数。它不是 OpenAI 的字段——OpenAI 没有"缓存写入"这个概念——但如果没有它,Anthropic 或 Bedrock 的一次缓存写入就表现为 prompt_tokens 无缘无故变大、调用方无法据此估价,而写入的单价是高于普通输入的。该字段仅在非零时发出,因此严格拒绝未知字段的客户端需要检查一下。
  • Gemini 模型的思考 Token 现在会被计入,并计费。 Gemini 会上报 thoughtsTokenCount,而网关此前在任何地方都没有解析它——因此思考模型的 completion_tokens 记录值少了思考部分,reasoning_tokens 在所有协议下都读作 0。现在两者都会被携带,reasoning_tokens 表示 completion_tokens 中的那一部分,是否包含则依据上游自己上报的总数来判定,因此在 Gemini 已经把思考计入自己的候选 Token 数的情况下不会被重复计算。费用按推理单价(未设置推理单价时按补全单价)对 reasoning_tokens 计费。如果你在使用会思考的 Gemini 模型,记录的补全 Token 数与费用会上升——上升到与 Google 本来就在向你收取、而网关此前没有记录的那部分一致。与上面那条协议转换不同,这一条确实会改变用量记录。
  • /v1/messages/count_tokens 现在会发出用量记录。 这个路由在任何结果下都不发用量事件,因此一个被入站护栏拒绝的请求,虽然被正确拒绝了,却无法在日志中找到——包括 Guardrail blocks 视图。它仍然不计费:无论是正常返回还是被拒绝,prompt_tokens 与 completion_tokens 都是零。"不计费"和"不记录"此前被当成了同一件事,其实是两件。
  • 会留下悬空引用的删除操作,现在会被拒绝、被修复,或者如实告知。 删除一个被语义护栏用作 embedding 模型的模型会返回 409,而重命名该模型会改写这条护栏,而不是把它变成孤儿。此前的代价很高,因为护栏默认失败即拒绝:在上个版本中这个删除会成功,而该护栏作用域内的每一个请求随后都会收到 422 semantic_embed_unresolved。删除一个被声明映射解析到的 API Key 同样返回 409,与 passthrough 路由的匿名 Key 已有的保护方式一致——悬空的映射虽然是失败即拒绝,但代价并非为零:匹配会取优先级最高的规则且不再向下回落,因此一条坏掉的规则会遮蔽一条本来仍然有效的低优先级规则。删除团队、移除成员现在都会清掉它们留在调用方 Key 上的归属,并把变更同步到网关。 这两列此前是被数据库外键置空的,而外键动作不产生投影事件,于是网关继续读着一份指向已不存在团队的文档——一条挂在被删团队上的限流会一直拦着那些 Key,而控制台上没有任何东西能解释那些 429。删除 MCP Server 也不再顺手删掉引用它的按 Key 限流:此前它会删掉限流却保留工具授权,于是"用同名重新创建"这条被支持的路径会恢复权限、却静默丢掉限流上限。删除 OIDC Provider 仍然会成功——它的两处引用持有的都是名称,重命名本身就是删除加重建,悬空是常态且失败即拒绝、可自愈——但响应现在会报告还有多少个 API Key 和声明映射仍在引用它。

新功能​

  • Cloud Admin API 按版本发布。 每个发布 tag 现在都会发布一份由该 tag 自身源码生成的、不可变的 OpenAPI 文档,API 参考会为每个已发布版本提供一个页面,并自动生成相邻版本之间的变更记录。你可以直接查阅自己这套部署所暴露的 API,并与要升级到的版本进行对比,而不必再去对照一份跟随开发分支变化的文档。
  • 用量记录与日志会归因到组织成员,而不只是凭证。 用量记录此前只写明请求是从哪个 API Key 进来的,却从不写明背后是谁,因此"查这个成员最近 24 小时的错误"意味着枚举他名下的每一个 Key 再手工合并结果——而一个既用 API Key 又用 OIDC 的成员,还会被拆成两个身份,没有任何一个筛选条件能把它们并起来。用量记录现在携带成员信息,日志页也可以按成员筛选。这个归因是在请求被处理时打的快照:重新绑定或删除一个 Key,不会改写它已经产生的历史记录。
  • 日志可以按精确的状态码筛选。 此前只提供按状态码族筛选,因此没有办法只查 429 而不把其他所有 4xx 一起带出来。现在支持精确状态码,也支持 500-599 这样的区间。
  • aisix_usage_events_emitted_total 与 aisix_usage_event_drops_total 带上了成员与精确状态码。 两个计数器都新增了 user_id 标签和一个保存原始响应码的 status 标签,因此"这个成员有多少请求被限流了"和"这个成员有没有丢过用量记录"现在可以直接从指标回答。原有的 status_code 族标签保持不变,基于它的告警不受影响——但如果某个仪表盘在聚合这两个计数器时没有显式写出标签,它会看到新增的维度。

改进​

  • 用量页面在加载过程中不再报零。 在第一个响应返回之前,/usage 会在两张写着"最近 30 天没有用量"的表格下面渲染出 $0.00、0 个请求和 0 个 Token,几秒之后再把它们全部替换成真实数字。在网络较慢时,运营方会被明确告知自己的网关没有任何流量。现在它显示 — 并配一行 Loading…,与概览页保持一致。
  • 离线安装脚本会报告所安装的版本,以及真正对外暴露的端口。 离线部署此前没有办法在安装结束时确认自己刚装的是哪个版本;而当端口来自环境变量而不是默认值时,结束时打印的横幅仍然显示默认端口——于是一套监听在某个端口上的部署,却告诉运营方去打开另一个端口。
  • 参考文档现在写明了自定义 PII 规则中替换文本的行为。 $1 不会被当作捕获组引用展开;而当正则里有捕获组时,只替换第 1 个捕获组而不是整个匹配——所以对 ACCT-([0-9]{4})-([0-9]{4}) 用 replacement: "ACCT-$1-****",得到的是 ACCT-ACCT-$1-****-5678:看上去像脱敏了,其实原文还在里面。控制台现在会在替换文本里含 $ 时给出提示。

修复​

  • 两个控制面副本同时启动不会再互相搞崩。 Schema 迁移全程都是"先检查再动作"——先探查系统目录,再执行创建或修改——而 PostgreSQL 并不会为此串行化,因此高可用部署可能在启动时让某个 Pod 以多种不同的错误码失败。启动期的 schema 操作现在会串行执行;对着全新数据库同时启动八个副本,现在八个全部起来,此前这一档大约八次里会失败七次。
  • 升级回填不会再把只作用于某个模型的护栏重新放大。 那个为"挂载关系出现之前就已存在"的护栏补一条环境级挂载的回填任务,会在每一次控制面启动时运行,并且用"没有环境级挂载"来判定目标——这个判据是在挂载表刚建立、所有护栏都还没有任何挂载时写下的,那时它只可能意味着"早于挂载机制"。而自从把护栏收窄到某个模型会删除它的环境级挂载之后,每一次重启都会悄悄把它重新放大回整个环境。
  • 删除护栏现在会把它的挂载关系从网关撤回;升级还会清理掉此前删除留下的残留。 挂载记录此前是被数据库级联删除的,而级联不会产生投影事件,因此那些挂载文档会一直留在网关侧,每个数据面在每次重建索引时都会打一条"引用了不存在的护栏"的日志,且永不停止。升级会把这些残留撤回,那条日志会自行消失,无需人工处理。

API 变化​

本次共有二十一条路由进入契约。它们是新增文档,而不是新增接口——每一条此前用 Admin Token 就已经可以访问;变化的是它们现在有了公开的 schema,并且请求会被校验(见「行为变化」)。

路由变化
  • GET /environments/{env_id}/usage_events
新增文档
  • GET /environments/{env_id}/usage_events/export
新增文档
  • GET /environments/{env_id}/usage_metrics
新增文档
  • GET /environments/{env_id}/usage_summary
新增文档
  • GET /invitations
  • POST /invitations
  • DELETE /invitations/{invitation_id}
新增文档
  • DELETE /members/{user_id}
新增文档
  • GET /model_pricing
  • PUT /model_pricing
  • DELETE /model_pricing/{id}
新增文档
  • GET /notification_deliveries
新增文档
  • GET /teams
  • POST /teams
  • GET /teams/{team_id}
  • PATCH /teams/{team_id}
  • DELETE /teams/{team_id}
新增文档
  • GET /teams/{team_id}/members
  • POST /teams/{team_id}/members
  • PATCH /teams/{team_id}/members/{user_id}
  • DELETE /teams/{team_id}/members/{user_id}
新增文档
  • DELETE /environments/{env_id}/api_keys/{api_key_id}
新增 409——该 Key 被某条声明映射解析到
  • DELETE /environments/{env_id}/oidc_providers/{oidc_provider_id}
200 响应新增可选属性 warnings,报告仍在引用该 Provider 的 API Key 与声明映射数量
  • DELETE /environments/{env_id}/models/{model_id}
409 此前已文档化;现在它还覆盖"该模型被某条语义护栏用作 embedding 模型"这一情形

任何此前已文档化的路由,其请求或响应形状都没有破坏性变化。有四处容易猜错的语义现在被明确写了出来,值得对照检查你的集成:

  • usage_summary 统计的是去重后的请求数,而不是上游尝试次数——一个重试了三次的请求只计一次。
  • 离线部署下 ModelPricing.source 可以是 snapshot,而不只是联网部署会产生的那些取值。
  • 六个用量筛选条件是大小写不敏感的子串匹配;provider_label 和 request_id 是精确匹配。
  • 调用方 API Key 的归属取的是 GET /members 返回的成员关系 ID,而不是该成员的用户 ID——这一条是对旧参考文档说法的订正。传用户 ID 会被拒绝。

升级说明​

从任何早于 0.12.0 的版本升级时,本节说明都适用,包括那些途中越过 0.12.0 直接升到更新版本的升级。

  • 安全护栏无需任何操作。 这次作用域变更不会改变你现有护栏实际拦截的范围:升级会把原来隐含的环境级作用域写成一条显式的环境级挂载,并把此前某次启动错误放大到环境级的护栏恢复成你配置的窄作用域;它还会撤回此前删除操作遗留下来的挂载记录,因此网关那条"引用了不存在的护栏"的日志会自行停止。升级之后新建的护栏,则只作用于你为它挂载的对象。
  • 如果你直接调用控制面 API,请检查这二十一条新纳入契约的路由。 对它们的请求现在会按公开的 schema 校验,因此此前被接受并忽略的未文档化字段,现在会返回 400。
  • 会思考的 Gemini 模型上,记录的费用会上升。 它们的思考 Token 此前完全没有被计入,现在会出现在 completion_tokens 与 reasoning_tokens 中并参与计费。按此前偏低的数字标定的预算和费用告警需要重新评估。其他模型和服务商不受影响。
  • 检查聚合 aisix_usage_events_emitted_total 或 aisix_usage_event_drops_total 的仪表盘。 这两个计数器新增了 user_id 与 status 标签,会改变未显式指定标签的 sum by (...) 的基数。status_code 族标签保持不变。

0.11.0​

发布日期: 2026 年 8 月 28 日

这个版本的主题是安全护栏。筛查新增两种类型——一种按语义而非模式判断,另一种运行你自己写的脚本——同时整个子系统变得可追责:护栏拒绝一个请求时,现在会说清是你的策略命中了,还是这条规则根本没跑起来;每一次强制命中也都会进入日志和用量记录。与此同时,网关滚动更新时不再丢弃流量,Anthropic 协议上的提示缓存用量得到正确计费与度量,还有几处可能让运营方悄无声息丢失数据、或者执行了一次什么都没做的"升级"的路径被堵上了。

行为变化​

  • 入站安全护栏现在会在每一个到达模型服务提供方的请求上运行。 此前只有当请求携带网关已经提取出的文本时,护栏链才会被调用,因此不带文本的请求——没有参数的 MCP 工具调用、没有 prompt 的语音转写、没有 prompt 的图片编辑、对空字符串做 embedding——都会绕过筛查直达上游,而 /v1/messages/count_tokens 与 /a2a/:agent 则从未被筛查过。按路由变化的是提供给护栏链的文本,而不是护栏链是否被调用。如果你依赖某条护栏把守数据外发,那么在这个版本之前,它并没有覆盖上述路径。 另外,当挂有护栏时,Anthropic 解析器无法读懂的请求体现在会被拒绝,而不再转发给上游。
  • 护栏拒绝现在会记录在它所产生的用量事件上。 控制台日志页 Guardrail blocks 视图筛选所依据的那个标记,此前只有十四个可能拒绝请求的接口中的两个会设置,因此在调用方正被拒绝的同时,那个视图可能显示为空——读起来就像网关完全没有记录任何护栏活动。现在所有接口都会设置它。
  • 无法运行的护栏不再声称你的内容被拦截。 当一条筛查规则失败时——上游不可达、脚本返回了不是裁决的东西、超时——这次拒绝现在会如实上报:调用方收到 422,其中 "code": "guardrail_unavailable",消息指出是哪条护栏以及失败原因(request rejected: guardrail 'x' could not evaluate it (...)),而不再是真正命中时才该出现的 request blocked by content policy。网关会打一条 WARN 日志,aisix_guardrail_latency_seconds 上的 error_type 也会标明原因。HTTP 状态码与 error.type 保持不变,因此基于它们的告警仍然会把两种情况都计入。这适用于所有类型的护栏、所有接口。aisix_guardrail_blocks_total 一如既往地把两者合并计数——它不带任何标签,因此无法区分二者,而且它只在 chat completions 这条路径上记录。要统计策略拦截,请使用 aisix_guardrail_latency_seconds_count{result="blocked", error_type="none"}; 同一序列上 error_type != "none" 的部分就是规则失败。不要只按 error_type 筛选——这个直方图记录的是每一次护栏执行,其中包含被放行的请求。
  • 安全护栏默认改为失败即拒绝(fail closed)。 两个平面上 fail_open 现在都默认为 false:无法连通其服务的规则会拒绝请求,而不是让它未经筛查地通过。需要保持旧行为的,在该护栏上设置 fail_open: true。脚本故障同样遵循这个默认值。
  • 超出服务商长度上限的内容改为分块,而不再截断。 超限的请求体此前会被截断后只筛查一部分,这在一个"本该看到全部内容"的控制上是个静默的漏洞。现在它会被分块并完整筛查——每一个分块都会被提交,且不设分块数量上限,因为一旦给分块数设预算,超出的部分就成了从后门溜走的未筛查内容。
  • mandatory 开关已移除。 它与 fail_open 表达的是同一件事。请从存量配置中删除;"不允许被绕过"的护栏就是 fail_open: false 的护栏。
  • 已移除的 /passthrough/* 隧道现在返回普通的 404。 0.10.0 用显式 passthrough 路由取代了隐式隧道,并保留了一个版本的 410 Gone 迁移指引。那个版本已经发布,因此未被任何路由认领的 /passthrough/* 路径现在走路由器的常规未命中路径,这个命名空间完全交由你用显式路由认领。随之移除的还有对应的 WARN 日志和 provider="unresolved" 指标序列。
  • /v1/messages 现在会上报 OpenAI 兼容上游的提示缓存命中。 当 OpenAI 兼容上游服务一个 Anthropic 协议请求时,命中缓存的前缀不再被计入 input_tokens:客户端收到的 input_tokens 是未缓存部分,cache_read_input_tokens 是命中部分;用量记录则不做这个转换,它沿用 OpenAI 的形状:prompt_tokens 仍是整个 prompt,cached_prompt_tokens 是其中命中缓存的那一部分,而不是需要再加上去的另一笔——正因如此,日志、用量 API、CSV 导出与计费才能把缓存部分按缓存读取的价格计费。流式响应在收尾的 message_delta 中上报。该计数器仅在非零时发出。此前整个 prompt 都按未缓存价格计费。
  • 十二个指标族新增 upstream_protocol 标签。 它标明实际服务该请求的协议——跨协议转换此前会让这一点不可见。聚合类查询不受影响;精确匹配标签的仪表盘、告警和记录规则需要更新。
  • 已停止的网关会显示为离线。 节点存活现在由控制面判定,而不再在浏览器里计算,DpNode 上新增 status 字段(healthy / warning / offline),依据心跳时间推导。已停止的实例不会再一直显示为健康直到刷新页面,数据面列表也会自行更新。
  • 环境没有 MCP 策略时,GET /environments/{env_id}/mcp_policy 返回 200 且策略为 null,不再返回 404。该接口的 404 现在只表示环境不存在。
  • 通知通道的 URL 不会再因为回写而被销毁。 读取响应会对 URL 打码,因为 webhook 的路径本身就是凭证。此前那个打码值会被当作写入值接受,因此任何"读取-修改-写回"都会静默地把真实 webhook 替换掉并返回 200。现在原样回显的打码值是空操作,指向不同主机的打码值会被拒绝,创建通道时使用打码 URL 也会被拒绝。投递错误不再回显远端响应体——它可能包含该 URL。

新功能​

  • 语义安全护栏。 筛查规则现在可以按语义而非模式判断:给出允许和拒绝的示例语句,它会用你指定的 embedding 模型为每条消息打分,两侧可分别设置阈值。它逐条筛查消息,可以只看用户消息,也可以看整段对话。
  • 自定义脚本安全护栏。 对于内置类型无法表达的策略,可以自己写检查逻辑:网关在沙箱中运行你的脚本,超时时间由你设置,密钥按名称注册而不是内联写入。钩子返回 {action: "none"}(或 "allow")表示放行,{action: "block", reason, reason_code} 表示拒绝,{action: "mask", segments} 表示改写。这四个就是全部词汇——返回其他任何东西都属于脚本故障,并会被如实上报。
  • PII 规则可以只作用于捕获组,并指定替换内容。 自定义规则可以只脱敏匹配中真正敏感的那一部分,并指定替换用的字符串,而不是用固定的记号遮盖整个匹配。
  • 强制生效的护栏命中会进入日志和用量记录。 每个 LLM 接口现在都会记录是哪条护栏作用于该请求,因此被拦截或被脱敏的调用事后可以归因,而不再只表现为一次拒绝。日志页会区分策略拦截与失败即拒绝导致的中断。
  • validate 会报出能加载但跑不起来的护栏。 配置能解析、却构建不出规则的行——非法的正则表达式、无法识别的检测器或动作取值、编译不通过的 kind: custom 脚本——此前只会打一条 WARN 日志后被移出护栏链,它所描述的筛查就这样悄无声息地不存在了。现在这类问题会在校验时暴露,而不是等到第一个请求。该检查在进程内构建配置、不发起任何网络请求,因此它不会告诉你某个服务是否可达;它还会完全跳过 kind: semantic 的行,这类行所指定的 embedding 模型不在检查范围内。
  • 网关开始排空时会退役 HTTP/2 连接。 收到 SIGTERM 后,网关在排空窗口开启时向 HTTP/2 下游发送 GOAWAY,客户端因此会停止在该连接上发送并改连他处,而不是与关闭过程赛跑。HTTP/1.1 此前已经收到 Connection: close。正在排空的网关同时会对健康探针保持存活,因此编排系统不会在排空中途把它杀掉。
  • POST /v1/images/edits。 multipart 图片编辑现在是一个有类型的接口,与代理的其余部分共享同样的认证、安全护栏和用量计量。
  • 提示缓存 Token 计数器与指标上的 upstream_protocol。 缓存读取与缓存写入现在各有自己的 Prometheus 计数器,因此"输入中有多少来自缓存"可以直接从指标回答,而不必再去聚合用量导出。
  • 网关的 trace id 会随每个请求存储,并可通过 trace_ui_url_template 中的 {trace_id} 插值成追踪查看器的链接,因此一条日志可以直接跳到它对应的链路。

改进​

  • 现在可以在控制台里重命名环境、编辑 embedding 模型。
  • 所有列表底部都支持直接跳转到指定页码,而不再只能逐页翻。
  • 邀请现在是新用户真正可以接受的东西:链接会先展示所属组织再让人加入,加入是一个显式动作而不是打开页面的副作用,并且邀请与被邀请的邮箱绑定。
  • 护栏配置的"读取-修改-写回"可以正常往返。描述已存密钥的那些字段原样回显时会被接受、被篡改时会被拒绝,因此脚本和基础设施即代码不必再手工剔除它们。编辑 Bedrock 护栏也不再索要 API 从不返回的 AWS 密钥。
  • 数据卷已存在而 .env 缺失时,离线安装包会拒绝启动并说明将会丢失什么,而不是重新生成密钥然后陷入崩溃循环。
  • AISIX_CLOUD_NOTIFY_ALLOW_PRIVATE_URLS、AISIX_CLOUD_MCP_SPEC_ALLOW_PRIVATE_URLS、AISIX_CLOUD_ALLOW_FRESH_BOOTSTRAP 与 AISIX_CLOUD_PRICESYNC_URL 现在可以在离线安装包的 .env 中设置;此前它们写在文档里却无法生效。
  • 用量按 UTC 自然日分桶,不受会话所在时区影响;请求总数为精确值而非抽样;估算得出的用量会被标注为估算值。
  • 日常使用控制台不会再耗尽自身的认证额度。受限流的 Token 刷新现在显示为"稍后重试",而不是"你已登出"——此前已登录的用户会被要求重新登录,另有几处流程也把一次失败的会话读取当成了会话丢失。
  • Overview、Logs、Budgets 与 Observability 页面在数据尚未加载完成时,不再渲染不完整或有误导性的数字。
  • 文档所述的 On-Premises 升级流程现在真的会更新版本。AISIX_VERSION 归安装包所有,每次启动时按包内容对齐;此前它固定在 .env 里,因此照着文档操作会让旧镜像继续运行,还报告成功。需要固定版本请改用镜像变量。降级会被拒绝,除非设置 AISIX_ALLOW_DOWNGRADE=1。
  • 控制面启动失败时会指出原因——数据库密码错误、主密钥错误、密钥 id 不匹配、缺少 CA 根——并同时读取 api 与 dpm 两侧的日志,而不再只留下一句"容器不健康"。

修复​

  • /v1/realtime 重新可以对接 OpenAI。 网关此前在每个 realtime 连接上都发送一个 beta 启用请求头;OpenAI 现已转正式版的接口会拒绝它并在客户端发出任何内容之前关闭会话。该请求头现在只在调用方主动要求时才转发,因此遗留客户端仍能得到 beta 形态,其他人则连到正式接口。
  • kind: custom 安全护栏现在可以在控制台里创建。 网关此前没有在能力清单里宣告这个类型,因此控制台把它显示为"不受支持",尽管两个平面都能运行它。
  • 没有配置 api_base 的 OpenAI 模型服务提供方 Key,现在在所有路由上都会回落到厂商默认地址,而不只是部分路由。
  • 对模型服务提供方 Key 的空操作更新——把已存的内容原样发回——现在会成功,而不再返回内部错误。
  • 所有接受 multipart prompt 字段的接口都会拒绝非 UTF-8 内容。
  • 控制台编辑表单中,逐项设置的 PII 处理方式不会再丢失。
  • 在三层 MCP 规则之前写入的 API Key 配置行仍然可以正常加载。已退休的 mcp_access.mode 选择器按普通的未知字段忽略,因此整行不会加载失败,该 Key 的 mcp_access 块其余部分照常读取——一行被拒绝的 API Key 会失去对它全部流量的认证能力,而不只是 MCP 流量。
  • 从未接线的静态 OTLP 导出配置块不再打印虚假的成功日志。

升级说明​

  • 先升级控制面,再升级网关。 这是受支持的顺序。在这个窗口期内,仍停留在 0.10.0 的网关无法运行新增的护栏类型(semantic、custom)、PII 的 replacement 字段,以及新增的 text_source 取值:它无法解析这样的配置行,会把整行丢弃,因此该规则在那里什么也不筛查。控制面仍然会保存这样的配置——它不会拒绝——并在写入响应中返回一个 warnings 数组,指出是哪个字段、从哪个版本起才能读取它,以及你有多少个网关受影响。请务必查看这些警告: 在所有网关升级完成之前,这条规则在尚未升级的网关上并未生效。
  • 重新核对你的安全护栏此前究竟覆盖了什么。 这个版本中有两处修复改变了答案:入站护栏链现在会在此前被跳过的路径上运行,拒绝也会记录在每一个可能拒绝的接口上。如果某条护栏此前看起来一直很安静,那可能是覆盖缺口,而不是流量少。
  • 重新录入升级前已被破坏的通知通道 webhook URL。 如果你曾经通过 API 读取某个通道再把整个对象写回,那么真实的 webhook URL 已经被它的打码形式替换,并且无法找回——它只存在于服务商那边。升级后,处于这种状态的通道会在投递错误中报告出来;请从 Slack(或你使用的服务商)重新取得该 URL 并填回。只通过控制台编辑过的通道不受影响。
  • 更新精确匹配标签的指标查询。 十二个指标族新增了 upstream_protocol。
  • 把 aisix_guardrail_blocks_total 当作策略命中量的查询,同时也在统计规则失败。 这个计数器不带任何标签,从来就没有区分过两者,而且它只在 chat completions 这条路径上记录(aisix_guardrail_bypasses_total 同理)。由于 fail_open 现在默认为 false,服务不可达的护栏会拒绝请求而不是放行,因此此前会计入 bypasses 计数器的失败,现在改为计入 blocks 计数器。要统计整个网关范围内的策略拦截量,请使用 aisix_guardrail_latency_seconds_count{result="blocked", error_type="none"}。

0.10.0​

发布日期: 2026 年 8 月 20 日

这个版本的主题是 Agent 流量。正向代理流量——把 IDE 或编码 Agent 指向网关——现在由一个显式、可审计的路由资源承载,而不再是那条需要猜测"该借用哪个凭证"的隐式隧道。MCP 支持了协议的 2026-07-28 修订版、面向无凭证客户端的匿名访问、OAuth 2.1 发现,以及一条统一的工具授权规则。模型组新增一致性哈希与优先级层级。网关在关闭前会保持一个排空窗口继续接受连接,不再拒绝负载均衡器尚未停止转发的请求;通过 OTLP 导出的链路追踪也形成了真正的层级结构。

行为变化​

  • 隐式的 passthrough 隧道被显式路由取代。 /passthrough/<provider>/<rest> 不再按模型服务提供方的名字自动解析;未被任何路由认领的 /passthrough/* 路径返回 410 Gone(error.code: endpoint_removed),并为每次命中打一条 WARN 日志指出调用方,便于找出尚未迁移的客户端。迁移方式:创建一条 passthrough 路由,path_prefix 设为 /passthrough/<provider>、target_url 设为原先的 API base、provider_key_id 设为它此前借用的那把 Key——客户端 URL 即可逐字节保持不变。有两处行为与旧隧道不同:路由是单次转发,上游 5xx 与传输层重试不再进行;由于路由不解析任何模型,这类流量也不再交叉标记模型冷却。访问权限是调用方 Key 上的显式授权(allowed_routes),没有授权的 Key 访问不到任何路由。
  • MCP 工具访问改为三层求交的一条规则。 环境策略、调用方所属团队的策略、以及 Key 自身的 mcp_access 块,各自携带 allow 与 deny 列表。allow 取交集、deny 取并集,因此任何一层都无法放宽另一层已经收紧的范围;未设置的层不施加任何约束,而三层都没有的调用方没有任何 MCP 访问权限。策略与 Key 上的 mode 均已移除,Key 上的 allowed_tools 也已移除(Key 这一层就是 mcp_access.allow),遗留 Key 的迁移流程一并删除。如果你配置过 MCP 工具策略,升级后请重新核对:最终生效的授权会按上述规则重新计算,可能与旧配置产生的结果不同。 其中两处变化影响最大:团队策略现在是在环境授权基础上进一步收窄,而不再是替换它,因此它无法再授予环境本身不允许的工具;没有 mcp_access 块的 Key 现在会跟随策略层,而不再游离于策略之外。每一层都必须写出 allow,因此一个只打算做减法的层需要把 allow 侧显式写成 ["*"]。
  • 安全护栏拦截 MCP 工具调用时,改为以工具错误的形式作答。 调用在协议层面返回成功,结果上带 isError: true,消息中指出是哪条安全护栏生效——绝不回显命中的内容——而不再返回 JSON-RPC 的 -32600。调用方 Agent 因此看到的是一段可以据此调整的工具输出,而不是一条中断的传输通道。此前依据 error.code == -32600 判断拦截的客户端,需要改读 result.isError。
  • weighted 路由策略与 sticky 开关已移除。 权重现在是每个目标自身的属性,在所有策略下都可用:round_robin 采用平滑加权轮询,因此权重相等或缺省时与此前的声明顺序轮转完全一致,权重不等时则严格保持比例。会话粘性成为独立策略 consistent_hash。通过 AISIX Cloud 管理的部署会自动迁移。声明式配置需要手工更新:weighted 改为 round_robin 并保留权重,weighted 加 sticky 改为 consistent_hash。仍然写着 weighted 的存量配置会加载失败,而不会被悄悄改变含义。迁移到一致性哈希后,会话与目标的对应关系会重新分布一次,因为它构建哈希环的方式不同。
  • 不受支持的 MCP 协议版本改为在 JSON-RPC 信封内被拒绝。 当请求的 MCP-Protocol-Version 请求头指定了该端点不提供的修订版时,返回 400 并附带一个 JSON-RPC 错误,其中列出受支持的版本,而不再返回游离于所有网关信封之外的裸 text/plain 响应。该端点提供 2025-03-26、2025-06-18、2025-11-25 与 2026-07-28;不再宣告 2024-11-05——它只存在于 HTTP+SSE 传输时代。
  • 通过 OTLP 导出的链路追踪现在形成层级结构。 到达上游的模型请求会产生一个 HTTP SERVER 跨度、一个覆盖全部重试与故障转移的逻辑 CLIENT 跨度,以及每次上游尝试各一个子跨度,取代了此前“每个用量事件一个扁平跨度”的形状。没有上游分发的已导出请求链路只有 SERVER 跨度;不采用逐次尝试追踪的协议包含 SERVER 跨度和一个 CLIENT 跨度。任何以“每个请求一个跨度”为前提的用法——跨度数量告警、按名字计数——都会看到结构性跨度出现。承载完整属性集的是尝试跨度,可用 aisix.attempt_index 识别;结构性跨度携带较少的关联属性,其中包括 aisix.request_id,SERVER 跨度的 Kind 为 2。另外,调用方的 traceparent 与 tracestate 不再转发给模型服务提供方;运营方为可信上游显式配置的 default_headers 条目仍然有效。
  • 文本转语音的延迟改为按首字节计。 /v1/audio/speech 现在边接收边转发合成的音频,而不再整体缓冲,因此播放器可以在首批字节到达时就开始播放,上报的延迟也随之从"到最后一个字节"变为"到第一个字节"。这与此处所有其他流式接口已有的口径一致。

新功能​

  • Passthrough 路由。 一条路由把一个网关入口——路径前缀、入站 Host 白名单,或两者兼有——绑定到一个上游目标,因此可以把 IDE 或编码 Agent 指向网关,在不改动客户端的前提下对其流量进行审计。Host 匹配在路由之前进行,因此携带原始 Host 送达的正向代理流量可以认领网关同样在用的路径;路径匹配则作为路由器的兜底,因此一条路由绝不会遮蔽网关自身的 API。调用方可以用网关 Key 认证、把 Key 放在你指定的请求头里(从而让 Authorization 留给上游凭证),或者以受源 CIDR 白名单约束的绑定主体身份匿名访问。上游凭证要么由模型服务提供方 Key 注入,要么在路由删除网关凭证和固定请求头集合后转发调用方凭证。可选的设备注入身份请求头会被记录为该请求的终端用户身份,用于按员工归因。请求信封按请求识别——chat、Responses、completions 或不透明——并据此驱动安全护栏取文、审计留存与 Token 计量;非 LLM 调用的流量不会产生虚假 Token。SSE 响应逐帧转发。参见 Passthrough 路由和面向 IDE AI 流量的正向代理。
  • 模型组的一致性哈希与优先级层级。 strategy: consistent_hash 通过把请求键哈希到目标环上,将每个会话固定到同一个目标:相同的键始终命中同一个目标,权重决定各目标的份额,而某个目标故障时只有它自己的会话迁移到环上的后继目标,其余键的映射全部保持不变。请求键来自你配置的来源链(hash_on:请求头、Cookie、调用方 API Key 或客户端 IP),默认使用路由键请求头并回退到 API Key。此外,每个目标都可以设置 priority:目标据此划分为若干层,数值越大越优先,只有当某一层内所有目标都失败或被健康状态摘除后,下一层才会收到流量——因此备用池可以在活跃池之后静默待命,而首个发现整层已死的请求也能在层内溢出并成功返回。
  • MCP 2026-07-28。 /mcp 与 /mcp/{server} 提供该规范的最终修订版,包含免握手的发现生命周期与无状态传输。已注册的 MCP 服务器可选配置 protocol_version,用于固定网关开启上游会话时使用的修订版——这是访问"不再响应旧握手"的服务器的唯一方式;不配置时网关按此前方式协商,因此既有配置保持不变。两个方向上都是显式选择:网关既不探测也不静默回退,因此版本不匹配会明确失败,而不会悄悄协商到一个你本想排除的版本。
  • MCP 匿名访问。 环境可以允许不携带任何凭证的 MCP 客户端访问指定入口,并以你指定的一把 API Key 的身份运行——该 Key 的工具授权、限流、预算与用量归因全部适用。它受一份必填的源 CIDR 白名单约束,需要列出所开放的入口,且聚合入口 /mcp 需要显式开启。携带凭证的客户端仍按正常流程认证;凭证无效时会被拒绝,而不会被降级为匿名服务。
  • 面向 /mcp 的 OAuth 2.1 资源服务器发现。 配置了规范资源 URL 并启用了身份提供方后,网关会发布受保护资源元数据,并对未认证的 MCP 请求返回指向该元数据的 WWW-Authenticate 质询,使标准 MCP 客户端能够自行发现到哪里获取 Token。Bearer Token 的 audience 必须包含该 URL。
  • 安全护栏可以限定到单个 MCP 服务器,从而只守护某一个已注册的服务器,而不必守护环境内所有 MCP 流量。安全护栏现在还会扫描工具的结构化输出,而不只是文本块。
  • 关闭时的排空窗口。 收到 SIGTERM 后,网关立即将自身标记为未就绪,随后至少在 shutdown.min_drain_secs(默认 30 秒)内继续接受新连接,然后才关闭监听器,使负载均衡器在其自身检测窗口内转发过来的连接仍能被正常服务。窗口期内 HTTP/1.1 响应会带上 Connection: close,让使用连接池的客户端在使用过程中自然退休这些连接。这个窗口是下限而非期限:只有窗口耗尽且没有请求在途时,监听器才会关闭。
  • 现在会采纳 W3C 链路上下文。 合法的入站 traceparent 会让网关产生的 span 成为调用方链路的子节点;格式错误或重复的请求头会被忽略并改用本地根节点,而不会导致请求失败。span id 与 trace id 每个请求只生成一次,因此投递重试会重发完全相同的 id,而不是新的一组。用量事件中携带 trace id 以便关联。
  • 流式音频转写改为实时转发。 /v1/audio/transcriptions 在 stream=true 时现在边接收边转发帧,而不再从完整读取的响应体作答,同时仍会记录该请求的 Token 用量。带拦截或掩码能力的输出安全护栏仍走缓冲路径,因为它必须在任何内容到达调用方之前看到完整的转写文本。
  • Cloud Admin API 支持角色管理。 自定义角色的增删改查、组织角色分配,以及环境级角色绑定,现在都纳入了公开的 API 契约,并具备生成的绑定代码与请求校验。

改进​

  • 发布镜像现在采用基于性能剖析的优化(PGO)构建,内存分配器会在负载回落后通过后台线程把已释放内存归还给操作系统。
  • 严格校验在拒绝"某个模型类型根本不读取的配置"时,现在会指出具体是哪个配置项,而不再只是报告文档校验失败。
  • Passthrough 流量会记录其识别出的信封所携带的全部用量维度。

修复​

  • 流式音频转写此前一直按零 Token 计费。 网关的 SSE 解码器只在遇到一对换行符时才认为事件结束,而模型服务提供方在转写流中使用回车换行分帧,因此携带 Token 计数的终止事件从未被解码,每一次流式转写都记录为零 Token。事件现在在任意两个连续的行终止符处结束。该解码器被所有流式桥接路径共用,因此任何使用回车换行分帧的上游都受此影响,不限于音频。
  • 在分层规则之前写入 MCP 访问配置的调用方 API Key 现在仍能正常加载,而不会被丢弃。
  • deployment 与 fallback 计数器现在会被正确发射;分发前的失败不再计入其中,失败的请求也会归因到已解析出的调用方。
  • Passthrough 流量在链路追踪与被拒请求事件中的归因已修正,基于请求头的认证返回 401 时会指出它期望的请求头。
  • 按 Host 匹配的正向代理路由现在可以认领网关保留的路径前缀,并镜像完整的请求路径。
  • 音频元数据解析不再对普通上传文件输出告警日志。
  • 控制台方面:创建模型时的选择器不再显示为"不支持",Dimensions 字段不再被错误标注为可选,页面路由切换有了加载态,MCP 认证设置也移到了 MCP Access 页面,与其余 MCP 配置放在一起。

升级注意事项​

  • 请先升级控制面,再升级网关。 这是受支持的顺序,中间的混合版本窗口可以持续任意长时间。在窗口期内,仍运行 0.9.x 的网关会停止服务此前使用 weighted 加 sticky 的模型组(迁移后的配置使用了该版本不认识的策略名),也不会应用 MCP 工具策略(其存储形状已变化)。调用方 API Key 在整个窗口期内始终可以正常认证——只是在尚未升级的网关上,它们的 MCP 访问处于关闭状态,直到该网关完成升级。这两种情况都可以在控制台的数据面兼容性视图中看到。
  • 通过 AISIX Cloud 管理的部署,会在升级后控制面首次启动时自动迁移存量的路由配置。声明式配置不会被自动迁移,需要按"行为变化"一节所述手工更新。

0.9.0​

发布日期: 2026 年 8 月 13 日

这个版本让网关明显更快,也让 Agent 流量变得可观测。代理层改为按核独立的 worker 模型,吞吐大约翻倍、p99 延迟减半。缓存学会了匹配“意思相同”的请求,而不再只能匹配“写法相同”的请求。A2A 调用现在会记录它推进了哪个任务、消耗了多少;经过验证的 JWT 也可以代替调用方 API Key,由身份提供方的 claim 决定请求以哪个调用方的身份运行。

这个版本同时完成了 0.4.0 中宣布的 Admin API 弃用:网关自带的 Admin API 现在是只读的,资源改为声明式管理或通过 AISIX Cloud 管理。

行为变化​

  • 网关的 Admin API 不再写入资源。 Admin 监听端口保留全部读取能力——各类资源的列表与详情、模型状态、健康检查、OpenAPI 参考和 Playground——但 /admin/v1/<kind> 上的 POST、PUT、DELETE 现在返回 405 并带 Allow: GET,API Key 轮转路由的两种拼写都返回 404。这完成了 0.4.0 中宣布的弃用。请改用资源文件管理资源(用 aisix validate --resources <file> 校验,用 SIGHUP 重载),或直接写入 etcd;连接 AISIX Cloud 的网关从不暴露该监听端口,不受影响。声明式轮转调用方 Key 的方式是:用同一个资源 id 写入新的 key_hash,写入传播后旧密钥立即失效。发布的 Admin API 参考中已不再包含写操作。参见资源文件。
  • 缓存条目默认按调用方 API Key 隔离。 缓存策略新增 scope 字段,默认值为 api_key,因此一个调用方的应答绝不会被回放给另一个调用方。依赖环境内跨 Key 共享的部署需要显式设置 scope: env。无论选择哪种,缓存键的形状都会发生变化,升级后会出现一次性的全量未命中。参见缓存。
  • 首 Token 时间改为在第一个流式帧处停表,不再区分帧的类型。 此前它会一直等到出现携带生成内容的帧,因此对于“先静默思考再作答”的模型,记录到的是思考结束的时刻——这个数值可能超过该请求自身上报的延迟,也无法与前置网关的口径直接比较。思考所花的时间仍可从上游延迟中看到。按旧口径校准过的监控面板和告警阈值需要重新调整。参见指标与日志。
  • 调用方传入的 request id 现在会被网关采用。 网关默认接受 x-aisix-request-id:该值会原样回传、记入访问日志与用量事件,并转发给上游。id 必须是 1–256 个可见 ASCII 字符;不满足的一律忽略并由网关自行生成,因此格式错误的请求头绝不会导致请求失败。若还想遵循 x-request-id 约定,将其加入 proxy.request_id.accept_headers;把该列表置空则恢复此前行为。由于该 id 现在由调用方控制,它既不唯一也不可信,因此不会被用作任何指标的标签。参见访问日志与请求关联。
  • 某个模型类型运行时根本不读取的配置,现在会被拒绝,而不再是存下来却被忽略。 模型组上的 retries、auto_prompt_caching、cost,Ensemble 上的通用调用参数,以及语义路由上的 auto_prompt_caching 和 cost,在写入时都会被拒绝并返回 400。携带这类字段的资源文件将加载失败,并指出出问题的条目。已经存下这类字段的模型不受影响:网关会剥离该字段并按“部分兼容”上报,而不会让这个模型停止服务。反方向上,语义路由和 Embedding 模型现在接受 timeout、stream_timeout 和 retries,此前这些是被拒绝的。
  • 若干此前被静默接受的配置现在会被拒绝。 创建模型时携带属于其他类型的配置块、把通配符别名用作 Ensemble 成员或裁判模型、用作语义路由的目标或默认模型、用作缓存策略的作用目标,把被引用的模型改名为通配符,以及让缓存策略指向不存在的模型,现在都返回 400。这些操作此前都会被接受,然后被悄悄忽略。
  • 经过通配符模型的流量按通配符自身的名字上报。 指标、限流计数桶和健康状态现在以配置中的通配符条目为准,而不再以各调用方随手写下的别名为准,因此一个模型就是一个身份,不会因写法不同而分裂成多条序列。按调用方别名过滤的监控面板,会看到对应序列在这个版本处中断。
  • 升级注意事项。 控制面把用量表的 request_id 列从 uuid 加宽为 text,以便保存调用方自己的 id。在大表上这会触发整表重写——大约每 1000 万行 6 分钟——重写期间控制面不对外服务。Helm Chart 的启动探针预算已相应放宽到 30 分钟;如果你使用自己维护的编排清单,请在升级前同步调大。

新功能​

  • 代理层改为按核独立的 worker 模型。 每个 worker 拥有各自的运行时、监听套接字和上游连接池,因此一个请求的接收、派发和应答都在同一个线程上完成,不再需要在线程之间来回移交两次。在 4 核上,吞吐随并发度提升 54%–88%,p99 延迟大约减半,每请求的系统调用次数从 11.9 降到 5.0。Linux 上默认开启。两个启动期生效的配置项:proxy.thread_per_core 和 proxy.workers,后者默认取进程可用的并行度并会跟随 cgroup 的 CPU 限制。当每个 worker 分到的客户端连接不足约 4 条时,内核的连接分配会不均,此模式反而慢于共享运行时;这种低并发场景请设置 proxy.thread_per_core: false。
  • 语义缓存。 缓存策略现在可以按语义匹配:未命中精确匹配的请求会被向量化,并从余弦相似度达到设定阈值的最近条目中返回结果。只有纯文本请求会走这条路径——包含图片、音频或工具调用的请求一律走精确匹配。条目可以存放在各网关自身的内存中,也可以设置 backend: redis,借助 Redis 向量检索在多个副本间共享。共享方式要求 Redis 8 及以上版本或加载 search 模块;网关在启动时探测,若不具备该能力,则继续提供精确匹配并在日志中说明,而不会让流量失败。策略也可以在不删除的前提下整体清空。参见语义缓存。
  • JWT Claim 映射。 新增的资源可以把经过验证的 OIDC claim 解析到一个已存在的调用方 API Key,从而无需为每个用户单独发放 Key,就能由身份提供方决定请求以哪个调用方的身份运行。规则按优先级顺序求值,第一条 claim 条件全部成立的规则选定目标 Key,随后请求完整继承该 Key 的模型与工具访问权限、限流和预算。条件支持对嵌套 claim 路径做精确字符串匹配和数组包含匹配。未命中任何规则的 Token 一律拒绝。用量事件会记录 subject、身份提供方和命中的映射——请注意 subject 属于最终用户标识,会随用量事件流向已配置的可观测性导出目标。参见 Claim 映射。
  • A2A 调用现在具备协议级可观测性。 每次调用都会记录操作类型、任务 id、上下文 id 和最终任务状态,并对两套线上词汇做归一,避免同一个指标被拆成两份。流式调用还会额外记录首个事件的到达时间、事件数量,以及流结束时调用方是否仍在接收,因此中途挂断的调用不再被计为成功。由于该协议本身不携带 usage 字段,网关会依据流经的消息文本估算 Token 并标记为估算值;成本保持为零,因为 Agent 的计费方式不是网关能够知晓的。指标按 Agent 和操作类型切分。参见 Agent 网关。
  • 模型服务提供方返回的响应 id 现在会被记录。 它会出现在访问日志中,也会出现在每次上游尝试各输出一条的专门日志行里——后者覆盖了单条访问日志在结构上无法覆盖的两种情况:流式响应,以及重试或故障转移产生的后续尝试。控制台的日志详情面板也会展示该 id,因此排查上游侧问题时无需再手工跨系统关联记录。
  • 限流策略支持 day 窗口,按 UTC 自然日计数。参见限流策略。
  • 控制台的请求日志按网关面拆分。 LLM、MCP 和 A2A 流量各有独立的标签页,且每个标签页只提供真正能用于筛选它的过滤条件,而不再是一个混合列表配一组只对部分流量有效的过滤器。
  • 控制台的下拉选择框支持搜索。 模型、模型服务提供方 Key、调用方 API Key 等可能变长的选择框,现在都可以边输入边筛选,不必在完整列表中滚动查找。
  • 控制台会提示网关的配置兼容性。 当你保存的某个配置并非环境内所有网关都能理解时,控制台会在保存时和数据面视图中给出提示,指明具体字段和引入该字段的版本,而不是让这个配置在旧版本网关上静默失效。

改进​

  • 除按核 worker 模型之外,每请求路径还做了一系列优化:改用 jemalloc 内存分配器并启用链接期优化、为零配置部署跳过不需要的处理环节、为每个 worker 缓存指标句柄、对下行连接设置 TCP_NODELAY、缓存上游端点 URL,以及每个请求只加载一次配置快照。
  • 限流条件中的模型维度,现在会同时匹配调用方寻址的条目和实际派发到的目标,因此以模型组为条件的策略能够覆盖所有寻址到该组的请求。此前只比较派发目标,这类条件永远不会命中。
  • 语义路由在选路时会遵守成员自身的访问规则,遇到调用方无权使用的成员会转向其他目标,而不是直接派发过去。
  • 按模型的限流现在适用于所有模型类型,控制台也在每种类型上提供限流表单。
  • 缓存策略的作用目标会在创建时校验;被策略引用的模型改名后,引用会同步更新。

修复​

  • 已过期的邀请不再继续占用邮箱地址,同一个人可以被重新邀请。仍在有效期内的邀请依然会阻止重复邀请。
  • 创建资源时把布尔字段显式设为 false,现在会真正存为 false。此前数据库列默认值会替换掉零值,导致创建时设为禁用的 OIDC 身份提供方被存成启用,API 也随之回显为启用。
  • Realtime 端点上认证通过之后发生的拒绝,现在会归属到已解析出的调用方,而不再是没有身份信息的记录。
  • 已停止上报心跳的网关不再计入控制台的配置兼容性提示,避免一个已下线的实例让健康的集群看起来处于部分不兼容状态。
  • 从源码构建且未注入版本号的网关会上报一个占位版本号;该占位值现在被视为“版本未知”,而不再被当作某个真实的旧版本,因此这类集群不会再对其实际可能支持的特性长期告警。

0.8.2​

发布日期: 2026 年 8 月 11 日

这是一个面向 A2A 网关的维护版本。网关现在会向上游声明每台 Agent 所固定的协议版本,能找到发布在路径前缀下的 Agent Card,把 Card 上公布的每一个地址都指向自身,并把 message/stream 按事件到达的节奏实时中继,而不再缓冲整个响应体。此外,Agent 与 MCP 服务器的命名规则和凭据约束现在适用于所有配置路径,而不再只有网关自带的 Admin API。

行为变化​

  • 通过资源文件提供的 A2A Agent 与 MCP 服务器定义,现在会按 Admin API 相同的规则校验:名称格式、各 auth_type 所需的凭据,以及基于 OpenAPI 的 MCP 服务器所需的字段。违反其中任何一条的文件不再加载,网关会指出是哪一条目缺少哪个属性,而不是带着一份无法工作的定义启动——名称中含 / 的 Agent 会把自己的 /a2a/<name> 路由劈成两段,auth_type: bearer 却未设置 secret 则等于用空凭据向上游认证。通过控制面配置的部署不受影响,因为这些规则在创建资源时就已生效;由控制面托管的网关只会拒绝出问题的那一条,其余配置继续服务。发布前可用 aisix validate --resources <file> 先行检查。参见 Agent 网关。

修复​

  • 网关现在会在发往某台 Agent 的每个请求中,用 A2A-Version 头声明该 Agent 所固定的协议版本,包括获取 Agent Card 的请求。此前网关从不发送该头,而 A2A 规范要求 Agent 把该头的缺失读作 0.3 版本——因此固定为 1.0 的 Agent 会回 VersionNotSupportedError,配置的 protocol_version 形同虚设。调用方自行提供的版本不会覆盖注册时固定的版本。
  • 发布在路径前缀下的 A2A Agent 现在能被正确发现。此前网关在源站构造 well-known Card URI,丢弃了注册时给出的路径,因此部署在 ingress 路径之后的 Agent、或按路径前缀区分租户的 Agent 平台,都会被请求一个它并不在该位置提供的 Card,而平台兜底返回的 405 会被当作 Agent 自己的应答。
  • 网关返回的 Agent Card 现在会把公布的每一个地址都指向网关自身。此前只重写顶层 url,supportedInterfaces 中仍是上游的真实地址——而 A2A 1.0 客户端正是从那里选取端点,因此可以绕过网关(连同调用方身份认证和按 Agent 的访问控制)直接访问上游 Agent。
  • message/stream 和 tasks/resubscribe 现在会按事件到达的节奏中继 Agent 的事件流。此前这两个方法走单响应路径,会缓冲整个响应体并按单个 JSON 文档解析;而事件流不是合法的 JSON,因此这两个本就用于观察长任务进展的方法都会失败并返回 502,完全无法使用。事件会跨数据块边界重新组装;遇到格式错误的事件会以错误结束流,而不是跳过它,从而避免被截断的任务被读成已完成的任务。

0.8.1​

发布日期: 2026 年 8 月 7 日

这是一个维护版本。它修正了网关判断上游是否使用 Anthropic 协议的依据,使指向自建 Anthropic 端点的模型可通过整个 /v1/messages 端点族提供服务,并原样转发请求体。此外,认证拒绝日志补充了排查问题所需的上下文,MCP 服务器重命名时工具授权会随之迁移,并修复了控制面上若干缺少可用请求格式或可操作错误提示的准入路径。

行为变化​

  • 启用 auto_prompt_caching 现在要求模型的服务提供方密钥采用 Anthropic 协议,即 provider: anthropic,或适配器为 Anthropic 的 BYO 密钥。该设置通过注入 Anthropic cache_control 标记实现;此前,该设置在其他上游上虽然可以保存,却从不生效,也不会提示运维人员提示词缓存并未开启。现在,在其他上游上启用该设置会返回 400。所有模型服务提供方仍可关闭该设置,因此可以清理本版本之前配置的模型;如果无法确定密钥的适配器,系统仍会允许操作,而不会在无法确认的情况下拒绝。参见 Anthropic 提示词缓存。
  • 配置为 provider: byo 且适配器为 Anthropic 的模型,现在可通过 /v1/messages 提供服务并原样转发请求体,不再通过跨模型服务提供方的桥接重新编码。客户端自行设置的 cache_control 标记会原样到达上游;此前,该标记会被丢弃,或在模型启用 auto_prompt_caching 时被改写为模型配置的 TTL。这也会改变适用的上游缓存写入价格:1 小时写入的价格是基础输入价格的 2 倍,5 分钟写入的价格是 1.25 倍。身份认证行为保持不变。

改进​

  • 认证拒绝日志现在包含排查问题所需的请求上下文:通过可信代理配置解析出的调用方地址、HTTP 方法和路径,以及请求 ID。密钥被禁用或已过期时,拒绝日志还会包含该密钥的 ID。返回 401 的请求会在任何处理程序运行前被拒绝,因此不会进入访问日志;拒绝计数指标此前是唯一的记录,但该指标无法说明调用方是谁、拒绝发生在何时或请求了哪条路由。日志级别保持不变:扫描器流量仍使用 debug 级别,默认日志级别的输出与之前完全相同。参见指标与日志。
  • AISIX Cloud Admin API 参考现在正确描述了模型服务提供方请求头和条件限流的计数器语义。此前,参考文档称修改策略的 conditions 会重置当前窗口;实际上,计数器 Key 由策略 ID 和所选 group_by 维度的值构成。因此,只修改 conditions 或 limits 会保留现有 Key 及其计数,而修改分组维度会使请求使用不同的 Key。

修复​

  • /v1/messages/count_tokens 现在依据适配器而不是模型服务提供方标识来判断上游是否使用 Anthropic 协议。指向 Anthropic 协议端点的 provider: byo 模型此前会在该端点上收到 400,但同族的 /v1/messages 可以正常提供服务。
  • MCP 服务器重命名时,工具授权现在会随之迁移。工具名采用 <server>__<tool> 格式,因此每项授权都通过名称引用服务器。按 API Key 配置的限流条目此前已经会随重命名迁移,但访问控制不会;这会在没有任何提示的情况下撤销对整台服务器的访问,使其工具从 tools/list 中消失。调用方 API Key 的 allowed_tools 和 mcp_access,以及环境级和团队级访问策略,现在都会一并重写。匹配名称模式而非某一台特定服务器的通配符(例如单独的 *)保持不变。参见工具访问控制。
  • Amazon Bedrock 和 Google Vertex 的模型服务提供方密钥现在可以仅通过 config 创建。两者的凭证无法放入单个 api_key 字符串,但 Schema 要求提供 api_key,而处理程序又会拒绝非空值,因此此前唯一可接受的请求必须使用文档中从未说明的空字符串。现在,缺少凭证的请求会指出该模型服务提供方实际接受的字段。参见选择模型服务提供方上游。
  • 用 PATCH 提交 "tls": null 现在会清除模型服务提供方密钥的 TLS 设置,与 rate_limit 等其他可选块的行为一致。此前它返回 400,只能用空对象清除。
  • 用量列表及其 CSV 导出现在包含 audio_duration_seconds。按时长计费的转写此前能看到费用,却无法从 API 读回它的计费基数。不含音频的请求会省略该字段。参见音频。
  • 离线包不再让两份安装变成一份。Compose 项目名此前取自解压出的目录名,因此在其他位置解压第二份安装包并运行 run.sh,会接管正在运行的安装,使用第二份安装的配置重建其容器,同时继续挂载原来的数据卷。项目名现在固定为安装包本身;若另一目录中已存在同名栈,启动会被拒绝,并同时显示两个目录路径和可选处理方式。原地升级不受影响;如需启动第二套独立安装,仍可显式指定 COMPOSE_PROJECT_NAME。参见 On-Premises 快速入门。
  • 离线包中的控制台容器现在拥有可写的 Next.js 缓存目录,与 Helm Chart 保持一致。
  • 可信代理 CIDR 与 User-Agent 客户端类型规则现在可以用环境变量设置。proxy.real_ip.trusted_proxies 和 observability.metrics.client_type_rules 此前只能写在配置文件里,用对应的 AISIX_* 变量设置会导致网关无法启动。因此完全依赖环境变量配置的部署——Helm Chart 与控制台给出的 docker run 片段——无法把自己的负载均衡器声明为可信代理,所有请求看起来都来自它。参见指标与日志。
  • 两处准入错误现在会说明如何修正。在策略不是 weighted 的路由组目标上配置 weight 时,错误会指出相关字段和策略,而不再只报告笼统的字段无效;provider 值无法识别时,错误会指出被拒绝的值,并说明目录路由需要控制台会话,而不是 Admin Token。
  • 控制台现在允许一个 API Key 访问多个模型组。此前,选择一个模型组会禁用其他选项,因此一个 API Key 只能引用一个模型组,尽管 API 始终接受包含多个模型组的列表,编辑对话框也从未实施该限制。两个对话框现在共用同一个选择器,这还修复了模型组、合议模型、向量嵌入模型和语义路由在编辑对话框中显示空箭头的问题。

0.8.0​

发布日期: 2026 年 8 月 6 日

此版本让限流足以表达真实的配额策略。单条策略现在可以通过条件树决定自己作用于哪些流量、按这些流量的任意维度拆分计数器、同时约束七种不同的量,并按周期性时间表自动暂停自身——例如工作日的非高峰时段、整个周末或指定的节假日。MCP 网关新增只服务单个 MCP 服务器的端点,并保留其原始工具名,使针对该服务器编写的客户端无需改动即可接入。Token、支出和请求指标现在覆盖所有上报用量的端点,而不再只有 Chat Completions 和 Messages;音频转写按音频时长计费。

行为变化​

  • 网关现在在所有 OpenAI 系列端点上都把 api_base 当作上游根路径。此前 /v1/chat/completions 会逐字把端点追加到所配置的 Base URL 之后,而 /v1/responses、/v1/rerank、/v1/audio/*、/v1/realtime、/v1/files、/v1/batches 和 /v1/fine_tuning/jobs 会在 Base URL 未以 /v1 结尾时插入一段 /v1,因此上游根路径不是 /v1 的密钥能正常处理聊天,其余端点全部返回 404。现在两条路径以同一方式解读 Base URL。带路径但不含版本段的 Base URL 现在会构造 https://proxy.corp/openai-shim/responses,此前构造的是 .../openai-shim/v1/responses;如果你依赖旧的补全行为,请把 /v1 写进 api_base。仅含主机名的 Base URL 仍会补上 /v1,以 /v1 结尾的 Base URL 行为不变,Anthropic 在所有 Base URL 形态下均不变。参见兼容 OpenAI 的模型服务提供方。
  • 两个指标的直方图桶边界发生变化。aisix_request_ttft_seconds 去掉了 50 毫秒以下的两个边界,因为它度量的是上游首 Token 时间,永远不会落在那里;aisix_request_e2e_latency_seconds 新增 420 秒和 600 秒两个边界,使 histogram_quantile() 能在 300 秒之上插值,而不是被钉在 300 秒。依赖旧边界的仪表盘和记录规则需要更新。两套边界现在都可以在 observability.metrics.buckets 下按指标分别配置。参见指标。
  • 首 Token 时间现在计入推理模型的首个推理增量。此前只有普通内容才会打点,因此先推理再作答的模型上报的首 Token 时间晚于调用方实际观察到的时刻。这类模型上报的数值会相应下降。参见指标与日志。
  • GET /v1/models 现在会连同直连模型、语义路由和合议模型一起列出模型组。模型组此前是唯一被过滤掉的虚拟别名,因此把模型组作为对外入口、并将调用方 API Key 限定到该模型组的部署,拿到的是一个空列表。授权没有任何变化,这些名字本来就可以被这些 Key 调用。只有断言精确模型列表的客户端会受影响。参见模型别名。

新功能​

限流​

  • 限流策略现在可以写成条件式,携带一棵条件树而不是单一作用域。条件可以匹配团队、成员、调用方 API Key、模型、模型名和模型服务提供方,通过显式的 and、or 分组组合,最多嵌套三层,支持取反,并可按相等、列表成员或正则表达式匹配字符串。因此同一个资源可以为不同流量承载不同配额,而不是只有一个固定数值。参见限流策略。
  • 条件式策略通过 group_by 拆分自己的计数器,按团队、成员、调用方 API Key、模型或它们的任意组合分桶。此前需要为每个租户各配一条策略,现在单条策略即可实施按租户的配额。
  • 一条策略可以任意组合约束七种量:每秒、每分钟、每小时、每天的请求数,每分钟、每天的 Token 数,以及并发请求数。
  • 匹配模型属性的策略会在具体模型确定处预留配额,对路由或合议模型的父别名而言即按每个目标预留。超限的目标被视为一次失败的尝试并故障转移到下一个,而不是消耗父别名自身的配额。
  • 限流拒绝现在会标明是哪条策略产生的。429 响应体携带该策略的 ID 和名称,aisix_ratelimit_rejections_total 现在统计所有端点上的拒绝,并带有生效层级和策略标签。在多条策略同时生效时,无归因的拒绝无法追溯成因。
  • 策略可以携带周期性的暂停窗口,窗口期内不予执行。每个窗口按星期或按显式日期选择生效日,起止时间是其自身 IANA 时区下的挂钟时间,结束时间早于或等于开始时间即视为跨越午夜,并归属于其起始日。多个窗口取并集,窗口结束后自动恢复执行,且切换不会重置计数器,因此无法通过在同一个限流窗口内暂停再恢复来清掉已消耗的配额。在 AISIX Cloud 中,控制台以限流策略表单上的时间表列表呈现该能力。参见限流策略。

MCP 网关​

  • 新增按服务器划分的端点 /mcp/{server},只服务单个已注册的 MCP 服务器,并以工具的原始名称列出其工具,不带聚合端点所加的 <server>__ 前缀。调用工具时同时接受裸名和带前缀两种写法,而工具访问控制始终在带前缀的形式上判定。因此针对某个服务器自身工具名编写的客户端,经由网关也无需改动即可工作。参见MCP 网关概述。

部署​

  • 新增 proxy.url_rewrites 配置,在网关入口处改写请求路径,按正则表达式匹配并支持在替换字符串中引用捕获组。启动时会校验这些模式,对于不携带配置文件的部署也可以通过环境变量提供。这让 Base URL 无法更改的客户端能够访问不同的网关路径。参见 URL 重写。

计费​

  • 音频模型现在可以按音频时长而不是 Token 计价。转写请求会以音频长度作为计费依据,模型价格按每分钟音频表示。在 AISIX Cloud 中,控制台的模型定价表单接受这类费率。参见音频和模型定价。

改进​

  • 详细请求指标以及 Token 和支出指标现在覆盖所有上报用量的端点,包括 Responses、Embeddings、Rerank、音频、图像和 Realtime。此前它们只覆盖 Chat Completions 和 Messages,因此其他端点上的用量虽然记入用量日志,却在指标中缺失。参见指标。
  • 配置读取现在向前兼容。携带了本网关版本不认识的字段的资源文档会正常加载并生效,未知字段被忽略并上报:配置状态端点的 partially_compatible、一条去重后的告警,以及一个新的 gauge 指标。此前任何未知字段都会导致整条文档被拒绝,这使控制面上每一次纯新增的变更,对尚未升级的网关而言都成了破坏性变更——携带新字段的调用方 API Key 会直接失效。写入路径仍然严格,依旧拒绝未知字段。参见配置状态。
  • 被拒绝的配置更新不再让最后一份可用值丢失。网关会在重新同步和重启之后继续提供此前为该键加载到的值,而不是丢弃该条记录。参见配置传播。
  • 模型服务提供方在已经开始的流中上报的错误,现在会带着其自身的状态码和消息呈现出来,覆盖 OpenAI 系列、Anthropic、Gemini 和 Amazon Bedrock 的流。此前 Anthropic 在流中途送达的 error 事件会被丢弃,被截断的流像正常完成一样关闭,客户端无法区分响应是被切断还是已经结束。这类流现在以一个错误帧结束,且不带完成标记。参见流式响应。
  • 因超出请求体大小限制而被拒绝的请求,现在会通过一个专门的指标上报其请求体读取是如何结束的,从而把客户端断开导致的拒绝与请求体被完整读完的拒绝区分开。参见访问日志与请求关联。
  • 当网关以明文 http 访问需要凭证的 MCP、OpenAPI 或 A2A 上游时,会告警一次,并按服务器和地址去重,使配置失误可见而不至于灌满日志。参见MCP 上游认证。
  • 发往 /v1/realtime 但并非 WebSocket 升级的请求,现在会被记录并以网关自身的错误格式作答;代理中其他位置的路径拒绝也走与其他早期拒绝相同的路径,因此会出现在访问日志和请求计数中。参见Realtime。
  • AISIX Cloud Admin API 参考现在记录了其公开的所有操作和 Schema,并将 Base URL 从固定的相对路径改为可编辑字段。该参考托管在 API7 文档站点,而不是读者的控制面上。因此,混合云或本地部署的读者可以把 Base URL 设置为自己的控制面,使示例使用正确的端点。

修复​

  • 流式转写现在会记录它上报的用量。此类请求此前记录零 Token,因此不产生费用,而同一个转写以非流式方式发起时会正常计费。参见音频。
  • 离线包的快速入门脚本现在打印可用的控制台地址。此前它打印的是容器内部端口,因此按默认安装路径操作时,照着打印出的 URL 访问会失败。参见On-Premises 快速入门。
  • 控制台的模型定价表单现在接受每分钟低于一美分的音频费率,多数模型服务提供方的音频定价都需要这一精度。
  • 控制台中的预算阈值提示不再暗示硬停止可以任意超出其上限。参见预算。

0.7.1​

发布日期: 2026 年 7 月 31 日

此版本让网关可以部署到此前无法接通的网络中。出站连接新增信任配置,因此证书由私有或企业 CA 签发的模型端点、安全护栏或 MCP 上游,无需进程级的变通手段即可访问,既可以在部署级配置,也可以在声明该端点的模型服务提供方密钥上逐个配置。运行在独立主机上、以 IP 地址寻址的数据面,现在可以完成双向 TLS 握手并接入其控制面。被调用方放弃的请求,以及网关在分发前就拒绝的请求,不再从访问日志和指标中消失。

行为变化​

  • 流式响应在传输中途被调用方放弃,现在记为 499 而不是 200。此前用量事件上报的是一次完整的投递,因此中途关闭连接的调用方与把整个流读完的调用方无法区分。按状态码 200 筛选的报表和仪表盘会看到这些请求转移到 499。参见指标与日志。

新功能​

出站 TLS​

  • 新增 upstream.tls 配置,通过 ca_file、client_cert_file、client_key_file 和 verify 设定网关在每一条出站连接上使用的信任配置。它适用于模型端点、所有安全护栏服务、MCP 和 A2A 上游、透传路由、JWKS 与 OIDC 发现,以及 OpenTelemetry 导出。此前私有 CA 之后的上游只会以一个笼统的连接错误失败,唯一的变通手段是进程级的 SSL_CERT_FILE 环境变量,而若干出站路径并不遵循它。参见TLS 与 mTLS。
  • 模型服务提供方密钥可以携带自己的 tls 块,其中包含内联的 ca_cert 和 verify 开关,因此面对多个私有 CA 的部署可以在声明端点的位置声明信任。证书以内联方式而非文件路径提供,因为配置模型服务提供方密钥的人没有办法把文件放到网关主机上。在 AISIX Cloud 中,控制台将其呈现为模型服务提供方密钥表单上的 Endpoint TLS 区块。
  • rediss:// 的缓存或限流后端可以携带字段相同的 tls 块,因为它通常位于你自己的部署内部,由与模型端点不同的 CA 签发。有两处限制被明确记录而不是静默忽略:Amazon Bedrock 支持 ca_file,但不支持客户端证书,也不支持 verify: false;Redis Sentinel 模式支持 verify,但不支持 ca_file。

改进​

  • 在分发前被拒绝的请求现在会出现在访问日志和 aisix_requests_total 中。请求体超过 request_body_limit_bytes 时会正确返回 413,但除此之外不留任何痕迹,这使得"客户端报告了一次网关毫无记录的拒绝"与"请求根本没有到达"无法区分。Content-Length 头冲突返回的 400 存在同样的缺口。这些拒绝发生在认证之前,因此不携带用量事件,也不会出现在 AISIX Cloud 的日志页上。
  • 在响应头之前就被放弃的请求会被记录,而不是凭空消失。此类请求此前同时缺席于访问日志、用量事件和指标,恰好掩盖了运维最想看到的情况:调用方在漫长的首 Token 等待中放弃。新增计数器 aisix_proxy_client_cancelled_requests_total 按端点统计它们。参见访问日志与请求关联。

修复​

  • 位于独立主机、以 IP 地址指向其控制面的数据面,现在可以完成双向 TLS 握手并接入。数据面管理器签发的服务端证书,其 SAN 只来自它的监听地址以及客户端发送的服务器名称,而在容器中这两者都得不到控制面的对外地址:监听器绑定在所有网卡上,因此没有主机名可读,而以 IP 地址发起连接的客户端根本不会发送服务器名称。现在对外公布的地址会传给数据面管理器,由它为该主机签发证书,因此 IP 地址与 DNS 名同样可用。通过 AISIX_CLOUD_DPMGR_BASE_URL 设置,或在 Helm Chart 中使用 api.dpmgrBaseURL。参见On-Premises 部署。

0.7.0​

发布日期: 2026 年 7 月 31 日

此版本让 AISIX 网关能够为 REST API 的 OpenAPI 3.x 文档中所描述的受支持操作生成 MCP 工具,无需另外部署 MCP 服务器。该能力在开源 AISIX 网关和 AISIX Cloud 中均可使用,由网关调用该 API 并注入所配置的凭证。MCP 服务器还新增了限定到单个服务器的按调用方限流。AISIX Cloud 增加了审核流程,可要求服务器在对调用方可见之前先获批准。此外,每个模型现在即使没有配置也会有上游截止时间,用量记录也把上游耗时与调用方实际等待的时间区分开来。

行为变化​

  • 用量事件的延迟字段被重命名以明确其作用范围,并新增一个字段记录调用方侧的等待。latency_ms 改为 upstream_latency_ms,ttft_ms 改为 upstream_ttft_ms,两者仍以单次尝试为范围。upstream_ttft_ms 现在从该次尝试开始处度量,而不是从请求进入处度量,因此可以与它旁边的延迟直接比较。新增的 downstream_latency_ms 以整个请求为范围。在 OpenTelemetry 导出中,span 属性 aisix.ttft_ms 改为 aisix.upstream_ttft_ms,并新增 aisix.downstream_latency_ms,因此任何读取这些名称的仪表盘或告警都需要更新。控制面同时接受新旧两种名称,因此由 AISIX Cloud 托管的网关无需改动。参见指标与日志。
  • 未配置超时的模型不再没有上界。新增部署级的 upstream.timeout_ms,默认 6000000,即 6000 秒,适用于既未设置 timeout 也未设置 stream_timeout 的任何模型。此前这类模型完全没有上游截止时间,因此接受了连接随后不再响应的上游会把请求无限挂住。这个默认值刻意宽松,它是兜底而不是响应性目标。要在部署级恢复此前的行为,设置 upstream.timeout_ms: 0;单个模型可用 timeout: 0 退出。参见配置文件。
  • 模型组上的 timeout 和 stream_timeout 字段此前没有效果,因为成员只会使用自己的取值。它们现在对两者都未设置的成员生效,按成员、模型组、部署默认值的顺序解析。已经携带这些字段的模型组在升级后会开始应用它们。
  • proxy.request_body_limit_bytes 的默认值从 10 MiB 改为 0,即不限制。模型服务提供方能接受的请求大小超过任何固定的网关默认值,因此原本直连模型服务提供方可用的客户端,经由网关反而可能失败。这只在配置文件中缺少该项时生效;文件中显式携带该值的部署保持原值。若要在省略该项的配置上保留限制,设置 request_body_limit_bytes: 10485760。取值 0 此前的含义是"拒绝所有带请求体的请求",现在的含义是"不限制"。

新功能​

MCP 网关​

  • 开源 AISIX 网关和 AISIX Cloud 都支持以普通 REST API 为后端的 MCP 服务器。把服务器类型设为 openapi 并提供 OpenAPI 3.x 文档,网关就会为每个受支持的操作生成一个 MCP 工具,并把每次工具调用作为一次 HTTP 请求发往该 API。网关持有所配置的凭证,将其注入出站调用,且不会暴露给发起调用的 Agent。参见将 REST API 暴露为 MCP 工具。
  • 生成的工具与来自真实 MCP 上游的工具经过相同的网关控制,包括工具访问策略、限流、安全护栏和用量记录。
  • 在 AISIX Cloud 中,运维可以粘贴 OpenAPI 文档、提供一个由控制面抓取一次的 URL,或通过控制台加载本地文件。每个由 OpenAPI 支撑的服务器都有一个工具页,用于查看生成的工具名和对应操作。
  • AISIX Cloud 可以要求 MCP 服务器在发布前经过审核。已提交的服务器在审核者接受之前对调用方不可见,而对已上线服务器提出的变更在等待审核期间不会影响正在运行的服务器。参见MCP 服务器上线前审核。
  • 在两个产品中,API Key 都可以携带按服务器设置的限流,因此在某个 MCP 服务器上循环的 Agent 不会消耗同一个 Key 在另一个服务器上的额度。限制可按秒、分钟、小时或天表示,另有并发数,且只对工具调用计量,因此某个服务器的额度耗尽后客户端仍可连接并列出工具。Key 自身的限流仍会叠加生效。参见限流与预算。

超时​

  • 新增两项网关配置 upstream.timeout_ms 和 upstream.stream_timeout_ms,为请求截止时间和流式分块之间的最大间隔提供部署级默认值。截止时间按模型、模型组、这些默认值的顺序解析,并适用于所有端点而不只是聊天路径。参见配置文件。
  • 模型组在控制面和控制台中暴露 timeout 和 stream_timeout,模型上显式的 0 现在会被保留而不再被归一化掉,因此模型可以退出部署级默认值。

可观测性​

  • 用量记录现在上报调用方所等待的时间,度量点在网关把字节交给客户端处,而不是上游分块到达处。在会脱敏响应的输出安全护栏之下,流会被扣留到整个响应扫描通过为止,只有调用方侧的数值反映这段等待。控制台的延迟分位数使用该数值,且只统计成功的请求。参见指标与日志。
  • 用调用方侧延迟减去上游首 Token 时间,就能分离出上游未计入的那段等待,从而在不关联两套系统的情况下看到网关侧开销。对于发生过重试的请求,这个差值还包含此前的各次尝试及其之间的间隔。

审计日志​

  • 审计日志支持在事件的操作者、动作和目标上做全文搜索,支持绝对时间范围、逐页浏览,以及导出当前结果集。参见日志与审计。

部署​

  • 数据面页面在基于清单的安装方式之外提供了真正的 Helm 安装页签,因此可以用已发布的 aisix Chart 安装数据面,其中该环境的连接配置已经填好。

改进​

  • 空闲的网关保持在服务中。就绪端点此前会在配置监听超过五分钟没有事件时报告网关未就绪,而资源不再变化的环境经常如此。在 Kubernetes 上所有副本会在同一时刻越过该阈值,于是完全健康的服务失去了全部端点。就绪现在只报告网关是否正在退出以及配置是否已应用。配置的新鲜度仍可通过健康端点、配置状态端点和 aisix_config_* 指标观察。参见配置状态。
  • aisix 数据面 Helm Chart 的就绪探针现在使用代理端口上的该就绪端点。
  • 超过所配置请求体大小限制的请求,在所有接受请求体的路由上返回相同的错误结构。此前若干 JSON 端点和两个原始请求体端点返回纯文本拒绝,multipart 上传报告一个笼统的客户端错误,而 MCP 和 Agent 端点返回裸的 400。这些端点上的畸形 JSON 现在同样返回标准结构。参见请求头与错误码。
  • Amazon Bedrock 模型现在遵守其所配置的截止时间和连接超时。AWS SDK 此前会用自己的默认值构建自己的 HTTP 客户端,因此 Bedrock 模型的超时并未生效。
  • MCP 上游连接遵守网关的 upstream 连接配置,包括连接超时、TCP Keepalive 和连接池规格。
  • Prometheus 指标占用的内存不再无界增长,指标序列句柄只解析一次并缓存,而不是每个请求都查找一遍。
  • 发布的网关二进制保留符号表,因此针对已发布镜像抓取的性能剖析记录无需特殊构建即可解读。
  • 概览页在其 Top 模型列表中显示完整模型名,不再截断。

修复​

  • 成功的那次尝试所记录的延迟以该次尝试为范围。发生故障转移的请求此前上报的是获胜尝试从请求进入处度量的延迟,因此包含此前所有尝试及重试之间的间隔,使一次成功的故障转移看起来像上游很慢。
  • 重命名 MCP 服务器时会带走其按服务器设置的限流,删除该服务器时也会一并删除。此前这些限制留在旧名字下并静默失效。
  • 审核者编辑 MCP 服务器时会发布它,而不是把它下线。
  • 网关原生支持但公共模型目录未收录的模型服务提供方现在可以重新配置,此前它们在校验阶段被拒绝。
  • 按地域的模型服务提供方 Base URL 与目录中的提供方标识匹配,因此地域相关的默认值可以正确解析,不再落空。
  • 客户端在请求中途断开时不再丢失审计记录。控制面会干净回滚、把断开记录一次,并返回一致的响应体。

0.6.0​

发布日期: 2026 年 7 月 29 日

此版本让调用方可以使用自有身份提供方签发的 JWT 认证,而不必使用网关 API Key。它还把按 Key 维护的 MCP 工具白名单,替换为由环境、团队和 Key 逐层解析的访问策略。此外,重试预算移到模型上,上游请求获得请求上下文变量和客户端请求头白名单,视频生成新增两个模型服务提供方。

行为变化​

  • 重试现在默认开启。此前未设置 routing.retries 的模型组完全不会重试。预算现在按模型、模型组、以及新增的部署级 upstream.retries 默认值 2 的顺序解析,因此从未配置过重试的部署在升级后会开始重试。每次重试都会重新发送完整请求体,并叠加在模型服务提供方自身边缘所做的任何重试之上。要保持此前的行为,在网关配置文件中设置 upstream.retries: 0。参见代理错误与重试。

新功能​

认证​

  • 调用方可以使用 OIDC 提供方签发的 JWT 认证,而不必使用网关 API Key。新增的 oidc_providers 资源按环境保存信任条目,固定 issuer、其接受的 audience 以及 JWKS 位置,网关在请求继续之前校验每一项声明。参见JWT 认证。
  • API Key 通过提供方与 subject 组成的一对与外部身份绑定,因此经 JWT 认证的调用方携带该 Key 的预算、限流、模型访问权限和用量归属。subject 只会针对该 Key 上指定的信任提供方解析,因此第二个受信 issuer 无法声明属于另一个提供方的 subject。
  • JWT 认证作用在网关唯一的认证点上,因此所有代理面都接受它,包括聊天、messages、responses、embeddings、rerank、音频、图像、视频生成、files、batches、fine-tuning、MCP 与 Agent 端点、realtime WebSocket 连接以及透传。
  • 校验默认拒绝:只接受非对称签名算法,必须有过期和 audience 声明,issuer 必须匹配一条已启用的信任条目,运维还可以额外要求 scope 或固定任意嵌套声明。

MCP 访问控制​

  • MCP 工具访问现在由分层策略治理,而不是在每个 Key 上维护白名单。环境默认策略适用于所有调用方,团队策略对该团队成员的 Key 取而代之,Key 再进一步收窄结果。参见MCP 访问策略。
  • 策略可以不授予任何工具、授予指定的一组工具,或授予全部工具。授予全部工具涵盖当前和未来的工具,是一个显式选择而不是默认值。
  • 各层的拒绝模式始终做减法,因此环境级的拒绝会穿透团队策略,并且对本版本之前创建的 Key 同样生效。
  • Key 只能收窄它所继承的权限,永远不能放宽。仍在使用此前 allowed_tools 字段的 Key 行为完全不变,因此升级不会静默授予访问权限。

视频生成​

  • 视频生成端点新增两个模型服务提供方:Runway(runwayml,覆盖 Gen 系列和由 Runway 托管的 Veo)以及 OpenAI Sora(openai)。
  • 内容路由现在使用两种方式交付成品视频。对于返回签名下载 URL 的模型服务提供方,内容路由仍返回 302 重定向,文件会直接从服务提供方存储传输到客户端。OpenAI 要求使用其凭证下载文件,因此网关会使用配置的模型服务提供方密钥获取文件并流式返回,不会将完整文件保存在内存中,也不会向调用方暴露服务提供方凭证。
  • 对于 OpenAI Sora,progress 现在会返回真实完成百分比。不提供百分比的模型服务提供方仍会在任务完成前返回 0,完成后返回 100。
  • OpenAI 是唯一具有内置默认 Base URL 的视频模型服务提供方。其他四个服务提供方仍要求在密钥上配置 api_base。

上游请求头​

  • 模型服务提供方密钥上的默认请求头取值可以引用请求上下文,例如 "x-tenant-id": "${request.api_key.team_id}",网关按请求渲染它们。内部模型服务因此可以把流量归属到发起调用的团队或 Key,而不必为每个租户单独配置一份模型服务提供方凭证。变量词汇表是封闭的且不含任何机密,变量未能全部解析的请求头会被丢弃,而不是以空值发出。参见上游请求头。
  • 模型服务提供方密钥可以通过一份精确名称或单通配符模式的白名单,把指定的入站客户端请求头转发到上游。它默认为空,且即使在通配符之下也会拒绝来自客户端的认证、传输和网关内部请求头。这让调用方可以在标准端点上传递模型服务提供方特有的请求头或传播 trace 上下文,而不必退化到透传。
  • 视频生成以及 files、batches、fine-tuning 端点此前完全不应用默认请求头,现在每个请求都会携带解析后的集合。

重试​

  • 重试预算现在是模型级配置,作用于所有端点而不只是聊天路径。它按模型、模型组、部署级默认值的顺序解析,并可在控制台中按模型配置。参见代理错误与重试。

连接管理​

  • 网关可以限定已接受的客户端连接在请求之间的最长空闲时间,也可以在尚未产生输出的流式响应上发送心跳注释,使前置代理不会把首 Token 较慢的模型当作已放弃的连接。进行中的请求或流永远不会被中断。参见配置文件。

改进​

  • 日志页支持跨请求的模型、Key、错误消息和标识符做全文搜索,可将当前结果集导出为 CSV 或 JSON,并在时间戳列中与时间一同显示日期。
  • 模型页可按模型名、上游模型或模型 ID 筛选。
  • 模型 ID 字段会提示所选模型服务提供方目录中的模型,同时仍为自由文本,因此目录未收录或刚刚发布的模型仍可手动输入。
  • API Key 和模型服务提供方密钥页面改用紧凑表格,配统一搜索、类型筛选和服务端分页,替换此前的卡片布局。
  • 控制台侧边栏显示控制面构建版本,运维无需登录终端即可确认某个环境运行的是哪个发布版本。
  • aisix-cp Helm Chart 为控制面 API 和数据面管理器新增启动探针,因此首次启动较慢或升级时耗时较长的 Schema 迁移不再被存活探针中断。

修复​

  • 输入安全护栏现在扫描消息文本内容与其结构化内容块的并集。这两者在协议上是相互独立的字段,而模型服务提供方桥接层在存在结构化块时会转发它们,因此此前一个文本无害、载荷藏在块中的请求可以通过所有输入安全护栏,而模型仍然收到该载荷。
  • 失败请求的访问日志行现在会说明失败原因,同时携带可用于筛选或告警的稳定错误类别以及底层原因。此前上游错误、域名解析失败、被回收的连接和未获应答的连接尝试都产生完全相同的日志行。参见访问日志与请求关联。

0.5.0​

发布日期: 2026 年 7 月 24 日

此版本新增统一视频生成端点、向外部系统发送通知的预算阈值告警,以及 Anthropic 模型的自动提示词缓存;同时修复重试、超时、限流和用量核算未覆盖所有请求路径的多个问题。

新功能​

视频生成​

  • 新增视频生成端点,通过 /v1/videos 接受文生视频任务、轮询状态并返回成品视频,遵循 OpenAI 视频 API 的三阶段形态。当前映射的模型服务提供方包括 Alibaba Cloud Model Studio、Zhipu AI CogVideoX 和 Volcengine Ark Seedance。
  • 视频请求现在会经过与聊天流量相同的网关控制:模型别名、调用方 API Key 访问检查、客户端 IP 白名单、模型级限流和提示词输入安全护栏扫描。此前,视频流量只能通过透传到达模型服务提供方,不会应用这些模型级控制。
  • 网关不存储任务状态。返回的视频 ID 携带路由信息,因此状态和下载调用可由任意网关实例处理。
  • 视频提交以零 Token 记录在用量日志中。此版本尚未应用按时长计费,因此视频流量不会消耗预算。

安全护栏​

  • 新增 Alibaba Cloud AI Guardrails 类型,调用 MultiModalGuard 服务并执行其建议判定。当服务返回脱敏内容时,网关会将脱敏文本写回请求,而不是直接拒绝。
  • 网关记录 aisix_guardrail_latency_seconds,这是按每次执行统计的延迟直方图,可将安全护栏开销与上游模型延迟区分开。参见指标。
  • Alibaba 安全护栏服务的响应会保留其上游请求 ID,网关会将该 ID 与自身请求 ID 关联,便于跨系统排查。

预算和告警​

  • 预算阈值告警会在支出达到预算配置百分比时通知外部系统。通知渠道支持通用 Webhook 和 Slack。
  • 控制台预算页面现在可以在同一位置管理所有作用域的预算,预算也已纳入 AISIX Cloud Admin API 契约。

提示词缓存​

  • 模型可以启用自动提示词缓存,由网关向符合条件的请求插入 Anthropic 缓存断点。调用方无需修改客户端代码即可获得提示词缓存折扣,也可以在控制台中按模型配置此选项。

用量上报​

  • 当上游未返回用量块时,网关现在会在本地估算 Token 数,而不再记录为零。估算记录会在用量上报和控制台日志页面标记,因此可与模型服务提供方报告的用量区分。
  • aisix_llm_tokens_by_client_total 指标新增 model 标签,并开始为 Responses 端点记录。
  • 内置客户端类型检测覆盖更多编程 Agent,运维人员也可为网关无法识别的客户端添加 User-Agent 映射规则。

部署​

  • 新增 aisix export 命令,可从正在运行的 etcd 存储导出 resources.yaml,作为现有部署切换到独立模式时的初始配置。
  • 对于使用声明式配置且不希望暴露写入 API 的部署,可通过 admin.enabled 设置禁用 Admin 监听器。
  • 状态监听器会报告每个模型的运行时健康状况,无需发送模型请求即可检查上游可达性。
  • 网关会在心跳中报告已应用配置的哈希值,控制面公共规范会公开网关节点和被拒绝资源,从而确认哪些网关已经应用配置变更。参见配置传播。

改进​

  • 模型服务提供方密钥的上游凭证现在可以原地轮换,无需重新创建密钥或重新关联使用它的模型。
  • 控制台模型服务提供方选择器支持搜索,并使用正确的显示名称列出服务提供方。
  • 控制台日志页面会显示完整上游错误消息,不再截断;上游筛选器也不再提供不属于上游的模型组。
  • 日志查询窗口会遵循组织的用量保留设置,不再使用固定范围。
  • 控制面会报告请求被拒绝的原因,而不是返回通用失败。
  • Admin API 写入路径已弃用,推荐使用声明式配置。此版本中它仍可使用。请改为在 resources.yaml 文件中声明动态资源,或通过 AISIX Cloud Admin API 管理它们。

修复​

  • retries 设置现在适用于流式聊天请求;此前独立的流式代码路径不会重试。
  • 对 Azure 模型,stream_timeout 现在按文档限制分块间隔,不再限制整个响应,因此耗时较长但健康的流不会被提前截断。
  • 连接失败会报告底层传输原因,而不是通用上游错误;连接层也开始应用显式限制,不再依赖库默认值。
  • 调用方提供的 cache_control 标记在 OpenAI 到 Anthropic 的桥接过程中会保留,因此使用 OpenAI 客户端访问 Anthropic 模型时仍能获得提示词缓存折扣。
  • 合议成员和评审模型子调用会在后端未报告用量时进行估算,避免合议请求少报 Token。
  • 透传隧道会执行请求正文中指定模型的限流。
  • 组分发会应用每个路由目标自身的模型限流和客户端 IP 白名单,而不再只检查组入口。
  • 每次尝试的错误消息不再截断到 256 个字符,使上游故障在日志中保持可读。
  • 将凭证交换为短期 Token 的服务提供方,其已签发 Token 缓存会按完整凭证建立键,因此密钥轮换会立即生效,无需等待旧 Token 过期。
  • 控制台 Pod 会挂载可写缓存目录,修复 Helm 部署中图片请求可能无限挂起的问题。
  • Playground 只接受控制台会话,个人访问 Token 无法再通过它消耗模型服务提供方配额。

0.4.0​

发布日期: 2026 年 7 月 16 日

此版本引入基于角色的访问控制、自定义角色和环境范围内的管理权限,增加基于状态码的路由故障转移,并通过延迟直方图和更丰富的失败诊断扩展可观测性。

新功能​

访问控制​

  • 组织可以定义自定义角色,按资源类型授予细粒度 read 和 write 权限,替代固定的所有者、管理员和成员划分。
  • 环境范围内的访问权限允许成员管理单个环境,而不授予组织范围内的权限。
  • SCIM 组到角色映射会根据身份服务提供方的组成员身份自动分配角色。
  • 控制面对每个 Admin API 请求执行这些权限检查。

路由​

  • fallback_on_statuses 可将选定的上游 HTTP 状态码纳入重试和故障转移,使 408、409 等服务提供方特定的临时状态码尝试其余目标,而不是直接返回调用方。

可观测性​

  • 分桶的首 Token 时间和端到端延迟直方图支持为服务级目标计算 p90、p99 等延迟分位数。详见指标。
  • 网关会在 Chat、Messages 和 Responses 端点的失败请求中采集请求体,并通过保留结构的截断限制大型载荷。
  • 新的 /status/config 端点会报告已加载的可观测性配置,网关也会发出配置指标。

部署​

  • 独立模式可以从 resources.yaml 加载资源,使网关无需控制面或 etcd 即可运行。

改进​

  • AISIX Cloud Admin API 现在暴露缓存策略、可观测性导出器和限流。
  • 控制台可以为定价目录中没有的模型设置价格覆盖项,使其用量仍能计费。
  • API Key 和限流列表支持分页与搜索。
  • 安全护栏配置错误现在会记录服务提供方的错误响应体,便于排查问题。
  • 阿里云内容安全护栏表单会显示 output_fail_open 选项。

修复​

  • 监控模式的输出安全护栏不再延迟或关闭流式响应。
  • aisix_deployment_state 指标现在根据目标的服务状态派生。
  • SCIM POST /Users 会返回持久化后的身份,而不是回显身份服务提供方的载荷。

0.3.1​

发布日期: 2026 年 7 月 9 日

此维护版本增加 SCIM 目录同步,并改进可观测性、核算、On-Premises Playground 访问和控制面可靠性。

新功能​

  • SCIM 2.0 目录同步可以通过新的 /scim/v2 端点,从 Okta、Microsoft Entra ID 等任意 SCIM 2.0 身份服务提供方自动预配和取消预配组织成员。

改进​

  • 网关构建现在会在 Server 响应头、aisix --version 输出和控制台显示的数据面版本中报告发布版本,不再报告静态构建版本。
  • 按客户端统计的 Token 指标现在包含计入缓存的 total 序列。当前指标目录请参见指标。
  • 健康状态变化时会发出部署冷却指标。
  • 安全护栏管理 API 现已加入 AISIX Cloud Admin API 契约。

修复​

  • 每个代理响应现在都包含 x-aisix-request-id 响应头,用于关联日志和用量事件。
  • Anthropic 提示词缓存 Token 现在会计入原生 /v1/messages 和 /v1/responses 端点的 Token 限流。
  • 单个格式错误的遥测事件不再阻止同一用量批次中的其它事件投递。
  • 启用 AISIX_PLAYGROUND_ALLOW_PRIVATE_IPS 后,On-Premises 控制台 Playground 可以访问私有或内部 LLM 端点。
  • 登录现在接受部署自身的 Origin 和对应的回环 Origin,并为限流或不受信任 Origin 的尝试返回更明确的消息。
  • 成员列表分页不再在视图加载后很快跳回第一页。
  • 控制面重启不再产生无害的重复约束错误日志。

0.3.0​

发布日期: 2026 年 7 月 9 日

此版本引入 MCP 网关和 Agent 网关,扩展代理 API 与安全护栏目录,并增加基于指标的路由。

新功能​

MCP 网关​

  • 新的聚合 /mcp 端点使用一个 AISIX 调用方 API Key 代理多个上游 MCP 服务器。
  • 上游 MCP 服务器成为一等资源,支持在控制面和控制台中注册、完整 CRUD、启用或禁用以及配置上游超时。
  • 工具访问控制将每个调用方 API Key 限定到指定 MCP 工具。
  • 上游认证支持 API Key 和 OAuth 2.0 客户端凭证。
  • MCP 工具调用与模型流量使用相同的限流、预算以及输入和输出安全护栏,同时发出用量事件和访问日志。

Agent 网关​

  • 新的 Agent 网关代理由控制面和控制台管理、作用域为组织的 A2A Agent。
  • allowed_agents 字段将每个调用方 API Key 限定到指定 Agent。

API​

安全护栏​

路由​

  • 多目标模型支持最低成本、最低延迟和最低负载目标选择。
  • 条件路由可按标签或元数据选择目标,通配符别名可路由 provider/* 等模型名称。
  • 粘性加权路由支持 A/B 测试和灰度发布。

流量控制与 API Key​

  • 调用方 API Key 生命周期控制可以设置过期时间、禁用 Key,或通过单次操作完成轮换。
  • 集群限流可以使用共享 Redis 存储,并在现有每分钟(rpm)和每天(rpd)限制之外增加每秒(rps)和每小时(rph)请求限制。

可观测性​

  • 请求和响应内容采集现在覆盖 Embeddings、Rerank、Images 和 Audio。

控制台​

  • 可以在控制台中管理 MCP 服务器,并在限流、预算和安全护栏视图中配置 MCP 治理。
  • 可以按组织配置用量日志保留时间。

改进​

  • 容器镜像以非 root 用户运行,并通过 CAP_NET_BIND_SERVICE 文件能力绑定端口 80 和 443。
  • 控制台提供统一、可筛选的模型视图,并在创建模型时使用单一模型类型选择器。
  • 路由目标可通过拖动重新排序,最低成本目标会显示每个目标的成本标记。
  • 成员和团队列表支持分页。

修复​

  • 缓存和限流 Key 按环境划分作用域,共享 Redis 存储不会混合不同环境的状态。
  • 透传端点现在会为成功和失败请求发出用量事件,并归因到调用方 API Key。