排查推理请求变慢、或者看板上的指标与预期对不上时,需要确认链路上每个 Span 对应哪个执行阶段、每个属性的统计口径是什么、指标该怎么计算。本文列出 ARMS Python 探针接入 vLLM / SGLang 推理引擎后实际上报的全部 Span、Span 属性、Span Event 与指标,可在分析调用链、配置指标看板和定位性能问题时逐项对照。
Span 的通用约定
所有 Span 的 SpanKind 均为 INTERNAL。探针自身生成的 Span 通过 gen_ai.span.kind 属性表达业务语义(取值 LLM / EMBEDDING / RERANKER);引擎原生埋点生成的 Span 不携带该属性,需要靠 Span 名称区分所处阶段。
耗时类属性的单位随引擎与版本不同,跨引擎或跨版本对照同名字段(如 gen_ai.latency.e2e、gen_ai.latency.time_in_queue、gen_ai.usage.prompt_tokens)时需注意:
引擎与版本 | 耗时类属性单位 |
vLLM V0 | 秒 |
vLLM V1 | 纳秒 |
SGLang 入口 Span 与请求 Span | 秒 |
配置看板或告警阈值前先确认单位;指标的单位见各指标表的“单位”列。
vLLM 的 Span
Span 构成与层级
vLLM 场景下的 Span 分为两类:探针在 OpenAI 兼容接口层生成的入口 Span,以及引擎内部生成的请求级 Span 与阶段子 Span。引擎内部 Span 的层级关系如下:
llm_request ← 单个请求在引擎内的完整生命周期,V0 与 V1 均产生
├─ wait ← 仅 V1、采集精度不低于 1
│ └─ kv_transfer ← 嵌套在 wait 之内,仅 V1、采集精度不低于 1
├─ prefill ← 仅 V1、采集精度不低于 1
└─ decode ← 仅 V1、采集精度不低于 1kv_transfer 嵌套在 wait 之内而非与之并列:vLLM 在等待远端 KV 期间请求始终处于 WAITING_FOR_REMOTE_KVS 状态,传输耗时被包含在等待窗口里,因此“wait 耗时减去 kv_transfer 耗时”才是真实的排队时间。在 PD 分离部署下,Prefill 节点只产生 prefill 子 Span,Decode 节点只产生 decode 子 Span。
Span 列表
Span 名称 | 产生位置 | 说明 |
| OpenAI 兼容接口层 | Chat Completions 请求入口, |
| OpenAI 兼容接口层 | Completions 请求入口, |
| OpenAI 兼容接口层 | Embedding 请求入口 |
| OpenAI 兼容接口层 | Rerank / Score 请求入口 |
| 引擎内部 | 单个请求在引擎内的完整生命周期,V0 与 V1 均产生 |
| 引擎内部 | 请求排队等待被调度的时间,仅 V1、采集精度 ≥ 1 |
| 引擎内部 | 从远端拉取 KV Cache 的耗时,挂在 |
| 引擎内部 | Prefill 阶段耗时,仅 V1、采集精度 ≥ 1 |
| 引擎内部 | Decode 阶段耗时,仅 V1、采集精度 ≥ 1 |
入口 Span 属性
入口 Span 由通用 GenAI 埋点生成,属性口径与其他大模型框架插桩保持一致。
属性 | 说明 |
| 业务语义类型, |
| 操作类型, |
| 请求指定的模型名 |
| 请求的候选数量(对应 |
| 采样温度 |
| Top-P 参数 |
| Top-K 参数 |
| 最大生成 token 数 |
| 是否为流式请求 |
| 请求携带的 user 字段 |
| 流式场景下的请求标识 |
| 响应 ID |
| 响应中返回的模型名 |
| 结束原因 |
| 输入 token 数 |
| 输出 token 数 |
| token 总数 |
| 输入内容,受内容采集开关控制 |
| 输出内容,受内容采集开关控制 |
llm_request Span 属性(vLLM V0)
V0 引擎的耗时类属性单位为秒。
属性 | 说明 |
| 引擎内部请求 ID |
| 模型名 |
| 采样温度 |
| Top-P 参数 |
| 最大生成 token 数 |
| 候选数量 |
| 序列数量 |
| 输入 token 数 |
| 输出 token 数 |
| 请求端到端耗时 |
| 排队耗时 |
| 首 token 耗时 |
| 调度耗时,引擎提供该数据时才上报 |
| 模型前向计算耗时,引擎提供该数据时才上报 |
| 模型执行耗时(含前向、跨 worker 同步、CPU-GPU 同步与采样),引擎提供该数据时才上报 |
llm_request Span 属性(vLLM V1)
V1 引擎的耗时类属性单位为纳秒。
属性 | 说明 |
| 引擎内部请求 ID |
| 模型名 |
| 采样温度 |
| Top-P 参数 |
| 最大生成 token 数 |
| 候选数量 |
| 输入 token 数 |
| 输出 token 数 |
| 命中缓存而无需重新 Prefill 的输入 token 数,含本地 Prefix Cache 命中与远端 KV 复用;命中为 0 时也会上报,便于计算缓存命中率 |
| 请求端到端耗时 |
| 排队耗时 |
| 首 token 耗时 |
| Prefill 阶段耗时 |
| Decode 阶段耗时 |
| 推理阶段总耗时(Prefill + Decode) |
| Prompt 分词耗时,发生在前端进程 |
| 增量反分词累计耗时 |
| 远端 KV Cache 传输总耗时,仅发生过传输时上报 |
| 请求被抢占的次数,仅发生过抢占时上报 |
| EngineCore 实例序号,多引擎部署下用于区分 |
| PD 分离角色, |
PD 分离下的耗时口径:Prefill 节点只有 Prefill 耗时是准确的,time_in_model_decode 恒为 0;Decode 节点只有 Decode 耗时是准确的,time_in_model_prefill 恒为 0。vLLM 在抢占时不会重置调度时间戳,因此 Prefill / Decode / Inference 耗时已经包含了抢占带来的停顿,gen_ai.request.preemption_count 是解释这类耗时突增的依据。
阶段子 Span 属性
wait、kv_transfer、prefill、decode 四个子 Span 都携带 gen_ai.request.id、gen_ai.request.model_name、gen_ai.engine.index、gen_ai.pd_role。kv_transfer 额外携带以下属性:
属性 | 说明 |
| 传输方向, |
| 本次传输覆盖的 token 数,即连接器远端解析出的 token 量;与表示缓存命中量的 |
| 连接器是否上报了本请求的加载失败 |
Span Event(仅采集精度 2)
采集精度为 2 时,llm_request 上会按引擎的调度迭代追加 Span Event,用于还原逐次迭代的执行过程。
Event 名称 | 说明 |
| 请求进入等待 |
| 一次 Prefill 迭代 |
| 一次 Decode 迭代 |
| 请求被抢占以释放 KV Cache 块 |
Event 属性包含 gen_ai.engine.index,以及 token 级信息 gen_ai.token.ids、gen_ai.token.texts、gen_ai.token.count、gen_ai.token.logprobs。
Event 数量与请求的迭代次数成正比,容易超过 OpenTelemetry 默认的单 Span Event 上限(128)而被丢弃,必要时调大 OTEL_SPAN_EVENT_COUNT_LIMIT。
vLLM 的指标
指标维度
vLLM 的指标分为引擎侧指标与接口层 token 指标两组,携带的维度不同。引擎侧指标携带的公共维度:
维度 | 说明 |
| 固定为 |
| 固定为 |
| EngineCore 实例序号,仅 V1 |
| 模型名,仅 V1 |
gen_ai_vllm_request_success 额外携带 finished_reason 维度。接口层的 token 指标(genai_llm_usage_tokens)携带以下维度:
维度 | 说明 |
| 固定为 |
| 固定为 |
| 固定为 |
| 模型名 |
|
|
|
|
通用指标(V0 与 V1 均上报)
除 genai_llm_usage_tokens 属于接口层 token 指标外,本表其余指标携带引擎侧公共维度。
指标名 | 类型 | 单位 | 说明 |
| Counter | 个 | 输入 / 输出 token 消耗量,按 |
| Counter | 次 | 引擎调度迭代次数 |
| Counter | 次 | 成功完成的请求数 |
| Counter | 秒 | 首 token 耗时累计 |
| Counter | 秒 | 单个输出 token 耗时累计 |
| Counter | 秒 | 请求端到端耗时累计 |
V0 指标
系统状态类指标为 Gauge,反映采集时刻的瞬时值。本表指标携带引擎侧公共维度,其中 engine_index 与 model_name 仅 V1 上报,V0 指标不含这两个维度。
指标名 | 类型 | 单位 | 说明 |
| Gauge | 比例 | GPU KV Cache 使用率 |
| Gauge | 比例 | CPU KV Cache 使用率 |
| Gauge | 个 | 运行中的序列数 |
| Gauge | 个 | 等待中的序列数 |
| Gauge | 个 | 被换出的序列数 |
| Counter | 个 | 迭代内处理的输入 token 数 |
| Counter | 个 | 迭代内生成的输出 token 数 |
| Counter | 个 | 迭代内处理的 token 总数 |
| Counter | 次 | 迭代内发生的抢占次数 |
Gauge 类指标仅由真正接收到引擎调度统计的进程上报。未参与推理的进程(如纯前端进程)不会上报 0 值,避免多进程部署下出现无意义的 0 曲线。
V1 指标
本表指标携带引擎侧公共维度,包括仅 V1 上报的 engine_index 与 model_name。
指标名 | 类型 | 单位 | 说明 |
| Gauge | 个 | 正在执行批次内的请求数 |
| Gauge | 个 | 等待处理的请求数 |
| Gauge | 比例 | KV Cache 使用率,取值范围 [0,1] |
| Counter | 个 | Prefix Cache 查询的 token 数 |
| Counter | 个 | Prefix Cache 命中的 token 数 |
| Counter | 次 | 引擎累计抢占次数 |
| Counter | 个 | Prefill 处理的 token 数 |
| Counter | 个 | 生成的 token 数 |
| Counter | 个 | 请求 |
| Counter | 个 | 请求 |
| Counter | 秒 | 请求在 WAITING 阶段的耗时累计 |
| Counter | 秒 | 请求 Prefill 阶段耗时累计 |
| Counter | 秒 | 请求 Decode 阶段耗时累计 |
| Counter | 秒 | 请求 RUNNING 阶段耗时累计 |
Prefix Cache 命中率可由 gen_ai_vllm_prefix_cache_hits / gen_ai_vllm_prefix_cache_queries 得到。
SGLang 的 Span
Span 构成与层级
SGLang 场景下的链路由两部分 Span 组成:探针在 OpenAI 兼容接口层生成的入口 Span,以及 SGLang 引擎原生埋点生成的 Span。探针会把入口 Span 的上下文注入引擎的请求头,因此原生 Span 会挂在入口 Span 之下,形成一条完整链路:
chat {模型名} ← 探针入口 Span
└─ Req {请求 ID 前 8 位} ← 原生请求 Span,每请求一个
├─ Tokenizer (host:… | pid:…) ← 原生线程 Span,前端进程
│ ├─ tokenize
│ └─ api_server_dispatch
└─ Scheduler [TP 0] (host:… | pid:…) ← 原生线程 Span,调度器进程
├─ prefill_waiting
├─ prefill_forward
│ └─ chunked_prefill
└─ decode_forward
└─ decode_loop原生埋点采用“请求 → 线程 → 阶段”三层结构:请求 Span 代表一次完整请求,线程 Span 代表参与处理该请求的每个进程/线程,阶段 Span 代表该线程内的一段处理逻辑。因此在多卡(TP / PP / DP)部署下,同一请求会出现多个线程 Span,分别对应各调度器进程。同一线程内相邻的阶段 Span、以及跨进程衔接的阶段 Span 之间会建立 Span Link,用于还原执行顺序,这类关联不是父子关系。
入口 Span 列表
探针的入口埋点为每个请求产生一个 Span,不再生成子 Span,请求内部的阶段拆分由原生埋点提供。
Span 名称 | 说明 |
| Chat Completions 请求, |
| Completions 请求, |
入口 Span 属性
请求侧属性:
属性 | 说明 |
| 固定为 |
|
|
| 请求指定的模型名 |
| 请求 ID,Chat 流式场景上报 |
| 是否为流式请求 |
| 采样温度 |
| Top-P 参数 |
| Top-K 参数 |
| 最大生成 token 数 |
| 候选数量 |
响应侧属性:
属性 | 说明 |
| 响应 ID |
| 响应中返回的模型名,非流式场景上报 |
| 结束原因 |
| 输入 token 数 |
| 输出 token 数 |
| token 总数 |
| 命中缓存的输入 token 数 |
| 请求端到端耗时,单位秒 |
| 流式场景下的输出 token 估算值,按流式增量数量乘以引擎的 |
| 输入内容,受内容采集开关控制 |
| 输出内容,受内容采集开关控制 |
工具调用相关属性(Chat 流式场景):
属性 | 说明 |
| 请求是否声明了工具 |
| 响应中是否检测到工具调用 |
| 检测到的工具调用数量 |
| 第 i 个候选、第 j 个工具调用的名称 |
| 对应的调用参数 |
入口 Span 不产生自定义 Span Event。当内容采集策略配置为 event 时,输入输出内容以 gen_ai.client.inference.operation.details 日志事件的形式上报,而不写入 Span 属性。
原生埋点的开启与采集层级
探针在引擎启动时会自动打开 SGLang 的原生 tracing 开关,无需手动添加 --enable-trace;原生 Span 复用探针注册的全局 TracerProvider 上报,因此也不需要配置 --otlp-traces-endpoint,原生 Span 与入口 Span 归属同一个应用。
原生埋点为每个阶段 Span 定义了采集层级,由环境变量 SGLANG_TRACE_LEVEL 控制:默认值 3 表示上报层级 1 至 3 的全部阶段 Span,调小则只保留更关键的阶段,设为 0 表示关闭原生埋点。引擎另外提供 /set_trace_level?level=N 接口用于运行期动态调整。原生埋点的 Span 数量随部署规模放大,单个请求在多卡部署下会产生十个以上 Span,链路数据量偏大时优先调低 SGLANG_TRACE_LEVEL。
请求 Span 与线程 Span
请求 Span 是原生埋点的根 Span,在前端进程创建并结束,名称格式为 {角色} Req {请求 ID 前 8 位},角色在 PD 分离下取 prefill / decode,非 PD 部署为空。
属性 | 说明 |
| 请求 ID |
| 固定为 |
| PD 分离下的请求关联标识,十六进制字符串,仅 PD 场景上报 |
| 请求 ID |
| 采样温度 |
| Top-P 参数 |
| Top-K 参数 |
| 候选数量 |
| 最大生成 token 数 |
| 服务端配置的模型名 |
| 结束原因,JSON 数组字符串 |
| 输入 token 数 |
| 输出 token 数,非 Embedding 请求上报 |
| 命中缓存的输入 token 数 |
| 首 token 耗时 |
| 请求端到端耗时 |
| 请求分发完成到首 token 的耗时 |
| 首 token 到请求结束的耗时 |
| 请求分发完成到请求结束的耗时 |
耗时类属性单位均为秒。这些耗时是前端进程视角的时间差,与调度器内部实际前向计算耗时不完全等价,后者请看阶段 Span 的实际耗时。请求 Span 上的属性只在请求正常结束时补齐。
线程 Span 的名称格式为 {线程标签} [TP n] [PP n] [DP n] (host:{主机标识} | pid:{线程 ID}),其中 rank 信息仅在对应值存在时拼接。线程标签取值 Tokenizer / MultiTokenizer-{编号} / DP Controller / Scheduler,PD 分离下带 Prefill / Decode 前缀。Detokenizer 进程没有原生埋点,不会出现对应的线程 Span。
属性 | 说明 |
| 主机唯一标识,用于区分不同节点上的同名 PID |
| 线程 ID |
| 线程标签 |
| 张量并行 rank,存在时上报 |
| 流水线并行 rank,存在时上报 |
| 数据并行 rank,存在时上报 |
请求异常终止时,错误状态与结束原因被记录在线程 Span 上(状态置为 ERROR,并追加结束原因相关属性),请求 Span 本身不会被标记为错误。排查失败请求时应关注线程 Span 的状态。
阶段 Span 列表
下表的“层级”对应 SGLANG_TRACE_LEVEL,层级值大于配置值的 Span 不产生。通用阶段:
Span 名称 | 层级 | 产生进程 | 说明 |
| 1 | 前端 | Prompt 分词耗时 |
| 2 | 前端 | 请求从前端分发到调度器的耗时 |
| 2 | DP Controller | 数据并行控制器分发请求的耗时,开启 DP 时才有 |
| 2 | 调度器 | 请求进入调度器后到进入等待队列的处理耗时,仅非 PD 分离部署 |
| 1 | 调度器 | 请求在等待队列排队,直到被调度执行 Prefill |
| 1 | 调度器 | Prefill 前向计算耗时 |
| 3 | 调度器 | 单个分块的 Prefill 耗时,嵌套在 |
| 1 | 调度器 | Prefill 完成到首个 Decode 被调度之间的等待 |
| 1 | 调度器 | Decode 阶段整体耗时 |
| 3 | 调度器 | 单轮 Decode 迭代耗时,嵌套在 |
decode_forward 没有独立的结束点,它在请求收尾时随线程一起关闭,因此其耗时覆盖从首次 Decode 调度到请求结束的整个区间。
推测解码阶段(开启 Speculative Decoding 时产生,嵌套在前向 Span 之下):
Span 名称 | 层级 | 说明 |
| 2 | 草稿模型生成候选 token 的耗时 |
| 2 | 目标模型校验草稿 token 的耗时 |
| 3 | 草稿模型的 extend 阶段耗时 |
流水线并行阶段:
Span 名称 | 层级 | 说明 |
| 4 | 流水线并行下 CPU 侧批次处理耗时。层级 4 高于默认值 3,需显式设置 |
PD 分离部署下的额外阶段,Prefill 节点:
Span 名称 | 层级 | 说明 |
| 1 | Prefill 节点接收请求后的准备耗时 |
| 1 | 与 Decode 节点建立传输连接的耗时 |
| 1 | 向 Decode 节点传输 KV Cache 的耗时 |
PD 分离部署下的额外阶段,Decode 节点:
Span 名称 | 层级 | 说明 |
| 1 | Decode 节点接收请求后的准备耗时 |
| 1 | 与 Prefill 节点建立传输连接的耗时 |
| 1 | 等待 KV Cache 传输完成的耗时 |
| 3 | Decode 节点补齐 Prefill 阶段输出的耗时 |
PD 分离下 Prefill 与 Decode 各有独立的请求 Span,是两条独立的链路,通过请求 Span 上的 bootstrap_room 属性关联同一次请求。decode_waiting 在 PD 分离的 Decode 节点上语义变为“KV Cache 传输完成到进入前向计算之间的排队”,与非 PD 部署下的含义不同。
阶段 Span 属性与 Span Event
阶段 Span 默认不携带自定义属性,仅以下三个例外:
Span 名称 | 属性 | 说明 |
|
| 当前是第几轮 Decode 迭代 |
|
| 本次校验通过的草稿 token 数; |
|
| 流水线并行的 micro-batch 编号 |
原生埋点产生两类 Span Event:
Event 名称 | 层级 | 属性 | 说明 |
| 1 | 无 | 请求因资源不足被回退、重新排队时记录 |
| 3 |
| 请求被编入某个批次时记录。 |
Event 按时间戳归属到覆盖该时刻的阶段 Span 上;不落在任何阶段区间内的 Event 会挂到线程 Span 上,因此同名 Event 在不同请求上的挂载位置可能不同。
SGLang 的指标
指标维度
引擎侧指标(调度器与前端统计)携带的维度:
维度 | 说明 |
| 固定为 |
| 固定为 |
| 固定为 |
token 消耗指标(genai_llm_usage_tokens)额外携带 modelName、spanKind、usageType(input / output)。
指标列表
除 genai_llm_usage_tokens 属于 token 消耗指标外,本表其余指标携带引擎侧维度。
指标名 | 类型 | 单位 | 说明 |
| Counter | 个 | 输入 / 输出 token 消耗量,按 |
| Counter | 个 | 运行中的请求数快照 |
| Counter | 个 | 队列中的请求数快照 |
| Counter | 个 | 当前占用的 token 数快照 |
| Counter | 比例 | KV Cache token 使用率快照 |
| Counter | token/s | 生成吞吐快照 |
| Counter | 比例 | 缓存命中率快照,引擎提供该字段时才上报 |
| Counter | 个 | 推测解码的接受长度 |
| Counter | 次 | 统计上报次数,用于对快照类指标做平均值计算 |
| Counter | 个 | 累计输入 token 数 |
| Counter | 个 | 累计输出 token 数 |
| Counter | 个 | 累计命中缓存的输入 token 数 |
| Counter | 次 | 累计请求数 |
| Counter | 秒 | 首 token 耗时累计 |
| Counter | 秒 | 单个输出 token 耗时累计 |
| Counter | 秒 | token 间延迟累计 |
| Counter | 秒 | 请求端到端耗时累计 |
SGLang 的系统状态类指标在实现上以 Counter 上报,语义上是每次统计周期的瞬时快照,包括 sglang_num_running_reqs、sglang_num_queue_reqs、sglang_num_used_tokens、sglang_token_usage、sglang_gen_throughput 与 gen_ai_sglang_cache_hit_rate,在看板上应配合 sglang_log_count 做周期内平均,而不是直接看累计值。gen_ai_server_time_per_output_token 由端到端耗时除以输出 token 数得到,是平均值口径;需要观察真实的 token 间隔时请使用 sglang_inter_token_latency_seconds。