转载自公众号:敢敢AUTOHUB
简介
RLT 的目标很直接:冻结大模型,只训练小控制头。VLA 继续负责理解视觉、语言和粗略动作,一个轻量 actor-critic 网络只负责在关键阶段修正动作。两者中间的桥,是一个从 VLA 表征中蒸馏出来的 RL Token。进一步看,这不是把强化学习硬塞进 VLA,而是把 VLA 变成一个稳定的状态编码器,让在线 RL 只在小空间里做局部搜索。
如果你关注 VLA、机器人操作或真机强化学习,这篇文章能帮你回答三个问题:为什么大模型在最后几毫米容易失败;为什么直接微调整个 VLA 很贵;以及如何用 RLT 把泛化能力和在线学习效率同时保住。这里的重点是结构选择,不是又换一个更大的骨干网络,而是重新划分“谁负责理解”和“谁负责控制”。
1. 问题背景
1.1 VLA 的能力边界
VLA 模型把视觉、语言和动作放进同一个策略里,擅长从大规模示教数据中学出多种操作技能。OpenVLA、RT-2、π0 这类工作已经说明,多模态预训练能带来明显的泛化能力。可是当任务进入接触丰富、位姿敏感、误差只有几毫米的阶段,模型常常变慢、停顿、重试,甚至因为小误差累积而失败。
1.2 最后几毫米的失败模式
这里的关键是,模仿学习上限受示教分布限制。示教者如果本身动作慢、保守或带犹豫,模型学到的也会是同样的行为。进一步看,示教数据往往缺少失败后的恢复策略,一旦真实环境偏离训练分布,策略就没有可靠的价值信号来判断“现在该加速、微调还是重试”。
难点提示:VLA 的失败常不是“看不懂”,而是“最后一步控不稳”。
2. 核心思想
2.1 RLT 是什么
RLT 是一个从 VLA 表征中抽出的 token。它保留了 VLA 对图像、语言和动作历史的理解,却不再让 VLA 参与在线梯度更新。换句话说,RLT 是一个压缩后的任务状态向量,既不是普通视觉特征,也不是最终动作,而是连接两个模型的中间表征。这个设计把泛化能力和学习效率拆开:大模型负责提供稳定表征,小网络负责快速试错。
2.2 为什么能保住泛化
直观理解是,冻结 VLA 等于把一个已经学好的视觉-语言-动作先验固定住。在线 RL 只在轻量 actor-critic 上更新,不会因为少量真机数据把大模型带偏,也避免了大网络在稀疏奖励下反复震荡。这意味着,泛化来自预训练,精度来自在线微调,两者不再互相牺牲,而是各自承担最擅长的部分。
工程价值
3. RLT 的构造
3.1 从 VLA 表征到 RL Token
设 VLM 末层 token 序列为 ,其中每个 token 都已经携带了图像、语言或动作块的部分上下文信息, 表示序列长度。为了把多模态上下文压成一个可供强化学习使用的状态向量,追加一个可学习查询嵌入 ,得到增强序列:
这一步把离散的多模态信息变成一个连续、低维、适合值函数估计的状态。
其中 的作用类似一个专门的查询位,它会在注意力过程中主动读取其他 token 的任务相关信息,而不是被动等待特征拼接。一个轻量 transformer 编码器对 做自注意力,使查询位与视觉、语言和历史动作 token 逐层交互,最终取查询位的输出作为 RLT:
由于查询位被固定放在序列末尾,编码器可以直接从其余 token 中聚合与任务相关的上下文。
这里的关键是, 融合了视觉、语言与动作历史中的任务相关信息,而不是只看当前帧。对于接触式操作来说,这种时序上下文很重要,因为末端姿态是否合理往往取决于前几步的接近方向、夹爪开合程度和物体接触状态。
因此,RLT 更像“当前局面的摘要”,而不是单帧图像特征。
3.2 重构训练与冻结
RLT 训练采用重构损失,目标是让压缩后的 token 仍然保留足够多的原始信息,避免表征在压缩过程中丢掉任务关键细节。解码器以 和被遮蔽或截断的 token 作为输入,试图重构原始 token 序列:
如果重构误差持续降低,说明单 token 足以携带完成任务所需的关键信息。
其中 表示梯度不回传给 VLA,VLA 只被当作固定的特征提取器使用,编码器自身的参数仍然可以学习。训练完成后,VLA 主干和 RLT 编码器一起冻结,后续只更新 actor-critic。这种做法让 RLT 保持稳定,不会随着 RL 的小批量数据漂移,也降低了部署阶段的计算负担。
直觉理解:先让 token 学会“看懂局面”,再让小网络学“怎么出手”。
4. Actor-Critic 在线学习
4.1 状态拼接
RL Token 不是直接当动作用,而是和机器人本体状态 拼接成强化学习状态。这样做的目的是把“任务理解”与“实时控制”分开,避免让小网络重新学习一遍视觉和语言表征,同时保留机器人自身的精确物理状态:
这样既降低了输入维度,也避免了视觉编码器在真机训练阶段继续漂移。
这意味着,策略看到的是“VLA 理解后的任务状态 + 机器人实时状态”。视觉和语言被压进 ,关节、夹爪或末端位姿则保留原始物理量,使 critic 既能判断任务语义,也能感知机器人在物理空间中的真实位置、速度和接触状态。
对精细插入类任务而言,末端速度和接触状态往往比全局场景更影响成败。
4.2 Critic 的 TD 目标
Critic 使用标准的时序差分目标来估计当前状态-动作对的长期价值,而不是只看单步奖励。对回放缓冲区中的样本,目标值由即时奖励和下一时刻的价值估计共同组成:
这个目标可以把稀疏的最终奖励转化为逐步可学习的价值估计。
这种做法也使策略能够从失败 episode 中恢复出有用的梯度信号。
其中 是折扣因子,控制未来奖励在当前价值中的权重; 是终止标志,用来避免把终止后的价值继续折回当前估计。对应的 TD 损失为:
当 episode 结束时,下一项价值被屏蔽,避免把终止后的虚拟状态纳入估计。
因此,终止边界会被显式写进目标值,而不是留给网络自行猜测。
奖励采用稀疏形式,只在 episode 结束时判断任务是否成功,中间步骤不提供逐步人工打分,也不要求设计复杂的进度奖励:
这让奖励定义保持简单,也减少了对人工进度标签的依赖。对工业场景来说,这种奖励形式比稠密人工进度奖励更容易维护。它也更接近任务验收的真实标准。
且任务成功其他
这里的关键是,只有最终成败才给信号,中间过程靠 critic 学出长期价值。这种设计减少了奖励工程和人工标注量,但也把学习压力转移到了价值函数的泛化能力和样本效率上。如果 value function 学得足够准,策略就能在稀疏奖励下稳定改进。换句话说,系统只需要知道任务有没有完成,而不需要知道每一步做得好不好。
4.3 Actor 的局部动作编辑
Actor 不是从零搜索高维动作块,而是围绕 VLA 给出的参考动作 做局部修正。这种设计保留了 VLA 的动作先验,同时允许策略在关键阶段偏离参考动作,以获得更高的长期价值。一个典型目标是:这类局部搜索比在连续高维空间中随机探索更符合真机安全约束。
其中 控制偏离参考动作的强度,值越大,策略越倾向于保持 VLA 的原始动作。当 critic 变准后,策略会在偏离能提高价值时主动偏离参考动作;当偏离无益或风险较高时,则回到 VLA 的稳定先验,避免无意义的探索。这也解释了为什么 RLT 能在小样本真机环境中快速收敛。
4.4 一步步看 RLT 怎么跑
把第四节拆开看,RLT 的执行链路其实很清楚。第一步,冻结的 VLA 先把图像和指令编码成一串末层 token;第二步,系统在末尾追加一个可学习的查询 token,让轻量 transformer 编码器把多模态上下文压缩成一个 RLT;第三步,RLT 和机器人本体状态拼接,形成 actor-critic 的输入状态;第四步,VLA 同时输出一个参考动作块,actor 只在这个参考附近做局部修正;第五步,环境执行修正后的动作,并把转移存入经验回放;第六步,critic 用 TD 目标学长期价值,actor 用价值最大化加参考动作约束来更新;第七步,训练时随机丢弃一部分参考动作,避免 actor 只学会照抄 VLA。
这条链路里最容易被忽略的一点是:VLA 和 actor-critic 的更新是解耦的。VLA 不参与在线梯度更新,RLT 编码器在预训练后也被冻结,真正在线学习的只有轻量 actor-critic。因此,系统既能保留 VLA 从大规模数据中学到的泛化能力,又能获得在线强化学习需要的样本效率和更新速度,不会因为少量真机数据把大模型带偏。
5. 训练流程
5.1 三阶段流程
整体流程可以概括为三步:先在小型示教数据上训练 RLT 表示,再冻结 VLA 主干和 RLT 编码器,最后在真机环境中在线训练 actor-critic,并同时采集新的交互经验。三阶段之间的边界清楚,便于分别诊断表征质量和控制性能;本地仓库的实际数据配置见第 7.4 节。
这也是它与常见的端到端联合微调方案最明显的差别。
这里的关键是,VLA 输出的是参考动作块,不是最终动作。actor-critic 在这个参考附近做在线修正,避免高维动作空间里的无约束探索,也减少了真机试错带来的安全风险、样本浪费和不可逆失败。因此,VLA 的动作先验既是搜索起点,也是一种安全护栏。当 critic 的估计趋于稳定后,这种护栏会逐渐从硬约束变成软先验。
5.2 人工干预与切换
训练阶段可以引入人工干预:基础 VLA 先执行简单部分,人类在困难阶段把控制权交给 RL 策略。随后系统继续执行,直到人类给出成功或失败的终止信号。这相当于用弱监督标注关键区段,而不是为每一步动作手工打分,既保留了人工判断的可靠性,又避免了密集标注的高成本。
解读:人工不是替模型写奖励函数,而是帮系统圈出“哪里值得学”。
6. 推理流程
6.1 粗阶段与精阶段
推理时,VLA 负责粗略动作,RL 策略只在关键阶段接管。具体切换可以由一个额外的门控模块完成。训练结束时,对 VLA 做一次轻微微调,让它额外预测“何时应移交给强化学习策略”。这样,系统不需要每次都依赖人工触发,也能在任务流程中自动区分简单阶段和困难阶段。
def infer(obs):
handoff = vla.predict_handoff(obs)
if handoff:
state = concat(rlt_encoder(vla.encode(obs)), obs.robot_state)
return actor.sample(state, vla.predict_action_chunk(obs))
return vla.predict_action_chunk(obs)
这里的关键是,复杂任务被拆成粗控制和精控制两段,每段用最适合的模型。粗阶段依赖 VLA 的泛化能力,精阶段依赖 actor-critic 的在线适应能力,这种分工让系统在保持整体技能覆盖的同时提高末段精度和执行速度。这种门控设计比让单一模型处理所有阶段更容易解释和调试。
6.2 自动切换
进一步看,自动切换是这套方法能否扩展的关键。如果每次都要人判断关键阶段,系统就很难大规模部署,也无法在长时间任务中保持稳定。原文做法是把人工干预记录为标签,再让 VLA 学会预测移交时机。换句话说,人类先教系统识别困难区段,之后系统自己接管。
7. 本地仓库代码导读
本节直接读取本地 RLT/ 仓库中的可运行代码,而不是继续停留在概念骨架。先说明边界:这份仓库对应的是 SakanaAI 的 Reinforcement Learning Teachers of Test Time Scaling,训练对象是文本推理教师,不是本文讨论的 VLA 版 RLT 官方实现。因此,下面的代码不能直接复现第 4 节的 actor-critic,但能提供三个真实工程线索:训练入口如何配置驱动、数据如何被整理成结构化字段、GRPO 如何把奖励、优势归一化和 KL 约束装配成损失。理解这些接口后,再回到 VLA 场景,就能更清楚地看到 RLT 应该接在哪里。
7.1 训练入口:配置驱动的主循环
RLT/train.py 的核心不是某个复杂算法,而是把“换模型、换数据、换训练器”这三件事全部交给配置层。入口先实例化 tokenizer,再实例化数据集,最后把数据集交给 trainer;训练、恢复 checkpoint、保存模型都由同一个主循环完成。这种写法的好处是,SFT 和 RL 可以共用同一套工程骨架,只需要替换 YAML 中的 trainer 和数据配置,而不需要重写训练入口。
# RLT/train.py
tokenizer = hydra.utils.instantiate(cfg.make_tokenizer_fn)
datasets = hydra.utils.instantiate(
cfg.make_dataset_fn, tokenizer=tokenizer)
trainer = hydra.utils.instantiate(
cfg.trainer,
**datasets,
)
train_result = trainer.train(resume_from_checkpoint=last_checkpoint)
if cfg.save_final_model:
trainer.model.config.use_cache = True
trainer.save_model(cfg.output_dir)
tokenizer.save_pretrained(cfg.output_dir)
这段代码对 VLA 版 RLT 的启发在于:主干、RLT 编码器、actor-critic、数据装载和 rollout 参数应当分层配置。如果把这些内容写死在训练脚本里,换一个机器人本体或换一个任务就要改主循环;而按照上面的方式拆开后,VLA 主干、机器人状态维度、动作块长度、奖励函数和回放缓冲区都可以独立替换。工程上,这能显著降低把研究代码迁移到真机系统时的维护成本。
7.2 数据层:从原始样本到结构化字段
RLT/custom_data/teacher_data.py 负责把原始问答数据整理成教师训练需要的格式。它先抽出问题、推理过程和答案,再把答案与解释重新包装成带标记的 teacher 输出;随后用 completion_div 把完整文本切成 rl_prompts 和 rl_solutions。前者是教师模型可见的输入,后者是被遮蔽或用于奖励计算的部分。这个“切分边界”比文本内容本身更关键,因为它决定了模型能看什么、不能看什么,以及奖励函数应该在哪里判断对错。
# RLT/custom_data/teacher_data.py
question_content, thought_process_and_solution = (
data.extract_question_and_completion_from_line(line))
solution, explanation = process_assistant_message(
solution_content=solution_content,
think_content=think_content,
new_solution_tag=new_solution_tag,
explanation_tag=explanation_tag,
)
new_content = new_pre + solution + new_delimiter + explanation
messages.append({"role": "assistant", "content": new_content})
line_text = tokenizer.apply_chat_template(
messages, tokenize=False, continue_final_message=False)
rl_prompts, rl_solutions = line_text.split(completion_div)
out_line = {
"prompt": rl_prompts + completion_div,
"student_system_prompts": data.system_prompt,
"questions": question_content,
"solutions": solution_s,
"solutions_content": solution_content,
}
数据装载则由 RLT/custom_data/sft_data.py 完成。它读取 Hugging Face 数据集,执行上面的格式化函数,最后返回 train_dataset、eval_dataset 和 data_collator。这里真正值得借鉴的是“字段结构化”和“掩码训练”两件事:字段结构化让奖励函数不用从自由文本里猜答案,掩码训练则保证损失只落在需要学习的 completion 上,而不是污染 system prompt 或 user prompt。
# RLT/custom_data/sft_data.py
dataset = load_dataset(dataset_local_directory, **dataset_loading_kwargs)
train_dataset = dataset[train_split]
if process_line_fn is not None:
train_dataset = train_dataset.map(
lambda x: process_line_fn(x, tokenizer))
out_data = dict(
train_dataset=train_dataset,
eval_dataset=val_dataset,
)
if completion_only_training:
out_data['data_collator'] = make_masked_sft_collator(
tokenizer=tokenizer,
model_name=model_name_or_path,
custom_start_of_response=custom_start_of_response,
)
把这一层映射回 VLA 场景,对应关系可以这样理解:question_content 相当于任务指令与视觉观测,thought_process_and_solution 相当于动作历史与末端执行结果,completion_div 相当于“粗阶段”和“精阶段”的切换边界,solutions 则对应最终成功标签。VLA 版 RLT 需要把图像、语言、机器人状态和动作块同样整理成结构化样本,否则 actor-critic 很难知道哪些动作步参与训练、哪些只是 padding。
7.3 GRPO 损失:优势归一化、KL 约束与掩码
RLT/trainers/grpo.py 中的损失计算分成两步。第一步,把同一个 prompt 的多个生成结果分组,计算组内奖励均值和方差,再把当前样本奖励归一化成 advantage;第二步,把 advantage 乘到 token 概率上,同时加入对参考模型的 KL 约束。这个结构和 VLA 版 RLT 的 actor-critic 不是同一个算法,但“用参考策略限制探索范围”的思想是相通的。
# RLT/trainers/grpo.py
mean_grouped_rewards = rewards.view(
-1, self.num_generations).mean(dim=1)
std_grouped_rewards = rewards.view(
-1, self.num_generations).std(dim=1)
mean_grouped_rewards = mean_grouped_rewards.repeat_interleave(
self.num_generations, dim=0)
std_grouped_rewards = std_grouped_rewards.repeat_interleave(
self.num_generations, dim=0)
advantages = (rewards - mean_grouped_rewards) /
(std_grouped_rewards + 1e-4)
per_token_kl = torch.exp(
ref_per_token_logps - per_token_logps
) - (ref_per_token_logps - per_token_logps) - 1
per_token_loss = torch.exp(
per_token_logps - per_token_logps.detach()
) * advantages.unsqueeze(1)
per_token_loss = -(per_token_loss - self.beta * per_token_kl)
loss = (
(per_token_loss * completion_mask).sum(dim=1)
/ completion_mask.sum(dim=1)
)
这段代码里有三个工程细节值得单独指出。第一,num_generations 把同一 prompt 的多个输出放在一组,advantage 只在组内比较,这降低了绝对奖励尺度对训练的影响;第二,per_token_kl 是对参考模型的软约束,作用类似 VLA 版 RLT 中的参考动作,防止策略为了稀疏奖励做过激探索;第三,completion_mask 保证 padding 不参与损失。对机器人动作块来说,这个 mask 尤其重要,因为一个动作块中往往只有末端几步真正对应关键接触阶段,其余步骤可能是填充或已执行过的历史。
7.4 配置与启动命令
仓库把训练分成两个阶段:先做 SFT warm-up,让模型熟悉 teacher 输出格式,避免一进入强化学习就因为格式不稳定而浪费采样;再做 GRPO 强化学习,让奖励信号在已经成型的输出分布上做选择。两个阶段分别对应 teacher_sft.yaml 和 teacher_rlt.yaml,也分别保存到 pre_rl_model 和 rlt_teacher。下面的命令来自 RLT/README.md,是这份仓库最直接的可复现入口。
./launch.sh 8 cfgs/run_cfg/teacher_sft.yaml
output_dir=path/to/save/pre_rl_model
./launch_with_server.sh 4 4 cfgs/run_cfg/teacher_rlt.yaml
model_name_or_path=path/of/saved/pre_rl_model
results_dir=path/to/save/rlt_model
| 阶段 | 配置文件 | 关键设置 | 作用 |
|---|---|---|---|
| SFT | cfgs/run_cfg/teacher_sft.yaml |
Qwen2.5-7B-Instruct,Bespoke-Stratos-17k,10 epochs,batch 16,lr 1e-5,max seq 16384 |
让模型先学会 teacher 的输出格式 |
| RL | cfgs/run_cfg/teacher_rlt.yaml |
125 steps,batch 1024,64 generations,temperature 0.7,lr 1e-6,KL 系数 0.04 |
用 GRPO 优化教师输出 |
| 学生模型 | teacher_rlt.yaml |
bespokelabs/Bespoke-Stratos-7B |
作为教师训练时的学生参照 |
这些超参数不能直接搬到 VLA。文本生成的 rollout 是 token 采样,机器人执行的 rollout 是连续动作和环境交互,两者的时间成本、安全约束和奖励稀疏程度都不同。但“先 warm-up、再在线优化”的两阶段结构是可迁移的:VLA 版 RLT 先训练 token 编码器并冻结主干,再让 actor-critic 在关键阶段做在线学习。
7.5 从代码到 VLA RLT 的映射
如果把这份仓库迁移到 VLA 场景,不能只把模型名从 Qwen 换成某个 VLA,也不能只把文本 token 换成图像 token。真正要替换的是数据接口、训练目标和交互边界:数据层要处理多模态观测与动作块,训练器要处理 TD 误差和 actor 局部编辑,rollout 要处理真机安全与异步回放。下表给出的是工程借鉴关系,不是算法等价关系。
| 本地仓库组件 | VLA 版 RLT 中对应的概念 | 需要替换的内容 |
|---|---|---|
make_dataset_fn |
图像、语言、机器人状态与动作历史 | 把 question/solution 换成多模态观测与动作块 |
process_line_fn |
样本结构化与边界划分 | 把 teacher 标签换成关键阶段切换标签和成功标签 |
trainer |
actor-critic 与 rollout | 把 GRPO 换成 TD critic、actor 局部编辑和经验回放 |
ref_per_token_logps |
参考策略约束 | 把 token KL 的思想换成参考动作约束与安全边界 |
completion_mask |
动作块有效位 | 只对关键阶段的有效动作步计算损失 |
所以,本地仓库能回答的是“工程上怎么组织”,不是“VLA 版 RLT 的官方公式怎么实现”。真正落地时,应保留它清晰的数据层和训练器边界,但把学习目标换成第 4 节的 critic TD 误差和 actor 局部动作编辑,再把 rollout 部分接到机器人环境与安全监控上。这样读者既能看懂概念,也能知道从代码层面应该从哪里动手。
8. 工程价值
8.1 与其他路线的关系
如果直接在整个 VLA 上做在线 RL,样本和算力开销都很大;如果只在小型专用策略上做 RL,又会丢掉预训练泛化能力。RLT 把两条路线的优点拼在一起:大模型冻结提供表征,小模型在线提供适应性。这和 PPO、SAC 这类通用 actor-critic 方法并不冲突,而是把它们的输入状态换成更高质量的 VLA 表征。
8.2 为什么适合真机
真机在线学习最怕两件事:一是更新太慢,二是探索太危险。RLT 的冻结主干让表征稳定,轻量 actor-critic 让更新快,参考动作让探索范围受限。进一步看,人工干预只发生在关键阶段,不需要为每个动作打标签。这些设计合在一起,让真机上的样本效率和安全边界都更好。
原文实验集中在四个精细任务上,任务覆盖面仍有限。虽然 RLT 在这些任务上表现强,但要推广到开放环境,还需要验证跨任务、跨物体和跨机器人平台的稳定性。核心问题在于,RLT 是否能保持任务无关的通用表征,还是每个任务都需要重新训练一个 token 编码器。
8.3 奖励与人工标注
稀疏奖励降低了标注负担,但仍然依赖人工判断成败。对于长时程任务或模糊成功标准,这个环节会成为瓶颈。另一个风险是,actor 可能学到只优化末端成功而忽略安全约束。这里要引入约束、代价或不确定性估计,避免策略为了完成任务而采取危险动作。
难点提示:稀疏奖励简单,但它把最难的部分留给了 value function。
9. 总结
RLT 的核心不是把 VLA 和强化学习简单相加,而是重新划分两者的职责:VLA 负责把视觉、语言和动作历史压缩成稳定表征,RL Token 负责把这个表征交给轻量 actor-critic,actor 只在关键阶段围绕参考动作做局部修正。这样既保留了预训练模型的泛化能力,也避免了在线 RL 直接更新大模型带来的高算力、低样本效率和安全风险。对工程实现来说,最重要的是把数据格式化、主干冻结、表征提取、actor-critic 训练和 rollout 安全监控分层解耦;本地 RLT/ 仓库虽然对应文本推理教师而非 VLA 官方实现,但它的配置驱动入口、结构化数据处理和带 KL 约束的 GRPO 损失,正好提供了可以借鉴的工程骨架。
28