Prhub

#2124 fix(agent) SWE coding-agent RL stability bugs (abort handling, session cleanup)

原始 PR 作者 jingshenghang 合并时间 2026-06-23 14:57 文件变更 5 提交数 1 评论 0 代码增减 +20 / -7

执行摘要

修复 SWE coding-agent RL 稳定性问题

修复 SWE coding-agent RL 训练中的稳定性 bug,确保中止样本不产生梯度,会话正确清理,以及避免 run_command 在 done 文件为空时崩溃。

建议精读。PR 展示了 agent RL 训练中异常处理的最佳实践:通过 drop_session 分离清理与样本生成,通过 rollout_log_probs=[0.0]remove_sample=True 优雅处理中止样本。测试覆盖不足,后续可补充。

讨论亮点

无 review 讨论。

实现拆解

  1. slime/agent/adapters/common.py 中新增 drop_session 方法:仅执行清理(关闭会话、弹出 store),并调用 manager.drop_session 丢弃轨迹树和轮次计数,不生成 Sample 对象。同时将 finish_sessionbase_sample 改为必需参数。
  2. slime/agent/trajectory.py 中新增 drop_session 方法:幂等地弹出 _trees_turn_count,与 get_trajectory 中的清理逻辑一致。
  3. examples/coding_agent_rl/generate.py 中:将 finally 块中的 finish_session 替换为 drop_session,确保异常/超时后仅做清理;并在 _abort_result 中设置 rollout_log_probs=[0.0]remove_sample=True,使中止样本不参与 GRPO/GSPO 基线计算。
  4. slime/agent/harness/common.pyrun_command 中:读取 done 文件内容后,先检查是否为空字符串,避免 int('') 崩溃。
  5. examples/coding_agent_rl/run_qwen36_35b_a3b_swe_8nodes.sh 中:将优势估计器从 gspo 改为 grpo,并调整 eps-clip 为 0.2/0.28,适配新版算法配置。
文件 模块 状态 重要度
slime/agent/adapters/common.py 适配器 modified 6.49
slime/agent/trajectory.py 轨迹管理器 modified 5.69
examples/coding_agent_rl/generate.py 训练脚本 modified 5.63
slime/agent/harness/common.py 沙箱适配器 modified 5.35
examples/coding_agent_rl/run_qwen36_35b_a3b_swe_8nodes.sh 部署脚本 modified 2.84

关键符号

drop_session finish_session run_command generate _abort_result

关键源码片段

slime/agent/adapters/common.py core-logic

新增 `drop_session` 方法,并调整 `finish_session` 参数,是核心清理逻辑的入口。

# slime/agent/adapters/common.py
# 新增的方法:只做清理,不生成 Sample,用于异常 / 超时后的 finally 块
async def drop_session(self, sid: str, *, wait_timeout: float = 5.0) -> None:
    await self.shutdown_session(sid, wait_timeout=wait_timeout) # 关闭并等待 inflight 完成
    self.store.pop(sid, None) # 移除 session 对象
    self.manager.drop_session(sid) # 丢弃轨迹树和轮次计数# finish_session 的 base_sample 参数从可选变为必需,强制调用者明确传入
async def finish_session(
    self,
    sid: str,
    *,
    base_sample, # 去掉了 =None,变为必需参数
    reward: float = 0.0,
    extra_metadata: dict | None = None,
    wait_timeout: float = 5.0,
) -> list:
    # ... 原有逻辑不变 ...
examples/coding_agent_rl/generate.py core-logic

核心训练脚本:将 `finally` 块改为 `drop_session`,并在 `_abort_result` 中设置 `rollout_log_probs=[0.0]` 与 `remove_sample=True`,实现中止样本的正确处理。

# examples/coding_agent_rl/generate.py
# 改动 1:finally 块使用 drop_session 确保只清理,不产生 Sample
finally:
    await state.adapter.drop_session(session_id) # cleanup only, idempotent# 改动 2:中止样本标记为无梯度,并排除出组基线
def _abort_result(sample: Sample, reason: str, instance_id: str) -> list[Sample]:
    sample.tokens = [0, 0]
    sample.response = ""
    sample.response_length = 1
    sample.loss_mask = [0]
    sample.rollout_log_probs = [0.0] # 新增:设为 0 使 loss 贡献为 0
    sample.reward = 0.0
    sample.remove_sample = True # 新增:从组基线中排除
    sample.status = Sample.Status.ABORTED
    sample.metadata = {**(sample.metadata or {}), "abort_reason": reason}
    return [sample]
slime/agent/harness/common.py core-logic

修复 `run_command` 在 done 文件内容为空时 `int('')` 崩溃问题。

# slime/agent/harness/common.py # run_command 函数片段
        if ec == 0:
            exit_code_text = (out or "").strip() # 先获取文本
            if exit_code_text: # 检查是否为空
                exit_code = int(exit_code_text) # 非空才转换
                break
        # 如果为空,继续等待或超时返回 EXIT_TIME_BUDGET_EXCEEDED
    return exit_code

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

风险较低。变更集中在 agent 异常路径和会话清理,正常路径不受影响。drop_session 幂等且被 finally 块保障,不会漏清理。remove_sample=True 在 GRPO 训练中可能影响基线计算,但符合预期。Shell 脚本参数变化需验证训练效果。

影响范围:仅 SWE coding-agent RL 训练流程。用户:训练稳定性提升,避免中止样本导致梯度异常或 crash。系统:会话资源及时释放,减少内存泄漏风险。团队:该 PR 修复了线上遇到的问题,值得尽快合并。

核心路径变更 缺少测试覆盖 参数调整

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论