令牌使用量计量
简介
Envoy AI Gateway 会暴露遵循 OpenTelemetry GenAI 语义约定的 Prometheus 指标,其中包括每个请求的令牌使用量。通过将调用方身份作为指标标签添加,并通过平台监控栈收集该指标,你可以按部门、命名空间和模型获得统一的令牌消耗视图。同一份数据还会通过 Alauda Cost Management 用于 chargeback。
该流水线如下:网关发出令牌指标,身份作为标签附加,PodMonitor 将指标收集到平台中,MonitorDashboard 负责展示。日常查看无需编写原始 PromQL。
用例
- 按模型展示每个部门的令牌消耗,并按项目隔离。
- 跟踪平台中哪些模型带来了最多的令牌使用量。
- 提供 Alauda Cost Management 用于生成 chargeback 报告的使用数据。
前提条件
-
已配置
llmRequestCosts的AIGatewayRoute。请参见配置令牌配额。如果没有llmRequestCosts,网关仍会发出gen_ai_client_token_usage_token,但每个请求的令牌计数都将为零。 -
调用方身份已作为请求头传递。请参见认证消费者。
-
集群已启用平台监控。可通过检查 Prometheus operator CRD 来确认:
-
在接入监控之前,先确认指标确实已经发出。通过网关发送一个请求,然后读取数据平面 proxy pod 上 ExtProc sidecar 的管理端口:
如果没有出现任何
gen_ai_*样本,那么下面的任何抓取都不会生效——请先修复路由 / ExtProc 连接。
请在专用 namespace 中创建 Gateway 和 AIGatewayRoute(例如 maas-system),不要创建在 Envoy Gateway 控制平面 namespace envoy-gateway-system 中。放在控制平面 namespace 中的 gateway 可能不会将 AI Gateway 请求处理 filter 和 SecurityPolicy 应用到其 listener,这会静默破坏路由和策略执行。请参见Envoy AI Gateway。
步骤
为令牌指标添加身份标签
默认情况下,令牌指标 gen_ai_client_token_usage_token 只包含 OpenTelemetry GenAI 标准标签(model、provider、operation、token type)。通过在 Envoy AI Gateway controller 中将身份 header 映射为指标标签,可将其扩展为包含调用方身份维度——计费 namespace 和调用方部门。
controller 从 ai-gateway-controller Deployment 上的 CLI flag --metricsRequestHeaderAttributes=<header>:<label>[,<header>:<label>...] 读取映射。如果 controller 是通过 Helm 安装的,则 chart 会从某个 values 键(例如 controller.metricsRequestHeaderAttributes)渲染此 flag;请提供你的 release 名称和 chart 引用,然后执行 helm upgrade --reuse-values。如果你直接管理 Deployment,则需要 patch 其容器参数。
该 flag 是一个单个以逗号连接的 <header>:<label> 映射,不是可重复列表:传入两次会导致 controller 只保留最后一份。平台还自带了默认键值对(例如 x-user-name:user 和 x-access-meta:client_id),数据平面的 sidecar 已经会发出这些标签——因此你必须将这一个 flag 改写为现有键值对与新键值对的并集。省略任何一对,都会在下次重启时从所有 proxy 中移除该指标标签。
先读取数据平面当前实际发出的键值对(proxy sidecar 才是事实来源——controller flag 可能已经被收窄):
然后用完整集合再加上 x-user-group:department 重写 controller 的单个 flag。请将下面左侧替换为上面命令实际输出的内容——不要删除任何键值对:
x-user-namespace→user_namespace:请求所计费的 namespace 或 tenant。这是 通过 Cost Management 进行 chargeback 所按组使用的按 namespace 键,因此只要 Cost Management 在使用,就应保留它。x-user-group→department:用于 dashboard 的低基数身份维度。由SecurityPolicy根据 IDPgroupsclaim 设置。
--metricsRequestHeaderAttributes 映射会在创建 proxy pod 时被固化到 ExtProc sidecar 参数中。仅 patch controller 并等待其 rollout 不够——必须重新创建 proxy pod(上面的 rollout restart)之后,新的标签才会出现。如果下面的验证返回空输出,说明 proxy pod 没有被重新创建。
user_namespace(计费 namespace)是可靠的默认分组——只要映射了 x-user-namespace,它就始终存在。department(x-user-group)只有在 IDP 发出单值 group claim 时才是有用的低基数维度——标准 OIDC groups claim 是数组,不受 claimToHeaders 支持,因此在其他情况下 department 会保持为空——请参见认证消费者。避免使用按用户标签(x-user-id):它会产生高基数 series(每个用户 × 模型 × 令牌类型一条),因此仅在需要按用户报表且保留窗口能限制 series 数量时才添加它。
rollout 完成后,发送一条新的请求并确认样本上出现了新标签。user_namespace 始终存在;只有在配置了标量 group claim 时才会出现 department:
将指标收集到平台中
该指标由 AI Gateway external processor(ExtProc)发出,它作为每个数据平面 proxy pod 的 sidecar 运行(声明为 Kubernetes 原生 sidecar / initContainer),并在容器端口 1064(名为 aigw-metrics)上暴露 Prometheus metrics endpoint。它通过 PodMonitor 直接从 proxy pod 抓取。平台工作流请参见 指标管理。
在 Alauda 平台上,此 sidecar 的 PodMonitor 往往已经预先安装。请先检查——如果在同一个 endpoint 上再创建第二个 PodMonitor,会形成重叠的 scrape pool,从而对每个 proxy pod 抓取两次,生成带有不同 job 标签的重复 series,并使 dashboard 以及 chargeback 查询中的每个 increase()/sum 翻倍(两者都不会按 job 过滤):
只有在没有任何 PodMonitor 已经指向 aigw-metrics 时,才去发现 Prometheus operator 用来选择 PodMonitor 对象的 label(以便下面的资源确实会被拾取),然后创建一个:
然后应用该 PodMonitor,并将该 label 放在其自身的 metadata.labels 中(不是 selector——这是两个不同的东西):
metadata.labels:Prometheus 通过它发现PodMonitor。没有正确的 label,资源虽然存在,但对 scrape 流程不可见。spec.selector:匹配集群中每个 Envoy Gateway 数据平面 proxy pod。若要限制到某个Gateway,请将其替换为gateway.envoyproxy.io/owning-gateway-name: <gateway-name>和gateway.envoyproxy.io/owning-gateway-namespace: <gateway-namespace>。port: aigw-metrics:ExtProc sidecar 上提供/metrics的命名端口,对应容器端口1064。
确认 Prometheus 正在抓取该 sidecar——并且恰好只有一个 scrape pool 覆盖它(两个 pool 说明重复的 PodMonitor 导致双重计数)。对 Prometheus 做端口转发,并按 pool 对活动目标分组:
构建统一的使用量 dashboard
创建一个 MonitorDashboard 来展示令牌使用量。使用 namespace、model 和 department 变量,以便消费者可以筛选,并依赖 User View,使每个 project 只能看到自己的数据。平台工作流请参见 监控 dashboards。
在 ExtProc /metrics endpoint 上,该指标以 Prometheus 文本格式暴露,OpenTelemetry 名称会规范化为下划线(如上面的前置检查所示,gen_ai_client_token_usage_token_sum)。不过,平台的 scrape 流程会以原始 OpenTelemetry UTF-8 名称存储该 series,并保留点号。因此在 Prometheus 中,该 series 为 gen_ai.client.token.usage_token_sum(以及 histogram 的 _sum/_count/_bucket 变体),必须使用带引号的 {__name__="..."} 形式来选择——裸下划线标识符将匹配不到任何内容并返回空 vector。内置的 GenAI 标签同样使用点号形式(gen_ai.request.model、gen_ai.token.type),并且需要带引号的 UTF-8 label 语法;而通过 header 映射得到的标签(例如 department 和 user_namespace)则保持普通标识符形式:
在首页面板中请按 user_namespace 分组:只要映射了 x-user-namespace,它就始终存在。department 标签只有在 x-user-group 被填充时才会出现,而这要求 IDP 提供单值 group claim——标准 OIDC groups claim 是数组,不受支持,因此否则 sum by (department) 会退化为单个空标签 series。只有在确认该标签确实存在(grep 'department=' 有输出)之后,才按 department 分组;否则,请在 IDP connector 中暴露一个标量 claim。
通过在 Prometheus UI 的 Status → TSDB 页面列出所有 gen_ai* series 名称,或使用以下命令,来确认该指标可查询:
验证
发送几条已认证且会解析到不同 namespace 的请求,然后通过对任意 proxy pod 的 ExtProc sidecar metrics 端口做端口转发,确认该指标携带了身份标签:
预期每个计费 namespace 至少有一个样本,例如:
如果你配置了标量 group claim,这些样本还会带有 department= 标签(可通过 grep 'department=' 检查)。打开 dashboard,确认令牌使用量已经显示,并且可以按 namespace、model 和 department 进行筛选。
了解更多
下一步
在收集到令牌使用量之后,配置对令牌使用量进行费用分摊,将该指标通过 Alauda Cost Management 计价并生成按 namespace 计费的账单。