Prhub

#2536 Carry the rollout id on both agentic paths

原始 PR 作者 fzyzcjy 合并时间 2026-08-14 11:47 文件变更 1 提交数 2 评论 1 代码增减 +1 / -1

执行摘要

修复 agentic v1/v2 的 rollout_id 不一致

PR body 指出 tests/e2e/sglang/test_session_v1_v2_parity.py::test_qwen3_8b_h200_fa3_agentic_v2_drop_retries_matches_v1_training_payload_bitwise 在 main 上稳定复现:AssertionError: sample.rollout_id is not bitwise equal left = None, right = 0。根因是 agentic_tool_call.py 只在 v2 分支把 input.sample.index 写进 sample.rollout_id,v1 分支从不写,而 parity 测试逐字段位级比较训练 payload,两条路径必然冲突。PR body 明确说 rollout id 是样本身份,不是 v2 概念,两条路径应当对齐。

值得精读,因为这是 session v1/v2 parity 设计与后处理语义交汇处的一次小而关键的修正。建议重点理解两点:一是为什么只对 v2 多叶写 rollout_id,二是它与 #2347 如何在同一个守卫上收敛;这两点对后续 agentic rollout 逻辑有直接影响。

讨论亮点

guapisolo 在 issue 评论中澄清最终行为:本分支对 v1 与 v2 单例结果保持 rollout_id=None,仅通过 if use_v2 and len(samples) > 1 为 v2 多叶结果分配共享 rollout id,并说明这样可以保留样本裁剪与动态全局 batch 元数据等普通后处理。此外 guapisolo 的批准意见为 Do changes to align with session server v2 design,表示该条件与 session server v2 的设计意图一致。PR body 也预判了与 #2347 的 rebase 冲突,最终两个意图兼容并收敛到同一条件。

实现拆解

  1. 变更入口:miles/rollout/generate_hub/agentic_tool_call.pygenerate(),在 collect_samples 返回后对 result.samples 做后处理。原始提交尝试把 rollout_id 的推导提升到分支外,让 v1 也能按需戳印,从而直接满足 parity 测试。
  2. 重定基修正:因 #2347 已把同一条件改为 if use_v2 and len(samples) > 1,guapisolo 将本 PR 调整为相同条件。v2 多叶结果需要共享 rollout id 以标识样本归属;v1 与 v2 单例结果保持 None,从而保留普通后处理(样本裁剪、动态全局 batch 元数据),避免触发 compact 判定。
  3. 配套验证:依赖现有测试,tests/fast/rollout/generate_hub/test_agentic_v2.py 的 7 个用例与 ruff check agentic_tool_call.py 通过;PR body 记录 CI lane 从 4/5 提升到 5/5 通过,证明问题被真实修复而非被跳过。本次没有新增或修改测试文件。
文件 模块 状态 重要度
miles/rollout/generate_hub/agentic_tool_call.py 样本生成 modified 4.89

关键符号

generate

关键源码片段

miles/rollout/generate_hub/agentic_tool_call.py core-logic

唯一改动文件。generate() 中 v2 分支原无条件对每个样本写 rollout_id,导致 v1/v2 parity 位级断言失败;将条件收窄为 v2 多叶场景后,单例语义与 v1 一致。

# miles/rollout/generate_hub/agentic_tool_call.py —— generate() 中样本收集完成后的核心处理samples = result.samples# rollout id 只对 v2 多叶结果做共享标注:多叶展开需要用 id 标识样本归属。
# v1 与 v2 单例结果一律保持 None,避免后处理误判为 compact rollout,
# 从而保住样本裁剪、动态全局 batch 元数据等普通路径。
if use_v2 and len(samples) > 1:
    # FIXME: handle sample index issues.
    rollout_id = input.sample.rollout_id if input.sample.rollout_id is not None else input.sample.index
    assert rollout_id is not None, "v2 agentic samples require input Sample.rollout_id or Sample.index"
    for sample in samples:
        sample.rollout_id = rollout_id# v1 路径:agent 元数据由驱动侧合并;v2 的元数据已随 wire 返回,无需在此叠加。
if not use_v2:
    for s in samples:
        s.metadata.update(agent_metadata or {})

评论区精华

rollout_id 戳印语义:两条路径都打还是仅 v2 多叶打 设计

PR body 提出把 rollout_id 推导提升到分支外、两条路径都打;guapisolo 重定基后改为 `if use_v2 and len(samples) > 1`,并在 issue 评论中说明最终行为,指出保持单例 None 可防止后处理把普通 rollout 当作 compact。

结论:采用仅 v2 多叶打 rollout_id,保留 v1 与 v2 单例的 None;PR 描述已过时,以评论记录为准。 · 已解决

与 #2347 的同一个守卫改动冲突 other

PR body 提示 #2347 将同一条件改为 `if use_v2 and len(samples) > 1`,原因是无关的;先合并的需要平凡 rebase。

结论:本 PR 最终头版本与该条件收敛一致,两个意图兼容;审阅人批准意见表示与 session server v2 设计对齐。 · 已解决

parity 测试与 CI 验证 测试

原始失败的 e2e parity 测试断言 sample.rollout_id 位级相等;PR body 记录 CI lane 从 4/5 提升到 5/5,重定基后快速验证只跑了 test_agentic_v2.py 与 Ruff。

结论:问题被真实修复;快速验证未重跑 e2e parity,依赖 CI 覆盖。 · 已解决

风险与影响

行为风险:v2 单例不再无条件获得 rollout_id,依赖该字段的下游(如 dashboard、训练数据转换)需要确认对单例路径没有隐含假设;现有测试通过但不代表所有消费方都被覆盖。测试覆盖:本次没有新增断言,e2e parity 验证依赖 CI;若未来 parity 测试扩展到多叶场景,v1 多叶仍无 rollout_id,可能再次暴露不一致。跨 PR 协调:#2347 与本 PR 改同一守卫,时序上已通过 rebase 解决,后续改动需注意保持单一职责。整体是单行核心逻辑变更,风险面较小但处于 rollout 主路径。

影响范围覆盖 agentic rollout 的 session v1/v2 样本生成路径,以及依赖 sample.rollout_id 的训练数据转换与 parity 校验。对用户而言,修复了训练 payload 中 rollout_id 不一致导致的确定性失败,且不会让 v1 承接到新的失败模式;对团队而言,CI 恢复绿色,同时明确了 v2 多叶与单例在 rollout_id 上的语义边界。该改动为单行条件收窄,无接口或配置变更。

核心路径变更 缺少新增测试 跨 PR 交互

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论