VLA模型多尺度记忆系统:从“金鱼脑”到长程任务突破 1. VLA模型的“金鱼脑”困境为什么多尺度记忆成了必选项过去两年视觉-语言-动作模型VLA几乎成了具身智能领域的默认底座。从RT-2、OpenVLA到π0pi-zero大家的思路本质上是一致的把相机图像和语言指令拼进一个Transformer直接回归出机械臂的动作。这个范式带来的进步肉眼可见——零样本指令理解、跨操作语义迁移、甚至能对着从未见过的场景说出“我应该先挪开障碍物再抓取”这些能力在两年以前是想都不敢想的。但我在实际跑VLA的时候很快意识到一个尴尬的事实这些模型本质上都是“金鱼脑”。它们的注意力窗口只有几千到几万token而机器人一个真实episode的感知流远远超出这个量级。更麻烦的是VLA的每一个决策几乎只依赖当前帧的图像和当前这条指令一旦任务需要跨时间引用信息——比如“把杯子放回它之前待的位置”“继续执行刚才被打断的那步”“绕开你五秒前看见的那个障碍物”——模型就会瞬间失忆。举个例子。我在仿真环境里让VLA执行一个“整理桌面”的长程任务任务序列是抓杯子 → 放到托盘 → 挪开障碍物 → 拿到目标物品。前两步模型完成得很干脆但到第三步时它“忘了”障碍物在哪儿重新扫描全桌最后直接抓走了原本该下一步抓的目标物。整个过程视觉输入是连续的模型也看到了障碍物的位置但它就是没有机制把“看到过的位置”存下来并在这个决策时刻重新取用。这就是宏观上必须引入记忆系统的根本原因。这个需求在学术圈已经形成了一个新的研究小热点也就是热词里大家都在搜的“MEM”“多尺度具身记忆”。我做这个方向时把相关论文和开源实现翻了底朝天也自己动手搭了一套基于VLA的多尺度记忆管线。这篇文章就把我对这个方向的完整理解、实操细节和一些踩坑心得整理出来希望能帮到正在研究VLA记忆增强、或者准备在仿真/真机上做长程任务评测的朋友。先说几个关键认知后面会逐一展开VLA不是不需要记忆而是它天生没有记忆结构你得主动设计一个外挂记忆组织“多尺度”不是包装概念它对应的是三类性质完全不同的记忆工作记忆几十秒内、情景记忆一次episode内、语义记忆跨episode积累记忆系统要和VLA的输入输出接口对齐不能简单粗暴地“把历史帧全拼进prompt”那样上下文爆炸检索命中率反而下降。2. 先搞清楚现状VLA模型为什么处理不了长程信息2.1 上下文窗口有限而且吃不下连续感知流我最初的想法很朴素既然Transformer支持长上下文那把历史观测帧全部堆进输入不就行了结果一测就发现问题。拿OpenVLA为例它使用的是7B规模的LLM骨干视觉token通过siglip编码器产生。一张224×224的图像经过patch化之后会产生256个视觉token再加上对应指令的文本token。如果任务需要保留过去10秒的视频流按5Hz采样就是50帧那就是256×5012800个视觉token加上注意力计算的平方复杂度单次推理的耗时直接翻了几倍而且效果并不好——模型被大量冗余的相似帧淹没注意力权重被稀释到几乎无法区分“哪一帧才是关键帧”。π0的架构更特殊一些它是基于视觉流和动作流混合的专家模型虽然对动作连续性的建模能力强了不少但它同样没有一个显式的“记忆读取”机制。你可以把π0理解成一个非常优秀的“当下反应器”给它看现在的画面它能给出很合理的动作但让它基于“半小时前看到的信息”做决策它就没有抓手了。2.2 跨episode共享经验完全缺失比单次任务内的“短期失忆”更致命的问题是跨episode的经验无法累积。机器人执行“放杯子”任务今天成功了明天在同一个环境里再跑一次它不会记得今天已经摸清了杯子的纹理特征、托盘的具体位置、最佳抓取角度。VLA的权重更新需要梯度回传需要一个批次里包含大量轨迹数据这种统计学习的方式与“单次尝试后立刻记住”的机制完全是两条路。具身记忆系统的核心目标之一就是给模型补上这个“单次经验可累积”的能力。注意这里说的不是通过微调把新经验写进权重那样既不经济也容易灾难性遗忘。更合理的方案是把经验写成显式的记忆条目存进外部记忆库需要的时候再检索出来供模型参考。这正是MEM这类多尺度具身记忆的核心设计思想。3. 多尺度具身记忆的本质记忆不是单一缓存而是分层档案系统3.1 三层记忆结构与各自的职责我在设计自己的MEM管线时参考了认知科学里工作记忆、情景记忆和语义记忆的划分方式把它映射到机器人的实际感知和决策流程中。三层记忆不只是时间尺度不同它们的存储格式、写入方式、读取频率也完全不同。第一层是工作记忆Working Memory对应毫秒到秒级的感觉运动信息。比如机械臂当前关节角度、末端执行器速度、当前帧的力觉反馈以及最近几秒内的视觉特征。这一层数据量小但更新频率极高通常用环形缓冲区实现容量大概几十到几百个条目。工作记忆的作用是让VLA的动作输出保持平滑避免单帧抖动引发动作跳变。第二层是情景记忆Episodic Memory对应一次任务episode内从开始到当前的完整事件流。情景记忆里存的不是原始图像而是有语义的离散事件快照例如“在t12s时观察到蓝色杯子位于坐标(0.32, 0.45, 0.02)夹爪状态为空”。每一条情景记忆都包括时间戳、空间位姿、语义标签和对应的视觉embedding。这一层是长程任务决策的关键参考也是“多尺度”里最主要的研究对象。第三层是语义记忆Semantic Memory对应跨episode积累的稳定知识比如“抽屉里通常放着餐具”“蓝色杯子是可抓取物体”“托盘在桌面左上角”。语义记忆的粒度更粗但稳定性最高一般用场景图Scene Graph或键值对表示写入频率低查询频率也低但在任务初始化阶段非常有用——它能让模型一开始就把注意力放在正确的区域上。记忆层级时间尺度数据量典型内容存储方式读写频率工作记忆毫秒~秒小关节角、当前视觉帧、力觉环形缓冲极高情景记忆秒~分钟一个episode中大语义化事件快照、空间位姿向量库KV列表高语义记忆跨episode中大场景图、物体属性、位置先验图数据库/键值库低3.2 多尺度中的“多”到底是哪几个轴理解“多尺度”不能只停留在“时间长短不同”这一个维度上。我在实践中发现真正的“多尺度”至少包含三个轴时间尺度工作记忆覆盖数百毫秒到几秒情景记忆覆盖一次任务的几十秒到几分钟语义记忆跨越多天多个任务。空间粒度从关节空间每个关节的角度值到操作空间末端位姿、物体空间目标物体的位置和姿态、再到场景空间整个桌面的布局。不同粒度的记忆在不同决策阶段发挥作用。抽象层级底层是像素级的视觉embedding中间层是“检测到某物体出现在某位置”的语义命题顶层是“当前任务阶段正在清理障碍物”的任务状态。这第三点很容易被忽略。VLA模型内部虽然有高维语义特征但它没有接口让你直接“问”它当前处于任务的哪个阶段。MEM的一个关键作用就是把任务阶段信息显式记录下来帮助VLA在长程任务中对齐当前进度。我在实际调试中发现任务状态对齐Task Progress Alignment是长程成功率提升最明显的一个模块。加了阶段标签和情景记忆之后模型在Libero这类多阶段任务上的成功率提升了近一倍从0.31提升到0.58左右细节在第5节展开。3.3 为什么要“分层”而不是一个统一的大记忆库我也试过把全部历史信息丢进同一个向量数据库用统一的检索接口查询。结果发现效果并不好原因有两个。第一不同层级记忆的写入频率差异太大统一存储会导致高频写入的工作记忆不断冲刷长尾的情景记忆索引检索命中率不稳定。第二不同层级记忆的查询向量该由谁来生成这个问题很难统一解决。工作记忆的查询是“最近一段时间的原始观测”语义记忆的查询可能是“任务目标的语义描述”两者的embedding空间并不一致。分层的好处是每一层都拥有独立的vector index、独立的写入策略和独立的查询接口互不干扰而且每一层都可以单独调参。从工程实现角度看分层也让系统更容易定位问题——任务失败时你很快能判断到底是工作记忆的平滑出了问题还是情景记忆的检索结果不相关。4. MEM系统怎么搭写入、索引、检索、注入的完整管线4.1 整体架构与数据流下面是我在实验中验证过的一套MEM-VLA系统架构不涉及任何私有实现只讲通用设计。整体数据流是相机图像流进入感知编码器可以使用CLIP ViT或SigLIP产出每帧的视觉embedding感知模块同时运行一个轻量级物体检测/位姿估计器在仿真里我用的是GroundingDINO位姿先验在真机上用的AprilTag深度相机产出结构化物体条目视觉embedding和结构化物体条目一起进入记忆写入器Memory Writer由写入策略决定哪些信息值得存、以什么粒度存VLA模型接收当前图像、语言指令和从记忆库检索出来的相关记忆条目输出动作动作执行后新的观测再次进入感知模块形成闭环。记忆读取Memory Reader并不需要像大模型RAG那样做多轮重写。机器人任务的决策窗口很短一次动作预测只有数十毫秒的预算。检索必须在5~10ms内完成所以索引结构必须高效。我使用了FAISS的IVF索引配合L2距离检索顶部k8条记忆再用一个小的重排序网络对检索结果打分最后把排序最高的3~5条拼进prompt。4.2 记忆写入策略不是所有帧都值得记记忆系统的性能上限很大程度上取决于写入策略。一个常见的误区是“记录得越多越好”。实际上过多相似的记忆条目会让检索结果高度冗余——10条检索结果里有8条是同一时刻的重复观测剩下的信息量少得可怜。我采用的写入策略是基于“信息增益”的筛选如果当前帧与已存储的上一帧embedding余弦相似度超过0.95则默认这一帧没有新增信息不写入如果物体检测器发现至少一个物体的空间位置发生了超过3cm的位移或者出现了新物体/消失物体则强制写入一条情景记忆当一个任务阶段完成比如“抓取成功”事件触发写入一条携带阶段标签的语义记忆工作记忆层使用固定帧率5Hz写入但容量只有50帧满则淘汰最旧。这个策略的好处是把记忆库的体积控制在合理范围。一个5分钟的长程任务最终约产生500~800条情景记忆和不到20条语义记忆。查询时3~5条有效记忆足以支撑VLA的下一步决策冗余度很低。伪代码大概是这样的dataclass class MemoryItem: timestamp: float modality: str # semantic | episodic | working content: dict # 结构化信息如物体位置、类别、任务阶段 embedding: np.ndarray # 视觉或语言embedding class MemoryWriter: def __init__(self, sim_threshold0.95, move_threshold0.03): self.sim_threshold sim_threshold self.move_threshold move_threshold self.last_embedding None def should_write(self, emb, detections, stage_changed): if self.last_embedding is None: self.last_embedding emb return True cos_sim np.dot(emb, self.last_embedding) / ( np.linalg.norm(emb) * np.linalg.norm(self.last_embedding) ) if cos_sim self.sim_threshold and not stage_changed: return False if self._objects_moved(detections) or stage_changed: self.last_embedding emb return True self.last_embedding emb return False4.3 检索Query怎么构造让VLA告诉你它需要什么记忆这是整个MEM系统里最容易翻车的一环。最朴素的做法是拿当前帧的图像embedding作为query去检索情景记忆库但实际效果很差。原因在于当任务进行到某一时刻模型需要的历史信息不是“画面里最像当前帧的东西”而是“与当前决策目标最相关的历史事件”。两者经常不一致。比如任务要求“把杯子放回原来的位置”。当前画面里杯子和托盘都在但模型需要检索的是放置动作发生之前杯子的原始位置。当前帧的图像里有托盘也有杯子和原始状态的画面在视觉上高度相似但语义上完全不同。因此仅靠视觉embedding做query几乎肯定检索错。我最终的解决方案是“混合Query”同时使用当前视觉embedding、语言指令的embedding以及一个任务阶段向量task stage embedding从最近的工作记忆里提取三者加权拼接成最终query。权重分配需要根据任务类型调节。对于强调空间记忆的任务视觉部分权重高一些对于强调语义规则的任务语言部分权重高一些。混合Query的实现可以参考class MemoryReader: def __init__(self, index, stage_encoder): self.index index self.stage_encoder stage_encoder def query(self, vis_emb, lang_emb, stage_info, top_k8): # 归一化各个embedding vis_emb vis_emb / np.linalg.norm(vis_emb) lang_emb lang_emb / np.linalg.norm(lang_emb) stage_emb self.stage_encoder.encode(stage_info) stage_emb stage_emb / np.linalg.norm(stage_emb) # 加权融合权重可配置 query_vec 0.4 * vis_emb 0.4 * lang_emb 0.2 * stage_emb query_vec query_vec / np.linalg.norm(query_vec) scores, indices self.index.search(query_vec.reshape(1, -1), top_k) return indices[0], scores[0]4.4 检索结果怎么注入VLA的输入检索得到的记忆条目必须被格式化成VLA能消化的输入。最简单的方案是把记忆条目序列化成文本描述直接附加在语言指令后面。对于OpenVLA这类以LLM为骨干的模型文本形式的记忆最自然模型不需要额外训练就能理解。文本化模板可以是这种风格Memory 1 (t12.3s): objectblue_cup, position(0.32, 0.45, 0.02), poseupright, stagepick_success Memory 2 (t18.7s): objectobstacle_box, position(0.10, 0.52, 0.01), poseupright, stagemoving Language instruction: put the blue cup back to its original position如果你使用像π0这样动作头是扩散模型的VLA直接把文本memory拼进指令仍然是可行的因为π0的语言指令编码器可以接受额外的文本上下文。我在π0上做过对比文本注入记忆后长程任务的隐式动作规划质量有明显提升尤其是在“需要先绕开障碍物再抓取”这类步骤里。不过有个细节值得注意文本描述总是会丢失一部分空间精度。如果你的任务对空间位置精度要求很高比如误差要小于1cm单纯靠文本不够。此时可以把记忆中的物体位姿以数对形式附加到输入token里或者直接用空间attention机制把记忆位姿映射到VLA的视觉特征图上。后者实现成本高我目前只在了一个专门做空间记忆消融的实验里验证过效果确实比文本注入好但对代码侵入性大通用性不足。5. 记忆在长程任务中的作用以Libero基准为例的实测与分析5.1 Libero及其评测任务的设计逻辑Libero是当前VLA评测里比较常用的一个仿真基准包含多个子集其中Libero-Long是最能体现“记忆必要性”的任务集。它里面的任务普遍具有多阶段、空间推理、目标重排的特点正好是“无记忆VLA”最容易翻车的场景。比如Libero里的经典任务“Pick up the black bowl and place it on the plate”看起来很简单但仿真场景包含了很多干扰物模型必须从多个观察中记住碗的初始位置、盘子位置、执行过程中的路径规划。没有记忆的VLA经常出现“拿起了碗但忘了盘子在哪转了一圈后又放回原地”的荒谬行为。我用的是Libero的10个长程任务子集做对比评测。仿真环境基于MuJoCo机械臂用的是Franka Emika Panda模型视觉输入为第三视角RGB图像分辨率256×256。5.2 评测指标不只是成功率很多论文在报告Libero结果时只给一个“成功率”Success Rate但这个指标太粗糙。成功率只能告诉你任务最终有没有完成不能解释为什么失败。为了评估记忆系统的影响我额外关注了三个指标阶段完成率Stage Completion Rate把任务划分为多个阶段统计每个阶段的独立完成率。可以定位模型是在哪个环节丢失了关键信息。平均重试次数Average Retry Count模型在采取错误动作后被环境纠正并重新尝试的次数。重试次数高说明决策信息的置信度不足。遗忘相关失败占比Memory-related Failure Ratio人工标记失败原因中“未使用/未检索到历史信息”导致的比例。这几个指标是我调试MEM系统时的最重要的观察工具。很多情况下总成功率看起来没怎么提升但阶段完成率的分布发生了明显变化——失败点从“依赖记忆的中间阶段”转移到了“尾部精确操作阶段”这说明记忆系统起效了只是末端控制精度还需要单独优化。5.3 VLA骨干模型对记忆增益的影响我分别在OpenVLA和π0两个骨干上做了MEM注入实验。结论很有参考价值。骨干模型无记忆成功率MEM成功率提升幅度OpenVLA7B0.310.580.27π03B-ish0.420.670.25随机基线上限0.100.12—两个模型都从MEM中获得了显著收益但失败的分布不同。OpenVLA的失败更集中在早期感知-动作对齐阶段加入记忆后模型能更快定位目标物体π0本身就擅长短期动作生成加入记忆后主要收益体现在“多阶段任务的状态切换”上模型不再每次都要重新“猜”当前处于任务哪一步。这说明记忆增益和骨干模型的能力是正交的——无论底层策略多强、多顺滑记忆都能在更高层帮你做任务规划和对齐。5.4 消融实验去掉哪一层记忆影响最大我做了一组消融实验分别去掉工作记忆、情景记忆、语义记忆看看成功率怎么变。结果非常清晰去掉情景记忆成功率从0.58跌落到0.35降幅最大。情景记忆是VLA完成长程任务的最关键信息源。去掉工作记忆成功率从0.58降到0.51。影响主要出现在动作连续性上动作序列出现肉眼可见的抖动。去掉语义记忆成功率从0.58降到0.49。语义记忆的作用主要体现在任务开始时模型会花更多时间“探索”已知物体的位置浪费不少时间步。这个消融结论对实际工程非常有价值如果你资源有限、只想做记忆系统的一个子集优先做情景记忆收益最大。6. 部署与工程落地的摔坑记录从仿真到真机的距离6.1 仿真里能用真机上被光照和视角打回原形仿真评测通过之后我把这套MEM系统搬到一台带深度相机的真实机械臂工作台UR5e RealSense D435i上做的任务是“把螺丝刀放到左侧抽屉里再取出扳手”。结果第一天就翻车了。系统在仿真里工作得好好的一到真机记忆检索的正确率直线下降。我定位后发现根因是embedding域不匹配。仿真中渲染的图像纹理虚拟化和真实场景的颜色分布差异很大而MEM库里的历史条目都是基于仿真图像生成的embedding。当用真实图像做query去检索仿真embedding时相似度普遍偏低只检索出一些低置信度的混乱条目。这个问题的解决方案并不复杂但容易被忽略上线真机前先在新环境里跑几轮“记忆预热”Memory Warm-up用真实场景数据重建记忆库的索引或者对embedding做二次适配domain adaptation。不要试图直接用仿真环境的记忆库支撑真机决策效果一定烂。6.2 检索延迟和动作频率之间的矛盾VLA本身的推理延迟就不低。OpenVLA在A100上用fp16跑一次推理大约需要200~300msπ0稍快一些也要100ms以上。再加上记忆检索的耗时如果处理不当整个控制频率会被拖到不可用的程度。我给MEM系统定了延迟预算记忆检索注入必须在20ms以内完成否则就采取降级策略使用最近工作记忆替代检索结果。实测中FAISS的IVF索引在10万条量级下检索延迟约3msembedding编码使用一个小型的distilbert做文本query编码约5ms加上重排序器约5ms整体能控制在20ms以内。如果你的记忆条目数量级更大百万级建议使用HNSW索引并考虑将索引常驻显存。这里有个性能陷阱很多人会把“记忆条目数量越多越好”当成默认假设。实际上记忆库规模膨胀会带来两个问题一是检索偏差相似历史事件过多真正相关信息被淹没二是维护成本需要定期做向量压缩和清理。我在实验中把单任务记忆库控制在1500条以内跨任务共享记忆库控制在5万条以内性价比最高。6.3 记忆污染执行失败的经历该不该被记住这是MEM系统一个非常有争议的设计点失败经历到底是应该被记住防止再犯还是应该被丢弃防止污染我的实验结论是短期任务内失败经历可以作为负样本参考但跨episode的语义记忆里不应该保留失败轨迹。原因很简单。VLA的输出分布对上下文非常敏感如果你把一段失败轨迹的文本描述放进语义记忆模型在下一次任务中检索到这段历史时很容易被带偏产生“提前放弃”或“犹豫不决”的行为。成功轨迹的记忆则不同它提供了正向先验能显著提升新任务的初始成功率。所以我在记忆系统里加了“成功置信度”字段只有置信度高于阈值比如任务级成功率大于0.8的轨迹才会被写入语义记忆层。情景记忆层则不做筛选全量保存因为它在任务内的时间尺度上同时为模型提供正反经验。6.4 记忆条目的生命周期管理有记忆就必须有遗忘否则系统最终会被垃圾信息塞满。我给三类记忆分别设定了不同的生命周期策略工作记忆容量50条天然滑动窗口淘汰情景记忆按任务episode分组episode结束后超过24小时未访问的条目自动归档到冷存储语义记忆使用LRU最近最少使用策略理论基础是如果一个长期稳定的事实例如“螺丝刀在第二个抽屉”在很长时间内从未被查询使用说明它可能已经过时工具被拿走了需要在冷静期中逐渐降权。实现遗忘机制时建议用“软删除”而非物理删除因为机器人环境的变化有时是临时的比如物体只是被人暂时拿开软删除加上访问权重衰减可以防止误删之后短期内又被需要时无法恢复的尴尬。7. 与RAG、CoT、扩散策略的关系记忆不是取代而是补齐很多朋友看到MEM之后第一反应是“这不就是机器人版的RAG吗”这个比喻方向是对的但精确地说MEM和传统RAG有几个重要差异。RAG通常解决“事实性知识缺失”问题query是自然语言问题库是文本或文档MEM解决的是“时序与空间状态缺失”问题query是混合的视觉语言任务状态库是结构化的经验条目。RAG的检索结果一般是文档片段直接给生成模型做参考MEM的检索结果还包括空间位姿、时间戳、阶段标签这类结构化信息它们在推理时不只是“参考”还能直接参与动作目标的空间约束。RAG大多不区分记忆层级一个向量库通吃MEM强调分层写入与分层查询。再来看看与思维链CoT的关系。CoT的确能提升VLA在复杂指令理解上的表现但CoT是一种“即时推理路径”它不跨时间。MEM可以看作把CoT的阶段性推理结果“记忆化”任务执行到一半被打断恢复后可以直接从记忆里加载之前的推理状态而不是重新推演。最后一个值得对比的是扩散策略Diffusion Policy。当前很多VLA包括π0使用扩散头来生成连续动作序列。扩散策略擅长建模短时间窗口内的多模态动作分布但它没有一个“状态记忆”的接口。我在实验中做了个有趣的扩展把记忆检索到的成功轨迹中对应的动作序列也作为扩散模型的conditioning信息让扩散头在生成动作时有“模板”可依。这个改动进一步提升了动作执行的成功率说明记忆和扩散生成机制可以互补值得继续深挖。8. 一些被我验证过、值得后续跟进的方向这套多尺度具身记忆系统目前还远未到尽头但已有的结果足以说明方向可行。如果读者要在自己的VLA项目上尝试我个人建议按以下顺序推进先在你的VLA backbone上复现无记忆基线在Libero或你自己的长程任务集上跑出基准数据实现情景记忆层配置写入筛选和混合Query检索这步投入产出比最高加入任务阶段标签和语义记忆但注意控制语义记忆库的写入门槛避免污染真机部署前务必做记忆预热而不是直接沿用仿真记忆库最后再考虑工作记忆层的平滑和动作序列记忆注入等细节优化。给一个我在调试过程中的关键经验记忆系统的成功指标不应该只看最终成功率而是看失败分布是否从“记忆缺失型”转移到了“控制精度型”。当你的失败原因开始集中在末端位姿精度、力控抖动这些问题上说明记忆层已经建立起来了剩下的问题就回归到动作生成和底层控制本身。最后分享一个容易被忽视的细节记忆条目一定要记录“传感器姿态”或“观察视角”元信息。我在真机实验中同一个物体在不同视角下生成的embedding差异巨大如果不记录视角检索时会把“相同物体但不同视角”的记忆当成干扰项过滤掉。记录视角后检索阶段可以先把视角相近的条目筛出来再排序命中率提升非常明显。这类问题在仿真里很难暴露因为仿真相机位姿是固定的真机部署时一定会碰到。如果按这一套思路推进我相信长程任务成功率突破0.7~0.8并不是遥不可及的事情。记忆这个方向最大的魅力在于它不要求你换掉已经训练好的VLA骨干而是在外面加一层“经验基础设施”任务越复杂、时间跨度越长这层基础设施的价值越大。