TL;DR
在和 issue #1 同一台 8× H200(143 GB/卡)上跑了一次 terminal-rl GRPO outcome-only (dense pass-rate reward,无 PRM、无 process reward),把模型换成 Qwen3-8B ,启动脚本与上游官方 terminal-rl/terminal-rl_qwen3-8b.sh 在 args/算法配置上完全一致 ——只在 wrapper 层加了 4 处与本机环境相关的兼容补丁(conda activate / .env / LD_LIBRARY_PATH / --no-gradient-accumulation-fusion),并复用了 issue #1 列出的 7 处源码补丁(无新增)。
1 期望训练结果
terminal-rl 至今没有官方公开的 expected accuracy / reward 曲线 ,issue #1 已经把这一点穷举调研过(arxiv/2603.10165 Table 4 terminal 行为空、blog openclawrl1 / openclawrl2 的表格也只有 GUI/tool-call、伴生 paper arxiv/2602.02488 不含 terminal、main repo gh issue list -S "terminal" 至今没有数字回复、HF Papers 讨论区也没有),不重复展开。
唯一仍有指导性的参考是 Tech Report Table 4 / Table 3:
来源
setting
outcome-only
Table 4
tool-call (250 step)
0.17
Table 4
GUI (120 step)
0.31
Table 4
terminal
空
Table 3
personal-agent Binary RL (8/16 step)
0.25 / 0.23
把本次 8B 全程 terminal/accuracy 均值 0.349 / 峰值桶 0.45+ 对照这两条只能说:量级合理,介于 GUI outcome-only(0.31)和 GUI integrated(0.33)之间,超出 tool-call outcome-only 基线(0.17)。仍然不能判断"达标"或"不达标" ——这只是没有对照组的自我度量。
2 启动顺序和命令
完整可运行脚本:run_qwen3_8b_experiment.sh (gist) 。该脚本对 上游官方 8B 脚本 的修改全部为 wrapper 层环境兼容 ,结构(cleanup_prev → start_router → check_router → check_gpus → detect_nvlink → start_ray_head → submit_job)和算法 args 完全保持。
2.1 4 处 wrapper 层 compat add
#
修改
为什么需要
1
conda activate tbench-rl(set +u 包围)
activate 脚本访问 unset 变量,set -u 会炸
2
source $REPO_ROOT/../.env
注入 WANDB_API_KEY/WANDB_PROJECT/WANDB_GROUP/WANDB_ENTITY
3
LD_LIBRARY_PATH=$CONDA_PREFIX/lib/python3.12/site-packages/nvidia/{cudnn,nvtx,cusparse,nccl,...}/lib
TE 2.13 运行时找不到 libcudnn_graph.so.9 / NVTX / NCCL
4
MISC_ARGS+=( --no-gradient-accumulation-fusion )
防御性保留:尽管本机最终装上了 Apex(pip install -v "git+...NVIDIA/apex" --no-build-isolation --build-option="--cpp_ext" --build-option="--cuda_ext"),保留该 flag 可在 Apex 更新失败时仍能跑(性能损失约 2–3 %)
diff 的算法 args 部分0 行变更 ——其它差异都是 wrapper 默认值(HF_CKPT=/nfs/models/Qwen3-8B / REF_LOAD=... / SAVE_CKPT=... / RAY_TMPDIR=/tmp/ray_tbench_8b)。
2.2 前置依赖
# /nfs/terminal-rl-workspace/ (NFS 工作区)
conda env ' tbench-rl' (Python 3.12)
torch 2.9.1+cu128
sglang 0.5.10.post1
ray 2.55.1
mbridge 0.15.1
transformer-engine 2.13.0 (prebuilt cu12 wheel)
flash-attn 2.8.3 (prebuilt cu12torch2.9 wheel)
apex (cpp_ext + cuda_ext) (本次相比 issue # 1 4B 跑新增)
+ slime -e . (editable install)
.env:
WANDB_API_KEY=< key>
WANDB_PROJECT=openclaw-terminal-rl
WANDB_GROUP=qwen3-8b-terminal-rl
WANDB_ENTITY=hansbug
WANDB_MODE=online
ckpt:
HF_HUB_DISABLE_XET=1 hf download Qwen/Qwen3-8B --local-dir /nfs/models/Qwen3-8B
cd slime && source scripts/models/qwen3-8B.sh
python tools/convert_hf_to_torch_dist.py " ${MODEL_ARGS[@]} " \
--hf-checkpoint /nfs/models/Qwen3-8B --rotary-base 1000000 \
--no-gradient-accumulation-fusion \
--save /nfs/models/Qwen3-8B_torch_dist
2.3 Pool server(与 issue #1 共用,不重启)
docker run -d --name openclaw_pool_server --restart unless-stopped \
-p 18081:18081 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /nfs/terminal-rl-workspace/OpenClaw-RL:/nfs/terminal-rl-workspace/OpenClaw-RL \
-e DATASET_DIR=/nfs/terminal-rl-workspace/OpenClaw-RL/terminal-rl/dataset \
-e TBENCH_OUTPUT_ROOT=/nfs/terminal-rl-workspace/OpenClaw-RL/terminal-rl/build_outputs \
-e TBENCH_DOCKER_IMAGE_SOURCE=build \
-e ENV_SERVER_PORT=18081 \
openclaw_pool_server:v1 \
bash -c " cd /nfs/terminal-rl-workspace/OpenClaw-RL && \
python -m terminal-rl.remote.pool_server --host 0.0.0.0 --port 18081 \
--max-tasks 8 --max-runs-per-task 4 \
--output-root /nfs/terminal-rl-workspace/OpenClaw-RL/terminal-rl/build_outputs"
2.4 启动训练
cd /nfs/terminal-rl-workspace/OpenClaw-RL
source /home/ubuntu/miniconda3/etc/profile.d/conda.sh && conda activate tbench-rl
: > terminal-rl/logs/training_8b.log
nohup bash terminal-rl/run_qwen3_8b_experiment.sh > terminal-rl/logs/training_8b.log 2>&1 &
# ckpt 保留守护(保留最新 KEEP_N=2 个 iter_*)
SAVE_CKPT=/nfs/terminal-rl-workspace/OpenClaw-RL/terminal-rl/ckpt/qwen3-8b-terminal-rl \
KEEP_N=2 nohup bash terminal-rl/ckpt_retention.sh \
> terminal-rl/logs/ckpt_retention_8b.log 2>&1 &
2.5 和官方 terminal-rl_qwen3-8b.sh 在算法 args 上的差异
0 项 ——MISC_ARGS / OPTIMIZER_ARGS / GRPO_ARGS / ROLLOUT_ARGS / DISTRIBUTED_ARGS / WANDB_ARGS / CKPT_ARGS / EVAL_ARGS / PERF_ARGS 与上游 terminal-rl/terminal-rl_qwen3-8b.sh 完全相同(除去 --no-gradient-accumulation-fusion 这一条防御性附加)。
3 源码修改清单
与 issue #1 完全一致的 7 处仓库内 + 1 处 site-packages 补丁 (继承自上次 4B 跑,未删未改)。完整 diff 内容、必要性、不打的后果、风险都在 issue #1 §4 详细列过,这里只列汇总并在右侧标注对本次 8B + TE + 8-GPU + 装 Apex 跑法是否仍严格必需 :
Megatron-LM/megatron/core/utils.py | 7 +++++--
slime/slime/backends/megatron_utils/initialize.py | 4 +++-
slime/slime/backends/megatron_utils/megatron_to_hf/qwen2.py | 11 +++++++++++
slime/slime/backends/megatron_utils/update_weight/update_weight_from_distributed.py | 22 ++++++++++++++++++----
slime/slime/backends/sglang_utils/sglang_engine.py | 6 ++++++
terminal-rl/remote/docker_compose_utils.py | 5 ++++-
terminal-rl/remote/terminal_env.py | 5 ++++-
7 files changed, 51 insertions(+), 9 deletions(-)
#
修改
本次跑法严格必需
备注
4.1
Megatron-LM/.../utils.py:TE 未装时 is_te_min_version 安全回退
❌
本次装了 TE 2.13,永远不进入 None 分支;保留无副作用
4.2
slime/.../initialize.py:numpy 2.x 硬 assert → warning
✅
sglang ≥ 0.5 把 numpy 拉到 2.3.5;不打补丁 0 步即崩
4.3
slime/.../megatron_to_hf/qwen2.py:补 local-impl 命名
❌
本次走 TE 路径,不会撞到 local-impl 名字
4.4
slime/.../update_weight_from_distributed.py:NCCL Duplicate-GPU catch
❌
本次 8 GPU 不会 dup;保留对 1-GPU debug 模式有用,对生产有风险 (吞掉真实 NCCL 错)
4.5
slime/.../sglang_engine.py:HTTP 端的 NCCL Duplicate-GPU catch
❌
同 4.4
4.6
terminal-rl/remote/docker_compose_utils.py:build(timeout=) try/except
✅
terminal-bench 0.2.18 砍掉了 timeout kwarg;不打补丁 pool_server /reset 全 500
4.7
terminal-rl/remote/terminal_env.py:Terminal.start(timeout=) try/except
✅
同 4.6
4.8
mbridge/models/qwen2.py(site-packages,非 git 追踪):补 local-impl mapping
❌
走 TE 路径不撞;对 local 路径是 bug fix
本次 8-GPU + TE + Apex 跑法严格必需的仍是 4.2 / 4.6 / 4.7 三条。 其它五处沿用,对当前路径 0 副作用,但 4.4 / 4.5 在生产环境应改为 env-var gate 或彻底删除。
4 关键指标曲线
单指标图(浅蓝原始 + 橙 EMA(α=0.1)):
terminal/accuracy(pytest 通过率)
terminal/reward_mean(= 2·accuracy − 1)
rollout/raw_reward(训练 batch 均值)
train/grad_norm
train/kl_loss
train/entropy_loss
terminal/non_trainable_ratio(无学习信号 group 比例)
rollout/response_len/mean(agent 输出 token 数)
5 全程指标统计(first20 / mean_all / last20)
指标
n
min
max
first20
mean_all
last20
terminal/accuracy
1093
0.000
1.000
0.221
0.349
0.276
terminal/reward_mean
1093
-1.000
1.000
-0.559
-0.302
-0.447
rollout/raw_reward
1096
-1.000
1.000
-0.357
-0.261
-0.492
train/grad_norm
1107
0.000
3.804
0.847
0.326
0.008
train/kl_loss
1107
0.000
2.491
0.012
0.151
0.073
train/entropy_loss
1107
0.000
0.539
0.064
0.103
0.066
terminal/non_trainable_ratio
1096
0.235
1.000
0.346
0.731
0.920
rollout/response_len/mean
1096
1.154
339.3
97.07
57.00
7.01
完整 summary_stats.json:
{
"wandb_run_id" : " dvu9eexe" ,
"wandb_url" : " https://wandb.ai/hansbug/openclaw-terminal-rl/runs/dvu9eexe" ,
"runtime_sec" : 161973 ,
"runtime_min" : 2699 ,
"runtime_h" : 44.99 ,
"lastStep" : 0 ,
"state" : " crashed" ,
"terminal/accuracy" : {"n" :1093 ,"min" :0.0 ,"max" :1.0 , "mean_all" :0.3487 ,"mean_first20" :0.2207 ,"mean_last20" :0.2764 },
"terminal/reward_mean" : {"n" :1093 ,"min" :-1.0 ,"max" :1.0 , "mean_all" :-0.3025 ,"mean_first20" :-0.5587 ,"mean_last20" :-0.4472 },
"rollout/raw_reward" : {"n" :1096 ,"min" :-1.0 ,"max" :1.0 , "mean_all" :-0.2611 ,"mean_first20" :-0.3565 ,"mean_last20" :-0.4917 },
"train/grad_norm" : {"n" :1107 ,"min" :0.0 ,"max" :3.8038 , "mean_all" :0.3256 ,"mean_first20" :0.8465 ,"mean_last20" :0.0083 },
"train/kl_loss" : {"n" :1107 ,"min" :0.0 ,"max" :2.4909 , "mean_all" :0.1511 ,"mean_first20" :0.0119 ,"mean_last20" :0.0726 },
"train/entropy_loss" : {"n" :1107 ,"min" :0.0 ,"max" :0.5387 , "mean_all" :0.1034 ,"mean_first20" :0.0638 ,"mean_last20" :0.0659 },
"terminal/non_trainable_ratio" :{"n" :1096 ,"min" :0.2353 ,"max" :1.0 ,"mean_all" :0.7306 ,"mean_first20" :0.346 ,"mean_last20" :0.9195 },
"rollout/response_len/mean" : {"n" :1096 ,"min" :1.1538 ,"max" :339.27 ,"mean_all" :57.0029 ,"mean_first20" :97.068 ,"mean_last20" :7.0105 }
}
6 训练阶段叙事(按时间序)
Phase A · iter 0 – 30 / 0–1.5h(冷启动)
Phase B · iter 30 – 200 / 1.5–8h(爬升 + 第一段平台)
accuracy 25 步桶在 0.30–0.49 摆动,三次跨过 0.45
raw_reward 维持 -0.20 ~ +0.10 区间
KL 短暂飙到 0.39 (25 min 内回落到 0.27),同期 reward 反而上升 → 是有效大步策略更新,不是发散
non_trainable_ratio 0.33–0.47,仍有充足学习信号
Phase C · iter 200 – 600 / 8–25h(plateau)
accuracy 桶均值长期 0.30–0.45 区间,没有持续突破峰值
raw_reward 开始系统性下滑:mean_all 从早期的 +0.05 缓慢退到 -0.20
non_trainable_ratio 慢慢从 0.4 涨到 0.7
KL 持续低位(0.10–0.20),未越过 0.3 警戒,没有发散
Phase D · iter 600 – 1000 / 25–40h(学习信号枯竭)
non_trainable_ratio 锁死 0.85–0.95:每个 batch 8 个 sample 几乎全同结果(要么全过要么全失败),advantage = 0,没梯度可回传
grad_norm 跌到 0.01 数量级,模型实际上停止更新
response_len 从 ~100 token 单调下滑到 ~30 token
Phase E · iter 1000 – 1095 / 40–45h(mode collapse + 主动停)
response_len 进一步坍缩到 ~7 token ——agent 几乎只输出空字符串 / 单个 token 的退化策略
accuracy 跌回 0.20–0.28
raw_reward 跌到 -0.50 区间
26 日 09:42 主动 kill(pkill -SIGTERM parent + ray stop --force),ckpt 守护保留 iter_0001087 + iter_0001095
最佳 ckpt 出现在 Phase A → B 转折期 (约 iter_0000127–iter_0000183,单步 accuracy 跨 0.45+ / raw_reward 翻正首例)。该段已被 ckpt retention 守护淘汰 (守护只保留最新 2 个)。这是和 issue #1 4B 跑同样的教训:outcome-only GRPO 的最佳 ckpt 出现在中前段,retention 策略需要换成"保留 best-by-eval-acc"而不是"保留最新"。
Phase C → E 的根因分析见本 issue 后续 comment ——把 wandb / 训练日志 / 源码 / dataset / rollout trace 串起来定位。
7 与 issue #1 (4B / 270 step)的对比
维度
issue #1 (4B)
本次(8B)
runtime
10 h
45 h(×4.5)
训练量
~270 wandb step / 261 rollout
1107 wandb step / 1093 rollout
accuracy 全程均值
0.345
0.349 (基本持平)
accuracy peak(25 步桶)
0.385(step 60–79)
0.45+ (iter 120–180 段,单步 1.0)
raw_reward 全程均值
-0.177
-0.261(更差)
raw_reward peak
+0.572
+1.000 (单 batch)
KL 漂移峰
0.54(279 步桶,主动停)
0.39(瞬时,自行回落)
grad_norm 末段
4.4(仍在更新)
0.008 (事实停止更新)
non_trainable 末段
n/a(无该指标)
0.92
response_len 末段
~150 token
~7 token
收尾原因
KL 漂移 0.54 主动停
non_trainable 锁死 + response 坍缩,主动停
最佳 ckpt 是否保留
否 (retention=2 淘汰)
否 (同前)
核心结论 :把 4B 跑了 270 步看到的 plateau,在 8B 上以 4× 时长走得更深,最终走到了 mode collapse ——response 从 100 token 塌缩到 7 token,accuracy 从早期峰值 0.45 跌回 0.27。这不是发散(KL 一直在合理区间,grad 单调降到 0),而是 GRPO 在稀疏 outcome 信号 + 87% non-trainable 数据下的退化吸引子 :既然几乎 ⅞ 的 prompt 拿不到学习信号,剩下 ⅛ 内出现的极端短输出(终端命令 1–2 token 就能 pytest pass 的简单题)会被反复加权,最后压垮其它行为。
issue #1 末尾对上游的建议(pin terminal-bench 版本 / --save-max-to-keep / 加大 --kl-loss-coef 或建议早停)继续成立;本次新增建议见 §9。
8 异常现象与诊断
8.1 SETA env /allocate 429 / /reset 500 风暴
训练中段(约 1h 左右)出现密集的 429 Too Many Requests 和 500 Internal Server Error 在 RolloutManager 日志里刷屏。诊断后是 SETA env 的 docker compose pool 短时拥塞,rollout 内部已重试,并未阻塞训练步。把诊断 Monitor 的 grep 收紧(去掉 Error|429|500 这些关键字,只保留 Timer train end | saving checkpoint | Killed | OOM | RayActorError | Traceback 等致命签名)即可避免噪音洗版。不是真故障,但需要在文档里说一句 (issue #1 没遇到,因为 4B 跑得短)。
8.2 grad_norm 单调下降到 0.01
4B 跑 270 步 grad_norm 仍在 4 量级,本 8B 1000+ 步后跌到 0.01 量级。直接原因是 advantage = 0 的 batch 占比 92% ——GRPO 对 advantage 用组内 z-score normalize,组内全成功或全失败时 advantage 全 0,不向上回传梯度。这不是数值错误,是数据信号问题。
8.3 response_len 从 97 → 7 token
最 surprise 的现象 。个别简单 SETA task 的 pytest pass 标准非常宽松("打印一行特定字符串"或"创建一个文件"),agent 在这部分用极短输出就能拿到 +1 reward。GRPO 在 ⅞ batch 没有信号、只有 ⅛ batch 有信号时,反复加权这些极短输出策略,长期累积压垮了其它行为模式。这是 outcome-only RL + 难度极不均匀数据集 + GRPO 的 well-known failure mode ——issue #1 4B 跑没有撞到只是因为步数不够。详见后续 comment 的实证分析。
9 给上游的建议(在 issue #1 § 8 基础上新增)
--save-max-to-keep N 或 --save-best-by <metric> :本次同样因为只保留最新 2 个 ckpt 而丢失 phase A→B 的最佳权重。slime 至今没这两个 flag。
non_trainable_ratio 早停 hook :当前 GRPO 实现下,如果 non_trainable_ratio 长期 > 0.7,训练实际上停止学习;建议默认加一个 patience-based 早停(比如连续 N 个 step 越过阈值就 abort)。
数据集难度自适应 / curriculum :SETA 1376 个任务难度极不均匀(最简单的是 echo / touch,最难的需要多步 shell + python 脚本),outcome-only 信号下天然让简单题主导梯度。建议给 terminal-rl/dataset/seta_env_convert/train.jsonl 配套一个难度分级或 reweight。
响应长度下界保护 :在 reward 上叠加一个对极短输出的轻惩罚(或 length-normalized advantage),防止 mode collapse。
README 加一条"已知失败模式"段落 ,把 §8.3 写进去——下游用户撞到 response 坍缩时无处对照。
issue 实验记录:terminal-rl Qwen3-4B GRPO outcome-only 单节点 8×H200(10h,wandb lpurziy1) #1 §8 的 5 条建议(pin terminal-bench 版本 / inspect.signature 自适应 / --save-max-to-keep / KL coef 保护 / single-node 跳过 router_server)继续成立。
10 Attachments
8 张单指标图 + 1 张 dashboard:见 §4,全部走 GitHub user-attachments CDN(无 commit / branch)
summary_stats.json:内联于 §5
完整启动脚本:run_qwen3_8b_experiment.sh (gist) (375 行,含 4 处 wrapper compat add 注释)
TL;DR
在和 issue #1 同一台 8× H200(143 GB/卡)上跑了一次
terminal-rlGRPO outcome-only(dense pass-rate reward,无 PRM、无 process reward),把模型换成 Qwen3-8B,启动脚本与上游官方terminal-rl/terminal-rl_qwen3-8b.sh在 args/算法配置上完全一致——只在 wrapper 层加了 4 处与本机环境相关的兼容补丁(conda activate /.env/LD_LIBRARY_PATH/--no-gradient-accumulation-fusion),并复用了 issue #1 列出的 7 处源码补丁(无新增)。iter_0001095,约num_rollout=2000目标的 55 %terminal/accuracy在 ~iter 120–180 段 25 步桶均值跨过 0.45(单 batch 0.59 / 全程 max=1.0),rollout/raw_reward同期翻正最高 +0.40non_trainable_ratio飙到 0.92、response_len从 97 token 塌缩到 7 token——典型的 outcome-only RL 后期 mode-collapse;issue 实验记录:terminal-rl Qwen3-4B GRPO outcome-only 单节点 8×H200(10h,wandb lpurziy1) #1 在 4B / ~270 步预演过同款 plateau,8B 在更大 step 数尺度上把这条路完整走了一遍1 期望训练结果
terminal-rl 至今没有官方公开的 expected accuracy / reward 曲线,issue #1 已经把这一点穷举调研过(arxiv/2603.10165 Table 4 terminal 行为空、blog openclawrl1 / openclawrl2 的表格也只有 GUI/tool-call、伴生 paper arxiv/2602.02488 不含 terminal、main repo
gh issue list -S "terminal"至今没有数字回复、HF Papers 讨论区也没有),不重复展开。唯一仍有指导性的参考是 Tech Report Table 4 / Table 3:
把本次 8B 全程
terminal/accuracy均值 0.349 / 峰值桶 0.45+ 对照这两条只能说:量级合理,介于 GUI outcome-only(0.31)和 GUI integrated(0.33)之间,超出 tool-call outcome-only 基线(0.17)。仍然不能判断"达标"或"不达标"——这只是没有对照组的自我度量。2 启动顺序和命令
完整可运行脚本:
run_qwen3_8b_experiment.sh(gist)。该脚本对 上游官方 8B 脚本 的修改全部为 wrapper 层环境兼容,结构(cleanup_prev → start_router → check_router → check_gpus → detect_nvlink → start_ray_head → submit_job)和算法 args 完全保持。2.1 4 处 wrapper 层 compat add
conda activate tbench-rl(set +u包围)source $REPO_ROOT/../.envWANDB_API_KEY/WANDB_PROJECT/WANDB_GROUP/WANDB_ENTITYLD_LIBRARY_PATH=$CONDA_PREFIX/lib/python3.12/site-packages/nvidia/{cudnn,nvtx,cusparse,nccl,...}/liblibcudnn_graph.so.9/ NVTX / NCCLMISC_ARGS+=( --no-gradient-accumulation-fusion )pip install -v "git+...NVIDIA/apex" --no-build-isolation --build-option="--cpp_ext" --build-option="--cuda_ext"),保留该 flag 可在 Apex 更新失败时仍能跑(性能损失约 2–3 %)diff的算法 args 部分0 行变更——其它差异都是 wrapper 默认值(HF_CKPT=/nfs/models/Qwen3-8B/REF_LOAD=.../SAVE_CKPT=.../RAY_TMPDIR=/tmp/ray_tbench_8b)。2.2 前置依赖
ckpt:
2.3 Pool server(与 issue #1 共用,不重启)
docker run -d --name openclaw_pool_server --restart unless-stopped \ -p 18081:18081 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /nfs/terminal-rl-workspace/OpenClaw-RL:/nfs/terminal-rl-workspace/OpenClaw-RL \ -e DATASET_DIR=/nfs/terminal-rl-workspace/OpenClaw-RL/terminal-rl/dataset \ -e TBENCH_OUTPUT_ROOT=/nfs/terminal-rl-workspace/OpenClaw-RL/terminal-rl/build_outputs \ -e TBENCH_DOCKER_IMAGE_SOURCE=build \ -e ENV_SERVER_PORT=18081 \ openclaw_pool_server:v1 \ bash -c "cd /nfs/terminal-rl-workspace/OpenClaw-RL && \ python -m terminal-rl.remote.pool_server --host 0.0.0.0 --port 18081 \ --max-tasks 8 --max-runs-per-task 4 \ --output-root /nfs/terminal-rl-workspace/OpenClaw-RL/terminal-rl/build_outputs"2.4 启动训练
2.5 和官方
terminal-rl_qwen3-8b.sh在算法 args 上的差异0 项——
MISC_ARGS / OPTIMIZER_ARGS / GRPO_ARGS / ROLLOUT_ARGS / DISTRIBUTED_ARGS / WANDB_ARGS / CKPT_ARGS / EVAL_ARGS / PERF_ARGS与上游terminal-rl/terminal-rl_qwen3-8b.sh完全相同(除去--no-gradient-accumulation-fusion这一条防御性附加)。3 源码修改清单
与 issue #1 完全一致的 7 处仓库内 + 1 处 site-packages 补丁(继承自上次 4B 跑,未删未改)。完整 diff 内容、必要性、不打的后果、风险都在 issue #1 §4 详细列过,这里只列汇总并在右侧标注对本次 8B + TE + 8-GPU + 装 Apex 跑法是否仍严格必需:
Megatron-LM/.../utils.py:TE 未装时is_te_min_version安全回退slime/.../initialize.py:numpy 2.x 硬 assert → warningslime/.../megatron_to_hf/qwen2.py:补 local-impl 命名slime/.../update_weight_from_distributed.py:NCCL Duplicate-GPU catchslime/.../sglang_engine.py:HTTP 端的 NCCL Duplicate-GPU catchterminal-rl/remote/docker_compose_utils.py:build(timeout=)try/excepttimeoutkwarg;不打补丁 pool_server/reset全 500terminal-rl/remote/terminal_env.py:Terminal.start(timeout=)try/exceptmbridge/models/qwen2.py(site-packages,非 git 追踪):补 local-impl mapping本次 8-GPU + TE + Apex 跑法严格必需的仍是 4.2 / 4.6 / 4.7 三条。 其它五处沿用,对当前路径 0 副作用,但 4.4 / 4.5 在生产环境应改为 env-var gate 或彻底删除。
4 关键指标曲线
单指标图(浅蓝原始 + 橙 EMA(α=0.1)):
terminal/accuracy(pytest 通过率)terminal/reward_mean(= 2·accuracy − 1)rollout/raw_reward(训练 batch 均值)train/grad_normtrain/kl_losstrain/entropy_lossterminal/non_trainable_ratio(无学习信号 group 比例)rollout/response_len/mean(agent 输出 token 数)5 全程指标统计(first20 / mean_all / last20)
terminal/accuracyterminal/reward_meanrollout/raw_rewardtrain/grad_normtrain/kl_losstrain/entropy_lossterminal/non_trainable_ratiorollout/response_len/mean完整
summary_stats.json:{ "wandb_run_id": "dvu9eexe", "wandb_url": "https://wandb.ai/hansbug/openclaw-terminal-rl/runs/dvu9eexe", "runtime_sec": 161973, "runtime_min": 2699, "runtime_h": 44.99, "lastStep": 0, "state": "crashed", "terminal/accuracy": {"n":1093,"min":0.0,"max":1.0, "mean_all":0.3487,"mean_first20":0.2207,"mean_last20":0.2764}, "terminal/reward_mean": {"n":1093,"min":-1.0,"max":1.0, "mean_all":-0.3025,"mean_first20":-0.5587,"mean_last20":-0.4472}, "rollout/raw_reward": {"n":1096,"min":-1.0,"max":1.0, "mean_all":-0.2611,"mean_first20":-0.3565,"mean_last20":-0.4917}, "train/grad_norm": {"n":1107,"min":0.0,"max":3.8038, "mean_all":0.3256,"mean_first20":0.8465,"mean_last20":0.0083}, "train/kl_loss": {"n":1107,"min":0.0,"max":2.4909, "mean_all":0.1511,"mean_first20":0.0119,"mean_last20":0.0726}, "train/entropy_loss": {"n":1107,"min":0.0,"max":0.5387, "mean_all":0.1034,"mean_first20":0.0638,"mean_last20":0.0659}, "terminal/non_trainable_ratio":{"n":1096,"min":0.2353,"max":1.0,"mean_all":0.7306,"mean_first20":0.346,"mean_last20":0.9195}, "rollout/response_len/mean": {"n":1096,"min":1.1538,"max":339.27,"mean_all":57.0029,"mean_first20":97.068,"mean_last20":7.0105} }6 训练阶段叙事(按时间序)
Phase A · iter 0 – 30 / 0–1.5h(冷启动)
Phase B · iter 30 – 200 / 1.5–8h(爬升 + 第一段平台)
Phase C · iter 200 – 600 / 8–25h(plateau)
Phase D · iter 600 – 1000 / 25–40h(学习信号枯竭)
Phase E · iter 1000 – 1095 / 40–45h(mode collapse + 主动停)
pkill -SIGTERMparent +ray stop --force),ckpt 守护保留iter_0001087+iter_0001095最佳 ckpt 出现在 Phase A → B 转折期(约
iter_0000127–iter_0000183,单步 accuracy 跨 0.45+ / raw_reward 翻正首例)。该段已被 ckpt retention 守护淘汰(守护只保留最新 2 个)。这是和 issue #1 4B 跑同样的教训:outcome-only GRPO 的最佳 ckpt 出现在中前段,retention 策略需要换成"保留 best-by-eval-acc"而不是"保留最新"。7 与 issue #1(4B / 270 step)的对比
核心结论:把 4B 跑了 270 步看到的 plateau,在 8B 上以 4× 时长走得更深,最终走到了 mode collapse——response 从 100 token 塌缩到 7 token,accuracy 从早期峰值 0.45 跌回 0.27。这不是发散(KL 一直在合理区间,grad 单调降到 0),而是 GRPO 在稀疏 outcome 信号 + 87% non-trainable 数据下的退化吸引子:既然几乎 ⅞ 的 prompt 拿不到学习信号,剩下 ⅛ 内出现的极端短输出(终端命令 1–2 token 就能 pytest pass 的简单题)会被反复加权,最后压垮其它行为。
issue #1 末尾对上游的建议(pin terminal-bench 版本 /
--save-max-to-keep/ 加大--kl-loss-coef或建议早停)继续成立;本次新增建议见 §9。8 异常现象与诊断
8.1 SETA env
/allocate429 //reset500 风暴训练中段(约 1h 左右)出现密集的
429 Too Many Requests和500 Internal Server Error在 RolloutManager 日志里刷屏。诊断后是 SETA env 的 docker compose pool 短时拥塞,rollout 内部已重试,并未阻塞训练步。把诊断 Monitor 的 grep 收紧(去掉Error|429|500这些关键字,只保留Timer train end | saving checkpoint | Killed | OOM | RayActorError | Traceback等致命签名)即可避免噪音洗版。不是真故障,但需要在文档里说一句(issue #1 没遇到,因为 4B 跑得短)。8.2 grad_norm 单调下降到 0.01
4B 跑 270 步 grad_norm 仍在 4 量级,本 8B 1000+ 步后跌到 0.01 量级。直接原因是 advantage = 0 的 batch 占比 92%——GRPO 对 advantage 用组内 z-score normalize,组内全成功或全失败时 advantage 全 0,不向上回传梯度。这不是数值错误,是数据信号问题。
8.3 response_len 从 97 → 7 token
最 surprise 的现象。个别简单 SETA task 的 pytest pass 标准非常宽松("打印一行特定字符串"或"创建一个文件"),agent 在这部分用极短输出就能拿到 +1 reward。GRPO 在 ⅞ batch 没有信号、只有 ⅛ batch 有信号时,反复加权这些极短输出策略,长期累积压垮了其它行为模式。这是 outcome-only RL + 难度极不均匀数据集 + GRPO 的 well-known failure mode——issue #1 4B 跑没有撞到只是因为步数不够。详见后续 comment 的实证分析。
9 给上游的建议(在 issue #1 § 8 基础上新增)
--save-max-to-keep N或--save-best-by <metric>:本次同样因为只保留最新 2 个 ckpt 而丢失 phase A→B 的最佳权重。slime 至今没这两个 flag。non_trainable_ratio长期 > 0.7,训练实际上停止学习;建议默认加一个 patience-based 早停(比如连续 N 个 step 越过阈值就 abort)。echo/touch,最难的需要多步 shell + python 脚本),outcome-only 信号下天然让简单题主导梯度。建议给terminal-rl/dataset/seta_env_convert/train.jsonl配套一个难度分级或 reweight。inspect.signature自适应 /--save-max-to-keep/ KL coef 保护 / single-node 跳过 router_server)继续成立。10 Attachments
user-attachmentsCDN(无 commit / branch)summary_stats.json:内联于 §5run_qwen3_8b_experiment.sh(gist)(375 行,含 4 处 wrapper compat add 注释)