<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Reinforcement Learning on 扎塔-Zata</title><link>https://www.zata.cc/tags/reinforcement-learning/</link><description>Recent content in Reinforcement Learning on 扎塔-Zata</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>扎塔-Zata</copyright><lastBuildDate>Tue, 06 Oct 2026 22:50:49 +0800</lastBuildDate><atom:link href="https://www.zata.cc/tags/reinforcement-learning/index.xml" rel="self" type="application/rss+xml"/><item><title>JitRL：不训参数也能边用边学，前提是有人告诉它这局成没成</title><link>https://www.zata.cc/p/jitrl-test-time-policy-optimization/</link><pubDate>Mon, 05 Oct 2026 21:20:00 +0800</pubDate><guid>https://www.zata.cc/p/jitrl-test-time-policy-optimization/</guid><description>&lt;img src="https://www.zata.cc/p/jitrl-test-time-policy-optimization/images/index/index.svg" alt="Featured image of post JitRL：不训参数也能边用边学，前提是有人告诉它这局成没成" />&lt;p>任务是在电商后台「找到客户评价」。模型列出几个候选动作并各自打分，排前两位的是 &lt;code>click(CATALOG)&lt;/code> 0.90 和 &lt;code>click(MARKETING)&lt;/code> 0.70：按直觉，评价该挂在商品目录下面。JitRL 查了一遍过去的经验，把这两个分数改成 0.40 和 1.40，agent 转去点了 Marketing，这个后台的评价管理确实在 Marketing 菜单下。整个过程没有更新模型的任何参数。&lt;/p>
&lt;p>这个案例来自新加坡国立大学团队的 JitRL（Just-In-Time Reinforcement Learning）论文。它主张冻结模型权重，把强化学习的策略改进挪到推理时做：在网页任务基准 WebArena 和文字冒险游戏 Jericho 上，成绩超过同类的免训练方法，也超过需要训练的 WebRL，花费低 30 倍以上。&lt;/p>
&lt;p>我对照论文读了作者开源的代码（提交 143d221，只读，没有运行）。第一节用开头的案例把机制走一遍，回答分数是怎么改出来的；第三节回答论文没交代清楚的一件事：写进记忆的每一步分数是谁打的，打分时知道什么。先给结论：&lt;/p>
&lt;ul>
&lt;li>机制在公平对照里成立，但领先幅度比正文表格小。同基座（Llama 3.1 8B）、同样 5 次尝试，JitRL 比在线训练的 WebRL 平均高 5.7 个点，在 Admin 站点低 10 个点；正文里 60.00 对 46.06 的差距，混进了基座和尝试次数两处不对等。&lt;/li>
&lt;li>代码和论文影响最大的出入在打分环节。WebArena 的默认流程里，给每一步打分的 LLM 事先就被告知这一局按标准答案判定是成功还是失败，论文把这一环写成 agent 的「自我反思」。&lt;/li>
&lt;li>能不能搬进生产，主要取决于两件事：有没有可靠的成败信号，同类任务会不会反复出现。两条都不满足时，论文里的提升很难照搬。&lt;/li>
&lt;/ul>
&lt;h2 id="一机制记忆不进提示词直接改候选动作的分数">一、机制：记忆不进提示词，直接改候选动作的分数
&lt;/h2>&lt;p>&lt;img src="https://www.zata.cc/p/jitrl-test-time-policy-optimization/images/index/train-time-vs-test-time.svg"
loading="lazy"
alt="标准强化学习与 JitRL 的对比"
>&lt;/p>
&lt;p>&lt;em>▲ 常规强化学习用历史轨迹算梯度、改权重，训练完的模型在推理时固定不变；JitRL 的权重全程冻结，经验存进记忆库，到选动作那一刻才拿来调整输出。图：本文依据论文图 1 绘制&lt;/em>&lt;/p>
&lt;p>先给三个术语一句直觉解释：&lt;/p>
&lt;ul>
&lt;li>logit：模型给每个候选打的原始分，经过 softmax 变成被选中的概率，分越高越可能被选。&lt;/li>
&lt;li>优势（advantage）：某个动作的预期回报比这个状态下的平均水平高多少。正值说明比平均好，负值说明在拖后腿。&lt;/li>
&lt;li>KL 约束：限制新策略离原策略不能太远。JitRL 用它推出更新公式，本节第三小节再讲。&lt;/li>
&lt;/ul>
&lt;p>JitRL 每走一步做四件事：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>检索邻居。&lt;/strong> 把当前状态和记忆库里的历史状态比相似度，取排在前 k 位的记录，论文默认 k = 10。WebArena 里的状态是去掉 ID 的网址加上最近几步动作。&lt;/li>
&lt;li>&lt;strong>算两个平均。&lt;/strong> 邻居们的平均回报，当作这个状态的价值 V；其中做过同一个动作的那部分邻居，平均回报当作这个动作的价值 Q。&lt;/li>
&lt;li>&lt;strong>算优势。&lt;/strong> 优势 A = Q − V，再除以所有候选里优势绝对值的最大值，缩放到 −1 到 1 之间。&lt;/li>
&lt;li>&lt;strong>改分数再选。&lt;/strong> 把缩放后的优势乘上系数 β，加到原来的分数 z 上，再按新分数的 softmax 采样动作：&lt;/li>
&lt;/ol>
$$z'(s,a) = z(s,a) + \beta \cdot \tilde{A}(s,a)$$&lt;p>回到开头的案例：Catalog 的分数被扣了 0.50，Marketing 加了 0.70。按这个公式读，记忆里在相似页面点 Catalog 的轨迹，平均回报低于邻居均值；点 Marketing 的高于均值，差距大到足以翻转模型原来的排序。&lt;/p>
&lt;p>候选集不只来自模型。记忆里在相似状态下做过、这次模型却没提的动作，也会被加进候选，原始分数记为 0，靠优势去竞争（论文附录 F）。反过来，模型提了而记忆里从没出现过的动作，以概率 λ 拿到「邻居均值加一个探索奖励」，否则 Q 直接记 0。WebArena 上 λ 只有 0.05，所以多数时候新动作的 Q 就是 0：邻居均值为正时它被往下压，均值为负时反而被往上抬。&lt;/p>
&lt;h3 id="写入每局结束才写每一步的分由-llm-评估器打">写入：每局结束才写，每一步的分由 LLM 评估器打
&lt;/h3>&lt;p>记忆库是一张三元组表：状态、动作、这一步之后的折扣回报 G。每局结束后，一个基于 LLM 的评估器（论文叫 Evaluator）读完整条轨迹，给每一步打一个分 r。WebArena 的评分区间是 −3 到 +3：+3 的定义是「明显有用，并且你确定」，0 是「判断不了、没有实际效果，或效果马上被撤销」（附录 G）。Jericho 沿用游戏本身的计分尺度。然后从每一步往后做折扣累加：&lt;/p>
$$G_t = \sum_{u \ge t} \gamma^{\,u-t}\, r_u$$&lt;p>γ 是折扣因子，决定一步的功劳能往前传多远。WebArena 取 0.1，几乎只看眼前这一步；Jericho 取 0.5，要照顾更长的因果链。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/jitrl-test-time-policy-optimization/images/index/jitrl-loop.svg"
loading="lazy"
alt="JitRL 的读写闭环"
>&lt;/p>
&lt;p>&lt;em>▲ JitRL 的读写闭环：推理时检索邻居、估优势、改分数；一局结束后由评估器给每一步打分，折扣累加后写回记忆库。底部那行说明来自第三节的代码核对。图：本文依据论文图 2 绘制&lt;/em>&lt;/p>
&lt;h3 id="理论保证了什么离实验有多远">理论：保证了什么，离实验有多远
&lt;/h3>&lt;p>论文的定理 4.1 说，在「最大化期望优势，同时用 KL 约束不偏离原策略」这个目标下，最优策略有闭式解：&lt;/p>
$$\pi^*(a \mid s) \propto \pi_\theta(a \mid s)\, \exp\big(\beta A(s,a)\big)$$&lt;p>两边取对数，就是上面第 4 步的更新。这个闭式解在强化学习里早有先例，REPS、AWR、AWAC 都从同一个目标出发，论文没有引用它们。JitRL 的新意在于把这一步从训练期挪到推理时：不用梯度去逼近这个分布，每次选动作时直接算出来。&lt;/p>
&lt;p>定理 4.2 和 4.3 证明，记忆估出的价值和优势会收敛到真实值，前提是每个动作被试过的次数趋于无穷、邻居数趋于无穷且只占记忆的一小部分、策略漂移趋于零（附录 C）。这是渐近意义上的保证。实验里每个 WebArena 任务只试 5 次，Jericho 每个游戏 50 局，离「无穷」很远。何况定理针对的是论文里的更新形式，不是默认代码的实际行为，两者的差别见第三节。&lt;/p>
&lt;h2 id="二证据换成同基座领先缩小但还在">二、证据：换成同基座，领先缩小但还在
&lt;/h2>&lt;h3 id="对免训练同行总分领先-56-个点shopping-贡献最多">对免训练同行：总分领先 5.6 个点，Shopping 贡献最多
&lt;/h3>&lt;p>WebArena 主实验用 Gemini-2.5-flash，每个任务连续尝试 5 次，前面的经验可以用于后面。Avg 是 5 次的平均成功率，衡量学得多快；Final 是第 5 次的成功率，衡量学到最后的水平。下表节选论文表 1 的总体成功率（%）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>方法&lt;/th>
&lt;th>Avg&lt;/th>
&lt;th>Final&lt;/th>
&lt;th>Final − Avg&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Static（不带记忆）&lt;/td>
&lt;td>35.63&lt;/td>
&lt;td>36.30&lt;/td>
&lt;td>+0.67&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Memory&lt;/td>
&lt;td>41.36&lt;/td>
&lt;td>43.00&lt;/td>
&lt;td>+1.64&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reflexion&lt;/td>
&lt;td>41.08&lt;/td>
&lt;td>42.12&lt;/td>
&lt;td>+1.04&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>AWM&lt;/td>
&lt;td>39.37&lt;/td>
&lt;td>40.32&lt;/td>
&lt;td>+0.95&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>EvoTest&lt;/td>
&lt;td>39.24&lt;/td>
&lt;td>42.49&lt;/td>
&lt;td>+3.25&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>JitRL&lt;/td>
&lt;td>46.98&lt;/td>
&lt;td>51.35&lt;/td>
&lt;td>+4.37&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>JitRL 的 Avg 比第二名 Memory 高 5.62 个点，Final 高 8.35 个点。分站点看，领先主要来自 Shopping：JitRL 的 Avg 是 41.67，这个站点上分数最高的基线是 Reflexion 的 30.83，差 10.84 个点；其余四个站点的领先只有 1.5 到 3.3 个点。&lt;/p>
&lt;p>论文写的「Shopping 比 Static 高 73.2%」是相对增幅（41.67 对 24.06），绝对差是 17.6 个点。论文把这里的大幅领先归因于结构化站点的轨迹复用率高，表 6 也显示 Shopping 上用到的记忆有 62% 来自其他任务，五个站点里最高。&lt;/p>
&lt;p>换一个基座模型，结论不变。论文在 Admin 和 Reddit 两个站点上换了 GPT-5-mini 和 DeepSeek-V3.2（表 4），两个模型、两个站点、Avg 和 Final 一共 8 格，JitRL 赢了 7 格；输的那格是 DeepSeek-V3.2 在 Reddit 上的 Avg，54.42 对 Reflexion 的 55.04。&lt;/p>
&lt;p>只能检索其他任务的记忆时（表 5），JitRL 在五个站点仍排第一，但四个站点的领先缩到 0.5 到 1.6 个点，Shopping 还有 5.2 个点。和允许用同任务记忆的表 1 相比，它比其他记忆方法多出来的优势，主要在同一任务反复做时兑现。&lt;/p>
&lt;h3 id="和训练方法比60-对-46-里有两处不对等">和训练方法比：60 对 46 里有两处不对等
&lt;/h3>&lt;p>论文正文表 2 在 WebArena-Lite 上比 Final。这 165 个任务没有参与 WebRL 的训练，结果是 SFT 23.0、WebRL 46.06、JitRL 60.00。这个差距里混着两处不对等。&lt;/p>
&lt;p>&lt;strong>不对等一：基座。&lt;/strong> SFT 和 WebRL 用的是 WebRL 作者放出的 Llama-3.1-70B 检查点，JitRL 用的是 Gemini-2.5-flash，两个基座本身的能力差多少，表里分不出来。&lt;/p>
&lt;p>&lt;strong>不对等二：尝试次数。&lt;/strong> JitRL 的 Final 是同一任务第 5 次尝试的成功率，前 4 次的轨迹和成败都已写进记忆；WebRL 是训练好的固定检查点，没有在这 165 个任务上边试边学的机会。&lt;/p>
&lt;p>论文在正文里提了一句，把同条件对照放进了附录 I：两边都用 Llama 3.1 8B Instruct，每个任务都给 5 次尝试，前几次的轨迹 JitRL 存进记忆，WebRL 拿去做在线强化学习更新。表 12 的 Final 成功率（%）如下：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>站点&lt;/th>
&lt;th>WebRL&lt;/th>
&lt;th>JitRL&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Admin&lt;/td>
&lt;td>38.89&lt;/td>
&lt;td>28.57&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>GitLab&lt;/td>
&lt;td>23.53&lt;/td>
&lt;td>30.00&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Map&lt;/td>
&lt;td>9.68&lt;/td>
&lt;td>20.00&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reddit&lt;/td>
&lt;td>50.00&lt;/td>
&lt;td>53.33&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Shopping&lt;/td>
&lt;td>17.39&lt;/td>
&lt;td>36.96&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>平均&lt;/td>
&lt;td>27.27&lt;/td>
&lt;td>32.97&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>平均领先 5.7 个点，不到正文差距（13.9 个点）的一半；Admin 上反而落后 10.32 个点。论文的解释是，梯度方法在样本很少的在线场景里难以稳定收敛，记忆检索没有这个问题。这组数据能支持的结论是：每个任务只有几次尝试时，JitRL 比在线训练的 WebRL 学得快。它不说明 JitRL 能胜过一个训练充分的 WebRL。&lt;/p>
&lt;h3 id="jericho领先更明显grpo-那一行也换了基座">Jericho：领先更明显，GRPO 那一行也换了基座
&lt;/h3>&lt;p>Jericho 是一组经典文字冒险游戏，agent 输入文字指令，拿游戏分数。每个游戏连续玩 50 局，Avg 是 50 局的平均分，Final 是最后一局的得分。每个游戏上分数最高的基线都是 EvoTest，和 JitRL 对比如下（论文表 3，「Avg / Final」）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>游戏&lt;/th>
&lt;th>EvoTest&lt;/th>
&lt;th>JitRL&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Library&lt;/td>
&lt;td>21.5 / 26&lt;/td>
&lt;td>25.9 / 30&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Zork1&lt;/td>
&lt;td>46.8 / 54&lt;/td>
&lt;td>53.0 / 69&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Zork3&lt;/td>
&lt;td>2.6 / 4&lt;/td>
&lt;td>3.1 / 5&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Library 和 Zork1 上，JitRL 的 Avg 分别高 4.4 和 6.2 分，Zork1 的 Final 高 15 分。Zork3 上各方法都只有个位数得分，差距说明不了太多。&lt;/p>
&lt;p>表 3 里还有一行 GRPO，用的是针对每个游戏单独训练的 Qwen3-32B 检查点，JitRL 和其他基线用的都是 Gemini-2.5-flash。拿上一小节的尺子量，Zork1 上 53.0 对 16.2 的差距同样混着基座差异，不能直接读成推理时优化胜过梯度训练。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/jitrl-test-time-policy-optimization/images/index/fig3-jericho-learning-curves.svg"
loading="lazy"
alt="Jericho 学习曲线"
>&lt;/p>
&lt;p>&lt;em>▲ Library（左）和 Zork1（右）上各方法 50 局的得分曲线。红色实线是 JitRL；紫、蓝、橙、绿虚线依次是 AWM、EvoTest、Reflexion、GRPO；棕色虚线是 Memory，粉色虚线是 Static。Zork1 上 GRPO 在 0 到 35 分之间来回，最后一局 10 分。图：论文图 3，arXiv:2601.18510，CC BY 4.0&lt;/em>&lt;/p>
&lt;h3 id="消融改分数比塞进提示词好只测了两个站点">消融：改分数比塞进提示词好，只测了两个站点
&lt;/h3>&lt;p>论文的消融实验（表 8）把同样检索出来的记忆写进提示词，和直接改分数对比（Avg，%）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>站点&lt;/th>
&lt;th>写进提示词&lt;/th>
&lt;th>改分数&lt;/th>
&lt;th>差&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Admin&lt;/td>
&lt;td>49.46&lt;/td>
&lt;td>52.31&lt;/td>
&lt;td>+2.85&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reddit&lt;/td>
&lt;td>53.02&lt;/td>
&lt;td>57.64&lt;/td>
&lt;td>+4.62&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>这组数据直接回答了「改分数这一步本身有没有用」，但只测了两个站点，也没有报告 Final。另外，49.46 和 53.02 恰好分别等于表 1 里 AWM 在 Admin、Memory 在 Reddit 的 Avg，是巧合还是填表时串了行，论文里看不出来。&lt;/p>
&lt;h3 id="成本30-倍比的是一次训练和一次评测">成本：30 倍比的是一次训练和一次评测
&lt;/h3>&lt;p>论文表 9 的成本：Static 200 美元，Memory、Reflexion、AWM、EvoTest 在 220 到 250 美元之间，JitRL 290 美元，WebRL 约 9900 美元。&lt;/p>
&lt;p>两边的计价口径不同。WebRL 的 9900 美元是附录 M 估算的一次完整训练：70B 模型，2 个节点共 16 张 H200，跑 154 小时，按每小时 64 美元计，不含之后的推理开销。JitRL 的 290 美元是跑完这一轮评测的 API 账单，包括每局结束后评估器打分的调用，部署之后这笔钱随任务量持续发生。「低 30 倍」对应的是训练一次、评测一次的场景，任务量上去以后，两条成本曲线的斜率不同。&lt;/p>
&lt;p>和免训练同行比，JitRL 多花 40 到 70 美元（贵 16% 到 32%），换来 5.6 到 7.7 个点的 Avg 提升。做技术选型时，这笔账比和 WebRL 的对比更有参考价值。&lt;/p>
&lt;h2 id="三代码打分器在打分前已经知道这局成没成">三、代码：打分器在打分前已经知道这局成没成
&lt;/h2>&lt;p>以下基于作者仓库 &lt;a class="link" href="https://github.com/liushiliushi/JitRL/tree/143d22185d95fbf633a0befe6861d5e8b732543b" target="_blank" rel="noopener"
>liushiliushi/JitRL&lt;/a> 的提交 143d221（2026-07-21，仓库只有这一个提交）。我只读了代码，没有运行，文中行号都指这个提交。&lt;/p>
&lt;h3 id="成败来自标准答案论文写成自我反思">成败来自标准答案，论文写成自我反思
&lt;/h3>&lt;p>论文第 4.1 节这样描述评估器：长轨迹的功劳分配很难，所以「利用 agent 的自我反思能力」，每局结束后由一个基于 LLM 的评估器给轨迹打步级奖励。只读论文，会以为评估器手里只有这条轨迹。&lt;/p>
&lt;p>WebArena 的默认流程是这样的：&lt;/p>
&lt;ol>
&lt;li>一局结束后，&lt;code>run.py&lt;/code> 调用 &lt;code>evaluate_trajectory_direct&lt;/code>，按任务配置里的标准答案判定成败（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/run.py#L795-L832" target="_blank" rel="noopener"
>run.py L795–832&lt;/a>）。判定方式随任务类型变化：比对网址，用浏览器打开页面检查元素，或者让 LLM 对照参考答案判断回答对不对（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/autoeval/evaluate_trajectory.py#L50-L167" target="_blank" rel="noopener"
>evaluate_trajectory.py L50–167&lt;/a>）。&lt;/li>
&lt;li>判定结果作为 &lt;code>success&lt;/code> 传进 &lt;code>end_episode&lt;/code>，再原样交给负责逐步打分的评估器（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/cross_episode_memory.py#L779-L790" target="_blank" rel="noopener"
>cross_episode_memory.py L779–790&lt;/a>）。&lt;/li>
&lt;li>评估器的提示词里直接写着这一局的结果（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/utils.py#L1210-L1220" target="_blank" rel="noopener"
>utils.py L1210–1220&lt;/a>）：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># When not evaluating success, we can use the known success value for scoring&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Score each action based on the WEBPAGE RESULT it produced, NOT on whether the action itself seems reasonable.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">task_goal_section&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">==========================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">FINAL TASK RESULT: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="s2">&amp;#34;SUCCESS ✓&amp;#34;&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">success&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="s2">&amp;#34;FAILURE ✗&amp;#34;&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">==========================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">IMPORTANT: Consider the final result when scoring each step.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">- This task &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="s2">&amp;#34;SUCCEEDED - reward actions that led to useful webpage results&amp;#34;&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">success&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="s2">&amp;#34;FAILED - penalize actions that led to wrong webpage results&amp;#34;&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>用标准答案判定成败，本身不算作弊。在强化学习的设定里，环境给的成败就是奖励信号：WebRL 训练时由结果奖励模型（ORM）判断成败，Jericho 的游戏分数也来自环境。问题出在两个地方：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>说法。&lt;/strong> 论文把这一环写成 agent 的自我反思，没有交代评估器事先知道外部判定的结果。读者会以为 JitRL 靠模型自己就能判断每一步的好坏，实际上它的价值尺度挂在一个外部判定上。&lt;/li>
&lt;li>&lt;strong>迁移。&lt;/strong> 生产环境通常没有标准答案。代码里有一个 &lt;code>--use_llm_success_eval&lt;/code> 开关，改由 LLM 自己判断成败（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/run.py#L352-L356" target="_blank" rel="noopener"
>run.py L352–356&lt;/a>），默认关闭，论文也没有报告打开它之后的成绩。&lt;/li>
&lt;/ol>
&lt;p>同一把尺子还要量到基线上：JitRL 拿到了外部判定的成败，基线有没有？&lt;code>run.py&lt;/code> 里留着 evotest、reflexion 等基线的分支（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/run.py#L1046-L1055" target="_blank" rel="noopener"
>L1046–1055&lt;/a>），看起来基线当时走的是同一套运行框架，Reflexion 分支的注释还写着它用到了前几轮的评测状态。但 &lt;code>--agent_type&lt;/code> 只放开了 &lt;code>memory&lt;/code> 一个选项（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/run.py#L225-L230" target="_blank" rel="noopener"
>L225–230&lt;/a>），基线的实现没有放出来，它们各自怎么用这个成败，查不到。Jericho 目录带了 Static 和 AWM 两个基线，它们和 JitRL 一样拿到游戏分数，那边不存在这个问题。&lt;/p>
&lt;h3 id="更新规则加在-0-到-1-的分数上取最大值">更新规则：加在 0 到 1 的分数上，取最大值
&lt;/h3>&lt;p>论文的更新是「logit 加上 β 倍的归一化优势，再按 softmax 采样」。WebArena 的默认代码是下面几行（中文注释为本文所加）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># jitrl_agent.py L337-340：只要存在正优势，全部除以最大的那个正优势&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">positive_advs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">adv&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">adv&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">adv_values&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">adv&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">positive_advs&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_positive&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">positive_advs&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">normalized_advantages&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">adv&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">max_positive&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">action&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">adv&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">action_advantages&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">()}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># L377-378：加在 0 到 1 的「概率」上，系数写死为 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">normalized_prob&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">option_data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;normalized_prob&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">corrected_logprob&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">normalized_prob&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">normalized_advantage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># L1130：取修正后分数最大的候选，不采样&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">best_corrected_option&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">updated_options_with_logits&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;corrected_logprob&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">float&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;-inf&amp;#39;&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>和论文相比，有四处不同：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>加在概率上。&lt;/strong> 两个环境默认都用 verbalized 模式：让模型自报 0 到 100 的置信度，代码除以 100 当概率用（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/jitrl_agent.py#L1044-L1053" target="_blank" rel="noopener"
>WebArena 的换算&lt;/a>；Jericho 的&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/main.py#L64-L65" target="_blank" rel="noopener"
>默认值&lt;/a>和&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/src/jitrl_agent.py#L707-L718" target="_blank" rel="noopener"
>换算&lt;/a>）。论文说会把置信度转换成 logit，代码里没有这一步；Jericho 的 token 模式也只是对 logprob 取指数，得到的同样是概率。论文表 7 三个案例里，两个选项的原始分加起来都超过 1，更像各自报出的置信度。&lt;/li>
&lt;li>&lt;strong>归一化方式不同。&lt;/strong> 论文公式 25 除以所有候选优势绝对值的最大值，结果落在 −1 到 1 之间。代码只要存在正优势，就除以最大的那个正优势：排第一的正优势动作固定得到 +1，负优势动作可能低于 −1。&lt;/li>
&lt;li>&lt;strong>β 没有给出。&lt;/strong> 论文的两张超参表（表 10、表 11）都没有列 β。WebArena 代码写死为 1，Jericho 代码按局数从 1 涨到 1.5（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/src/jitrl_agent.py#L377-L383" target="_blank" rel="noopener"
>jitrl_agent.py L377–383&lt;/a>）。&lt;/li>
&lt;li>&lt;strong>取最大值，不采样。&lt;/strong> 论文的算法按 softmax 采样，两个环境的代码都直接取修正后分数最大的候选（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/src/jitrl_agent.py#L771" target="_blank" rel="noopener"
>Jericho 的写法&lt;/a>）。&lt;/li>
&lt;/ol>
&lt;p>四处叠在一起，后果很直接。只要记忆里有动作的优势为正，排第一的那个修正后至少是 1.0；优势不为正的候选，修正后不超过它原来的置信度，也就不超过 1.0。所以除了恰好打平，被选中的总是优势为正的动作，哪怕模型这一步根本没提它：记忆独有的动作以 0 分进入候选，加 1 就是 1.0，模型自己打分最高的候选只要优势不为正，置信度再高也赢不了。论文的公式是「用记忆温和地修正模型」，默认代码的行为更接近「有成功先例就照着做」。&lt;/p>
&lt;h3 id="超参论文和默认代码有五处对不上">超参：论文和默认代码有五处对不上
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>参数&lt;/th>
&lt;th>论文&lt;/th>
&lt;th>默认代码&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>β（优势系数）&lt;/td>
&lt;td>未给出&lt;/td>
&lt;td>WebArena 为 1；Jericho 从 1 涨到 1.5&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>α（探索奖励）&lt;/td>
&lt;td>5&lt;/td>
&lt;td>两个环境都是 1&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>λ（Jericho 探索率）&lt;/td>
&lt;td>探索概率 0.65&lt;/td>
&lt;td>0.65 是公式里的指数，实际概率在 0.05 到 0.8 之间自适应&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>k（WebArena 邻居数）&lt;/td>
&lt;td>10&lt;/td>
&lt;td>截断那行被注释掉，超过相似度阈值的全用；阈值随步数从 0.8 降到 0.7&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Jericho 步数上限&lt;/td>
&lt;td>60&lt;/td>
&lt;td>50&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>对应代码：WebArena 的 &lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/jitrl_agent.py#L306-L308" target="_blank" rel="noopener"
>λ 和 α&lt;/a>、&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/cross_episode_memory.py#L604" target="_blank" rel="noopener"
>k 截断&lt;/a>、&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/cross_episode_memory.py#L451-L460" target="_blank" rel="noopener"
>动态阈值&lt;/a>；Jericho 的&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/src/jitrl_agent.py#L139-L231" target="_blank" rel="noopener"
>探索概率&lt;/a>和&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/main.py#L20" target="_blank" rel="noopener"
>步数上限&lt;/a>。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/jitrl-test-time-policy-optimization/images/index/fig4-neighbor-count.svg"
loading="lazy"
alt="检索邻居数 k 的影响"
>&lt;/p>
&lt;p>&lt;em>▲ 检索邻居数 k 对 Library（蓝）和 Zork1（绿）的影响：k 在 8 到 14 之间表现平稳，太少或太多都会掉分。这组实验做在 Jericho 上；WebArena 的开源实现没有按 k 截断。图：论文图 4，arXiv:2601.18510，CC BY 4.0&lt;/em>&lt;/p>
&lt;h3 id="复现前要知道的六件事">复现前要知道的六件事
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>模型版本说法不一。&lt;/strong> README 说论文结果来自 OpenRouter 上的 &lt;code>google/gemini-2.5-flash-preview-09-2025&lt;/code> 快照，这个快照已经下线（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/README.md?plain=1#L152-L154" target="_blank" rel="noopener"
>README L152–154&lt;/a>）；作者 7 月 14 日在 &lt;a class="link" href="https://github.com/liushiliushi/JitRL/issues/1" target="_blank" rel="noopener"
>issue #1&lt;/a> 里的回复则说，论文结果都是用 gemini-2.5-flash 跑的。两处说法对不上，复现时没法确定该对齐哪个模型。&lt;/li>
&lt;li>&lt;strong>测试脚本的默认值不是论文协议。&lt;/strong> &lt;code>test_webarena_lite.py&lt;/code> 默认每个任务只跑 1 次（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/test_webarena_lite.py#L697" target="_blank" rel="noopener"
>L697&lt;/a>），成功一次就跳过剩下的重复（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/test_webarena_lite.py#L3-L6" target="_blank" rel="noopener"
>L3–6&lt;/a>），步数上限 25（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/test_webarena_lite.py#L695" target="_blank" rel="noopener"
>L695&lt;/a>）。论文是 5 次尝试、步数上限 10，复现时要显式传 &lt;code>--repeat 5 --no_early_stop --max_steps 10&lt;/code>。&lt;/li>
&lt;li>&lt;strong>README 结果表对不上论文。&lt;/strong> README 列的 Jericho 成绩里有论文没测过的 Detective，Zork1 写的是 35.2 到 52.8；WebArena-Lite 写的是 Gemini-2.5 从 25.3% 到 34.7%（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/README.md?plain=1#L248-L266" target="_blank" rel="noopener"
>README L248–266&lt;/a>），论文里都找不到对应数字。&lt;/li>
&lt;li>&lt;strong>站点识别写死了端口。&lt;/strong> 记忆的状态键带着站点名，代码按端口号认站点（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/utils.py#L39-L46" target="_blank" rel="noopener"
>utils.py L39–46&lt;/a>），这套端口和 README 建议的部署端口（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/README.md?plain=1#L113-L118" target="_blank" rel="noopener"
>L113–118&lt;/a>）对不上。照 README 部署，Admin 和 GitLab 都会被认成 &lt;code>unknown_site&lt;/code>，其余站点名字错位但仍各自唯一。网址路径还能区分开大部分记录，影响有限。&lt;/li>
&lt;li>&lt;strong>Jericho 缺依赖不报错。&lt;/strong> 向量检索依赖 faiss 和 OpenAI 的嵌入接口。没装 faiss 时只打印一条警告，检索直接返回空列表（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/src/cross_episode_memory.py#L11-L14" target="_blank" rel="noopener"
>L11–14&lt;/a>、&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/src/cross_episode_memory.py#L380-L382" target="_blank" rel="noopener"
>L380–382&lt;/a>）；没设 &lt;code>OPENAI_API_KEY2&lt;/code> 时，取嵌入的函数打印警告后返回 None（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/src/openai_helpers.py#L130-L134" target="_blank" rel="noopener"
>openai_helpers.py L130–134&lt;/a>）。两种情况程序都会接着跑完，跑出来的已经不是论文里的方法，不翻日志看不出来。&lt;/li>
&lt;/ol>
&lt;p>第六件影响结果本身：折扣回报的累加有 bug。两个环境的代码都是这样写的（WebArena &lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/cross_episode_memory.py#L562-L569" target="_blank" rel="noopener"
>L562–569&lt;/a>，Jericho &lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/Jericho/src/cross_episode_memory.py#L437-L440" target="_blank" rel="noopener"
>L437–440&lt;/a>）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">u&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">step_reward&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">enumerate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">future_rewards&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm_step_score&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">step_data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;llm_step_score&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 当前这一步的分&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">discount&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gamma&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="n">u&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">discounted_return&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">discount&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">step_reward&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">step_reward&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">step_reward&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="n">llm_step_score&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>future_rewards&lt;/code> 是从当前步往后每一步的分数。遇到 0 分的后续步骤，代码拿当前这一步的分数顶上。假设某一步打了 +3，后面两步都是 0，γ = 0.5：正确的回报是 3，代码算出 3 + 1.5 + 0.75 = 5.25。&lt;/p>
&lt;p>WebArena 的 γ 是 0.1，这个 bug 带来的放大约一成；Jericho 的 γ 是 0.5，后面跟着一长串 0 分时接近翻倍。评估器给 0 分的含义是「判断不了或没效果」，这类步骤在长轨迹里并不少见。高分步骤后面跟着一串 0 分时，它的回报被放大，优势跟着被高估；负分步骤同理被放大成更负。&lt;/p>
&lt;h2 id="四能不能用先回答谁来判定成败">四、能不能用：先回答谁来判定成败
&lt;/h2>&lt;p>搬进自己的系统之前，至少要满足三个条件：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>有可靠的成败信号。&lt;/strong> JitRL 学到的东西基本都来自评估器给的分，WebArena 默认代码里的评估器参考了标准答案。你的场景里要有对等的东西：测试是否通过、订单状态、工单是否关闭、页面上能检查的终态。拿不到的话，先单独验证 LLM 自己判断成败的准确率。&lt;/li>
&lt;li>&lt;strong>同类任务会反复出现。&lt;/strong> 只能用其他任务的记忆时，JitRL 在五个站点里有四个领先不到 1.6 个点；任务结构高度重复的 Shopping 还领先 5.2 个点。任务各不相同时，更简单的记忆方案差不多够用。&lt;/li>
&lt;li>&lt;strong>能拿到每个候选的分数。&lt;/strong> 要么模型开放 logprob，要么让模型自报置信度。论文给了两种变体，但没有分别报告它们的成绩。&lt;/li>
&lt;/ul>
&lt;p>成本上，每局要多调一次评估器给所有步骤打分，论文报告的账单比 Static 高 45%（290 对 200 美元）。&lt;/p>
&lt;h3 id="不整套用也有三处可以抄">不整套用，也有三处可以抄
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>状态键。&lt;/strong> WebArena 把网址里的数字 ID 换成占位符，再拼上最近几步动作，作为检索用的状态。代码注释里的例子是 &lt;code>/admin/customer/edit/123/&lt;/code> 改写成 &lt;code>shopping_admin/admin/customer/edit/ID&lt;/code>，换一个客户也落到同一个键上，经验可以在同类页面之间复用（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/utils.py#L9-L24" target="_blank" rel="noopener"
>utils.py L9–24&lt;/a>）。&lt;/li>
&lt;li>&lt;strong>动作归一化。&lt;/strong> &lt;code>click('1240')&lt;/code> 里的元素编号每次加载都可能变，代码把它改写成 &lt;code>click(&amp;lt;combobox[Sort by:]&amp;gt;)&lt;/code> 这种「元素类型加可见文本」的形式再存进记忆；取回时在当前页面找不到对应元素就跳过（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/jitrl_agent.py#L257-L284" target="_blank" rel="noopener"
>jitrl_agent.py L257–284&lt;/a>）。&lt;/li>
&lt;li>&lt;strong>按文本重叠检索。&lt;/strong> 相似度用 Jaccard，即两段文本的词集合交集除以并集。WebArena 先按网址过滤，再算 Jaccard；Jericho 先用向量召回，再用 Jaccard 重排。论文附录 K 比较过状态的两种表示：结构化的文字摘要和稠密向量。向量版本在 Zork1 上起伏很大，论文的解释是向量会把描述相似、位置不同的状态判成相似，取回错的记忆。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://www.zata.cc/p/jitrl-test-time-policy-optimization/images/index/fig5-state-representation.svg"
loading="lazy"
alt="文本状态与嵌入状态的对比"
>&lt;/p>
&lt;p>&lt;em>▲ 粉线是文本状态（默认），蓝线是嵌入状态。Zork1 上嵌入版本最高约 44 分，中途两次跌到 0；文本版本最后一局到 69 分。图：论文图 5，arXiv:2601.18510，CC BY 4.0&lt;/em>&lt;/p>
&lt;h3 id="上线前要补的防护">上线前要补的防护
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>准入控制。&lt;/strong> 按第三节的分析，一条回报足够高的记录只要被检索到，对应动作在相似状态下几乎一定会被选中，模型自己没提这个动作也一样。被投毒或者被评估器打错分的记录，会直接变成行为。自进化 agent 的研究里已经有现成的攻击：EVOMAL 实验中，agent 会自己复制出恶意技能，数量是植入源的 4.9 到 9.0 倍，删掉植入源之后，Qwen3 在第 5 轮的攻击成功率仍有 68%（详见&lt;a class="link" href="https://www.zata.cc/p/self-evolving-agents-open-source-audit/" >《Agent 自进化开源盘点：什么能跑，什么在腐烂，什么被门控救回来》&lt;/a>）。写入记忆之前，至少要校验来源和打分依据。&lt;/li>
&lt;li>&lt;strong>淘汰与隔离。&lt;/strong> 记忆库只追加不删除，唯一的清理手段是整库清空（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/cross_episode_memory.py#L93" target="_blank" rel="noopener"
>cross_episode_memory.py L93&lt;/a>）。存储格式是 pickle（&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/cross_episode_memory.py#L64" target="_blank" rel="noopener"
>读&lt;/a>、&lt;a class="link" href="https://github.com/liushiliushi/JitRL/blob/143d22185d95fbf633a0befe6861d5e8b732543b/WebArena/memory_agents/utils/cross_episode_memory.py#L90" target="_blank" rel="noopener"
>写&lt;/a>），加载来路不明的记忆文件，等于允许它执行任意代码。&lt;/li>
&lt;li>&lt;strong>按场景调参。&lt;/strong> 论文里两个环境的超参差别很大：γ 0.1 对 0.5，相似度阈值 0.8 对 0.95，步数上限 10 对 60，探索率 0.05 对 0.65。换到新场景，这些都要重新调，论文只给了 k 的敏感性实验。&lt;/li>
&lt;li>&lt;strong>许可证。&lt;/strong> 仓库里没有 LICENSE 文件，默认保留所有权利。商用或复制代码之前，先向作者确认授权。&lt;/li>
&lt;/ul>
&lt;h2 id="五查过论文代码和-issue-之后仍没有答案的问题">五、查过论文、代码和 issue 之后仍没有答案的问题
&lt;/h2>&lt;ol>
&lt;li>不告诉评估器成败时，JitRL 还剩多少提升？代码有 &lt;code>--use_llm_success_eval&lt;/code> 开关，论文没有报告这组成绩。&lt;/li>
&lt;li>WebArena 的四个基线，以及附录 I 里在线训练的 WebRL，有没有拿到同样的成败信号？运行框架里有基线的分支，实现没有放出来；附录 I 也没写两边各用什么判定成败。&lt;/li>
&lt;li>Static 连试 5 次、至少成功一次的比例（pass@5）是多少？在知道成败的协议下，只要能把之前的一次成功照着重放，Final 就能逼近这个数，它是衡量 JitRL 学到多少的自然参照。&lt;/li>
&lt;li>论文的数字对应哪套配置？β 取多少，α 是表里的 5 还是代码里的 1，用的是 token 还是 verbalized 变体，模型是哪个 Gemini 版本。&lt;/li>
&lt;li>评估器的打分和人工判断一致吗？论文没有测量。&lt;/li>
&lt;/ol>
&lt;h2 id="六结论记忆能替代梯度替代不了裁判">六、结论：记忆能替代梯度，替代不了裁判
&lt;/h2>&lt;p>JitRL 把一个已有的闭式解搬到了推理时。在同类任务反复出现、每次尝试后都知道成败的小样本条件下，它比在线梯度训练起效快，同基座对照里赢了 WebRL 5.7 个点。默认代码比论文公式激进，实际是一条「有成功先例就照着做」的规则；它能学到什么，上限由评估器决定，而 WebArena 的评估器在打分前已经知道标准答案的判定。&lt;/p>
&lt;p>如果你的场景有测试结果、交易状态这类可靠的成败信号，同类任务又会反复出现，可以先抄状态键、动作归一化和文本重叠检索这三样，配上准入控制，再决定要不要上整套改分机制。如果成败只能靠 LLM 自己判断，先等一组不给评估器标准答案的成绩，或者在自己的一小批任务上测出来。&lt;/p>
&lt;p>记忆能替代梯度，替代不了裁判。&lt;/p>
&lt;h2 id="出处">出处
&lt;/h2>&lt;ul>
&lt;li>论文：Yibo Li、Zijie Lin、Ailin Deng、Xuan Zhang、Yufei He、Shuo Ji、Tri Cao、Bryan Hooi，&lt;a class="link" href="https://arxiv.org/abs/2601.18510" target="_blank" rel="noopener"
>Just-In-Time Reinforcement Learning: Continual Learning in LLM Agents Without Gradient Updates&lt;/a>，arXiv:2601.18510v1，2026-01-26，CC BY 4.0。本文引用了正文第 1 到 6 节和附录 A、B、C、E、F、G、H、I、K、M。&lt;/li>
&lt;li>代码：&lt;a class="link" href="https://github.com/liushiliushi/JitRL" target="_blank" rel="noopener"
>liushiliushi/JitRL&lt;/a>，提交 143d221（2026-07-21），文中行号都指这个提交。另读了 issue #1 到 #3。未合并的分支 &lt;code>codex/single-forward-decisions&lt;/code> 不在本文范围内。&lt;/li>
&lt;li>图：图 3、图 4、图 5 取自论文（CC BY 4.0）；两张机制示意图依据论文图 1、图 2 绘制。&lt;/li>
&lt;li>线索：B 站「Lau博士的云组会」的视频&lt;a class="link" href="https://www.bilibili.com/video/BV1rtHW6oEGw/" target="_blank" rel="noopener"
>《不训一个参数！准实时强化学习：JitRL【论文精读】》&lt;/a>。视频和另一篇精读都称它为 ICML 2026 论文，arXiv 页面上只有模板自带的关键词「Machine Learning, ICML」，没有录用信息，本文不采用这个说法。&lt;/li>
&lt;li>相关：&lt;a class="link" href="https://www.zata.cc/p/self-evolving-agents-open-source-audit/" >《Agent 自进化开源盘点：什么能跑，什么在腐烂，什么被门控救回来》&lt;/a>。&lt;/li>
&lt;/ul></description></item></channel></rss>