这两年做强化学习RL的朋友应该都有同感训练曲线跑得漂漂亮亮真正放到环境里却经常判若两“鼠”。这个问题我自己踩了不知道多少回每次卡到最后才发现模型没坏、奖励没写错真正拖后腿的往往是部署阶段那套过于朴素的“动作选择”机制。最近在某AI顶会投稿列表里看到一篇很扎心的题目Breaking the Performance Ceiling in Reinforcement Learning requires Inference Strategies。意思是强化学习性能天花板并不总是训练问题而可能出在推断策略inference strategies上。这篇博文我想基于这个方向把我自己的理解、方案选型思路、以及在一个模拟项目X中完整实验过的一套推断策略实操流程从零到一讲清楚。适合正在做RL落地、做策略部署、或者想把已有训练产物“吃干榨净”的开发者参考。1. 项目概述性能天花板到底卡在哪里1.1 训练上限与推断上限是两回事我们在评估RL效果时习惯性盯着一组训练曲线看前期rm上升慢中期陡增后期收敛。曲线一旦不涨第一反应就是调学习率、换算法、加探索奖励但很少有人问一句就算我把策略网络训练到接近完美部署时的动作选择方式是否真的能拿到那个“完美”的性能先拆一个最简单的强化学习部署闭环。训练阶段我们获得一个策略网络π和通常是配套的价值网络V或Q。到了部署阶段最常见的行为模式是离散动作场景取argmax即选概率最高的动作连续动作场景直接用策略网络输出动作均值甚至不做任何平滑偶尔会在动作上加一点噪声美其名曰“探索”实际上既增加抖动又掩盖真实性能。这背后有一个巨大的隐性假设策略网络已经足够准确且推断时每一步做局部最优选择就能得到全局最优结果。但真实世界的任务往往是稀疏奖励、非平稳分布、状态被局部遮蔽甚至环境本身就是多阶段决策问题。此时贪心推断带来的次优性会随着决策步数逐级放大。换句话说训练上限是“这个模型理论上能学到多好”推断上限是“这个系统实际能用多好”二者之间隔着的正是推断策略。我在某实验室参与过一个迷宫导航模拟项目X智能体只能看到当前位置和目标相对坐标奖励只在到达终点时给1其余所有步数都是0。PPO训练到后期训练集成功率可以到75%但换到未见过的测试迷宫成功率直接掉到30%。一开始怀疑过拟合后来把同一套参数用更复杂的网络重训训练Set指标涨了一些测试Set依然纹丝不动。最后我们发现测试时如果用价值网络对多条候选轨迹重新排序而不是直接argmax成功率能拉到接近60%。那个差距就是训练和推断之间的天花板。1.2 推断策略为什么在2025年成了显学这个题目在2025年出现其实不意外。过去两年大语言模型领域把“test-time compute”炒得非常热同样的模型权重推断时多花一点计算做搜索、验证、重排效果可以大幅提升。这个逻辑迁移到强化学习上就是模型训练阶段的产物只是一个“可用的决策基础”并不等于“决策上限”。你完全可以在部署时用多条rollout采样、树搜索、价值重排、不确定性引导的自适应计算分配这些手段从同一个模型中榨出更高性能。这类做法并不是新东西。AlphaGo系列早就靠MCTS把同一个策略网络玩出远超纯策略推断的水平在线规划、MPC这些领域也一直在用“想一想再动”的思路。但问题是过去大部分RL论文的评测流程默认“训练完就贪心部署”导致很多人对推断策略的认知停留在“后处理”层面甚至觉得“这是工程优化不是算法贡献”。2025年前后大家忽然看清一个关键点如果推断阶段能带来肉眼可见的性能突破那么它本身就是RL系统设计的一部分而不是可有可无的补丁。落地层面这意味着两件事第一做RL项目时训练阶段产出的策略网络和critic网络要尽量为推断策略预留接口第二评估实验时不能只报告“训练模型直接部署”的效果而应该对比“朴素推断”和“推断策略加持”的差异。这篇文章后面所有的实操环节都围绕这个思路展开。2. 方案选型为什么推断策略能打破性能天花板2.1 贪心推断的隐性假设与失效场景先明确一下“贪心推断”到底在做什么。离散控制下贪心推断的策略是在当前状态s_t下选择使得策略网络输出概率或Q值最大的动作a_t执行后进入下一个状态再重复这个过程。这个机制成立的前提有三策略网络和价值函数都是有偏低的估计误差至少不能出现系统性高估当前状态的局部最优动作不会把决策推向一个发生概率很低的全局死胡同环境满足马尔可夫性且单步决策之间没有隐藏的长期依赖。这三条在学术benchmark里有时成立但在真实工程里几乎没有一条是严格成立的。以模拟项目X为例智能体在迷宫拐角处策略网络能看到的局部信息严重不足argmax动作经常是在两个相邻的高概率动作之间犹豫一旦选错方向后面就跑进死路而价值网络实际上知道“下一步只要能绕出拐角后续成功概率很高”。这种“单步概率高、累积价值低”的情况光靠训练改进很难解决因为训练数据的分布主要来自局部成功路径对于一些关键岔路口的区分度天然不足。另一个极端是连续控制里的“均值执行”模式。很多基于高斯策略的RL训练训练时采样的动作是有方差的推断时却直接把均值当成确定性输出。这个做法默认策略分布是单峰的且峰足够尖但真实训练出来的策略分布往往是多峰或者带有大量偶然性偏置的。忽略分布信息去执行均值会把策略“去随机化”成一条中穿过障碍物边界的路径导致部署性能雪崩。这个现象在一些机械臂抓取任务里特别明显同样一个策略直接执行均值和从分布中采样多个候选再选优成功率能差好几个百分点。2.2 三种可落地的推断策略路线既然问题出在“决策方式过于简单”那推断策略可以怎么做我在实际操作中把常见方案收敛成三条路线分别对应不同场景和限制条件。第一条是候选轨迹生成与价值重排rollout reranking。核心思路是既然单次动作选择可能看走眼那就从策略网络里采样多个候选动作、展开多条轨迹然后用训练好的价值网络对每条轨迹的期望回报打分最后执行最优轨迹的第一步。这条路线实现成本最低几乎不需要修改训练流程只要具备两个条件即可策略网络自带随机性以及critic网络有一定可靠性。第二条是决策时树搜索search-based inference。把当前状态当成根节点利用策略网络作为先验分布生成子节点候选利用价值网络对叶节点做评估通过多次playout把值反向传播回根节点再选择经过搜索加权的动作。这套方案的性能通常最高但需要定义推理时的状态转移模型在仿真环境或存在环境模型的场景下很合适如果没有模型就只能生成开环候选轨迹相当于第一条路线的复杂版本。第三条是自适应计算分配adaptive compute allocation。不是每个状态都需要同等规模的推断计算。有些区域策略网络很自信、价值网络的不确定性很低直接贪心执行就够有些区域是高价值冲突区才需要启动重排或搜索。用一个轻量级的不确定性估计器来判断“这次推断要不要加大计算量”可以在不明显牺牲性能的前提下大幅降低平均推断成本。这三条路线不是互斥的。模拟项目X里我实际用的是“自适应开关多候选重排关键节点有限深度树搜索”的组合先判断状态是否属于高不确定区域如果是就临时把候选数扩到64条同时对顶层动作做一次深度12的树搜索。这个组合在效果上最稳在计算上也可控。2.3 选型判断该上哪种推断策略做选型时我习惯按四个维度打分动作空间类型、critic可靠性、是否有环境模型、计算预算高低。维度偏“轻”方案偏“重”方案动作空间离散且动作数少连续或动作组合爆炸critic可靠性critic明显可信与真实return相关critic估计噪声大或容易过乐观环境模型无法快速获取下一状态有仿真器或可学习的近似模型计算预算每决策毫秒级响应允许秒级甚至更长的决策时间离散动作critic可靠无模型优先上多候选重排N从8起测效果不够再叠加树搜索。连续动作critic可靠有模型优先上MPC或CEM式的规划推断把训练好的policy作为采样先验而不是直接当作答案。critic不可靠先修critic否则任何依赖价值评估的推断策略都会越修越歪甚至出现“越搜索越差”。计算预算超级紧张考虑自适应分配让90%的普通状态走贪心10%的高风险状态走重搜索整体收益依然可观。我的核心建议是不要一上来就贪图搜索型推断。先看一个便宜的“多候选重排”能在你的任务上带来多少增益如果增益很小甚至为负问题大概率不在推断算法而在底层模型的可信度。磨刀不误砍柴工。3. 核心实操在模拟项目X中突破性能瓶颈3.1 环境设计与基线训练模拟项目X的环境定义如下一个15×15的网格迷宫墙随机生成智能体从随机的起点出发目标是到达唯一终点。每回合最多100步动作只有上下左右四选一。状态输入是11维的张量包含当前位置坐标、目标相对坐标、四周是否墙的判断以及一个4×4的局部视野。奖励函数刻意设计成极度稀疏到达终点返回1其他任何情况都返回0。这样设计的目的是构造一个典型的“训练拿不到足够有效梯度、部署时容易局部短视”的性能天花板场景。基线训练使用PPO额外加一个以好奇心驱动的内在奖励模块鼓励智能体访问未见过的区域。超参数如下actor和critic共享一个两层128维的MLP主干学习率3×10^-4GAE系数0.95batch大小64clip系数0.2每回合总步数上限10万步。训练过程做了5个seed取成功率中位数。结果如预期训练集上中位成功率约78%但测试集上直接贪心部署只有32%。这里点名一个问题测试集表现远低于训练集不一定全是过拟合。因为我们使用了不同的迷宫布局策略网络在训练时见过的“局面类型”有限遇到未见过的局部构型时单步argmax会迅速积累误差。这个现象在稀疏奖励任务里特别常见因为它本身就没有足够的“中间信号”让策略对每个局面建立稳健的偏好。3.2 推断策略层候选轨迹生成与价值重排先实现最便宜的多候选重排。思路很简单在当前状态s_t下从策略网络π_θ(·|s_t)采样N个动作作为起点每个起点都用策略网络自动回归展开一条完整的轨迹到回合结束或者到提前终止条件然后用critic网络V_φ对每条轨迹的累计回报做估计。因为稀疏奖励环境下直接看累计return是大量零所以我们实际用的是“critic在每条轨迹末尾状态上的估计值已经获得的奖励”。选择这条轨迹中“价值估计最高”的那条执行它的第一步动作然后进入下一状态重复。下面是我实际使用的Python伪代码骨架def infer_with_reranking(state, policy, critic, num_candidates, horizon): trajectories [] for _ in range(num_candidates): traj [] s state.clone() done False while not done and len(traj) horizon: action_probs policy(s) action sample_action(action_probs) next_s, reward, terminated env.step(action) traj.append((action, reward, next_s)) s next_s done terminated or len(traj) horizon last_value critic(s) if not terminated else 0.0 total_score sum(r for _, r, _ in traj) last_value * discount_factor trajectories.append((total_score, traj)) trajectories.sort(keylambda x: x[0], reverseTrue) best_traj trajectories[0][1] return best_traj[0][0]关键点在于动作采样如果策略网络输出的分布比较尖锐直接采样N条很容易得到雷同的轨迹重排失去意义。我实际测试时发现在动作概率后面加一个温度参数τ把概率分布“摊平”一点再采样候选多样性会明显增加。τ取0.8到0.9之间通常比较好太低则多样性差太高则候选退化到随机策略。N的选择也有讲究。N1就是普通采样推断N8时测试成功率从32%涨到48%N32时达到55%N64时大约57%再往上基本平缓。这个边际递减效应很正常候选轨迹再多如果价值估计不准确提升空间终究有限。所以第一版推断策略建议把N固定在32不要盲目堆算力。3.3 搜索型推断树搜索与回溯剪枝多候选重排本质上是一种“开环序列重排”它仍然依赖策略网络自回归展开一旦中途走偏就没有回头路。要更进一步就得在“决策时”把搜索树展开让前面的选择能根据后面节点的评估回传修正。我采用的实现是简化版蒙特卡洛树搜索可以理解成以当前状态为根迭代进行选择、扩展、求值、回传四个步骤。每一步迭代的流程从根节点出发按UCB公式选择子节点直到到达尚未扩展的节点在该节点调用策略网络生成若干个候选动作扩展出子节点对叶子节点调用critic或执行一条模拟轨迹来获取价值估计把价值沿访问路径回传到根节点更新每个动作的平均胜率。当迭代预算耗尽选择根节点下访问次数最多或平均价值最高的动作执行。这里需要注意不要直接选“平均价值最高”的动作因为某个动作只要被探索过一次且恰好拿到一个乐观估值它就会占据榜首访问次数更均衡的动作通常更可靠。我用的是“访问次数为主、平均价值为辅”的排序方法效果比纯价值排序稳。关键代码骨架如下class SearchNode: def __init__(self, state, prior): self.state state self.prior prior self.visits 0 self.value 0.0 self.children [] def tree_search(root_state, policy, critic, num_simulations, expand_depth): root SearchNode(root_state, prior1.0) for _ in range(num_simulations): node root path [] while node.children: node select_by_ucb(node) path.append(node) if node.state.is_terminal(): v node.state.terminal_value() else: v critic(node.state) for n in reversed(path [node]): n.visits 1 n.value (v - n.value) / n.visits if not node.state.is_terminal() and len(node.state.to_actions()) 0: actions_probs policy(node.state) for a in top_k_actions(actions_probs, expand_depth): child_state node.state.transition(a) node.children.append(SearchNode(child_state, prioractions_probs[a])) return root在实际迷宫环境里expand_depth取4、num_simulations取32时测试成功率提升到63%左右。这个版本比多候选重排高了约8个点但单步决策耗时也上去了平均每步约35毫秒多候选重排只用了不到8毫秒。如果部署环境允许这个开销搜索型推断是更优的选择如果延迟敏感就需要自适应分配来缓解。3.4 关键参数与效果对照把三种模式放在一起对比数据会更直观推断策略测试成功率平均完成步数单步决策开销贪心argmax32%522ms候选重排N3255%418ms树搜索重排组合63%3535ms自适应分配混合61%3712ms自适应分配混合的做法是在普通状态走贪心在不确定性高的状态触发重排或树搜索。我用critic的ensemble方差作为不确定性指标两个独立训练的critic对当前状态估值差超过0.15时认为该状态需要重排超过0.3时升级成树搜索。这样平均单步开销只有12毫秒性能却接近满搜索版本这是工程部署最推荐的折中。有几个参数需要特别提一下。候选数N、温度τ、树搜索预算三者是需要一起调的联动变量。我见过不少人把N加到很大温度却不调结果候选轨迹全部雷同也有人树搜索预算很高但UCB系数没调导致搜索始终集中在某个前期表现好的子树里。UCB系数C建议从1.0起步如果搜索过程中发现“某个动作从头到尾没被访问过”就适当增大C如果发现根节点下访问分布极度不均衡就减小C。用户环境不同最优值差异很大不要迷信默认参数。4. 常见问题与排查技巧实录4.1 推断增益消失分布偏移与价值误估最典型的失败现象是加了推断策略之后训练指标没变但测试性能不升反降。这个我见过太多次根源通常不在推断算法本身而在于critic对推断时遇到的状态给出的估值是错的。训练时critic主要见过“策略正常探索”生成的状态分布推断时如果你用更强的搜索或更多候选找到的轨迹可能会把智能体带进训练分布中极少出现的新局面此时critic的估值会发生很大的外推偏差甚至出现“系统性的乐观估计”。我自己踩过最狠的一次坑是用MCTS在模拟项目X里搜索搜索结果找出一条critic估值高达0.9的路径但实际执行时智能体第一步就走进了死胡同。事后检查发现那条路径在训练数据里几乎没出现过critic对“看起来像是死胡同但估值很高”的状态完全没有分辩能力。所以我在后来所有的推断策略实验里都加了一条规则所有候选轨迹展开后不仅要看critic估值还要检查轨迹中出现过的状态是否落在训练分布的“支持区间”内。用简单办法衡量就是保存训练时所有状态特征的均值推断时对偏差过大的状态施加惩罚折扣。这个偏保守的做法会减少一部分理论最优增益但能防止灾难性的外推翻车。4.2 计算预算、延迟与吞吐的平衡推断策略的代价不能只看“多采几条轨迹”要看整体系统延迟。在真实环境里单步决策如果花费几十毫秒对于游戏AI或仿真推演还能接受对于工业控制、高频交易、在线推荐这类场景就是灾难。解决思路有三个层级第一层是降低单次推断成本。比如模型蒸馏训练一个结构更小的“推断专用头”只在需要重排或搜索时使用主网络保持大模型精度小模型负责快速采样候选。第二层是并行化评估多条候选轨迹在推断时是互相独立的可以用多进程或GPU batch一次性展开把N条轨迹的评估从串行的“N倍时长”变成并行的“单倍时长”。第三层是异步预计算对可以预知的状态转移路径提前缓存搜索结果命中缓存时直接返回。自适应计算分配还有一个常见变体按episode阶段分配开局阶段探索需求大重排/搜索预算就调高接近结束时策略相对确定直接阈值判断。模拟项目X里我在前20步使用N64重排中间40步用N32最后40步用贪心结果测试成功率几乎不变平均开销降到了原来的三分之一。做延迟敏感项目时强烈建议先试这种简单的分段预算分配再上复杂的不确定性模型。4.3 训练阶段要为推断策略留出余地推断策略不是部署阶段才需要想的事情。如果训练阶段没有留下可用接口后面所有推断技巧都会绑手绑脚。我在实践中最基础的四个动作是至少保存两个不同checkpoint不要只留“最后一代”模型。不同训练阶段的策略分布不同推断时做集成或切换往往比单个末期模型稳。训练时在critic之外额外记录每条状态的不确定性度量比如用dropout多次前向的方差或者维护一个小型的密度估计器。这个度量在自适应计算分配里是刚需。不要让critic只输出一个期望回报标量可以考虑再加一个“置信度头”输出熵或方差。只要在训练loss里加一个辅助建分母成本很低但推断时它会很有用。如果条件允许在训练收尾阶段用“推断策略”产生的轨迹做一点微调。让模型浅浅地见过一些搜索会选择的状态分布可以有效减少部署时的分布偏移。这些动作说起来简单但大多数RL训练框架没有默认支持。我用过的一些现成库要么只能保存单一checkpoint要么critic输出就是一个标量导致到了部署阶段寸步难行。如果项目目标明确包含“提升最终部署性能”请在搭训练流程的第一天就考虑到推断层的需求不然后面要返工很久。4.4 一份自查清单最后整理一份我在项目实战中反复核对的问题清单按优先级排列排查项判断方法参考解法基线性能是否意外偏低先用N8重排看增益是否为正无增益则先修criticcritic是否高估对比critic估值和真实return保守化处理、ensemble取低位候选轨迹是否单一打印动作概率分布看熵值调温度τ、增加随机化搜索是否偏移到坏子树观察根节点动作访问次数分布调UCB系数、增加剪枝推断分布是否离训练太远检查状态的密度估计加行为约束或状态惩罚计算开销是否失控测量P95单步延迟上自适应分配、分段预算评估口径是否公平对比同一checkpoint下贪心/重排/搜索统一随机seed与评估集这套清单可以帮助快速定位“推断策略没有效果”的问题出在哪个环节。本质上推断策略设计得再好也弥补不了底层模型与训练流程的结构性问题。我自己踩过几次坑之后最大的体会是强化学习项目的性能天花板很多时候不是被训练算法焊死的而是被部署时“只用argmax”这个默认习惯焊死的。如果模型本身没问题你花半天时间写一个多候选重排就可能拿到比调一个月超参数更大的收益。而如果重排带来的是负增益也不要急着否定推断策略这条路先回头看看critic是不是在自欺欺人。这个方向后续的扩展空间还很大比如在连续控制里引入模型预测规划、在多智能体场景中引入交互式推断但最值得做的永远是先把“部署决策机制”这块短板补上。