Files
Qwen3-30B-A3B-OpenClaw-RL-i…/README.md
ModelHub XC f1e869b047 初始化项目,由ModelHub XC社区提供模型
Model: HansBug/Qwen3-30B-A3B-OpenClaw-RL-iter335
Source: Original Platform
2026-09-26 19:24:01 +08:00

315 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
license: apache-2.0
base_model: Qwen/Qwen3-30B-A3B
tags:
- qwen3
- qwen3-moe
- terminal-agent
- reinforcement-learning
- grpo
- camel-ai
- openclaw-rl
- agent
- terminal-bench
- moe
library_name: transformers
language:
- en
- zh
pipeline_tag: text-generation
---
# Qwen3-30B-A3B-OpenClaw-RL-iter335
把 [`Qwen/Qwen3-30B-A3B`](https://huggingface.co/Qwen/Qwen3-30B-A3B) (vanilla, 30B total / 3B active MoE) 用 [`HansBug/OpenClaw-RL`](https://github.com/HansBug/OpenClaw-RL) 的训练框架做 **GRPO outcome-only RL**(dense pass-rate reward,无 PRM、无 process reward)跑出来的 **best 中间 checkpoint**,对应 [wandb run `b0il0mq4`](https://wandb.ai/hansbug/openclaw-terminal-rl/runs/b0il0mq4) 的 rollout 335 (megatron iteration 335)。
在 [`terminal-bench` v0.1.x](https://github.com/laude-institute/terminal-bench/tree/v0.1.x) 66 个 OOD task 上把 base Qwen3-30B-A3B 的 pass@1 从 0.0606 推到 **0.0808** (+33%)、pass@3 从 0.1212 推到 **0.1515** (+25%),是这次 30B fresh run 训练中**唯一明确"超越自身 base"的 ckpt**。
> **完全 drop-in 兼容**:config / generation_config / tokenizer 全部跟上游 `Qwen/Qwen3-30B-A3B` 字节级一致;任何能跑 Qwen3-30B-A3B 的工具链(HF transformers、vLLM、sglang、ollama、llama.cpp 转 GGUF 等)**一行都不用改**。
完整的训练 + eval 详细分析见 [`HansBug/OpenClaw-RL` issue #14](https://github.com/HansBug/OpenClaw-RL/issues/14)。
---
## 目录
1. [快速开始](#快速开始)
2. [模型从哪来](#模型从哪来)
3. [训练设置](#训练设置)
4. [训练曲线](#训练曲线)
5. [评测结果](#评测结果)
6. [为什么是 iter_335 而不是最新 ckpt](#为什么是-iter_335-而不是最新-ckpt)
7. [推理时的 on-the-wire 协议](#推理时的-on-the-wire-协议)
8. [已知限制](#已知限制)
9. [复现 / 推理工具](#复现--推理工具)
10. [引用 / 致谢](#引用--致谢)
---
## 快速开始
### 用 HF `transformers`
```python
from transformers import AutoTokenizer, AutoModelForCausalLM
tok = AutoTokenizer.from_pretrained("HansBug/Qwen3-30B-A3B-OpenClaw-RL-iter335")
model = AutoModelForCausalLM.from_pretrained(
"HansBug/Qwen3-30B-A3B-OpenClaw-RL-iter335",
torch_dtype="bfloat16",
device_map="auto",
)
messages = [
{"role": "user", "content": "Write a one-line bash command to recursively count *.py files under /usr/lib."}
]
text = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tok(text, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=256, temperature=0.2)
print(tok.decode(out[0][inputs.input_ids.shape[1]:], skip_special_tokens=True))
```
### 用 sglang(推荐,配 tool-call 支持 + MoE 加速)
```bash
python -m sglang.launch_server \
--model-path HansBug/Qwen3-30B-A3B-OpenClaw-RL-iter335 \
--served-model-name qwen3-30b-rl-iter335 \
--tp 4 --port 30000 \
--mem-fraction-static 0.85 \
--tool-call-parser qwen \
--disable-custom-all-reduce
```
跟 base Qwen3-30B-A3B 一样的启动参数。TP=4 时 30B MoE 单 rank ~15 GB params + ~120 GB kv cache,放 4× 80 GB GPU 或 4× 143 GB GPU 都没问题。`--disable-custom-all-reduce` 是 [issue #8](https://github.com/HansBug/OpenClaw-RL/issues/8) 已知 Hopper bug 的兜底 flag,保留即可。`--tool-call-parser qwen`(或 `qwen25`)把模型的 `<tool_call>{...}</tool_call>` 还原成 OpenAI 结构化 `tool_calls`,这正是训练时 rollouts 用的 parser。
### 用 vLLM
```bash
vllm serve HansBug/Qwen3-30B-A3B-OpenClaw-RL-iter335 \
--tensor-parallel-size 4 \
--enable-auto-tool-choice --tool-call-parser hermes
```
### 用 oc-repl 直接交互(端到端 demo)
[`HansBug/oc-repl`](https://github.com/HansBug/oc-repl) 是一个针对这个 family 量身写的 Codex 风格 REPL:
```bash
pip install git+https://github.com/HansBug/oc-repl
# 起一个 sandbox 容器(任何 ubuntu/python image 都行)
docker run -d --name oc-sandbox -w /app ubuntu:24.04 sleep infinity
# 启动交互式 REPL
oc-repl --sandbox docker:oc-sandbox \
--api-base http://127.0.0.1:30000/v1 \
--model qwen3-30b-rl-iter335
```
oc-repl 默认 `--protocol camel-terminal-toolkit` 对齐训练分布,详见仓库 README。
---
## 模型从哪来
`Qwen3-30B-A3B-OpenClaw-RL-iter335` = `Qwen3-30B-A3B` (vanilla, **不是** Coder-30B-A3B-Instruct,也**不是** 30B-A3B-Instruct-2507) + **335 个 RL rollout** 的 GRPO outcome-only 训练,rollout 在 [SETA terminal env pool](https://github.com/camel-ai/seta) 提供的 **1376 个 terminal task** 上。每个 task 是一个真实的 Linux shell 任务(修脚本、解 base64、起 server、跑 pytest…),在隔离 docker 容器里跑,agent 通过 [`camel.toolkits.TerminalToolkit`](https://docs.camel-ai.org/key_modules/terminaltoolkit) 暴露的 4 个工具操作 shell。
| | 值 |
|---|---|
| 基座 | [`Qwen/Qwen3-30B-A3B`](https://huggingface.co/Qwen/Qwen3-30B-A3B)(**vanilla** MoE,30B total / 3B active,128 expert / topk=8 / 48 layer / hidden 2048)|
| 训练框架 | [`HansBug/OpenClaw-RL`](https://github.com/HansBug/OpenClaw-RL) (Megatron + slime + sglang rollout) |
| Agent harness | [camel-ai `ChatAgent` + `TerminalToolkit`](https://docs.camel-ai.org/key_modules/terminaltoolkit) |
| 数据 | [seta_env](https://github.com/camel-ai/seta) 1376 task pool(含 [terminal-bench](https://github.com/laude-institute/terminal-bench) v0.1.x 86 task 子集) |
| 算法 | GRPO outcome-only,dense pass-rate reward |
| 训练 rollout 数 | 335 rollout(约 4× n_samples × prompt 数) |
| 训练硬件 | 8× NVIDIA H200,actor 4×TP + 4×EP + ETP=1,rollout 4×TP |
| 训练时长 | 约 4 天到 iter_335 完成(完整 fresh run 直到 iter_367 共 ~5.5 天 / 367 rollout)|
| Wandb | [`hansbug/openclaw-terminal-rl/runs/b0il0mq4`](https://wandb.ai/hansbug/openclaw-terminal-rl/runs/b0il0mq4) |
| Group | `qwen3-30b-a3b-vanilla-fresh-run1` |
**为什么是 vanilla 而不是 Coder-30B-A3B-Instruct?** 初次用 Coder-30B-A3B-Instruct 跑了 1114 个 rollout 全 fail —— 它的 `chat_template.jinja` 用 `tool_call.arguments|items` 要求 `arguments` 是 dict,但 slime/sglang 走 OpenAI 协议把 `arguments` 序列化成 JSON string → jinja2 `TypeError`。vanilla `Qwen3-30B-A3B` 的 chat_template 与 8B 字节级相同,整条 slime + terminus-2 + harbor 链路 0 修改通过。详见 [`HansBug/OpenClaw-RL` issue #14 §1.1](https://github.com/HansBug/OpenClaw-RL/issues/14)。
---
## 训练设置
完整启动命令见 [`run_qwen3_30b_a3b_experiment.sh`](https://github.com/HansBug/OpenClaw-RL/blob/main/terminal-rl/run_qwen3_30b_a3b_experiment.sh)。关键超参(与 8B run-3 算法侧完全相同,仅 MoE 并行差异):
```bash
# GRPO 算法 (同 8B run-3, issue #4)
--advantage-estimator grpo
--use-kl-loss --kl-loss-coef 0.01 --kl-loss-type k3
--dynamic_history
# Optimizer (low LR + Adam beta2=0.98)
--optimizer adam --lr 1e-6 --lr-decay-style constant
--weight-decay 0.1 --adam-beta1 0.9 --adam-beta2 0.98
# Rollout (同 8B)
--rollout-batch-size 16
--n-samples-per-prompt 8 # GRPO group size = 8
--num-steps-per-rollout 2
--rollout-temperature 1
--rollout-max-response-len 8192
--rollout-max-context-len 16384
# Megatron — MoE 并行(与 8B 不同)
--tensor-model-parallel-size 4
--expert-model-parallel-size 4 # 128 expert 分到 4 张 actor 卡,每卡 32 expert
--expert-tensor-parallel-size 1
--sequence-parallel
--recompute-granularity full
# Save / freq
--save-interval 16 # save 每 16 rollout(≈ 5.3h/save)
--num-rollout 2000 # 训练目标(实际跑到 367 停)
# Rollout agent + tool-call parser
--custom-config-path configs/rollout_qwen3.yaml # tool_call_parser: qwen25
# max_iteration: 10
```
Reward signal:**dense pass-rate, outcome-only** —— 每个 rollout 跑完后由任务自带的 `run-tests.sh` 在 sandbox 里跑 pytest,`reward = passed / total_tests ∈ [0, 1]`,再线性变换到 `score = 2·reward − 1 ∈ [-1, +1]` 喂给 GRPO;**没有 PRM / process reward**,整个 episode 共用一个标量。
`max_iteration: 10`:训练时 agent loop 上限 10 轮。
---
## 训练曲线
来自 [wandb run b0il0mq4](https://wandb.ai/hansbug/openclaw-terminal-rl/runs/b0il0mq4):
![training curves](training_curves.png)
六个子图说明:
| 子图 | 解读 |
|---|---|
| **raw_reward** | rollout 阶段 reward 均值。-0.07 (rollout 0-49) → +0.21 (rollout 320-335) 单调上升。**穿越 0 出现在 rollout 50 左右**,即模型从"过的 test < 一半"转向"过的 test > 一半"。iter_335 这个 ckpt 对应的训练窗口 raw_reward 均值 **+0.21**,比 base 提升 ~0.28。|
| **response_length** | 每轮 assistant 输出的平均 token 数。从 217 涨到 413,**单调上升、没有 plateau**——是 30B 远未到达容量上限的关键信号(vs 8B run-3 后期横盘 300-400)。|
| **grad_norm** | 梯度幅度(log 尺度)。median 0.30-0.50 健康,期间 5 次单步 spike(最大 step 38 grad=1.36e8 / kl=5.6e5),全部被 megatron `--clip-grad 1.0` 兜底,下一步即恢复。|
| **kl_loss** | K3 KL estimator。median 0.05-0.15 健康,远低于 0.5 阈值。spike 与 grad_norm 同步出现,clip-grad 同样吸收。|
| **entropy_loss** | 0.13-0.17 持续,无 collapse。|
| **pg_clipfrac** | PPO clip 比例 ~0.6%(合理)。|
详细的训练曲线、异常事件分析、vs 8B run-3 叠加图见 [`HansBug/OpenClaw-RL` issue #14](https://github.com/HansBug/OpenClaw-RL/issues/14)。
---
## 评测结果
### 在 terminal-bench v0.1.x(66-task harbor 子集)上的 pass@1 / pass@3
iter_335 这个 ckpt 在 OOD eval(agent harness 切到 `harbor run --agent terminus-2`,与 [issue #8](https://github.com/HansBug/OpenClaw-RL/issues/8) 8B run-3 同协议)上的成绩:
![eval pass rate](eval_pass_rate.png)
| Model | pass@1 | pass@3 | unique solved (/66) | solved trials (/198) |
|---|---:|---:|---:|---:|
| `qwen3-30b-a3b-base` (vanilla) | 0.0606 | 0.1212 | 8 | 12 |
| **`qwen3-30b-a3b-OpenClaw-RL-iter335`**(本 ckpt) | **0.0808** ✨ | **0.1515** ✨ | **10** | **16** |
| `qwen3-30b-a3b-OpenClaw-RL-iter351` (later) | 0.0556 ⚠ | 0.0758 ⚠ | 5 | 11 |
| `qwen3-30b-a3b-OpenClaw-RL-iter367` (final) | 0.0657 | 0.1212 | 8 | 13 |
**iter_335 是这次 fresh run 中唯一 pass@1 / pass@3 / unique_solved 三项全部超过 base 的 ckpt**。iter_351 在中间出现明显回落(甚至跌穿 base),iter_367 部分恢复但仍未回到 iter_335 峰。详细分析见 [issue #14 eval comment](https://github.com/HansBug/OpenClaw-RL/issues/14#issuecomment-4537976268)。
### vs 8B run-3([issue #8](https://github.com/HansBug/OpenClaw-RL/issues/8) 同 66-task 标尺)
![leaderboard](leaderboard.png)
| Model | pass@1 | pass@3 | 体量 | 备注 |
|---|---:|---:|---|---|
| **Qwen3-30B-A3B-OpenClaw-RL-iter335**(本 ckpt) | **0.081** | **0.152** | 30B / 3B active MoE | **本 ckpt** |
| Qwen3-30B-A3B (vanilla base) | 0.061 | 0.121 | 30B / 3B active | 训练起点 |
| Qwen3-8B-OpenClaw-RL-iter215 ([issue #8](https://github.com/HansBug/OpenClaw-RL/issues/8)) | 0.056 | 0.091 | 8B dense | 8B run-3 OOD 峰 |
| Qwen3-8B (base) | 0.020 | 0.030 | 8B dense | 8B 起点 |
| Qwen3-235B-A22B + Terminus 1 | 0.066 | n/a | 235B / 22B active | TB 官方 80-task |
| DeepSeek-R1 + Terminus 1 | 0.057 | n/a | 671B / 37B active | TB 官方 80-task |
| Qwen3-32B + TerminalAgent | 0.155 | n/a | 32B dense | TB 官方 80-task |
| Claude 4.5 Sonnet | 0.645 | n/a | 闭源 | frontier |
| GPT-5 | 0.525 | n/a | 闭源 | frontier |
> 注:本 ckpt 跑的是 66-task 子集([harbor migration 失败 20 task](https://github.com/HansBug/OpenClaw-RL/issues/8) 后剩下的可跑部分),与 leaderboard 80-task 全集**不可直接横比**;但唯一靠谱的同标尺对比是与 issue #8 同样 66 子集的 Qwen3-8B 数字,本 ckpt 的 pass@1 = 0.081 比 Qwen3-8B-iter215 (0.056) 高 **44%**。
### 任务级别的 OOD 解题分布
![per-task heatmap](per_task_heatmap.png)
14 个 task 在所有 4 个 ckpt × 3 attempt 中至少被解出 1 次,其余 52 task 全部 0 solved(与 [issue #8](https://github.com/HansBug/OpenClaw-RL/issues/8) 60/66 全 0 同 pattern)。iter_335 独占解出的 task:`csv-to-parquet`、`path-tracing-reverse`、`processing-pipeline 2x`。
---
## 为什么是 iter_335 而不是最新 ckpt
完整 30B fresh run 跑到 iter_367 停(rollout 367 ≈ 训练 4.5 天),按 retention daemon 配置仅保留 latest 3 ckpt:iter_335 / iter_351 / iter_367。所有 4 个候选(含 base)都在 TB v0.1.x 跑过 OOD eval,得到的训练→OOD 轨迹是:
| ckpt | rollout | in-domain raw_reward (训练侧) | OOD pass@1 | 训练→OOD 是否对齐? |
|---|---:|---:|---:|---|
| base | — | — | 0.0606 | — |
| **iter_335** | **335** | **+0.21** | **0.0808** ✨ | ✅ 训练 ↑ + OOD ↑ |
| iter_351 | 351 | +0.18(含全局峰 r346 +0.5651) | 0.0556 | ❌ 训练保持高位但 OOD 跌穿 base |
| iter_367 | 367 | +0.232(最高窗口均值) | 0.0657 | ❌ 训练 ↑ 但 OOD 没跟上 |
iter_335 是这次训练**唯一明确"训练侧 ↑ + OOD ↑"的 ckpt**。这是 [issue #8 iter215](https://github.com/HansBug/OpenClaw-RL/issues/8)(8B run-3 也在中段 ckpt 拿 OOD 峰,最后回落)同款现象。如果你要拿一个最有可能在新 OOD task 上 work 的 30B fresh-run ckpt,**应该用这个 iter_335**,不要用最新的 iter_367。
---
## 推理时的 on-the-wire 协议
**训练时这个 ckpt 看到的协议是 [camel-ai `TerminalToolkit`](https://docs.camel-ai.org/key_modules/terminaltoolkit) 的 4 工具 OpenAI function-calling**(与 [`Qwen3-8B-OpenClaw-RL-iter215`](https://huggingface.co/HansBug/Qwen3-8B-OpenClaw-RL-iter215) 完全相同),**不是** terminal-bench 的 `terminus-2` JSON 协议。
| 文件 | 说明 |
|---|---|
| [`terminal-rl/agent/camel_agent.py`](https://github.com/HansBug/OpenClaw-RL/blob/main/terminal-rl/agent/camel_agent.py) | rollout agent = `camel.agents.ChatAgent` 子类 |
| [`terminal-rl/remote/terminal_env.py`](https://github.com/HansBug/OpenClaw-RL/blob/main/terminal-rl/remote/terminal_env.py) | env 在 reset 时把 `camel.toolkits.TerminalToolkit` 的 4 个工具(`shell_exec` / `shell_view` / `shell_write_to_process` / `shell_write_content_to_file`)封装成 OpenAI tool schema 喂给 rollout |
| [`terminal-rl/configs/rollout_qwen3.yaml`](https://github.com/HansBug/OpenClaw-RL/blob/main/terminal-rl/configs/rollout_qwen3.yaml) | `tool_call_parser: qwen25` — sglang 把模型 `<tool_call>{...}</tool_call>` markup 转回 OpenAI tool_calls |
System prompt 是 [`terminal-rl/agent/camel_agent.py::get_developer_agent_prompt()`](https://github.com/HansBug/OpenClaw-RL/blob/main/terminal-rl/agent/camel_agent.py) 在 `system='Linux (in Docker)', machine='x86_64', non_think_mode=True` 配置下产出,结尾加 `/no_think` 关闭 qwen3 的 think trace。
如果你想 100% 复刻训练分布在 inference 用这个 ckpt,用 [`HansBug/oc-repl`](https://github.com/HansBug/oc-repl) 的默认 `--protocol camel-terminal-toolkit`。
---
## 已知限制
1. **30B 在 OOD 上的 RL 边际收益比 8B 小**。本 ckpt vs 30B base:pass@1 +33%;[Qwen3-8B-iter215](https://huggingface.co/HansBug/Qwen3-8B-OpenClaw-RL-iter215) vs Qwen3-8B base 是 +180%。如果你的目标是 frontier OOD 性能,纯 RL 已经 saturating,需要换 cold-start SFT。这与 [issue #11 容量假说](https://github.com/HansBug/OpenClaw-RL/issues/11) 一致。
2. **iter_351 / iter_367 的存在说明 RL 训练后期有 OOD 漂移风险**。iter_335 是这次训练全 4 ckpt 中唯一 net-positive 的;更晚的 iter_351 反而跌穿 base。如果你打算复现这个训练 pipeline,建议把 ckpt freeze 频率提高,每 50-100 rollout 都做 OOD eval 看 trajectory。
3. **模型不会主动停止 tool_call**。训练时 agent loop 由 `max_iteration: 10` 硬截断 + outcome reward 兜底,inference 时要自己设上限([oc-repl 默认 12 轮](https://github.com/HansBug/oc-repl/blob/main/src/oc_repl/engine.py))。
4. **复杂多步 task adherence 中等**。简单任务(chmod、cat、ls)adherence 满分;多文件 Python 服务器、复杂 awk 这种偶尔会 thinking 太久没产出 tool_call。
5. **terminus-2 / terminus-XML 协议是 OOD**。模型没在这些协议上 RL 训练过,能不能跑通靠 qwen3 底座的通用指令跟随能力。要复刻训练分布请用 camel TerminalToolkit 协议。
6. **不是 frontier 水平**。pass@1 0.081 跟 Qwen3-235B 同水位(甚至略高),但跟 Claude 4.5 / GPT-5 还有 6-8× 差距。这个 ckpt 适合做 RL 训练框架的 baseline / case study / MoE base 上 RL 的对比基准,不适合直接当 production agent 用。
---
## 复现 / 推理工具
| 仓库 / 工具 | 用途 |
|---|---|
| [`HansBug/OpenClaw-RL`](https://github.com/HansBug/OpenClaw-RL) | 完整的训练框架(slime + Megatron + sglang),含 launch script、配置、agent code |
| [`HansBug/oc-repl`](https://github.com/HansBug/oc-repl) | 针对这个 family ckpt 的 Codex 风格 REPL,支持 4 种推理协议 (`camel-terminal-toolkit` 默认 = 训练分布字节级复刻) |
| [`HansBug/Qwen3-8B-OpenClaw-RL-iter215`](https://huggingface.co/HansBug/Qwen3-8B-OpenClaw-RL-iter215) | **同 family** 的 8B ckpt(base = Qwen3-8B),用于 same-protocol 同标尺横比 |
| [`HansBug/Qwen3-8B-OpenClaw-RL-tboverfit-iter311`](https://huggingface.co/HansBug/Qwen3-8B-OpenClaw-RL-tboverfit-iter311) | 同 family 的 8B eval-as-train 上界 probe ckpt |
| [`HansBug/OpenClaw-RL` issue #14](https://github.com/HansBug/OpenClaw-RL/issues/14) | 本 ckpt 的完整训练 + eval 报告(118h 训练曲线 + 4 ckpt OOD eval + vs 8B 对比) |
| [`HansBug/OpenClaw-RL` issue #4](https://github.com/HansBug/OpenClaw-RL/issues/4) | 8B run-3 训练报告(同算法 / 同 dataset / 同 lr,仅 base 模型不同) |
| [`HansBug/OpenClaw-RL` issue #8](https://github.com/HansBug/OpenClaw-RL/issues/8) | 8B run-3 在 TB v0.1.x 66-task 的同标尺 OOD eval(本 ckpt eval 完全复用了该协议) |
---
## 引用 / 致谢
- 基座:[`Qwen/Qwen3-30B-A3B`](https://huggingface.co/Qwen/Qwen3-30B-A3B)(Apache-2.0,vanilla 版,2025-04 release)
- 训练框架:[`HansBug/OpenClaw-RL`](https://github.com/HansBug/OpenClaw-RL)
- Agent harness:[`camel-ai/camel`](https://github.com/camel-ai/camel) [`TerminalToolkit`](https://docs.camel-ai.org/key_modules/terminaltoolkit)
- Eval benchmark:[`laude-institute/terminal-bench`](https://github.com/laude-institute/terminal-bench)
- Rollout 训练数据 pool:[`camel-ai/seta`](https://github.com/camel-ai/seta) 1376 task
License: Apache-2.0(继承自 Qwen3-30B-A3B)。
如果你用这个 ckpt 做 paper / blog post,欢迎引用 [`HansBug/OpenClaw-RL`](https://github.com/HansBug/OpenClaw-RL) 仓库 + 这个 model card。