我一度以为,教机器人干活只有一条路:录数据、标动作、然后砸算力。直到我试着把机器人当成一个“只有方向键和确认键的游戏角色”,事情才开始变得不一样。Show-Harness 的核心思路就是:不给机器人喂动作数据,而是递给 VLM 一个“操作键盘”——一组定义了位移、旋转、夹爪开关的底层动作原语。VLM 观察当前画面,读自然语言指令,像人打游戏一样一下一下按按键,完成抓取、移动、放置这类任务。
这篇文章是我基于这套思路做的一次完整复盘。没有飘在空中的概念,只有从动作空间设计、机械臂接线、VLM 接入到踩坑调优的全程记录。如果你正被“数据采集贵、泛化差、端到端策略难收敛”折磨,或者刚接触 VLM 想让它真正动起来做点实事,这篇内容应该能帮你省下至少两周试错时间。先说好,它也不是万能的,最后我会把边界和适用场景一起讲清楚。
1. 先聊聊“喂动作”这条路为什么越走越累
不铺垫了,直接说我为什么从主流路线转向“键盘”思路。现在做机器人操作,十个团队里有八个第一反应是模仿学习,也就是行为克隆:找操作者遥操作机械臂,把轨迹存下来,训练一个从图像到动作的映射。听起来很直接,但这条路的隐藏成本,很多人一开始根本没算清。
1.1 模仿学习与行为克隆的隐形成本
数据采集本身就是反人类的。机械臂示教不是拿手机拍视频,你得让机械臂实打实走一遍轨迹,人在过程里不停微调姿态。一条干净路径重录三五次很正常。任务一旦要求多视角、多物体摆放、多种光照条件,数据量直接指数级上升。我见过一个团队为“叠衣服”任务录了两周数据,最后模型换件新衣服还是露怯,气到把机械臂砸了的心都有。
更坑的是轨迹数据里的无效冗余。遥操作时人手会抖,路径会绕弯,这些都会被当成“标准答案”学进去。你本来只想让模型学会“把螺丝拧到底”,结果它把“先在空气里画半个圈再下去”这种坏习惯一起学会了。不是不能清洗,而是清洗成本高到让你怀疑人生:一段 30 秒的轨迹,人工逐段修剪可能要花一小时。训练端到端策略的算力开销也得单独算一笔账,动辄几十卡时的训练,加上一轮轮超参调优,凌晨爬起来看曲线的滋味,经历过的人都懂。
1.2 端到端连续控制真正难在哪:搜索空间太大
行为克隆难,难点不完全在模型容量,而在“动作空间”本身。一台常见六轴机械臂,关节角是连续值,加上夹爪开合,这就是一个极高维连续空间里的规划问题。图像进来直接映射成 7 个 float,整个映射过程没有任何结构化和可解释性,模型就是在纯拟合。
连续输出对误差还特别敏感。预测的关节角偏差哪怕只有 0.05 弧度,末端就可能偏出去一厘米,任务直接失败。可 VLM 的训练目标从来不是“精确回归数值”,它是按 token 生成文本的。你逼它输出浮点数序列,等于让一个擅长看图说话、逻辑推理的模型去干伺服运动学这种它最不擅长的事。我做过对比实验:同一个桌面抓取任务,让 VLM 直接输出末端坐标和让它在离散动作里选按键,成功率差了 3 倍以上。问题不是模型笨,是输出范式不匹配。
2. Show-Harness 的做法:把机器人抽象成一个“键盘游戏”
Show-Harness 这个名字其实很贴切。Harness 的直译是挽具、束缚带——模型本身有潜力,但你不给它戴上合适的挽具,它的力气根本使不出来。这里的挽具,就是一套精心设计的“操作键盘”。这个抽象层让 VLM 的控制问题变成一个近乎游戏的任务。
2.1 核心思路:动作原语,就是键盘上的按键
所谓操作键盘,并不是真的给 VLM 接一个 USB 键盘。它指把机器人可执行的动作空间压缩成一组离散的原语,每个原语对应一小段底层运动:沿某个方向移动两厘米、腕部旋转十度、夹爪张开或闭合。只要这些原语覆盖了任务的子动作,VLM 就可以像玩游戏一样,每个时间步输出一个“按键”,走一步看一眼。
这带来的最大改变是:我们不教模型“手具体怎么动”,只告诉它“有哪些动作可以用”。策略学习从高维连续回归问题,变成了离散序列决策问题。任务再怎么变,底层的动作集合是固定的,模型要学的只是“在什么状态下按哪个键”的策略,搜素空间小了很多,可解释性也强得多。你翻日志就能看到:“它先向前,再向右,然后下降了夹爪”,而不是一串让人头大的浮点数矩阵。
2.2 为什么 VLM 用键盘比直接控制关节靠谱
这里有个很容易被忽略的先验:现成的 VLM 在预训练阶段看过海量“人通过按钮和界面操作系统”的截图像,游戏攻略截图、软件教程、机器操作面板,全是这种多模态语料。所以当机器人控制被抽象成“当前画面 + 候选按钮 + 下一步该按哪个”时,VLM 的视觉理解能力和语言推理能力能直接被调动起来。
换个说法就很好懂。你让大模型“算一下机械臂第 3 关节该转到多少度”,它不知道从哪下手;但你要是让它看桌面照片,问“杯子在托盘右边,夹爪该往哪边移”,它几乎不会出错。前者要数值精度,后者要场景理解,后者正好是 VLM 的长处。离散按键输出天然带容错性:按错一个键影响的是当前这一小步,下一步还能靠视觉反馈纠回来;连续输出一旦错一个数值,整条轨迹就崩了。键盘方案让 VLM 的错误以“可观察、可恢复”的方式暴露出来,这是它最大的工程优势。
2.3 动作空间设计:按键到底有哪些
动作键的设计是整套方案的地基。我给一个经过实测的可复用参考,一般分三组:
- 平移组:沿机械臂基座坐标系的 x/y/z 三轴正负方向移动,单次步长 1~3 厘米,负责接近、对齐、抬升。
- 旋转组:腕部 roll/pitch/yaw 的正负方向旋转,单次 5~15 度,负责调整抓取姿态。
- 夹爪组:OPEN、CLOSE,以及可选的压力步进增减,负责抓取与释放。
我在实验里实际用过的动作表大概长这样,你可以按自己任务调分辨率:
| 键名 | 执行内容 | 单次幅度 | 使用场景 |
|---|---|---|---|
| MOVE_FWD / MOVE_BACK | 沿基座 x 轴平移 | 2 cm | 接近/远离目标 |
| MOVE_LEFT / MOVE_RIGHT | 沿基座 y 轴平移 | 2 cm | 左右对准 |
| MOVE_UP / MOVE_DOWN | 沿基座 z 轴平移 | 1.5 cm | 抬升/下降 |
| ROT_L / ROT_R | 腕部偏航旋转 | 10° | 调整抓取姿态 |
| OPEN / CLOSE | 夹爪开闭 | 全行程 | 抓取/释放 |
设计动作键最重要的原则是:每个键执行完之后,机器人必须落在一个“稳定、可被相机再次确认”的状态。按键的终点要能被视觉系统清楚分辨。如果有动作键执行后会让画面剧烈变化、或者把机械臂挪到相机盲区,这个键要么拆细,要么干脆去掉。VLM 一旦看不清“按下按键后发生了什么”,整个决策循环就断了。
3. 实操记录:把 Show-Harness 接到真实机械臂上
概念聊清楚,下面进入我实际搭建系统的过程。机械臂平台我用的是协作臂加夹爪,头顶一个深度相机做全局观察,手腕上再挂一个小型 RGB 相机看近景。无论你用的是 ABB、KUKA 这类传统工业臂,还是开源桌面臂,这套抽象逻辑是完全一致的。
3.1 系统组成的四层结构
整个软件结构我分成四层,每层只解决一个问题,这个拆分非常关键:
- 感知层:两个相机负责采集图像。头顶相机负责看全局:物体在哪、夹爪大概在什么位置、有没有碰撞风险;手腕相机负责看局部:夹爪和目标物体的相对关系。两路图像在 prompt 里一起喂给模型。
- 决策层:VLM 接收图像、机器人状态文本和任务指令,输出一个动作键或一段按键序列。
- 解析层:把 VLM 的自由文本输出解析成预设动作原语。强烈建议用结构化输出,比如 JSON,不要让模型自由发挥。
- 执行层:动作原语通过 ROS2 或厂商 SDK 发给底层控制器,由运动学求解和轨迹插值完成实际小步运动。
为什么要这么拆?因为每一层遇到问题的方式完全不同。感知决定“我看到什么”,决策决定“下一步做什么”,解析负责把模型的话痨文本变成可执行指令,执行负责“怎么安全走完这一小步”。出了问题你能精确定位在哪一层,而不是对着一个黑盒子干瞪眼。之前我把 VLM 直接接到控制接口上,模型输出格式一变,整个系统就废了,后来拆开才知道有多香。
3.2 核心控制循环:照着这个骨架接你自己的平台
核心就是这段循环,你直接用自己平台的接口替换里面的函数就行:
while not task_done: eye_img = capture(eye_camera) # 头顶全局图 wrist_img = capture(wrist_camera) # 手腕近景图 state_text = get_robot_state_text() # 例:"gripper open, pos(0.42,-0.10,0.33)" prompt = build_operator_prompt(instruction, eye_img, wrist_img, state_text, history) response = vlm.generate(prompt, max_new_tokens=64) action = parse_keypress(response) # 解析成 {"type": "MOVE_FWD", "value": 1} if action is None: print("model says:", response) # 输出不规范,跳过这一轮 continue ok = execute_on_robot(action) if ok: history.append(action) else: # 执行失败,把错误信息回灌给模型,让它重新规划 history.append({"type": "EXEC_FAIL", "detail": result.error})这里最容易被忽略的是history。VLM 不能只靠当前帧做决策,它得知道“刚才自己按了什么键”,否则画面稍微变化它就会失忆。我的习惯是保留最近 10~20 步的键名文本,不保留图像,避免上下文爆炸。parse_keypress这个函数也值得多花心思,我前后迭代了四个版本,才找到一个稳定兼容的解析方式:让模型输出一个 JSON,例如{"subgoal": "move to above cup", "key": "MOVE_FWD"},解析层就按 JSON 字段读,几乎不会出错。最开始让模型直接给按键名,它动不动就夹带解释性文字,正则写到我崩溃。
3.3 标定与坐标系协调
很多人项目进程卡在这一步:相机图像里的“右”和机械臂基座标系的 y 正方向未必同一边。不做标定的话,VLM 说“向右”,你根本不知道该往哪个坐标系转向。初期调试可以先在 prompt 里显式告诉模型“当前机械臂位置在世界坐标下为 (x, y, z),前后左右分别对应坐标增量的正负方向”,让它基于机械臂中心坐标去判断。这样最简单,前提是你先把相机和基座的粗略变换关系定下来。
如果你走“手腕相机视角”的路线,可以不上完整的标定流程,让动作键相对于当前相机朝向定义。这个方案上手快,但每一步都有估计误差,跑不了太久就会发生明显累积漂移。这部分没法偷懒,要么标定,要么给末端位置做视觉反馈修正,不然任务做到后半程全都偏到姥姥家。
3.4 安全机制:键盘也要装“软保险”
VLM 输出是概率性的,它可能在一个瞬间按出一个离谱的键。安全不能只靠信任模型,我建议至少做三层保护:
- 单键幅度限制。每个动作键的执行量锁死在毫米/度级,即使模型乱按,也不会瞬间撞坏设备。
- 执行层限位。在机器人控制器里设置速度上限、加速度上限、力矩阈值,一旦触碰立即停止。
- 物理急停键。必须保留,键盘方案只是决策中间件,不是安全机制的替代品。
另外有个很实用的小细节:在解析层给每个动作键加“执行前置条件”。比如“CLOSE 之前,夹爪必须处于某个高度范围内”,这是简单规则,却能把很多低级错误扼杀在执行前。成本低,收益大。
4. 实测落地时踩过的坑,以及补救办法
理论到落地之间永远隔着一堆实际问题。这节记录我实测中踩过最痛的四个坑,每个都附上了最终的补救方案。前两个坑差点让我放弃这条路线,你把对应策略收好,应该能直接绕开。
4.1 推理延迟:VLM 不是伺服,别拿它当实时控制器
我第一个版本的设想很美好:VLM 放进 10Hz 控制循环,实时指挥。结果现实很骨感:本地跑一个 4B 参数量的视觉语言模型,单次生成就要 400 毫秒到 1 秒,加上图像传输、解析、执行,一个按键周期能拉到两三秒,整个循环根本转不起来。
我的对策很简单:放弃“实时伺服”的执念,接受“慢决策”的节奏。每按一次键,机械臂彻底停下来,等画面稳定后再拍下一张图,再推理下一步。桌面抓取这种任务天生不要求毫秒级响应,慢一点没关系,稳才是关键。如果模型在简单场景下比较稳定,你还可以让它一次输出 3~5 个按键序列,执行层按顺序播放,相当于“开连招”,交互次数直接减半,任务耗时大幅缩短。
4.2 动作太碎导致抖动与累积漂移
非标定方案下,模型每按一次“向右”,都基于它对当前朝向的估计,估计肯定有误差,误差还会一路叠加。最初我把步长设 1 厘米,VLM 每一步的判断都没错,但跑到 20 步以后,末端位置肉眼可见地偏了。另一个问题是步长太碎的时候,模型会在目标附近来回横跳,看起来像得了帕金森。
补救方案是两级操作:粗调阶段用大步长(3~5 厘米)快速逼近目标,等到视觉上判断“已经靠近了”,通过一个专门的“切换键”进入微调模式,再切小步长逐帧修正。这个切换动作本身也可以作为键盘上的一个键,让 VLM 自己决定什么时候切。同时在每 5 步左右加入一次视觉校准,用头顶相机重新估计末端位置,把漂移拉回来。还有一个小技巧:连续两个时间步需要按同一个键时,让解析层只执行一次。这一条能直接消除大量抖动。
4.3 上下文爆炸:图像不能全塞进去
这是我踩过最隐蔽的坑。初始方案里每步都往 prompt 里塞两张图像,跑到第 40 步左右输入长度就超了窗口,模型开始胡言乱语,输出一堆不存在的键。这个坑你很难第一时间发现,因为前面的步骤看起来运行正常,突然某一步 VLM 就像喝醉了一样乱来。
后来我把“记忆”拆成两路:当前帧保留图像,历史记录只用文本摘要。每跑 5 步,让模型输出一句状态摘要,比如“已完成接近,夹爪位于杯子上方约 2 厘米”,然后只把摘要放进后续的 prompt。效果立竿见影,模型不再丢上下文,输入长度稳定可控。另外一个细节:图像分辨率不需要拉满,顶层决策只需要看到大致空间关系,我把输入图压到 512×512,推理速度快一截,任务成功率反而没怎么跌。
4.4 指令歧义与“乱按”的定位问题
“拿杯子”这种指令本身是模糊的:是拿杯把手还是杯身?放到托盘左上角还是正中央?VLM 会用自己的语言先验去猜。猜错了你光看按键日志很难定位问题到底出在哪一步:是它理解错了,还是按错了?
我后来把 prompt 模板改成强制模型先输出“当前子目标”,再输出按键。每一步的日志都会有“我认为现在该干什么”和“我为这个目标做了什么”两行,排查问题的时候一眼就能看出偏差发生在理解环节还是执行环节。这个习惯我现在在别的项目里也一直保留。如果你要做 VLM 机器人控制,这个“先想后做”的方式强烈建议抄走。
5. 把键盘日志变成微调数据:更省力的优化闭环
Show-Harness 还有一个隐藏优势:它天然能把运行日志变成微调数据,跟主流 VLM 微调工具链无缝衔接,解决“数据从哪来”的老大难问题。
5.1 为什么这种轨迹比遥操作示教更“好用”
先对比一下。遥操作示教产生的轨迹,本质是一串高维关节角序列,里面混着大量冗余动作,清洗和标签都费劲。Show-Harness 跑出来的轨迹,本身就是“图像 + 文本指令 + 离散动作”的结构化数据,一条成功轨迹天然就像对话上下文,直接转成微调样本就行。更妙的是失败轨迹也是数据:保留错误前缀,在末尾用几笔人工纠偏动作续接,就构成了带“错误恢复”语义的样本,这种数据教模型“偏离后怎么回来”,泛化价值比单纯模仿正确轨迹高得多。
我在实验里做了一套简单的数据闭环:先跑通 50~100 个成功任务,记录全部“状态-按键”序列;挑出执行干净、没有反复横跳的轨迹;再把少部分失败样本人工补上正确的按键续接;最后统一转成对话格式:system 说明动作键表,user 放任务和图像,assistant 放按键序列。整个流程不需要人工标注关节角,只需要在失败样本尾部做简单处理,数据生产效率比遥操作高出几个数量级。
5.2 用开源工具链微调 VLM 的实践参数
数据处理完成后,微调本身就比较标准了。我用的是社区里常用的 VLM 微调框架,比如 LLaMA-Factory 这类支持图文对话数据的工具。核心是把动作键当作普通文本 token 来对待,图像照常当作多模态输入。下面是一条微型训练样本的格式,你应该见过类似结构:
{ "system": "你正通过操作键盘控制机械臂,可用按键包括MOVE_FWD,MOVE_BACK,...,OPEN,CLOSE。先说明子目标,再按键。", "user": "把右侧的红色杯子放到左侧托盘内", "assistant": "subgoal: 接近红色杯子 | key: MOVE_LEFT" }我用 LoRA 只调语言解码器,视觉塔冻结,跑了几轮之后效果已经比较明显:同一任务下连续按键的错误率比基座模型降低了大约四成,对“右侧的”“左侧的”这类位置修饰词的理解也稳定多了。微调还有一个好处:它让模型的输出格式更听话,parse_keypress解析时几乎不用再做容错处理,因为模型习惯了结构化输出。
5.3 微调之后,键盘仍然必须保留
权重微调了,不代表键盘这层中间表示可以拆掉。我见过有人在微调后直接让模型输出关节角,结果模型像忘掉了语言一样疯狂输出数字。千万别拆中间层。微调提升的是“在给定状态下选择哪个按键”的准确率,而不是模型变成万能控制器。底层运动原语、运动学求解、控制器限位必须原样保留。
在工程上,这条原则可以表述为:动作空间不变,只是给定状态下选择动作的概率分布被更新了。所有微调风险被限制在“决策层”,底层永远是安全兜底。你任何时候都可以切回人工操作键盘或者传统规划器,一点都不影响。这个设计是整套框架最稳妥的地方。
6. 这套“操作键盘”适合什么场景,哪些场合别硬上
写到最后,泼点冷水。Show-Harness 不是银弹,说清楚了边界,你才能真正判断该不该在自己的任务上用。
6.1 不适合的场景远比适合的多
任何要求高速闭环的任务,比如动态抓取、打磨、焊接跟踪,都别指望这套方案。VLM 推理延迟决定了控制周期至少百毫秒级,这是物理瓶颈,再强的模型也突破不了。亚毫米级精度要求也基本没戏,键盘离散步长有限,每步机械和视觉误差会累积,你让它做高精度插孔,它每一步都觉得自己对齐了,实际还差好几道丝。工业产线上“几百台设备固定跑同一个动作”的场景,也无需启用 VLM——示教器、离线编程、PLC 逻辑已经又快又稳又便宜,让一个会聊天的模型去掺和纯属自找麻烦。
6.2 真正适合它的土壤在哪里
真正适合这套方案的是“任务多变、环境半结构化、允许慢决策”的操作场景。比如桌面随机摆放物体的抓取与放置,家庭服务里的整理杂物、递水、开关柜门,科研里的灵巧操作原语验证,以及小批量装配线里频繁换型、但基础动作相似的生产节拍。在这些场景里,传统编程要反复写轨迹,端到端行为克隆要反复录数据,而操作键盘 + VLM 只需要任务能用二三十个基础动作表达,换任务基本不用重录数据,改一下指令文本就能跑起来。
6.3 落地建议:先跑通一个最小闭环再说
如果团队想试这套思路,别一上来就上大模型、换机械臂。先用你手上现有的设备,加两个动作键(前进、后退),接一个开源 VLM,在仿真或真实桌上跑通“靠近目标”的最小闭环。确认图像采集、prompt 组织、解析、执行四个环节都顺畅了,再逐步扩展按键集和任务难度。
键盘这层抽象怎么设计,值得花比模型选型更多的时间。我自己的体会是:VLM 能不能按出正确的动作,往往不取决于模型聪明程度,而取决于你给的键盘顺不顺手。按键定义得越符合视觉直觉,模型成功率越高,后面调起来也越省力。我曾经因为一个步长参数不匹配,让模型在目标物体上方来回横跳了两分钟,换掉参数后任务瞬间顺了——这种问题,跟模型智商一点关系都没有。
我个人现在做机器人任务时已经养成了一个习惯:拿到需求先问一遍,这个任务能不能拆成一组离散的可观察、可返回的按键动作?能,Show-Harness 就会给出一条比录数据微调更快、更可控的路径;不能,说明底层还是得靠传统控制,VLM 只做高层规划就够了。方向别搞反,工程收益会大很多。下一阶段我会继续折腾双机械臂协同的“双键盘”方案,到时候再把新坑整理出来分享。