递归技能增强强化学习:让智能体沉淀可复用技能

发布时间:2026/10/17 4:12:31
递归技能增强强化学习:让智能体沉淀可复用技能 你训练过最让人头疼的强化学习任务是什么我先说我的让智能体在一个几十步才能完成的稀疏奖励任务里稳定学到策略。试过各种奖励塑形、课程学习、辅助损失最后发现一个更本质的问题——智能体每学一个新任务几乎都是从零开始它不会把之前学会的本事沉淀下来。这就是SKILLRL这类方法想解决的核心矛盾怎么让智能体像人一样把会做一件事变成可复用的技能甚至让技能去调用技能。这篇文章基于我实际接触过的递归技能增强强化学习项目聊聊这套思路背后对进化式智能体的增强逻辑、落地实现时的关键细节以及我在实验里踩过的坑。如果你正在做分层强化学习、技能发现或者被长时程稀疏奖励问题折磨过这篇应该对你有参考价值。1. 单一策略的天花板为什么智能体总在重复造轮子1.1 稀疏奖励下的学习困境不只是等不到奖励那么简单先说个很典型的场景。我在某个仿真环境里训练智能体完成一个多阶段任务先推门再绕过走廊最后按下一个开关。每个子阶段单独拿出来都算简单但串在一起就变成了一个长时程稀疏奖励问题——整个轨迹可能有上百步而唯一的正奖励只会在最后按下开关时出现。用PPO直接端到端训练你会发现几个令人头秃的现象学习极不稳定前几千回合几乎学不到任何东西策略一直在一个低水平徘徊偶尔瞎猫碰上死耗子拿到一次奖励接下来几轮又会退回去。时间信用分配困难就算最后拿到了奖励这上百步里到底哪几步起了作用早期的推门动作和最终的奖励之间的因果关系隔得太远优势函数几乎被稀释没了。灾难性遗忘好不容易学会了推门结果训练后半段策略调整时它可能又把推门忘掉了仿佛这个技能从未存在过。这三件事本质上是同一个问题单层策略网络把感知—决策—记忆全部塞进一组权重里所有知识耦合在一起改一处就牵动全身。一个动作序列如果太长反向传播时梯度信号早就衰减得不成样子。1.2 人类学习的关键技能的切分、沉淀与再组合换个角度看人类解决长任务的方式完全不是这样的。我学做饭不是把做一顿饭当成一个端到端的黑盒策略去背而是先会切菜再会热锅然后会炒。切菜这个技能学会了不管今天做西红柿炒蛋还是明天做青椒肉丝我都能直接用不需要每次重新发明一遍。这个观察就是技能增强类方法的核心动机把一个长时程、高复杂度的问题拆解成可复用、可组合、可迁移的短时程子策略集合。每个子策略就是一个技能skill它有明确的入口条件、行为模式和作用效果。智能体学习新任务时不是从零训练一个巨型策略而是先看看技能库里有没有现成的积木可以用。而SKILLRL这个名字里的递归recursive指向一个更进一步的思路技能本身不一定是原子的、不再拆分的。一个技能内部完全可以再次调用更底层的技能形成层级化的技能调用链。这就有点像软件的模块化——函数可以调用别的函数而每个函数内部的实现细节对外不可见只暴露一个调用接口。1.3 递归技能与传统分层强化学习的本质区别分层强化学习HRL并不是新概念经典的Options框架、HIRO、FeUdal Networks都做过类似的高层决策低层执行的划分。但传统分层方法有几个绕不过去的坎高层和低层的训练经常不稳定高层给出的子目标subgoal低层根本达不到信号互相干扰。子目标的设定往往需要人工先验定义了子目标就相当于人为限定了任务分解方式。各层之间通常是严格的一对多调度关系——高层只能选一个option往下派option内部不能再做复杂的组织。递归技能方案做了一个关键转变技能不再只是行为片段而是行为生成器。一个技能内部有自己的策略网络这个策略网络不仅可以输出原始动作motor command也可以选择调用其他技能从而在自定义技能体系内部形成一个递归的调用图。这种设计让技能的表达能力从固定长度的轨迹段扩展成任意深度的行为子树而组合出来的行为空间随技能库深度指数增长。这个思路我当时看到时眼前一亮它真正解决了组合爆炸的问题——智能体不需要把每一个长任务都显式建模而是把长任务表示为技能调用树每一层只需要做一个小选择。2. 机制拆解技能召回、递归扩展与双向学习回路2.1 技能的发现不需要人工标注从行为轨迹里自动切分SKILLRL中技能从哪来靠人工设计每个技能的奖励函数吗如果这样就又回到人工先验决定一切的老路了。实际更可行的做法是从已有的成功轨迹中自动挖掘技能段。我当时采用的做法分为两步轨迹分割跑大量随机策略或稍好的探索策略收集成功轨迹然后通过行为特征的变化点比如动作分布突变、访问状态区域切换、兴趣区域变化把轨迹自动切成若干段每一段就是一个候选技能的行为模板。技能抽象把每一段的观测序列和动作序列封装成一个技能用变分自编码器的思路训练一个技能嵌入向量skill embedding。这个向量描述这段行为是在做什么后续要调用时就拿它作为检索和决策的接口。这个过程任何人都可以用公开的skill discovery思路复现比如基于互信息最大化或者基于行为熵的方法都能切出有意义的行为片段。关键在于切出的技能必须短暂、专注且可重复——太长的片段没有复用价值太短的片段又退化成原始动作没有抽象意义。我当时调参的一个经验是轨迹分割窗口我设为80步兴趣区域判定阈值选为0.85切出的技能平均长度大约在20-40步之间。太碎会让技能库膨胀严重太粗则每个技能内部混杂多种行为模式后续递归组合时反而容易互相干扰。2.2 递归调用的技能栈高层技能如何编排底层技能递归技能最核心的执行机制是一个技能栈skill stack。类比操作系统的函数调用栈——当技能A决定调用技能B时A的执行状态被压栈保存控制权移交给BB执行完毕返回时A从之前中断的状态继续往下走。在智能体执行层面这个机制体现在三个要素上调用接口技能输出两种可能的信号一是直接执行底层动作二是发起一个技能调用放一个子技能到栈顶。每一种技能内部都有一个决策头决定当前时刻是该结束自己、继续执行、还是调用子技能。中断与恢复子技能执行期间父技能的策略网络不更新梯度相当于进入挂起状态只保留隐状态在栈里。子技能结束后父技能拿到返回值比如子技能执行前后的状态变化、内秉奖励信号再继续自己的决策。这个设计保证了技能组合的封闭性——父技能不需要关心子技能内部怎么做只需要知道它把世界状态改成了什么样。深度上限为了防止递归无限套娃必须限制栈的深度。我在实验里把它设为3层。为什么是3因为1层退化成普通技能复用2层能表达技能内部的流程组合到3层已经能覆盖绝大多数实际任务的分解深度。再深不是不行但对训练稳定性要求极高梯度要穿过更多层的调用边界。2.3 双向强化学习回路上层学规划下层学动作互相给信号递归技能系统里强化学习不是发生在单一策略上的而是发生在两个相互嵌套的层次上技能选择层上层输入当前状态和技能库中所有技能嵌入输出技能分布。它的奖励信号来自该技能被执行后带来的任务进展对应一个技能级别的价值函数。技能执行层下层输入当前状态加上被选中的技能嵌入作为条件变量输出原始动作。它的奖励信号来自是否完成了这个技能预期的效果由内外结合的信号构成——外部任务奖励为主辅助以技能完成度奖励。这两个层次必须交替训练不是先训好一层再训另一层。实际训练时每一轮迭代里上层和下层按一定比例交替更新梯度。我试过的最稳配置是上层每更新一次下层更新2-3次比例再高会让上层学到的技能选择信号滞后于下层实际能力的提升。这个双向回路是整个系统性能的分水岭。很多复现失败的项目就是没处理好这个交替节奏要么下层没学稳上层就开始调度要么上层锁定了一套技能选择策略下层一旦变化上层就完全失配。3. 从公式到代码递归Bellman方程与技能库迭代的落地写法3.1 技能价值函数的递归形式把技能运行结果当成状态转移普通强化学习的Bellman方程写的是状态到状态的转移当前状态的价值等于即时奖励加下一状态的价值。递归技能系统的关键改动是价值函数的主角从状态变成技能执行的结果。我用一个简化的形式描述这个递归关系。设当前状态为 ( s )当前正在执行的技能为 ( g )技能执行结束后到达状态 ( s )那么技能级价值函数满足V(s, g) E[ R(s, g) γ * V(s, g_next) | g 执行完毕 ]这里的 ( R(s, g) ) 是整个技能执行期间累积的外部奖励总和而 ( g_next ) 是技能 ( g ) 内部下一步调用的子技能如果存在或者由上层策略新选出的技能如果 ( g ) 本身结束。如果你把 ( g_next ) 看作递归调用这就是一棵技能调用树上的价值传播。实际上训练时不能只靠最终奖励稀疏问题仍然存在。我在技能执行层额外加了一个内秉奖励intrinsic reward鼓励技能执行产生可预测的、一致的状态变化。具体说技能执行前后状态编码的差异越接近技能自身的预期变化奖励越高。这一条对技能质量的提升非常明显没有它下层技能很容易坍缩成什么都不做地磨时间。3.2 网络结构与训练Pipeline我在实现时怎么搭的整个系统的网络结构可以分成三块技能嵌入库一个嵌入表每行代表一个技能的128维向量。这个向量不是随机初始化的是通过自编码器对技能行为序列编码得到的训练过程中也会被持续微调。技能选择策略上层输入为状态编码拼接当前可用技能嵌入输出为技能分布。我用了一个两层MLP每层256个神经元激活函数选择GELU相比ReLU在这个场景下收敛更平滑。技能执行策略下层输入为状态编码拼接技能嵌入输出为动作分布。这个部分我建议用类似SAC的连续控制结构但它不维护单独的Q函数而是把技能级价值函数通过递归Bellman形式共享。我整理了一个核心训练循环的伪代码基本按先跑一批环境得到转换数据再分层更新的节奏# 技能库list of Skill每项含embedding和内部策略参数 # stack: skill调用栈初始为空或只含根技能 def train_skill_rl(total_steps200_000): replay_high, replay_low [], [] # 分层经验缓冲 for step in range(total_steps): state env.reset() stack [root_skill] done False while not done: skill stack.top() # 技能决策头输出继续执行 / 结束 / 调用子技能 mode, arg skill.decide(state) if mode call_subskill: sub_skill skill_library.retrieve(arg) # 按嵌入相似度检索 stack.push(sub_skill) elif mode exit: stack.pop() if stack.empty(): # 由上层策略决定下一个技能 next_skill_id high_level_policy.select(state) stack.push(skill_library[next_skill_id]) else: # mode execute action skill.policy.sample(state) next_state, reward, done env.step(action) replay_low.append((state, skill.id, action, reward, next_state)) # 两个层次的经验都收集好后交替更新 if len(replay_high) batch_size: update_high_level(replay_high, skill_library) if len(replay_low) batch_size: update_low_level(replay_low, skill_library)我特别想强调最后一段的交替更新。很多人在复现时习惯先把下层执行策略训练到收敛再训练上层——但这样会导致下层过度适应某一批旧技能的使用方式一旦上层开始选择新技能组合下层立刻失灵。正确做法是让两个层次的更新频率保持一定比例让上层跟上下层能力的变化。上面代码里我写的batch_size实际我用的是8192条转换更新频率上做成了1:2.5上层一次下层两到三次。这个比例调参时值得反复试。3.3 技能库的迭代新技能怎么入库旧技能怎么淘汰递归技能系统有个不太好注意但非常关键的问题技能库不是固定不变的。智能体学会了一个新技能应该让它进库某个技能长期没被调用应该让它淘汰某个技能被调用后效果和数据预期偏差很大说明它已经过时或有缺陷需要重新训练或修正。我把技能库迭代设计成三步流程入库add当一条轨迹片段被判定为行为新颖且结果一致性高时生成新技能嵌入加入库中。判断新颖性的指标是它与库中已有技能嵌入的最大相似度低于阈值0.6。出库remove当某个技能被选中的频率连续多个循环低于1%并且它的执行成功率低于50%时把它标记为冗余退出活跃列表。这能防止技能库无限膨胀导致上层策略的检索空间爆炸。修订revise技能不是永远不变。当技能的实际执行轨迹和它声明的行为目标偏差过大时用最近的成功轨迹重新拟合技能嵌入和内部策略参数让它更贴近真实行为。这个迭代机制有点像操作系统的虚拟内存换页——在库和策略之间形成动态平衡。少了它技能库会越来越像一堆互不关联的碎片无法支撑深层递归。4. 实验验证与调参复盘递归技能在什么场景下真正值回票价4.1 我在某仿真环境里测出的关键对比结果我在某个室内导航与物件操作组合仿真环境里对比了四套方案端到端PPO、普通技能库非递归、分层Option方法、SKILLRL递归技能方案。任务是一个包含开门—穿过走廊—取物—原路返回—放置到目标区的五阶段复合任务全程稀疏奖励只有最后放置成功给一个大的正奖励。结果有几个值得细看的数据首次拿到正奖励的训练步数端到端PPO大约在4万步左右才第一次碰到奖励普通技能库大约在1.5万步而递归技能方案在6000步内就能稳定地拿到第一个正奖励。这里面最关键的提升其实不是更快碰到奖励而是碰到奖励之后策略不再退回原点——递归结构让成功经验以技能为单位被保留下来而不是分散在一整条长轨迹里。最终成功率训练到10万步时端到端PPO的成功率在34%普通技能库在57%递归技能方案达到了83%。差距最明显的阶段是在训练后期——端到端和普通技能库都会出现策略漂移导致成功率回落的涡旋而递归技能方案的成功率曲线更平稳。任务泛化我把目标区位置随机改变重新测试。普通技能库需要重新收集大量轨迹SKILLRL只用了约1/5的训练量就恢复了90%以上的成功率。原因是技能调用树的上层只学了一个取物—返回—放置的规划逻辑底层技能的具体运动参数独立于目标位置可以复用。4.2 实操中最容易翻车的五个坑以下是我在这个项目里真实踩过、并且花了不少时间排查的坑每个都值得单独记一笔坑一技能嵌入的维度太低检索就混乱。我开始用64维嵌入结果技能库里30多个技能时就已经频繁出现语义重叠的现象——取物技能和推门技能在嵌入空间里距离很近上层策略经常把它们混淆。换到128维并加了一个正交性正则化让不同技能的嵌入互相接近正交之后检索准确率明显提升。坑二技能栈深度上限设置过高训练梯度被稀释。我把深度上限放到5层测试时虽然理论上表达能力更强实际训练中却发现下层技能很难学到稳定的行为因为上层技能的调用序列太长每次子技能的错误都会被累加传播。回到3层之后问题立刻缓解。这个经验是先浅后深等浅层技能质量足够了再放开深度。坑三内秉奖励强度太大导致刷状态变化走捷径。内秉奖励鼓励技能产生明显状态变化但如果系数设置太高超过0.5技能会学会在原地反复执行能产生状态变化的小动作来刷奖励反而阻碍了任务奖励的学习。我最终把内秉奖励权重压到0.25以下并要求内秉奖励只在技能结束后结算一次不允许时间步级累加。坑四上层策略网络输入了过多当下没必要的技能嵌入。如果技能库有50个技能而当前状态明显不适合其中30个把这些都塞给上层策略只会让它花精力去学哪些技能不该选。我加了一个简单的门控过滤——用一个状态编码器和技能描述做一次粗粒度匹配筛掉明显不适用的候选技能上层策略只从5-8个候选中选择训练速度快了将近一倍。坑五递归调用处梯度截断方式不对。如果用RNN式的贯穿时间反向传播让梯度穿透整个技能调用栈去更新上层策略不仅计算量爆炸而且上层策略的梯度会被子技能内部的细节淹没。我最后的做法是在技能调用边界上做停止梯度stop-gradient处理——子技能内部的损失不回传到父技能的选择决策父技能只接收子技能的嵌入和返回状态这样上层和下层的学习目标才各自清晰。4.3 递归技能方案不太适合的场景别把它当万能药任何方法都有适用边界SKILLRL也不是所有任务的最优解。我后来在几个不同环境里试过遇到以下情况建议谨慎使用单次交互极度简单、任务周期短比如一步到位的分类决策任务递归技能纯属多余端到端策略或普通多任务头就够了。技能抽象本身有开销短任务里看不到收益。技能之间强因果依赖且不允许组合变体比如每个任务只有一个正确技能序列严格线性的流程技能库的灵活性完全派不上用场。状态表示与技能嵌入空间严重不匹配如果状态编码本身不包含技能效果所需的信息技能执行层的条件输入拼接技能嵌入就成了无源之水下层策略没法把技能语义和状态关联起来。在这些场景里硬上递归技能方案不仅训练时间更长最终性能也不一定优于精心调过的端到端方案。做技术选型时应该先问一句你需要的到底是更好的策略还是更好的策略复用能力前者端到端可能就够后者才是递归技能的舞台。5. 写给想复现这份工作的人几条不那么显性的建议很多人看完这类思路后第一反应是我能不能直接拿开源代码跑一跑。但这类项目的复现难度通常不在代码本身而在超参数和训练节奏的配合。这里分享几条我反复踩过之后沉淀下来的实操建议。第一先把技能库做小再做深不要一上来就追求全技能可用。我在首个验证任务里只放了三个预置技能接近目标、抓取物体、移动物体。这三个技能手动指定行为模板都能跑通后再开始实验自动技能发现不然你永远分不清是技能本身有问题还是技能调度逻辑有问题。小库状态下任何错误都更容易定位。这一步大约能帮你省下两到三周的排查时间。第二务必监控技能使用频率分布这个指标。技能库之间如果出现严重的幂律分布少数几个技能被疯狂调用大部分技能几乎不用说明上层策略并没有真正学会组合调度而是在走捷径反复使用某几个最顺手的技能。这时候不是继续训练的问题而是需要检查技能的语义区分度甚至人工审一下技能库里的技能是否重复、冗余或者边界模糊。我在实验里常用一个简单的熵指标当技能使用分布熵低于某个阈值时触发技能合并或者重新切分的步骤。第三尽量把技能执行层设计成对动作噪声鲁棒的。递归结构有一个副作用父技能对子技能的预期建立在子技能稳定行为之上如果子技能的动作执行有小幅抖动误差会在调用链里往上累积。解决办法一方面是在训练技能执行层时加入动作噪声增大探索性另一方面是在子技能返回给父技能的行为摘要里做平滑——传状态差异而不是精确最终状态减少父母对细节的过分敏感。第四不要忽略技能失败信号的用途。递归技能系统中子技能执行失败本身就是宝贵的学习信号。某个子技能频繁失败通常说明父技能的调用条件不合理或者子技能自身的策略需要重新训练。我在设计经验回放时单独维护一份失败技能轨迹缓冲上层策略训练时每次抽样都会混入一部分失败案例让它学会什么状态不该调用什么技能。这个细节让系统在复杂任务里的稳定性提升了一个档次。6. 递归技能之后还能往哪走进化智能体的下一步聊到最后我想说说SKILLRL这种思路对进化智能体的长期意义。普通强化学习训练出的智能体是一次性的——它在固定环境、固定任务上训练换一个任务就得重新来。但带递归技能库的智能体天然具备一个类似文化积累的机制训练过程中沉淀下来的技能库相当于这个智能体种群的知识基因库。新个体不需要重头学习全部技能只需要在上层策略里学会如何组合现有技能去解决新任务。这就是标题里进化智能体这几个字的重量所在。技能库的扩充与淘汰机制本质上是在做行为层面的自然选择——有用的技能保留并被反复调用无用的技能淘汰出库新技能通过探索和抽象不断产生。如果配合种群训练的思路比如多个环境变体同时训练、定期交换技能库智能体的适应能力还能再上一个台阶。我目前正在尝试的一个方向是让技能库本身也可以通过进化操作类似交叉和变异来生成新技能而不是完全依赖轨迹切分。比如把两个已有技能的行为模板拼接、融合生成语义更大的复合技能再通过验证轨迹决定是否入库。这个方向上递归结构和进化机制的结合会更紧密但坦率说目前实验只跑到了一半稳定性控制还远没到能写教程的程度。等后续有更完整的结果再来和大家分享。递归技能这套思路第一眼看上去会觉得复杂但拆开看每一块都还是熟悉的强化学习基本功价值函数、经验回放、策略梯度。关键在于它重新组织了知识的存储单位——从权重变成了技能——而技能之间可以用递归的方式组合成几乎无限的行为空间。就冲这一点我觉得它值得在复杂长期任务上多试几次。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询