语义引导任务规划:LLM监督VLA模型实现机器人长程操作 我的机器人操作实验台被同一个问题卡了快两周机械臂抓取、放杯子都准得离谱但让它完成把桌上的苹果放到红色托盘里再把托盘放到厨房台面上这种两段任务时它经常做完第一步就愣住。后来发现问题不在控制精度而在任务规划。这个项目围绕 Semantically Guided Task Planning 展开核心思路是让 Large Language Models 去监督一个 Vision-Language-Action Model 的训练——用语言把长任务拆成有语义层次的子目标再把这些子目标喂给 VLA 模型做动作学习。听起来不复杂但真正做到语义引导和监督这两个词落地中间全是坑。这篇文章把我从架构设计、数据管线、训练调试到端侧部署的完整过程都写下来希望能帮你少走点弯路。1. 内容整体设计与思路拆解1.1 任务规划为何成为 VLA 模型的短板VLA 模型的全称是 Vision-Language-Action Model它做的事情看起来很统一输入一张当前观测图像加上一条语言指令输出一组动作末端位姿序列、关节角增量或者离散的动作原语。这类模型在单步操作任务上表现相当好比如抓取指定物体、按下开关、推开门。因为它们本质上是在学习一个条件策略条件就是眼前的像素和耳朵边上的指令输出就是下一步动作。但问题出在长时任务上。你让机械臂完成把苹果放进托盘、再把托盘放到台面这样的任务底层策略其实并不缺放的能力缺的是当前该放哪一个、放完之后下一件事是什么这种规划信息。端到端 VLA 模型很难自己长出任务分解能力原因很简单训练数据里的动作序列是连续的但语义事件比如苹果已放入托盘没有被显式建模模型学到的更多是碰到什么样子的图像就往哪边挪而不是我现在处于哪个子任务阶段。我打个比方端到端 VLA 像一个方向感极强但没地图的司机指令给到哪里它就能开到哪里但没人告诉它途经几个路口、每个路口拐之前要确认什么标志它就容易在长途线路上开岔。任务规划就是要解决这个缺少地图的问题。而语义引导相当于在这张地图上标出带文字说明的里程碑让模型每一步都知道自己踩在哪个点位上。1.2 为什么选择 LLM 当语义导师既然要在训练过程中给 VLA 模型补充任务规划级别的语义监督谁来提供这个监督信号就非常关键。这里我们选择了大型语言模型担任语义导师角色而不是自己写规则或者人工标注。原因有三层。第一任务分解本身高度依赖常识。拿把苹果放到托盘再放到台面来说正确的子目标顺序是放苹果→转移托盘→定位台面而不是反过来。这种顺序约束可以写成专用规则但换了任务就得重写。LLM 天然具备大规模文本里学到的常识和步骤推理能力稍微设计一下 prompt 就能在不同任务之间泛化不用为每个新任务去写分支逻辑。第二训练监督信号需要带有语义层级。直接让 LLM 输出移动 12.5 厘米没有意义因为这不是任务规划而是动作指令而且这些低层动作很难迁移。我们需要的是当前子目标描述和完成条件描述比如将苹果从桌面拿起目标容器红色托盘。这些都属于语言语义层恰好是 LLM 最擅长生成的内容。第三这套方案的投资回报率很高。实际部署时LLM 不需要在每一步都参与运算只需要在训练阶段生成监督标签以及在推理阶段做粗粒度决策。也就是说VLA 模型获得了一个随时能给语义辅导的老师但真正做实时动作执行的还是轻量级的 VLA 主干这比在端侧硬跑一个超大推理模型要现实得多。我一开始也犹豫过要不要让 LLM 直接接管推理时的每一步决策但后来发现没必要。把规划职责交还给一个专门的小型语言模型SLM把动作执行职责留给 VLA两者分工干净调试起来也轻松。1.3 整体架构把规划与执行拆成两层这个项目的核心架构可以总结为一条链任务输入 → 顶层语义规划器LLM/SLM → 子目标序列 → 低层 VLA 策略 → 动作执行 → 环境反馈。顶层规划器不直接出电机指令它只负责把用户的长指令转换成若干条带顺序的子目标文本。低层 VLA 策略负责接收当前观测图像和当前子目标输出具体的动作。为了提高鲁棒性我在中间加了一个很薄的语义缓冲层保存两个东西当前正在执行的子目标下标以及该子目标的历史观测摘要。这样一旦底层执行器发现连续几步都没有推进子目标就可以把控制权交还给规划器让它重新规划或者给出新的尝试方向。这个架构里最关键的设计决策是任务规划与任务执行解耦。传统一层式 VLA 把所有能力揉在一个模型里出问题时分不清是哪一部分的锅。拆成两层之后规划器出了问题你直接看它输出的子目标序列是否合理执行器出了问题你看它给定子目标下的动作预测是否合理。定位 bug 的时间至少少一半。同时解耦也带来了训练上的灵活性。规划器可以单独用文本数据集微调VLA 主干可以保持大参数量的视觉骨干不动只训练动作头。后面章节我会把每个环节的细节展开讲。2. 核心细节解析与实操要点2.1 语义样本生成先让 LLM 当标注员要让 VLA 模型在训练阶段就学会按照子目标执行动作首先得有带子目标标签的训练数据。我们的做法是让 LLM 先当标注员。具体来说从仿真环境或者真实机器人上采一批成功的专家轨迹每条轨迹包含一系列 (观测图像, 动作指令, 动作) 三元组。然后用 LLM 把这条轨迹切成若干语义段为每个段生成当前状态描述、当前子目标文本和完成条件。这里有个很容易踩的坑直接拿原始文本指令去让 LLM 切分它容易切出手臂缓慢向前移动这种毫无规划价值的句子。所以我在 prompt 里强制要求标注员只输出三种语义类型物体状态苹果在桌面上、操作目标将苹果放入红色托盘、功能状态苹果已就位。这样切出来的子目标才是稳定的抽象层级而不是对动作的低层描述。还有一点是关于子目标命名的一致性。同一类任务LLM 这一次写放置苹果下一次写放下苹果再下一次写将苹果放到托盘里虽然语义相同但文本表达不一致会让 VLA 模型的学习变得困难。所以标注完以后还要加一步子目标归一化做一个轻量的规则映射加向量检索把相近表达统一到同一套词表。这个步骤极其重要它能大幅降低训练数据的噪声。2.2 子目标表示三种方案怎么选训练 VLA 时子目标最终要变成模型能消费的 token 或向量。我在项目里对比过三种表示方式各有取舍。第一种是自然句子表示例如拿起蓝色杯子。优点是可读性和可调试性最强人类可以肉眼确认规划器的输出是否合理LLM 生成也最自然。缺点是句子表达多样性高如果不做归一化模型容易被同义表达干扰。第二种是结构化谓词表示例如 pick_up(agentrobot, targetblue_cup)。优点是非常适合程序解析下游如果要做形式规划器比如转成 PDDL可以直接套。缺点是 LLM 生成这种形式化描述时容易出错而且表达能力受限一些语义含糊的状态很难用固定谓词写干净。第三种是技能调用表示例如 skill_grasp(targetblue_cup, modepower)。这介于谓词和动作原语之间。优点是能直接在动作层面约束输出减少规划器生成 VLA 处理不了的指令。缺点是技能库需要人工预定义一旦遇到库外任务就失效。三种方案对比下来我实际项目里选的是混合方案训练时以自然句子为主同时让模型输出一个辅助的技能候选词表用来在推理阶段做动作可行性约束。简单说规划器给出自然语言子目标VLA 先解析这个文本再用技能词表限制动作头的选择范围。这样既保留可读性和生成质量又避免输出不可执行的动作。2.3 语义指令注入 VLA 的几种做法子目标文本不会自己钻进模型需要考虑怎么把语义信息注入到 VLA 策略里。我试过三种做法说下效果和取舍。第一种是文本 prompt 拼接。把当前子目标文本、上一子目标的完成状态、全局任务描述拼成一段连续的指令连到 VLA 的文本编码器里。这个做法改动最小你的 VLA 主干如果是 CLIP 风格的文本编码器直接拼进去就能用。缺点是有时候模型分不清当前子目标与全局任务的主次关系所以我建议在 prompt 里用特殊标记把当前目标单独框出来比如用subgoal.../subgoal标签包住。第二种是多模态特征融合。把子目标文本和视觉观测一起送进 transformer 层做 cross-attention让语义信息在注意力层里和视觉特征交互。这个对模型结构改动比较大但效果往往比 prompt 拼接好因为语义信息不再只是初始化输入而会参与每一层的信息交互。如果你的 VLA 主干是 transformer-based可以试。第三种是辅助语义损失。在训练时额外加一个当前子目标预测的头让模型除了预测动作之外还要根据视觉特征判断自己正在执行的子目标是什么。这相当于逼着视觉编码器去提取任务阶段相关的特征。推理阶段这个辅助头可以整个丢掉不影响部署只在训练时起正则化作用。我的建议是第一版先用 prompt 拼接加辅助语义损失跑通之后再考虑改 cross-attention。少改结构先验证思路能省下大量时间。2.4 损失函数动作为主语义为辅模型训练时我用了一个多任务损失主损失是动作模仿损失采用离散动作分类交叉熵或者连续动作的 L2 损失取决于你的 VLA 输出形式。在这个基础上叠加辅助语义损失也就是让语义预测头用交叉熵预测当前子目标类别或者用对比学习拉近视觉特征与子目标文本 embedding 之间的距离。两个损失的权重我没有用默认的 1:1而是把语义损失权重压得很低大概 0.2 左右。原因很简单主任务毕竟是动作生成如果让语义监督信号权重过高模型会倾向于把表征能力花在描述当前状态上而忽略了下一步动作推荐最终动作精度反而下降。我这里给个经验值动作损失权重 1.0辅助语义损失 0.2优化器用 AdamW基础学习率 1e-4。我实际实验里还对比过完全去掉辅助损失的情况。结果很有意思在动作精度上两者差不多但在长时任务累计成功率上加辅助语义损失的版本明显更高高出大概 15 个百分点。原因推测是辅助损失迫使模型显式编码了状态语义一旦当前子目标切换特征空间的跳变更加明确动作策略更容易跟随语义切换而切换。3. 实操过程与核心环节实现3.1 数据管线从轨迹到带语义标签的训练集在仿真环境里生成轨迹本身不是瓶颈自动化 rollout 就可以拿到大量成功样本。真正的瓶颈在把轨迹切分并标注成子目标化的训练集。我的数据管线分三个阶段。第一个阶段是轨迹切分。我不直接拿整条轨迹做训练而是先检测轨迹中的关键事件帧。做法是看物体姿态变化率如果某个物体的位置忽然发生明显位移说明一个操作事件发生了这就是语义段的边界。这一步用规则检测就够不需要机器学习。检测出来的边界用于确认 LLM 输出的子目标分段是否和真实事件一致。第二个阶段是 LLM 标注。把每个语义段内的观测摘要物体位置、手爪状态、末端位姿轨迹摘要和段前后的状态变化描述传给 LLM让它输出该段的子目标文本、完成条件和失败条件。这里强调一点我不把整条轨迹的原始数据全塞给 LLM而是给一段压缩的摘要文本。模型上下文有限原始 token 序列太长会稀释注意力摘要反而让标注质量更高。第三个阶段是数据清洗。做完标注后建议人工抽检 10% 到 20% 的数据重点检查子目标文本是否和执行行为一致。如果有标注错误最好建立一个小型的脏数据规则库比如文本里有拿起但动作轨迹未发生 z 轴变化就标记为可疑。清洗后的数据进入训练集脏数据可以直接丢弃不要抱有侥幸心理。3.2 规划器 Prompt 模板示例顶层规划器用的 LLM 我选择了参数量在 8B 左右的开源模型在端侧部署时再用量化压缩。系统 prompt 我调了很多版下面这个版本实测最稳。[角色] 你是一个室内操作机器人任务规划器。你只负责将用户的长任务指令拆解为有序的子目标。 [输入] 任务描述{task} 当前已知可执行技能{skill_list} 历史子目标摘要{history} [要求] 1. 每个子目标必须描述一个语义可验证的状态变化。 2. 子目标必须从技能列表中选取可执行的能力。 3. 输出格式严格为 JSON禁止输出任何其他文本。 [输出格式] { subgoals: [ { id: 1, text: 抓取桌上的苹果, verify_condition: 苹果在手爪中 }, { id: 2, text: 将苹果放入红色托盘, verify_condition: 苹果在红色托盘内 } ] }这里面最关键的是 verify_condition。它给底层的语义缓冲层提供一个文本形式的验收条件底层执行器每走几步就会用语言模型或者规则校验器检查这个条件是否满足。如果没有它规划器输出的子目标序列就只是一串空话机器根本不知道这一步算不算完成。我在实际测试中还发现在 prompt 里加入历史子目标摘要字段能显著抑制 LLM 规划器的重复输出问题。没有历史字段时模型容易在第三次子目标重复第二次的内容加了摘要之后重复率下降非常明显。3.3 训练配置与微调参数VLA 主干的微调我用了 LoRA单卡也能跑起来。下表是实测下来比较稳的配置参数项推荐值说明视觉编码器冻结预训练编码器语义已够用降低显存占用文本编码器冻结与视觉编码器保持一致减少分布偏移LoRA rank32动作头与语义头都插入 LoRA学习率2e-4超过 1e-3 会出现发散Batch size64混合了正样本和负样本语义损失权重0.2见 2.4 节太高会伤动作精度训练轮数20 epoch早停在验证集动作损失最小处冻结视觉编码器这个决定我最初有点犹豫担心大参数骨干不更新会限制模型能力。实测下来VLA 的视觉骨干是在互联网海量图文数据上预训练的识别能力和通用性已经足够真正缺的是视觉特征到动作输出的对齐这部分靠训练动作头就能解决。冻结之后显存占用明显降低训练速度提升近一倍动作精度反而没有下降。数据里的负样本也别忘了。我指的不是 NLP 里的负样本而是当前状态不满足子目标时应该停下等待的训练样本。比如子目标是抓取苹果但当前观测里桌子上没有苹果模型应该输出等待/重新扫描而不是胡乱抓取。这种样本采集起来容易但让 VLA 学会判断条件不满足时按兵不动非常有效。加入负样本之后我的部署场景里因为误动作导致的任务失败率降了四成。3.4 推理执行两级任务调度的落地逻辑训练好模型之后推理阶段的调度逻辑可以直接用一段简单的状态机描述。整个流程如下机器人收到用户任务先把任务文本交给顶层规划器规划器输出 JSON 格式的子目标序列。语义缓冲层初始化 current_index 为 0。VLA 模型开始执行时输入当前观测图像和 subgoals[current_index].text输出动作并执行。每执行完一步缓冲层会做一个轻量校验从当前观测中抽取关键状态物体位置、手爪开合度和当前子目标的 verify_condition 做匹配。如果匹配通过current_index 加一进入下一个子目标如果连续 N 步没有匹配通过就把控制权交还给顶层规划器让规划器基于历史执行摘要重新生成后续子目标。这个 N 我一般设成 15 到 20 步。设太短容易误判比如抓取过程中物体滑动导致的暂时未成交会频繁触发重规划设太长则会浪费执行时间机器人卡在同一个错误的子目标上反复尝试。实际场景里可以自己调但我测下来 15 步以下的误判率直线上升。再说一个我踩过的坑不要只在 VLA 里输入当前子目标文本把全局任务文本也带上。否则当执行到第三个子目标时模型容易忘记整个任务的终局是什么。全局任务文本的主要作用是让 VLA 能做出长远规划语义上的修正。比如它正在执行把苹果放入托盘同时知道全局目标是把托盘搬到台面那么它的姿态估计会更倾向于把苹果放稳而不是随手丢进去。3.5 端侧部署让 LLM 规划器跑在机器人身边关于 on-device LLM 的部署和模型压缩最近讨论度很高我在这里把实际做法说细一点。端侧部署规划器的原因很直接真正的机器人不可能每次都把图像和任务文本传到云端等一个超大型模型返回。延迟高、网络抖动影响大而且在工厂这类环境里数据隐私很敏感。所以我最终把规划器模型压缩后部署在了机器人旁边的边缘计算设备上。模型压缩我按顺序做了四步。第一步是知识蒸馏用一个大参数量 LLM 作为教师在任务规划数据集上蒸馏出一个 3B 规模左右的学生模型。这里数据集的覆盖面比模型参数量更关键蒸馏出来的学生模型在常见任务上的规划成功率能达到教师模型的 95% 以上。第二步是量化用 4-bit 量化把 3B 模型压到约 1.8GB 内存。这里要注意量化之后要重新跑一遍规划器的输出测试因为低比特量化可能会导致 JSON 输出的 token 概率分布变形偶尔会出现不可解析的输出。第三步是结构剪枝把注意力头里贡献最低的那部分去掉。我在这个项目里剪掉了 20% 的注意力头跑测之后准确率没有显著下降。第四步是 KV cache 优化因为规划器每次输出子目标序列长度不太长但历史上会多次调用所以缓存之前几轮的语音状态下文可以有效降低推理时延。VLA 这边我做了一个更直接的轻量优化。动作头原本输出 256 维连续向量我把它改成离散动作库上的分类输出配合技能词表约束。这个改动让 VLA 模型变小了不少又因为动作空间受限推理稳定性反而更高。端侧部署不是简单塞进设备就完事每一步都要回到数据上验证输出质量。4. 常见问题与排查技巧实录4.1 规划器输出与动作空间不对齐这是我最开始做这个项目时遇到的头号问题。规划器信心满满地输出子目标切好苹果但实际上 VLA 的动作空间里根本没有切这个原语只有抓取/放置/移动/推开四种。结果模型在推理阶段无论怎么解析文本都映射不到可执行动作上。解决这个问题得分两步走。第一步是缩窄规划器的输出范围在 prompt 里强制传入当前技能列表并明确要求每个子目标必须从列表中选择能力。第二步是在 VLA 输入端加一个动作可行性校验器一旦文本偏离技能列表就直接丢弃并触发重规划。经过这两步之后规划器输出不可执行指令的比例从 40% 降到 5% 以内。别小看这个校验器它只是一个薄的规则层但能把整条链路的稳定性提升一个量级。4.2 规划器幻觉导致计划不可执行LLM 的幻觉在任务规划场景里同样存在。实际测试中规划器有时会编造任务里不存在的物体比如用户说把苹果放到盘子规划器子目标里却出现了先拿起香蕉这种乌龙。更隐蔽的是它会预测出环境中根本不存在的物理状态例如苹果已在托盘内。我的排查思路有两个方向。一是输入侧约束把环境中的实际物体清单传入 prompt规定规划器只能引用清单里的物体并在输出后再做一次字符串匹配发现清单外的词就触发重采样。二是输出侧自洽性校验同一任务让规划器采样三次取子目标序列的交集或者投票结果。这个方案慢一点但可靠。作者模式实测中三次采样把所有候选子目标做并集再用规则把不一致的地方合并幻觉出现的概率显著下降。另外别忽略 verify_condition 的校验逻辑。如果校验条件本身写得太抽象比如苹果处理完毕规则校验器根本没法判断。要把条件写成可计算的谓词比如苹果 x 坐标在托盘范围内且 z 轴高于托盘底面 2cm。这类条件在仿真环境里很好抽取在真实环境里也能通过粗略的姿态估计做到。4.3 训练数据里有脏噪声怎么处理数据噪声几乎没办法避免尤其是当 LLM 自动生成子目标标注时一定会有少量标签和实际动作不一致。脏数据不清理模型学到的就不是苹果放入托盘时应该放下而是苹果的某种状态可能和放这个动作有弱相关。我的方法分两层。第一层是规则过滤基于事件边界检测的结果把 LLM 标注的子目标和实际动作事件做交叉验证。例如标注写抓起苹果但轨迹数据显示手爪在接近苹果之前就已经闭合那就是异常直接丢弃。第二层是置信学习用一个在干净子集上预训练的语义分类器给整批数据打置信分把低置信样本再交给人工复核。注意不要盲目丢弃低置信样本因为有些只是文本表达比较特殊并不是真的标签错误人工复核这一步在项目启动阶段一定要做等规则库成熟之后可以减少复核比例。4.4 训练不收敛、过拟合与辅助损失失衡我在训练初期遇到过一次非常典型的发散前两个 epoch 的动作损失下降正常第三个 epoch 突然飙升然后一去不回。后来定位到原因是学习率偏高LoRA 里低秩矩阵的更新幅度过大导致视觉特征空间被大幅扰动。把学习率从 1e-3 调到 2e-4 之后训练曲线立刻恢复正常。过拟合的问题更多出现在数据量不够时。VLA 主干虽然冻结但动作头和语义头本身有数千万参数如果训练集只有几千条轨迹后几个 epoch 验证损失就容易反弹。我的经验是观察到验证集动作损失开始上升时不要急着加正则化先看数据多样性够不够。如果场景只有一种桌面布局最简单的做法是加仿真时域随机化把物体位置、光照、背景颜色都做随机比堆数据量有效得多。辅助语义损失失衡这个问题前面说过一次但值得单独列出来。如果你发现模型的动作精度不高但语义预测准确率却异常高就说明语义损失权重太大了模型的容量都被拿去维护语义表征忽略了动作策略。这时候把权重调低或者干脆在最后五轮训练里把语义损失关闭让模型把动作头重新校准回来。4.5 仿真跨真机的语义鸿沟这个项目最初是在仿真环境里训练和验证的转移到真实机器人时我发现一个非常典型的现象模型在仿真环境里执行子目标切换很流畅到了真机上偶尔会出现视觉上物体就在眼前但模型判定子目标未完成的僵局。原因是语义校验器在仿真里依赖精确的物体姿态真机上物体检测有误差导致最终状态判断不稳定。我的解决方案有两个。第一在子目标完成条件里加入时间累积判定不要求单帧满足条件而是连续 5 帧都满足才算完成。这能过滤掉检测器抖动带来的误判。第二引入一个简单的重试机制当前子目标未通过校验时VLA 不是卡死原地而是先做一个小幅度的巡检动作比如左右移动 5 厘米重新观察再重新预测动作。这个方法朴素但很有效真实场景操作成功率提升了大概 20%。另外仿真到真机之间的视觉差异也是一个大问题。我在仿真阶段就特意加了相机噪声、光照变化和物体纹理随机化而不是等到真机阶段再去微调。这一步要尽早做越晚换到真机上你越难分清任务失败是因为规划器还是因为视觉语义没对齐。我在实际项目里最深的体会是语义引导任务规划这条技术路线真正的难点不是模型不够聪明而是工程链条太长。每一个环节数据标注、子目标表示、损失设计、推理调度、端侧压缩单独看都不难但任何一个地方没做好最终成功率都会被拉垮。如果你也想做类似的项目我的建议是先从一条固定场景的细分任务开始把数据管线和语义校验逻辑打扎实再用 LLM 换着花样去提高泛化别一上来就挑战全场景。最后再分享一个小技巧模型输出子目标序列时一定把当前子目标文本单独框进特殊标记里别和全局任务混在一起。这个细节最不起眼但对底层执行效果影响却非常大。