跳到主要内容
版本:1.2.0

指标与用量事件

AISIX AI 网关会公开聚合指标和可导出的用量事件。这些信号共同反映服务健康状况、流量趋势,以及每次请求尝试对应的模型、路由和策略结果。

选择遥测来源

请先选择与运维问题匹配的来源;需要深入调查问题时,再按请求、模型或服务提供方关联各类信号。

运维问题首选来源提供的信息
各网关实例的流量是否健康?Prometheus 指标请求速率、延迟分布、Token 和成本计数、策略结果、路由健康、缓存行为和导出器投递健康。
单个请求发生了什么?访问日志结构化请求字段,包括状态、延迟、模型、模型服务提供方、请求 ID,以及可用时的路由结果。
调用应用可以观察到什么?响应头受支持路由上的请求关联、缓存结果、重试时机和选中目标提示。
请求记录可以存储到哪里、如何分析或用于核算?用量事件通过可观测性导出器投递的逐次尝试结果和消耗记录。

抓取 Prometheus 指标

AISIX 默认通过专用指标监听器在 /metrics 提供 Prometheus 指标。你可以通过启动期可观测性设置修改路径或禁用该端点。

该端点设计上不做认证。请保持专用指标监听器私有。

在启动配置中配置 Prometheus 暴露:

config.yaml
observability:
metrics:
prometheus:
enabled: true
path: "/metrics"

专用监听器默认绑定到 0.0.0.0:9090。如果 Prometheus 应从其他接口或端口抓取指标,请设置不同的监听地址。

抓取默认指标端点:

curl -sS "http://127.0.0.1:9090/metrics"
产生流量后才会出现流量指标

AISIX 会在每次抓取时发布配置状态。其他指标族会在首次观测时注册,因此流量指标可能不会在启动后立即出现。请先发送一次模型请求,再检查 aisix_requests_totalaisix_tokens_consumed_total 等序列。

AISIX 使用 aisix_ 前缀输出原生指标名称。使用直方图序列计算跨网关实例的延迟百分位数,并使用请求计数器分析成功率和路由情况。精确指标名称、标签范围和 PromQL 示例请参见指标参考

通过 observability.metrics.labels 可以选择各指标族输出的标签。配置示例、默认值和完整变量列表参见指标标签与变量

导入 Grafana 概览仪表板

预构建的 AISIX AI Gateway 仪表板提供网关流量、延迟、Token 吞吐量、支出、治理(限流、安全护栏和入站身份认证)及上游健康状况的概览。版本 1 使用本版本提供的指标族,并且仅使用 Grafana 内置面板类型。其 JSON 声明使用 Grafana 11.0.0;如果使用较早的 Grafana 版本,请在使用前验证该仪表板。

下载版本 1:

curl -sS "https://grafana.com/api/dashboards/25746/revisions/1/download" -o aisix-dashboard.json

在 Grafana 中依次选择 DashboardsNewImport,并上传 JSON 文件。选择抓取网关指标的 Prometheus 数据源。直接导入仪表板 ID 25746 会改为选择其最新版本,该版本可能在此文档版本发布后发生变化。

解释仪表板数据时,请考虑以下覆盖限制:

范围覆盖情况
指标目录仪表板没有缓存、预算、导出器、MCP、A2A 或配置状态指标的专用面板。完整列表和针对具体任务的 PromQL 请参见指标参考
模型服务提供方和模型筛选器筛选面板要求默认的 providermodel 标签。如果通过 observability.metrics.labels 删除了任一标签,请更新变量和受影响的查询。参见指标标签与变量
可选信号功能产生数据之前,相关面板会保持空白。安全护栏面板要求已附加安全护栏;只有调用方在响应头发送前断开连接时,才会出现客户端取消数据。
支出网关支出目前只覆盖 Realtime 会话。对于开源网关,它要求模型配置 cost 元数据。AISIX Cloud 会在控制面计算其他请求成本,包括 Chat Completions、Messages 和 Responses 请求;这些值请通过模型定价请求日志查看。

区分请求计数与尝试计数

请求是一次调用方交互。重试或故障转移可能让一个请求产生多次用量事件尝试。部分尝试会在目标级限流或请求组装阶段停止,尚未调用模型服务提供方,因此 AISIX 在不同信号中对尝试的计量方式也不同:

单位统计位置一个样本或一行代表什么
请求aisix_proxy_requests_totalaisix_llm_requests_total一次客户端请求,状态是调用方实际收到的状态码。
尝试aisix_deployment_requests_total 及部署指标族对某一个目标模型的一次上游调用。
发出尝试aisix_usage_events_emitted_total一次用量事件的发出尝试,在投递队列接受或拒绝它之前计数。
尝试用量事件记录,以及基于其构建的用量日志一次已记录的处理尝试,包括在上游调用前停止的尝试。同一请求的各次尝试共享 request_id,并按 attempt_index 排序。

如果某个目标返回 502,而后备目标成功,请求计数器只记录最终返回给调用方的 200。部署计数器和用量事件则会保留失败的尝试。因此,用量日志中的 5xx 尝试数可能远高于请求指标;两者计量的单位不同。

请按各查询真正回答的问题选用:

# 最终以服务端错误结束的请求——调用方实际经历的情况。
sum(increase(aisix_proxy_requests_total{status=~"5.."}[24h]))

# 发生过故障转移、但最终仍以服务端错误结束的请求。
sum(increase(aisix_proxy_requests_total{status=~"5..", is_fallback="true"}[24h]))

# 失败的上游尝试,按目标聚合——包含后续被故障转移救回的那些。
# 这是 5xx 用量日志行数在尝试层面的对应视图,范围限于通过模型组下发的端点。
sum(increase(aisix_deployment_failure_responses_total[24h])) by (model)

# 成功救回请求的故障转移,按模型组和实际到达的目标聚合。
sum(increase(aisix_routing_successful_fallbacks_total[24h])) by (model, fallback_model)

# 用量事件的发出尝试,以及被交接队列拒绝的事件。
sum(increase(aisix_usage_events_emitted_total{status_code="5xx"}[24h]))
sum(increase(aisix_usage_event_drops_total[24h]))

# 某个成员被限流拒绝的次数。`status` 携带原始 HTTP 状态码,
# 因此无需扫描整个状态族即可定位单一故障模式。
sum(increase(aisix_usage_events_emitted_total{user_id="<member-id>", status="429"}[24h]))

# 哪些队列交接被拒绝了。两个计数器携带相同的模型与 Provider Key 标签,
# 因此该差值在按模型的粒度上同样成立,而不只是总量。
sum(increase(aisix_usage_event_drops_total[24h])) by (model, provider_key_name)

比较相同的数据范围

在将两个总数视为不一致之前,请先检查它们的覆盖范围:

差异原因检查方法
抓取覆盖范围请求计数器不带环境标签。只有 Prometheus 抓取了服务该环境的每个网关,单环境用量总数才可与之比较。jobinstance 对原始计数器分组,再与正在运行的网关实例核对。
时间覆盖范围increase(...[24h]) 只使用该区间内存在的样本。重启或更短的 Prometheus 保留期可能造成用量日志查询中没有的缺口。在相同时间范围内绘制原始计数器。
投递覆盖范围aisix_usage_event_drops_total 只统计接收端被禁用、队列已满或关闭而无法进入投递队列的事件。队列接受后的失败不会增加该指标。model 对队列丢弃分组。监控控制面投递的 telemetry batch failed (events dropped) 和导出器投递的 sink delivery dropped after retries
没有上游调用目标级限流和请求组装失败仍会产生用量事件,但没有部署计数器样本。组装失败包括凭证不可用、缺少 model_name,以及 api_base 缺失或格式错误。配置错误的目标会产生失败请求,但没有部署失败,因为模型服务提供方从未被调用。

部署指标族覆盖通过模型组分发的端点,而用量事件也覆盖直连模型。请逐项隔离差异,不要将全部差值都解释为网关侧拒绝。

导出用量事件

用量事件是受支持代理路径输出的逐次尝试记录。发生重试或故障转移的请求会生成多条具有相同 request_id 的事件,并按 attempt_index 排序。因此统计这些记录得到的是尝试数而非请求数——在拿记录条数与请求指标作比较之前,请先阅读区分请求计数与尝试计数

用量事件不能从本地端点读取。请在可观测性导出器中配置导出器,将其投递到 OTLP/HTTP、对象存储、阿里云 SLS 或 Datadog。

每条事件都会包含请求结果、消耗详情、调用方请求的模型别名,以及网关能够观测到时处理该次尝试的解析模型。由响应缓存返回的响应会把命中层记录在 cache_hit_layerexactsemantic),语义命中还会把匹配相似度记录在 cache_similarity

延迟字段会区分服务提供方耗时和调用方可见耗时:

字段范围
upstream_latency_ms一次上游尝试所花费的时间,不包括请求解析、安全护栏、路由、重试延迟和先前尝试。
upstream_ttft_ms从一次上游尝试开始到首个流式帧的时间,无论帧类型为何——包括 response.created、仅含角色的 chat 增量等元数据起始帧,与调用方侧代理的统计口径一致。非流式请求、错误和缓存命中时省略或为零。
downstream_latency_ms从收到请求到向下游投递的时间:非流式响应为完整响应,流式响应为首个 Token 或转发帧,A2A 则为整个流。它包括网关处理、重试及重试延迟和输出暂存,仅出现在最后一次尝试中。

如果调用方在流式响应传输中途断开,仍会生成用量事件,因为上游已经执行工作并可能计费。该事件的状态码为 499 而不是 200,Token 计数仅覆盖断开前已到达的内容。统计流式成功请求时请使用 status_code = 200,以排除被放弃的响应。

区分请求类型

每条事件都携带 operation,用于标识匹配端点所执行的工作类型。inbound_protocol 和模型名称都无法可靠地区分对话、图像、视频或其他操作,因此按请求类型聚合流量时请使用该字段。

其取值是一个适合索引、分组和绘图的固定集合:

取值端点
chat/v1/chat/completions
messages/v1/messages
count_tokens/v1/messages/count_tokens
responses/v1/responses
completions/v1/completions
embeddings/v1/embeddings
rerank/v1/rerank
image_generation/v1/images/generations
image_edit/v1/images/edits
transcription/v1/audio/transcriptions
translation/v1/audio/translations
speech/v1/audio/speech
video_generationPOST /v1/videos
realtime/v1/realtime
filesbatchesfine_tuning文件、批处理和微调管理端点
batch_completion网关自己对已完成批处理作业的计量,在作业完成时记录,而非在提交时记录
mcpa2aMCP 网关和 A2A 网关
passthrough透传路由

查询该字段时,请注意以下行为:

  • 它描述的是请求,不是结果。 失败的请求、被护栏拒绝的请求,携带的取值与成功请求相同。它是这类记录上唯一能说明端点的字段。
  • 它以请求为作用域。 发生重试或故障转移的请求会为每次尝试生成一条事件,且每次尝试携带相同取值,因此按 operation 统计事件数得到的是尝试数。参见区分请求计数与尝试计数
  • 轮询视频作业不是视频生成。 只有提交(POST /v1/videos)会产生用量事件,查询作业状态或下载结果都不会。因此 video_generation 的计数是被请求生成的视频数量,而不是围绕这些视频发出的请求数量。

由于 operation 属于元数据,导出器即使在不接收提示词内容的 metadata_only 模式下也会保留它。在阿里云 SLS 中,该字段会作为独立列写入。请为查询使用的字段启用分析,然后按操作类型聚合流量:

* | SELECT operation, COUNT(*) AS calls, SUM(prompt_tokens + completion_tokens) AS tokens GROUP BY operation ORDER BY calls DESC

要筛选某一类流量,请直接按操作过滤,例如 operation: video_generation。不要从模型推断操作类型:同一个模型可以服务多个端点,而 requested_model 标识的是配置的别名或模型组,不是请求类型。

将事件归因到成员

每条事件使用 user_id 标识请求发生时拥有调用方 API Key 的组织成员:

情况记录行为
调用方 API Key 没有关联成员省略 user_id。所有权必须显式分配,不会从 Key 的创建者推断。
一个成员使用多个凭证事件可以有不同的 api_key_id,但共享同一个 user_id。这包括同一成员通过 API Key 和 OIDC 调用、且两者解析到不同 Key 的情况。
Key 被重新分配或删除既有事件保留原始 user_id。重新分配后,后续请求归属于新所有者;删除 Key 不会清除早期归属。
事件产生时的网关尚不支持该字段不记录成员,因此成员筛选只覆盖升级后的流量。

user_id 筛选可包含成员拥有的所有凭证;按 api_key_id 筛选则只查看一个凭证。

在控制台的 Logs 页面中,Member 筛选器提供该能力,旁边的 Status 筛选器可接受状态族(4xx)、具体状态码(429)或区间(500-599)。二者组合即可用一次查询回答「该成员最近 24 小时内哪些请求被限流了」这类问题。CSV 导出同时包含 user_id 和成员名称。

OpenAI 缓存写入 Token

AISIX 可以识别 Chat Completions usage.prompt_tokens_details 或 Responses usage.input_tokens_details 中的 cache_write_tokens。它会将该原始值保留为用量事件的可选 cache_write_tokens 字段,包括通过 /v1/messages/v1/responses 桥接的请求,以及支持协议感知的透传路由。此功能要求网关版本高于 1.1.0。

用量事件字段
{
"prompt_tokens": 101,
"completion_tokens": 11,
"cached_prompt_tokens": 19,
"cache_write_tokens": 37
}

上游未提供时省略此字段;明确返回 0 时保留零值。AISIX Cloud 的日志详情、用量事件 API 和 JSON/CSV 导出均保留这一区别,CSV 用空单元格表示缺失值。对于使用字段前缀的日志后端,沿用其原有前缀,例如 Datadog 中为 aisix.cache_write_tokens

此字段与 Anthropic 的可累加字段 cache_creation_tokens 相互独立,不增加输入/输出 Token 总量,也不改变现有计费计算。上例的输入加输出仍为 112。现有缓存计数器不会因此重命名或合并。

下一步

配置可观测性导出器,把用量事件发送到外部收集器、日志目标、对象存储或数据仓库工作流。使用访问日志与请求关联调查单个请求;构建 Prometheus 仪表板或告警时,请使用指标参考