slime 训练可观测性实践:W&B/TensorBoard 指标、SGLang Prometheus 抓取与 Trace 时间线回放
【免费下载链接】slimeslime is an LLM post-training framework for RL Scaling.项目地址: https://gitcode.com/GitHub_Trending/slime12/slime
slime 是一个面向 RL Scaling 的 LLM 后训练框架,其默认可观测性路径刻意保持精简:训练指标继续上报 W&B / TensorBoard,SGLang 的高频 serving 指标不再上云,而是通过 Prometheus 就近抓取;每个请求的耗时明细则从 SGLang responsemeta_info写入 sample trace,按 rollout step 聚合成紧凑的perf/...指标,并可由 trace viewer 做逐请求的时间线回放。读完本文,你将掌握 slime 中训练指标与 serving 指标的分工边界、perf/...指标的来源与含义、Prometheus 的正确启动与数据持久化方式,以及如何用 debug rollout dump 还原单条请求的 Prefill/Decode 分段时间线。
一、slime 可观测性的整体设计
slime 的可观测性遵循"分层采集、就近存储、按需回放"的原则,整体分为三条互补路径:
- 训练指标路径:reward、loss、KL、entropy、eval 等训练过程指标,继续进入 W&B 与 TensorBoard;
- Serving 指标路径:SGLang / router 暴露
/metrics与/engine_metrics两个 Prometheus HTTP endpoint,由 Prometheus 周期性 scrape 并写入自己的 TSDB;slime 本身不保存这些每秒级高频指标,也不会把它们上传到 W&B; - 请求级时序路径:SGLang response 中的
meta_info携带每个请求的排队、prefill、decode 等耗时字段,slime 将其写入 sample trace,并在每个 rollout step 结束时聚合成少量perf/...指标;debug rollout dump 保存的 sample trace 则可以通过 trace viewer 逐请求回放。
这样的设计保证了:高频 serving 数据不会拖垮 W&B,需要深入排查单请求耗时时有 trace 级数据兜底,需要观察 serving 实时状态时有 Prometheus/Grafana 支撑。
二、W&B / TensorBoard 中会看到什么:perf/...指标详解
W&B 与 TensorBoard 仍然接收 reward、loss、KL、entropy、eval 等全部训练指标。除此之外,SGLang 的 request timing 会被聚合到perf/前缀下,例如:
perf/request/e2e_latency/mean perf/request/queue_time/median perf/request/count perf/request/profiled_count perf/decode/throughput/mean perf/prefill/bootstrap_queue_duration/mean perf/prefill/bootstrap_duration/mean perf/prefill/alloc_wait_duration/mean perf/prefill/forward_duration/max perf/prefill/transfer_speed_gb_s/mean perf/decode/prealloc_duration/mean perf/decode/bootstrap_duration/mean perf/decode/alloc_wait_duration/mean perf/decode/transfer_duration/max perf/decode/forward_duration/mean2.1 聚合方式与上报时机
这些指标每个 rollout step 聚合一次,而不是每个 request 上报一次,因此不会像直接上传完整 Prometheus 原始指标那样显著拖慢 W&B。其实现位于 slime/observability/rollout_metrics.py:
compute_perf_metrics_from_samples(args, samples, rollout_time)计算 rollout 整体吞吐(tokens_per_gpu_per_sec、longest_sample_tokens_per_sec等),并调用_compute_sglang_request_perf_metrics(samples);_compute_sglang_request_perf_metrics遍历每个 sample trace 中的sglang_generatespan 的attrs,从 SGLang 返回的字段中取值,并调用compute_statistics(values)(见 slime/observability/metric_utils.py)对每个指标计算mean / median / max / min四类统计量;- 统计后的字典在
log_rollout_data中被统一加上perf/前缀后,经 slime/observability/logging_utils.py 的log()分发到 W&B(args.use_wandb)与 TensorBoard(args.use_tensorboard)。
2.2 字段映射:meta_info→perf/指标
指标与 SGLang 返回字段的映射关系定义在_SGLANG_REQUEST_PERF_FIELDS、_SGLANG_PREFILL_PERF_FIELDS、_SGLANG_DECODE_PERF_FIELDS三组元组中(slime/observability/rollout_metrics.py):
perf/指标键 | 来源字段(SGLangmeta_info) | 说明 |
|---|---|---|
request/e2e_latency | e2e_latency | 请求端到端耗时 |
request/queue_time | queue_time | 排队等待时长 |
decode/throughput | decode_throughput | Decode 阶段吞吐 |
prefill/bootstrap_queue_duration | pd_prefill_bootstrap_queue_duration | Prefill 启动队列时长(PD 场景) |
prefill/bootstrap_duration | pd_prefill_bootstrap_duration | Prefill bootstrap 时长 |
prefill/alloc_wait_duration | pd_prefill_alloc_wait_duration | Prefill 分配等待时长 |
prefill/forward_duration | pd_prefill_forward_duration | Prefill 前向时长 |
prefill/transfer_queue_duration | pd_prefill_transfer_queue_duration | Prefill 传输队列时长 |
prefill/transfer_speed_gb_s | pd_transfer_speed_gb_s | KV 传输速度(GB/s) |
prefill/transfer_total_mb | pd_transfer_total_mb | KV 传输总量(MB) |
prefill/retry_count | pd_prefill_retry_count | Prefill 重试次数 |
decode/prealloc_duration | pd_decode_prealloc_duration | Decode 预分配时长 |
decode/bootstrap_duration | pd_decode_bootstrap_duration | Decode bootstrap 时长 |
decode/alloc_wait_duration | pd_decode_alloc_wait_duration | Decode 分配等待时长 |
decode/transfer_duration | pd_decode_transfer_duration | Decode 传输时长 |
decode/forward_duration | pd_decode_forward_duration | Decode 前向时长 |
2.3 是否出现取决于 PD 配置
不开 PD(Prefill/Decode 分离)时,通用的perf/request/...指标与可用的perf/decode/throughput/...依然存在;而perf/prefill/...与更细粒度的perf/decode/...duration只有在 SGLang 返回对应pd_*timing 字段时才会出现。此外,代码中对取值做了严格校验:只有int/float且非布尔、数值有限的字段才会进入统计(not isinstance(value, (int, float)) or isinstance(value, bool) or not np.isfinite(value)会被跳过);只有至少携带一个有效 perf 字段的请求才会计入profiled_request_count,因此perf/request/count与perf/request/profiled_count的差异可以反映"能被剖析的请求比例"。
2.4meta_info是如何进入 trace 的
在 rollout 端,非流式路径 slime/rollout/sglang_rollout.py 在拿到output["meta_info"]后调用build_sglang_meta_trace_attrs(...)将 timing 写入 span attrs;流式路径 slime/rollout/sglang_streaming_rollout.py 则在最后一个 chunk 携带finish_reason时同样调用该函数。这正是"request timing 从meta_info写进 sample trace"的代码级落点。
三、Prometheus 数据存在哪里:slime 与 Prometheus 的职责边界
slime不存储按秒采样的 Prometheus 数据。SGLang / router 只暴露两个 HTTP endpoint:
/metrics/engine_metrics
Prometheus 周期性 scrape 这些 endpoint,并把时间序列写入Prometheus 自己的 TSDB。slime 在启动 SGLang 服务时总是显式开启enable_metrics: True(见 slime/backends/sglang_utils/sglang_engine.py),确保 router 的/engine_metrics随时可被外部抓取。
由此可以明确三条结论:
- 没有启动 Prometheus 时,serving 指标只存在于当前 SGLang 进程内存与 endpoint 的即时输出中,不会形成历史记录,训练结束后也无法补回;
- 启动 Prometheus 后,历史数据存放在
--storage.tsdb.path指定的目录; - slime 不把这些高频指标上传到 W&B,避免拖慢训练实验管理平台。
3.1 值得关注的 SGLang serving 指标
在 Prometheus / Grafana 中,下面这些指标对观察 serving 侧状态最有价值:
sglang:num_queue_reqs sglang:num_running_reqs sglang:num_prefill_bootstrap_queue_reqs sglang:num_prefill_inflight_queue_reqs sglang:num_decode_prealloc_queue_reqs sglang:num_decode_transfer_queue_reqs sglang:kv_transfer_speed_gb_s_bucket sglang:kv_transfer_latency_ms_bucket sglang:kv_transfer_total_mb_bucket它们适合在 Prometheus / Grafana 面板中观察实时的 queue buildup(队列堆积)、transfer speed(传输速度)、latency histogram(延迟直方图)、失败计数等 serving 侧症状,是训练指标之外诊断 serving 瓶颈的第一手数据。
四、如何启动 Prometheus:配置、命令与数据持久化
Prometheus必须在训练运行时保持运行——它只能 scrape 当前正在暴露的 endpoint,训练结束后无法从 SGLang endpoint 补回过去的数据。它不需要放进训练 Python 进程,推荐作为同一台机器或同一个作业里的旁路进程运行。
4.1 最小抓取配置
global: scrape_interval: 10s scrape_configs: - job_name: slime-sglang metrics_path: /engine_metrics static_configs: - targets: - "ROUTER_IP:ROUTER_PORT"把ROUTER_IP:ROUTER_PORT替换为 slime 日志打印的 router 地址,或者用户通过--sglang-router-ip/--sglang-router-port显式指定的地址。这两个参数由 slime/backends/sglang_utils/arguments.py 注册,分别用于指定 SGLang router 的 IP 与端口。
4.2 启动命令与持久化
prometheus \ --config.file=/path/to/prometheus.yml \ --storage.tsdb.path=/path/to/prometheus-data \ --storage.tsdb.retention.time=7d \ --web.listen-address=0.0.0.0:9090- slime 镜像内已内置
prometheus二进制,因此可以直接在容器里运行上述命令; - 也可以从同一镜像再起一个旁路容器,只要它能访问 router 地址,并把
/path/to/prometheus-data挂载到持久化目录即可; --storage.tsdb.retention.time=7d设置 7 天保留期,可按需调整。
持久化的关键:如果--storage.tsdb.path指向容器本地盘,容器被回收后数据也会丢失;如果指向 NFS、持久化卷或作业输出目录,训练结束后可以重新启动 Prometheus 指向同一个 TSDB 目录,再用 Prometheus UI 或 Grafana 查询历史时间段。
需要强调:这里的"回放"是时间序列回放与图表分析,不是 per-request trace 的完整重放。逐 sample 的 request timing 仍然来自 sample trace / debug rollout 数据,这正是下一节 trace viewer 的用武之地。
五、Trace viewer:从 debug rollout dump 回放单请求时间线
5.1 生成 debug rollout dump
在训练命令中传入--save-debug-rollout-data即可保存 debug rollout 数据(参数定义见 slime/utils/arguments.py):
--save-debug-rollout-data /path/to/debug/rollout_{rollout_id}.pt该参数支持{rollout_id}占位符,文件会保存到按 rollout_id 展开的路径;保存的 sample trace 中包含 SGLangmeta_info里的全部 timing 字段。
5.2 启动 trace viewer
python tools/trace_timeline_viewer.py /path/to/debug/rollout_0.ptviewer 脚本位于 tools/trace_timeline_viewer.py,它直接读取 debug dump 中的 sample trace 事件,重建 span 与点事件,并在源文件旁边生成一个轻量 JSON cache(*.trace_timeline_cache.json)与自包含的 HTML viewer(*.trace_timeline_viewer.html),随后本地起 HTTP 服务供浏览器交互查看。
该默认路径不需要单独保存ReqTimeStats(...)日志,也不需要Loki 或 compact 工具——数据全部来自 sample trace 自身。
5.3[P]/[D]虚拟 lane 的渲染原理
viewer 之所以能渲染出 Prefill / Decode 虚拟 lane,依赖的是 trace 中写入的pd_*字段。在 rollout 端,slime/observability/trace_utils.py 的build_sglang_meta_trace_attrs负责:
- 从
meta_info抽取通用字段(prompt_tokens、completion_tokens、cached_tokens、queue_time、e2e_latency、decode_throughput、finish_reason、sglang_request_id),对应常量SGLANG_TRACE_META_KEYS; - 依据
SGLANG_PD_PREFILL_SEGMENTS(pd_prefill_bootstrap_queue_duration→sglang_pd_prefill_bootstrap_queue等 5 段)与SGLANG_PD_DECODE_SEGMENTS(pd_decode_prealloc_duration→sglang_pd_decode_prealloc等 5 段)构建父子 span 结构的 trace children; - 将
pd_transfer_speed_gb_s、pd_transfer_total_mb、pd_prefill_retry_count汇总为sglang_pd_summary事件。
在 viewer 端,_build_items_from_trace中的pd_lane_specs(tools/trace_timeline_viewer.py)把包含pd_prefill_*/pd_decode_*attrs 的 span 追加为名为"{span_name} [P]"/"{span_name} [D]"的虚拟 lane span,从而在时间线上并排展示同一条请求在 Prefill 与 Decode 两个阶段的耗时切片。配合 viewer 提供的过滤、按 attempt 查看、排序、缩放与 tooltip 等交互能力,可以非常直观地定位单个样本的排队、bootstrap、alloc_wait、transfer、forward 各环节瓶颈。
六、三条路径的选择建议
| 场景 | 推荐路径 | 数据来源 |
|---|---|---|
| 观察训练收敛与整体吞吐趋势 | W&B / TensorBoard 的perf/...、rollout/...指标 | slime/observability/rollout_metrics.py 聚合 |
| 观察 serving 侧实时队列、传输与失败计数 | Prometheus + Grafana,抓取/engine_metrics | SGLang router endpoint |
| 训练结束后回放单请求 Prefill/Decode 分段时间线 | tools/trace_timeline_viewer.py+ debug rollout dump | sample trace 中的meta_infotiming 字段 |
实际使用中,建议在训练开始前就同时规划好 Prometheus 的持久化挂载(NFS / 持久化卷)与--save-debug-rollout-data的输出目录;训练结束后用同一 TSDB 目录重启 Prometheus 做历史查询,再用 trace viewer 对可疑样本做逐请求定位,即可形成"宏观趋势 → 实时 serving 状态 → 单请求耗时"的完整排查闭环。
【免费下载链接】slimeslime is an LLM post-training framework for RL Scaling.项目地址: https://gitcode.com/GitHub_Trending/slime12/slime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考