Repository navigation
【No.5】fix(agentic): aggregate speculative decoding metrics - #391
Pinoeer-kingxi wants to merge 9 commits into
Conversation
|
@rai-studio-bot review |
Nyanpasu 审查看板审查状态: ✅ 已通过 审查版本: 70356c8 目标分支: main 70356c8 轮复核完成并已提交 APPROVE:本提交仅新增 5 个回归用例(+77 行),生产代码与已批准的 5d92395 逐字节一致;连同 059e5e3 的验收 JSON 删除一并确认(维护者要求,删除完整、零残留引用)。新用例闭合了前轮审计标注的两个次要缺口(导出/序列化/artifact 嵌套计数隔离、森林冲突 ValueError),本机 40 项全部通过,6 个定向变异均被检出,检出能力经变异验证。三项历史发现保持修复状态,无新发现。当前 head 无失败 CI 检查(八项测试检查最近一次绿于 5d92395,PR 描述已如实披露待重跑)。
审查发现待处理
已解决或已取代
提交范围 · 接收 14 · 建议移出 0 · 待确认 0接收 14 个文件 · 建议移出 0 个文件 · 待确认 0 个文件。移出与待确认部分暂停深审,不代表审查通过。
精简审查与验证依据
生产代码的必要性与替代方案
测试的必要性与替代方案
Powered by Nyanpasu with glm-5.3[1m] xhigh, please check the suggestions carefully.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
01b3d27 to
1b11590
Compare
1b11590 to
d54bc50
Compare
rai-studio-bot
left a comment
There was a problem hiding this comment.
审查结论:无阻塞问题,3 条非阻塞建议
完整审查在 01b3d27 上进行(含独立设计参考与测试审计两个深度证据源),并在 rebase 后的当前 head d54bc50 上复核:relax/utils/metrics/speculative_metrics.py 与前次逐字节一致,20 个新增测试本机全部通过,新增的别名整对优先逻辑、文档口径与 append_resp 重排后的等价性均已核对。核心设计(样本级生成记录 + 批内去重 + 计数可用性区分 + 旧名兼容)与从相同需求独立推导的最小设计一致,未发现多余机制;去重正确性、abort/重试下的单次提交、跨 session 隔离与旧序列化兼容均有验证。3 条非阻塞建议见行内评论,汇总与验证依据见看板。
| has_data |= any( | ||
| counts is not None | ||
| and any(value is not None for value in (counts.accepted, counts.proposed, counts.verify, counts.completion)) | ||
| for counts in sample_counts | ||
| ) |
There was a problem hiding this comment.
has_data 探测把 counts.completion 也当作 speculative 数据,而 completion_tokens 是 SGLang 每条响应 meta_info 的常规字段(与是否开启投机解码无关,见 relax/utils/speculative.py:58 的提取)。结果是 update_from_meta_info 改为无条件累计后,任何非 speculative 的 colocate 批次都会满足 has_data,从而输出约 25 个 spec/* 指标键(spec/sample/completion_total、spec/sample/accept_count_coverage=0.0 等);旧实现在 sglang_speculative_algorithm is None 时返回 {}(见被替换的 relax/distributed/ray/rollout.py _compute_spec_metrics)。对未启用投机解码的用户,这是日志与看板面板的指标噪音,PR 描述与文档也只在这些指标属于投机解码的前提下描述它们。
本机用 head 代码验证:3 个样本、meta_info 仅含 {"completion_tokens": 5, "prompt_tokens": 10, "finish_reason": "stop"}、enabled=False 时,输出 25 个键,其中 spec/sample/completion_total = 15。
建议从探测条件中去掉 completion,只看投机解码特有的字段(accepted / proposed / verify):
| has_data |= any( | |
| counts is not None | |
| and any(value is not None for value in (counts.accepted, counts.proposed, counts.verify, counts.completion)) | |
| for counts in sample_counts | |
| ) | |
| has_data |= any( | |
| counts is not None | |
| and any(value is not None for value in (counts.accepted, counts.proposed, counts.verify)) | |
| for counts in sample_counts | |
| ) |
这样投机解码批次不受影响(enabled=True 本来就会输出;有 spec 字段时探测也为真),非 speculative colocate 批次恢复旧行为。
另外一个相关问题请确认意图:非 speculative 的 agentic 批次因首个条件 spec_generations is not None(新导出恒成立)同样会输出 spec/* 指标(unique_generation_count、record_occurrence_count 等生成计数与投机解码无关)。如果这是有意保留的诊断信息,建议在文档中说明这些指标在未开启投机解码时也会出现;否则同样可以按「记录中存在任一 spec 专有字段」来收紧。
There was a problem hiding this comment.
已确认修复(commit 48b66a5):has_data 探测重写为 has_speculative_fields,仅检查 accepted / proposed / verify;completion_token_num 已从 legacy 正数触发条件移除;原先恒为真的 spec_generations is not None / agentic_trace 子句也一并删除,因此非 speculative 的 agentic 批次同样不再输出——与我评论中询问的第二点一致。
本机在 48b66a5 上复验:原复现用例(3 个仅含 completion_tokens 的样本、enabled=False)现返回 {};含 spec 字段的 colocate 与 agentic 批次仍正常输出(accept_rate、legacy 别名不变);旧序列化样本(9/10/2/11)仍产出 spec_accept_rate=0.9、spec_accept_length=5.5。新增 test_completion_only_metadata_does_not_enable_speculative_logging 与 test_enabled_speculative_logging_can_report_unknown_counters 固定门控行为,中英文文档已补充说明。
| def _compute_spec_metrics(args, all_samples: list[Sample]): | ||
| if getattr(args, "sglang_speculative_algorithm", None) is None: | ||
| return {} | ||
| num_samples = len(all_samples) | ||
| metrics = {} | ||
| metrics["spec_accept_rate"] = sum(sample.spec_info.spec_accept_rate for sample in all_samples) / num_samples | ||
| metrics["spec_accept_length"] = sum(sample.spec_info.spec_accept_length for sample in all_samples) / num_samples | ||
| return metrics | ||
| return compute_speculative_log_metrics( | ||
| all_samples, | ||
| enabled=getattr(args, "sglang_speculative_algorithm", None) is not None, | ||
| ) |
There was a problem hiding this comment.
本 PR 的用户可见行为(rollout 日志中的 spec/* 指标)没有接线级测试保护。在本 head 副本上把 _compute_spec_metrics 改为 return {} 后,全部 20 个新增测试以及可运行的既有相关测试依然全绿(本机实际运行验证);全仓也没有任何用例经由 compute_metrics_from_samples / _compute_spec_metrics 断言 spec/* 键(tests/utils/test_repetition_integration.py 调用了该入口但只断言重复度指标)。也就是说,未来一次重构若悄悄删掉这几行委托,指标会整体静默消失且 CI 不会被察觉。
建议补一个直接断言加权指标从日志入口产出的小型测试(可放在 tests/distributed/ray/ 下,沿用该目录 conftest 的 HAS_DEPS 条件导入模式,缺依赖时跳过):
def test_compute_spec_metrics_emits_weighted_spec_metrics():
args = SimpleNamespace(sglang_speculative_algorithm="ngram")
samples = [
_sample(_record("a", SpeculativeCounts(1, 2, 1, 2)), _record("b", SpeculativeCounts(9, 10, 2, 11))),
_sample(_record("a", SpeculativeCounts(1, 2, 1, 2))), # 共享 generation "a"
]
metrics = _compute_spec_metrics(args, samples)
assert metrics["spec/unique_generation_count"] == 2
assert metrics["spec/accept_rate"] == 10 / 12(_sample / _record 可复用 tests/utils/test_speculative_metrics.py 的构造方式。)
同类缺口同属本 PR 新增行为、均无覆盖,可一并补:
relax/engine/rollout/data_source.py中new.spec_generations = None的重置:回归会让浅拷贝样本携带模板样本的旧生成记录,重采样时重复计数(适合放tests/engine/rollout/test_data_source.py)。- 冲突语义(
spec/conflicting_generation_count的排除与旧别名抑制)和enabled/has_data门控行为。
说明:接线测试在本评审的纯 CPU 环境因 relax/distributed/ray/rollout.py 模块级的 sglang / transfer_queue 依赖无法端到端运行;上述变异实验与全仓检索均在本 head 副本上完成,测试草案在依赖可用的环境下可直接运行。
There was a problem hiding this comment.
已确认修复(commit 48b66a5):新增 tests/distributed/ray/test_speculative_metrics_wiring.py,沿用该目录的 HAS_DEPS 条件导入模式,在真实 _compute_spec_metrics 入口断言加权指标(spec/unique_generation_count == 2、spec/accept_rate == 10/12)与禁用批次返回 {};tests/engine/rollout/test_data_source.py::test_shallow_copy_drops_generation_export_state 覆盖浅拷贝重置;tests/utils/test_speculative_metrics.py::test_conflicting_generation_is_excluded_from_ratios_and_aliases 覆盖冲突排除语义。
本机复验:相关测试通过(接线测试在本环境因 rollout 模块级依赖缺失按设计跳过,其断言已逐条核对);此前「移除 _compute_spec_metrics 委托后全部测试仍绿」的变异现在会被接线测试以 KeyError 检出。
| return "".join(chr(token) for token in tokens) | ||
|
|
||
|
|
||
| def test_cpu_agentic_export_report() -> None: |
There was a problem hiding this comment.
test_cpu_agentic_export_report 与 tests/test_agentic_speculative_export.py::test_export_tracks_committed_branch_nodes_and_excludes_discarded_branch 是同一场景的两份副本:相同的 A/B/C 计数 (1,2,1,2) / (9,10,2,11) / (2,4,1,3)、相同的 A→B / A→C 树形和共享节点、相同的 12/16 断言,且二者都不经过 service 层——本文件真正的集成边界是 test_cpu_metadata_accumulation_reaches_committed_generation(覆盖 _accumulate_request_meta → 森林 → 指标的链路)。
本轮测试审计做过删除实验:移除本测试后,两类关键变异(dedup key 改为逐次唯一、session_id 从 key 中移除)仍被其余测试检出,检出力不降;本测试独有的两条断言 record_occurrence_count == 4 与 spec/tokens_per_verify == 16 / 4 各一行即可并入导出测试。建议删除本测试、把这两条断言并入 C1,少维护一份场景副本——本次 rebase 中两份副本已各自同步改过一遍(token_delta 改名),后续 append_resp 签名再变化时也要改两处。
There was a problem hiding this comment.
已确认(commit 48b66a5):test_cpu_agentic_export_report 已删除,其独有断言 record_occurrence_count == 4 与 spec/tokens_per_verify == 16/4 已并入 tests/test_agentic_speculative_export.py 的导出测试;集成文件现仅保留真正的服务边界测试 test_cpu_metadata_accumulation_reaches_committed_generation。
本机复验:4 个测试文件 22 通过 + 2 跳过(接线测试在本环境因依赖缺失跳过),导出测试含吸收后的断言全部通过。
rai-studio-bot
left a comment
There was a problem hiding this comment.
审查结论:通过
前一轮的三条建议已在 48b66a5 全部修复并逐项验证:门控收紧为仅投机专有字段(原复现用例现返回 {},speculative 批次与旧序列化样本行为不变);新增日志接线、门控、冲突与浅拷贝测试;重复的集成场景已合并进导出测试。本轮增量 diff 已全量审阅,未发现新问题;本机复跑相关测试 22 通过 + 2 项按设计跳过(接线测试在缺依赖环境跳过,断言已核对)。汇总与验证依据见看板。
一个非阻塞小提醒:PR 描述的 Testing 一节仍写「20 passed(4 个文件)」,当前 head 相应文件已有 22 个测试,另有接线与 data_source 测试,方便的话可顺手更新。
# 🐛 Bug Fix - Compute acceptance and verification ratios only from generations with both counters available. - Keep every known counter in diagnostic totals without synthesizing ratios from unrelated records. --- # ✅ Tests - Cover disjoint and mixed counter availability in the existing aggregation regression. - Exercise service metadata accumulation in the shared forest export fixture and remove its duplicate integration scene. - Merge the legacy identity fallback into the content-addressed export regression. - Verify 25 core tests, 2 rollout wiring tests, and 60 related regression tests. - Confirm the consolidated export tests still detect service parser and untracked-node regressions. --- # 📝 Documentation - Document complete-pair ratio semantics and independent counter totals in the English and Chinese Agentic guides. - Pass pre-commit checks across all tracked files before committing.
rai-studio-bot
left a comment
There was a problem hiding this comment.
审查结论:通过
cb38e75 增量已复核:比率口径改为仅使用分子分母均完整的计数对——修正了未配对计数混入导致接受率可能超过 100% 的缺陷(本机构造未配对记录验证:旧口径 8/6≈1.33,新口径按完整对 3/6=0.5,覆盖率如实报告 0.5),totals 仍保留全部已知值,文档两处口径同步;服务累计边界并入导出测试(_response 助手经真实 _accumulate_request_meta 累计,原集成文件删除后检出力保持);未跟踪节点断言合并进保留用例。三项历史发现(F1 门控、F2 接线测试、F3 测试合并)在本 head 均保持修复状态。本机复跑相关测试 21 通过 + 2 项按设计跳过(接线测试在缺依赖环境跳过)。汇总与验证依据见看板。
# 🐛 Bug Fix - Preserve legacy counter field presence through Sample serialization and resumed generation. - Require known counter pairs before emitting compatibility ratios, preserving explicit zero and new pending-sample classification. - Reuse parsed metadata counters when updating legacy numeric totals. --- # ✅ Tests - Extend the existing legacy regression to cover deleted fields, null values, explicit zero, zero denominators and repeated JSON roundtrips. - Aggregate CPU integration metrics after artifact and JSON restoration. - Targeted CPU suite: 34 passed, no skips. Saved real GPU metadata replays match speculative and non-speculative results. --- # 📝 Documentation - Explain compatibility and missing-counter semantics in both Agentic guides. - Include the Task5 acceptance report with manually checkable input/output cases and GPU evidence provenance.
rai-studio-bot
left a comment
There was a problem hiding this comment.
审查结论:通过
e7ed28e 增量已复核:旧序列化数据的缺失字段不再被补成 0——legacy_field_counts 在反序列化、重复 JSON 往返与继续生成时保留已知/未知计数状态,兼容比率改用可用性感知的数值对(本机验证:缺失 accepted 的旧 payload 此前会伪造 spec_accept_rate=0.0,现在按可用性省略该比率,显式 0 仍产出真实的 0%,状态经 3 次往返保持不变;8 场景参数化矩阵测试覆盖)。导出测试改为在 TrainingFieldArtifact + JSON 序列化恢复后的样本上断言指标,捕获序列化丢失。验证记录 docs/public/validation/task5-speculative-metrics.json 沿用 docs/public 既有数据工件惯例并被双语指南链接,GPU 证据为修复前 head 采集 + 修复后 CPU 回放,披露如实。三项历史发现保持修复状态;本机复跑 28 通过 + 2 项按设计跳过。汇总与验证依据见看板。
# ♻️ Refactor - Keep one normalized counter snapshot for new samples and preserve unknown fields when resuming legacy data. - Decode committed generation records once for batch and sample metrics. - Use normalized verify/completion values in metadata accumulation. --- # ✅ Tests - Extend existing roundtrip and ratio tests for mixed new/legacy batches. - Check negative and nonnumeric backend counters at metadata accumulation. - Targeted CPU regressions: 35 passed. Saved GPU metadata replay matches both speculative and non-speculative results. All pre-commit checks pass. --- # 📝 Documentation - Update compatibility notes and the checkable Task5 acceptance report.
rai-studio-bot
left a comment
There was a problem hiding this comment.
审查结论:通过
eeddb2f 增量已复核:计数状态统一为单一权威来源——_aggregate 单遍解析生成记录并同时产出指标、样本计数对与门控信号(消除了首审指出的双遍解析);known_counts 统一兼容口径访问器,新样本 add 后清除兼容快照(消除双份序列化);服务层 verify/completion 复用同一份规范化计数;混合批次别名的纯度限制被移除,可用性感知的样本对使新旧混合批次可证明(本机验证混合批 spec_accept_rate=0.7、spec_accept_length=3.75,与手算逐样本比率一致),文档与验证记录同步更新。三项历史发现(F1 门控、F2 接线测试、F3 测试合并)保持修复状态,F1 门控经回归复验。本机复跑 29 通过 + 2 项按设计跳过。汇总与验证依据见看板。
| - Output metadata 的顶层 numeric field 使用 `<field>/mean|median|max|min`,不带 `rollout/` 前缀。 | ||
| - Rollout dump 保留完整 metadata。 | ||
|
|
||
| Agentic 导出还会保留每个已提交生成节点的 ID 及 |
| 生成节点,汇总为 `(accepted, proposed, verify, completion)=(12,16,4,16)`, | ||
| 所以 `spec/accept_rate=0.75`、`spec/tokens_per_verify=4`。 | ||
|
|
||
| [Task5 验收结果报告](/Relax/validation/task5-speculative-metrics.json)记录了可人工核对的 |
There was a problem hiding this comment.
这两点确实应当由我先指出,是我的疏漏:换行风格与仓库文档既有的单行长段落排版不一致,验收报告段落服务的是本 PR 的验收记录而不是文档读者——我在审查中把重心放在指标正确性与必要性上,没有把文档风格与内容海拔问题报出来。
已复核 5d92395:两份指南均已重排为单行段落(英文内容逐字一致,中文仅代码 span 周围因换行产生的空白差异),验收报告段落已从中英文指南移除;docs/public/validation/task5-speculative-metrics.json 仍保留在树中、仅由 PR 描述引用——若评审认为它也不宜入库(只留 PR 引用或外部存档),删掉该文件即可,我这边没有发现其它引用。
rai-studio-bot
left a comment
There was a problem hiding this comment.
|
以及如果完成了,记得按照流程「提交」 |
您好,@SigureMo 请问是提交什么? |
PR 里跟我直接说就好 |
# ✅ Tests ## Protect speculative generation export boundaries - Verify nested counters and lists remain isolated across forest exports, Sample serialization and training artifacts. - Reject duplicate generation IDs with conflicting counters or response states without mutating the committed forest. - Preserve idempotent identical generation commits without duplicate counts. - Validate 38 CPU cases; two rollout wiring tests skip because optional deployment dependencies are unavailable. All pre-commit hooks pass.
|
@SigureMo 任务已完成,请求 review。 |
rai-studio-bot
left a comment
There was a problem hiding this comment.
审查结论:通过
70356c8 增量已验证:本提交仅新增 5 个回归用例(+77 行,tests/test_agentic_speculative_export.py),生产代码与已批准的 5d92395 逐字节一致;上轮因 head 推进未发布的 059e5e3 验收 JSON 删除(维护者要求)一并确认——342 行全删、无任何残留引用。新增用例针对前轮审计标注的两个次要缺口:嵌套计数在森林导出 / Sample 序列化 / 训练 artifact 间的隔离,以及森林冲突 ValueError;本机运行相关 40 项全部通过,6 个定向变异(导出共享缓存、序列化别名 ×2、移除冲突检查、冲突部分写入、删除幂等守卫)均被对应用例检出。三项历史发现保持修复状态,未发现新问题。


What
Fix speculative decoding metrics for Agentic rollouts.
(session_id, generation_id)and itsaccepted,proposed,verify, andcompletioncounters in exported samples.spec/accept_rateandspec/tokens_per_verifyfrom summed counters.spec_accept_rateandspec_accept_lengthas arithmetic per-sample compatibility metrics.Why
The previous implementation averaged per-sample acceptance rates and could count a shared generation node once for every exported trajectory. Missing backend fields could also become false zero values. The new metrics therefore use committed generation work and preserve legacy metric names and serialized data.
How
Agentic exports carry committed generation records through the session forest,
TrainingFieldArtifact, andSampleJSON serialization. Rollout aggregation validates records, deduplicates(session_id, generation_id), sums known counters, computes ratios from complete counter pairs, omits a ratio only when its summed paired denominator is zero, and reports coverage for each counter pair. Discarded branches and uncommitted nodes are excluded. Legacy payloads retain known and unknown field state across JSON round trips and resumed generation.The acceptance examples are covered directly:
(accepted, proposed) = (1, 2)and(9, 10)producespec/accepted_total=10,spec/proposed_total=12, andspec/accept_rate=10/12 ≈ 83.33%.A→BandA→C, withA=(1,2,1,2),B=(9,10,2,11), andC=(2,4,1,3), four record occurrences become three unique generations; totals are(12,16,4,16), sospec/accept_rate=0.75andspec/tokens_per_verify=4.Testing
Previous targeted CPU regression at
eeddb2fin the dependency-complete environment: 35 passed, 0 skipped. The covered command is:Latest targeted CPU regression at
70356c8: 38 passed, 2 skipped with the same five-file command. The two Ray rollout wiring tests skip because optional rollout deployment imports are unavailable in the local environment. The five new cases cover nested export/serialization/artifact isolation, duplicate generation IDs with conflicting counters or response states (both rejected without forest mutation), and idempotent identical generation commits without duplicate counts.Real GPU evidence: an NVIDIA RTX A6000 Qwen3-0.6B NGRAM rollout at source revision
cb38e75produced six metadata records. The post-fix CPU replay of those records reproducedaccepted/proposed=326/476,completion/verify=384/68,spec/accept_rate=0.6848739496, andspec/tokens_per_verify=5.6470588235; the non-speculative control emitted nospec/*metrics.pre-commit run --all-files --show-diff-on-failurepasses for70356c8.GitHub Actions at
5d92395: all eight checks passed — Python 3.10/3.11/3.12 tests and pre-commit, H20 unit tests on four GPUs, and GPU/NPU training integration (Qwen3-VL-4B-2xgpu,Qwen3-4B-4xgpu-async, andQwen3-4B-4xnpu-async). These validations are complete; no further action is required for those runs. Task5-specific A6000 inference was collected atcb38e75; later metric fixes were checked by CPU replay.The Task5 validation JSON was removed in
059e5e3in response to maintainer feedback; validation evidence is retained in this PR description. The latest commit,70356c8, adds only regression tests for the remaining export-isolation and forest-conflict coverage gaps identified by the review. Production code is unchanged from the validated5d92395. The eight successful GitHub checks above are historical results for5d92395; CI/GPU/integration results for70356c8are not yet confirmed.Compatibility
spec/accept_rateandspec/tokens_per_verifyare weighted batch metrics over deduplicated generation records.spec_accept_rateandspec_accept_lengthretain arithmetic per-sample averages when every sample has the required complete positive-denominator pair. Missing ratios are omitted, while an explicit zero numerator can produce a real0%. Completion-only ordinary samples do not emitspec/*metrics.Type of Change
Reference
Task 5 requirements