跳转至

第 6 章 长程任务

第 1 章立的那把判断尺,到这一章正式碰到它最难的一格:任务一旦超过两分钟,端到端就开始崩。崩的方式不是噪声,是结构。这一章解释那个结构,以及为什么再大的网络也不会把它"训没"。


2025 年下半年圈内反复传过这么一段不到两分钟的 demo。一台双臂 VLA 机器人在做收拾餐桌:先把脏碗一个一个放进水池,然后回桌上擦水迹。前 60 秒非常漂亮,每个碗的位姿都对得上,水池里没有任何剐蹭。

第 90 秒它做了一件让看的人安静下来的事:把一个已经放进水池的碗又拿了回来,重新放到餐桌上,然后伸手去抓它,再放回水池。

来回三趟。没有报错,没有犹豫,电机声音平稳,姿态优美。它认认真真地进入了一个死循环,直到工程师把急停按下。

事后回放数据,每一帧单看都"合理"。模型看到桌上有个碗,桌上有碗就该抓;抓起来旁边有水池,就该放进去;放进去之后再看一眼桌子,咦还有个碗(那是它自己刚拿回来的),那就再来一遍。任务级的状态在网络里不存在,每一步只是在做"现在这一帧最像演示数据里的哪一帧"的最近邻。前 60 秒像是因为前 60 秒的状态分布跟训练数据完全重合;第 90 秒分布开始飘,飘到一个训练集里没人收拾过的中间态,模型就退化成了一个对当前画面的反射。

这是 2025 年所有人都在反复看的画面。看十次就能学到一件事:长程任务不是"训得不够长"。是没拆


VLA 在两分钟以上为什么必崩,可以拆成四个独立的原因。这四个不重叠,每一个都得单独解决。

第一是训练数据的长度分布。teleop 收集的演示绝大多数在 10-60 秒之间。原因很物理:操作员注意力撑不住更长,标注成本随时长线性涨,剪辑长 demo 时人会下意识把停顿剪掉。整个数据集的中位数大概 25 秒。π0 在折衣服上能跑近 5 分钟已经是把训练 budget 全压在长 demo 上换来的,而且只在那一类任务上。让同一个模型去跑 5 分钟的厨房任务,立刻退化。

第二是 context window。当前 VLA 的视觉 token 化效率很差,30Hz 的双目摄像头一秒钟可以吃掉两三千 token。即使是支持 1M context 的语言模型骨干,纯视觉跑 90 秒之后窗口就快满了,再之后只能丢早期帧。早期帧丢掉,机器人就忘了"这一步之前我已经把碗放进水池了"。这件事不是写一个长 context 模型就能解决的,是 token 经济学的问题。

第三是累积误差。每一步动作都有几毫米的位置误差、几度的角度误差,单步看微不足道。但闭环里下一步是基于上一步的状态拍的,180 步之后误差能堆到桌面边缘外面去。经典控制器有 Kalman filter(一种持续融合传感器读数把状态估计拉回真值的迭代滤波器)在每一步把误差拉回来,端到端策略没有任何机制做这件事,因为它的状态估计是隐式的,藏在 transformer 的 hidden state 里,没有地方挂一个 correction step。

第四是状态估计漂移(state estimation drift,机器人对自己当前位姿/任务进度的内部估计随时间偏离真值),更准确说是任务进度漂移。机器人能估计自己手在哪儿(本体感觉,关节编码器给的关节角度,很准),能估计桌上有什么物体(视觉够好),但它估计不出"这个任务我已经做到第几步"。这第四件事是这一章最关键的,下面会单独再讲。

这四件事加起来就是死循环画面的全部解释。不是模型不聪明,是它在用一个为短时反射优化的架构去做一件需要任务级记忆的事。


所以这一章要立第一条立场:长程任务 ≠ "训更长"。是"该分层"

这句话有人不爱听,特别是 2024-2025 那一波相信"scale is all you need"的人。立场要点名说清楚:scale 在两分钟以下买到了真东西,π0 折衣服、Helix 抓取片段、GR00T 的 manipulation skill,这些都是 scale 带来的。但长度这一维 scale 不进去,因为它需要的不是更多参数,是一个能把任务拆成若干个两分钟以下子段的外部结构。这件事网络自己生成不出来,因为生成它需要的不是 pattern matching,是 planning。

planning 这件事 LLM 已经会了。让 VLA 也学一遍 planning 是把两个本来已经分得很好的能力强行混在一起。分层不是为了仿生大脑的 system 1 / system 2,是为了把两件不同的优化问题分开


LLM 当 planner 这条线的简史值得一段。

最早是 SayCan(Ahn 等,Brian Ichter 和 Karol Hausman 在 Google Robotics,2022 年 4 月)。SayCan 的想法很朴素:让 LLM 列出可能的下一步动作,每一步用一个学到的 affordance 函数打分("机器人在当前状态下做这件事能不能成"),用 say × can 的乘积选下一步。那时候 GPT-3 刚出,让一个语言模型去给机器人列动作,是当时的所有人都觉得"反正试试"的实验。它跑通了,证明 LLM 知道"想喝可乐先去拿可乐再带回来",这件事在 2022 年是新的。

紧接着是 Code as Policies(Liang 等,Google,2022 年 9 月)。这一篇换了思路:不让 LLM 直接选动作,让它生成一段调用 API 的 Python 代码grasp("red_block"); place("on_top_of", "blue_block") 这种。代码这种结构天然就有 if-else、for 循环、变量绑定,比一个个 step token 表达力强得多。这条路后来变成主流。

ProgPrompt(Singh 等,NVIDIA,2022 年)把这一思路用到家务任务,证明了 LLM 在结构化代码下能做相当复杂的厨房任务规划。Inner Monologue(Huang 等,Google,2022 年中)做了另一件事:让 LLM 在执行过程中听得到反馈,视觉模型说"我看到红色方块倒了",LLM 要能根据这个调整后续步骤。这是第一次把 LLM 用成闭环的而不是开环的 planner。

2023 年这条线分叉。VoxPoser(Wenlong Huang 在 Stanford,2023 年 7 月)走的是用 LLM 生成 3D value map,让一个轨迹优化器在这个 map 上跑出动作。这是个聪明的中间方案:LLM 不直接说动作,说"哪些区域吸引、哪些区域排斥",把语义和几何拼到一起。ViLA(Hu 等,2023 年)和 Tidybot(Wu 等)继续推 LLM + scene graph 的路线。同年 Google 的 PaLM-E(Driess 等)走另一极端,把视觉直接拼进语言模型的 token 序列里,让 LLM 自己端到端做规划+执行。PaLM-E 在某种意义上是 RT-2 的前身。

2024 年这一线开始进工业。每家具身公司私下都有某种形式的 LLM-as-planner,用法大同小异:把高层指令拆成 2-5 个子任务,每个子任务对应一个已知的 skill API,调下去执行,根据返回值决定下一步。这件事 2026 年初已经是默认选择,争议的不再是要不要做,是 skill API 到底长什么样

flowchart TB
  T[任务: 收拾厨房] --> L[LLM planner]
  L -->|pick(red_bowl)| S1[VLA skill 1<br/>30-90s]
  L -->|place(sink)| S2[VLA skill 2<br/>30-90s]
  L -->|wipe(table)| S3[VLA skill 3<br/>30-90s]
  S1 --> SF[安全层<br/>力矩限幅 / e-stop]
  S2 --> SF
  S3 --> SF
  SF --> M[电机]
  S1 -.->|success / fail / stuck| L
  S2 -.->|success / fail / stuck| L
  S3 -.->|success / fail / stuck| L

skill API 是这一层成败的全部。子任务接口划得好,整套系统稳;划得不好,LLM 在上面规划得再漂亮,下面的 VLA 也接不住。

什么是坏的 skill?clean_kitchen()。这个粒度太大,下面没有任何 VLA 能稳定执行 5 分钟连续动作,于是这个 skill 名字其实只是把死循环延后到了下一层。

什么是好的 skill?pick(object_id, grasp_pose=None)place(target_pose, support_surface)wipe(area_polygon, tool_id)open_drawer(handle_pose)。注意几个特征。第一是参数化,能接 LLM 传下来的具体物体 ID 和位姿。第二是单步时长在 10-60 秒之间,正好是 VLA 在演示分布里能稳跑的窗口。第三是有明确的成功/失败返回,让上层 LLM 能据此重规划。第四是接口语义足够窄,窄到可以为它专门收一两千条 demo 训练一个小 policy。

不好的 skill 的另一个失败模式是自然语言当 API。"Pick up the red bowl that's on the left side of the table" 这种。听起来很 LLM-friendly,但下面的 VLA 不一定理解"left side of the table"在当前坐标系里是哪边。LLM 是个无视觉的 planner,它写出来的指代要靠下面的 VLA 自己去消歧,消歧失败就是另一种死循环的来源。靠谱的做法是上面那一层先过一个 vision-language grounding 模块,把"红碗"变成 object_id=37, bbox=[...],再传给 skill。多一层翻译,少一类 bug。

至于 skill 该有多少个,2025 年的工业经验是一个家庭机器人 30-80 个 skill 够用,再多管理成本就压人。每一个 skill 单独 fine-tune、单独评估、单独 versioning。这件事跟 2010 年代的 motion primitive library 心智上接近,差别是每个 primitive 现在是个神经网络。


把任务拆出来还不够,得能从失败里恢复

失败恢复这一类工作 2024-2025 集中爆发了一批。REFLECT(Liu 等,2023 年底)做的是让机器人在失败后用 LLM 自己分析失败原因,比如"我刚才没抓住,是因为我抓的位置太靠边",再据此调整下一次尝试。AHA(Duan 等,2024 年)走类似路线但加上了视觉证据。RACER(Dai 等,2024 年)专门做长程任务的 recovery,把失败片段和恢复片段都收进训练集。Robotic Recovery 这一类工作(不同组在做)核心都是一件事:承认会失败,给系统一个失败之后干什么的协议

最值得拎出来的是 Yell At Your Robot(Shi 等,Lerrel Pinto 在 NYU,2024 年)。这一篇的设定很简单:机器人正在执行任务,人在旁边喊"不对,往左一点",机器人立刻调整。意义不在喊话本身,在它承认了人和机器人在长程任务里需要一个低带宽的纠错通道。这件事在工业部署里其实早就在做(Figure、1X 都有遥操作员盯着实时纠偏),Yell At Your Robot 是把它学术化的第一步。

把这几条放一起看,长程任务的 recovery 设计有三类。第一类是retry:失败之后重试一次,对抓滑这种偶发错误有用。第二类是replan:让 LLM 重新规划,对子任务执行不下去(比如门打不开)有用。第三类是ask:让人来帮忙,对前两类都解决不了的疑难有用。好的长程系统三类都有,分级处理,不指望任何一类能兜住所有情况


记忆是另一根硬骨头。

LLM 那边的记忆结构现在大致分三层。短期是 transformer 的 context window,所有当前对话内容直接进去。中期是 agent scratchpad,把关键事实和中间结论结构化地写下来供下一步引用。长期是 RAG over experience,把过往会话存成 embedding 索引,需要时检索回来。这一套在 LLM 那边已经相对成熟。

机器人记忆为什么比聊天 agent 难,三件事。

第一是带宽。聊天 agent 一秒钟新增几百 token,机器人一秒钟新增几千 token 的视觉、加上几百 token 的本体感觉、加上几十 Hz 的力觉。把这些全塞 context 跑两分钟就爆。所以机器人的中期记忆必须先压缩再写入,怎么压是个开放问题。

第二是连续性。聊天里两条消息之间的状态切换是离散的,机器人世界里碗落到水池的水溅出来这件事是连续的。压缩的时候保留多少帧、多少粒度的物理细节,没人知道答案。

第三是检索的信号。在文本 RAG 里,下一句问的关键词跟过去某段记忆的关键词重合度高,就 retrieve 那段。机器人在执行第 47 步时该 retrieve 训练集里的哪一段经验?基于物体?基于姿态?基于子任务名?目前没有一个 embedding 同时把这三件事编码得好。VLM 的 image embedding 太粗,CLIP 那一类对纹理敏感对几何不敏感,全是已知问题。

2025 年实战里见到的折中方案:短期 = transformer context(30 秒内的视觉 + 动作);中期 = LLM 维护的任务进度文本("已完成步骤 1、2、3,当前步骤 4,下一步 5");长期 = 几乎不用。最后一项不是不重要,是检索没解决。所以现在的家用机器人在你家跑了三个月,并不会因此变得更懂你家。它每天醒来都是同一个模型权重。这件事是 2026-2028 这三年明显会有突破的方向之一。


立场二,写在这一章中段最显眼的位置:state estimation 是这一波被遗忘的问题

机器人这门学科在 2010 年代有半本书都在讲 state estimation(状态估计:从带噪声的传感器读数反推机器人当前位姿/速度/任务变量的真实值)。SLAM 一整套(EKF-SLAM、graph SLAM、ORB-SLAM、LSD-SLAM、Cartographer)都在解一个很基本的问题:我自己现在在哪儿、姿态是什么。VIO(visual-inertial odometry,视觉 + IMU 融合估自己在动多快往哪走)这一线把 IMU 加进来。这一切一直到 2020 年都是机器人栈的核心。

VLA 出来之后这件事被悄悄绕过去了。"反正网络看着图像直接输出 action,它内部肯定隐式知道自己在哪。"这话部分对,对 60 秒以内的短任务确实够用。但长程任务里要估计的不只是位姿,是任务进度

任务进度这个量,传统机器人学没有正经研究过,因为传统机器人的任务都是手写的状态机,第几步执行到哪里是状态机自己的变量,不需要"估计"。VLA 时代任务变成了语言指令、变成了 LLM 生成的子任务序列,"我现在在第几步"突然变成一个需要从感知里反推的隐变量

反推它要的信号其实蛮多。视觉里有"这个碗已经在水池里了",本体感觉里有"我刚才抓过一次东西然后放下了",LLM 的 plan 里有"下一步该是擦桌子"。把这三类信号融合成一个对任务进度的估计,这件事本质就是一个 state estimator,只是状态空间从 SE(3) 换成了 plan tree 上的一个游标。

2025 年开始有一两篇 paper 在做这个方向("task progress estimation""subtask completion classifier"这一类标题),但还远没有成体系。我赌这一块在 2027 年之前会出来一个像 Kalman filter 之于位姿估计那样的标准方法,整个长程任务的稳定性会随之上一个台阶。在那之前,工程上的兜底做法是:让 LLM planner 在每一步执行后回看一眼,自己判断"刚才那一步成了吗",本质上是把 state estimator 的工作 hack 给了 LLM。这个 hack 比想象中能用,但它要花掉一次 LLM 调用(几百毫秒、几分钱),所以高频任务里跑不动。


到这里,"分层"这个词其实包含了两种心智上完全不同的东西,要分开讲。

一种是 RT-H、RT-Trajectory(Belkhale 等,DeepMind,2024 年)这一线的动作 hierarchy。它的层级是在动作空间里的:上层输出一段轨迹或一段语言动作描述("move arm forward, then down"),下层把这个翻译成关节角。整个系统还是端到端训出来的,分层是为了让网络内部更好优化、为了让数据更易标注、为了让中间表示更易于人工干预。它不解决长程任务,只让短程任务训得更稳、更可控。

另一种是 SayCan、Code as Policies、本章一直在讲的这一线的语义 hierarchy。它的层级是在任务空间里的:上层是 LLM、是符号化的子任务、是带变量的 API 调用;下层才是 VLA 或经典控制器去执行每一段。这一类专门为长程任务设计,每一层之间的接口是离散的、可读的、可记 log 的。

两种 hierarchy 解决的是不同的问题,公司和实验室经常混着说。要在简历里、在白板会议上、在 paper review 里听清楚对方说的是哪一种。RT-H 风格的动作分层不能替代 LLM planner 风格的任务分层,反过来也不行。一个长程家庭服务机器人这两层都需要。


最后给一段实操,对应第 1 章那个工程信号:你已经收了一万条演示,VLA 还是过不了验收。

第一步,把这一万条 demo 按时长重新切。看分布,多半你会发现集中在 20-40 秒,少量长 demo 是把若干段拼出来的。把所有超过 90 秒的 demo 砍成 30-60 秒的小段,每段独立标一个子任务名(不需要严格,"pick","place","wipe","open" 这种粒度就行)。

第二步,画 plan。把你最终要做的那个长任务(比如"清理餐桌")人工写成 LLM-friendly 的伪代码:

for dish in dishes_on_table:
  pick(dish.id)
  place(sink_pose, "drop")
for spot in wet_spots:
  wipe(spot.area, towel.id)
done()

这个写法暴露了你需要的 skill 集合:pick、place、wipe,加上 vision 模块给的 dishes_on_table、wet_spots 检测。这一步如果你写不顺,说明你对自己的任务还没拆够,回到 demo 数据里继续拆。

第三步,每个 skill 用对应那批数据 fine-tune 一个小 VLA。量级 2-3k 条 demo per skill,远比一万条直接训长任务有效。每个 skill 单独评估,能跑稳再拼。

第四步,把 LLM planner 接上。skill API 的 docstring 要写得 LLM 看得懂,每个 skill 返回 success/failure 信号。失败时 retry 一次,再失败 replan,再失败 ask。

第五步,加任务进度 tracker。最简单的版本就是每个 skill 调用前后让 LLM 看一眼当前画面回答"上一步成功了吗、下一步该做什么"。这个 hack 解决 80% 的死循环。

这个流程下来,原来那个一万条 demo 训不动的长任务,通常一周到两周能跑稳。不是因为更多数据,是因为问题被拆对了


练习

找一段你看过的最长的 VLA demo video(π0 折衣服、Helix 操作 demo、1X NEO 家庭片段都行),用秒表卡时间。从开始到第一个明显走样、卡住、或者动作变怪的时刻,多久?这个时间和章里说的"两分钟以上崩"对得上吗?

重读 SayCan 那篇 paper,但这次跳过 affordance 函数那一节,只看它给 LLM 用的 prompt 和 LLM 输出的子任务序列。把里面的子任务粒度拎出来,它们是 pick(object) 这种参数化形式,还是 "go to the kitchen" 这种自然语言?这个粒度选择带来的代价和好处分别是什么?

找一个你身边的人做一件 5 分钟以上的家务(叠衣服、煮一顿饭、整理书桌),录下来,回放时把它拆成离散子任务的列表。你拆出来多少个?子任务之间有没有顺序约束?有没有哪一段你拆不出来、只能用一个名字概括(比如"调味")?这种拆不动的子段就是端到端 VLA 真正的用武之地。

给你正在做的任务写一份 skill API 文档,每个 skill 一段 docstring,参数和返回值标清楚。写完之后让 Claude 或 GPT 去读这份文档,让它生成完成你那个长任务的伪代码。它写出来的代码能跑吗?如果不能,缺哪个 skill、哪个参数没暴露好?这个练习能在两小时内告诉你你的接口有没有划对。

下一章:第 7 章 仿真到现实