
JitRL 是我最近反复读的一篇 Oral 论文它做的事情可以用一句话概括让 LLM Agent 在不做任何梯度更新的前提下完成持续强化学习。更抓眼球的是成本——整套流程跑下来大约 98 美元而同等任务规模下走传统全参数强化学习路线GPU 账单通常落在 3500 美元这个量级。这个数字对比乍一看像是营销话术但把机制拆开看它其实是必然结果既然不训练模型权重就不用买 GPU 小时你付的只是推理 API 的 token 钱。JitRL 要解决的问题也很具体——真实业务里的 Agent 每天都在产生新轨迹、遇到新任务分布你不可能每周重训一次模型但又确实希望它越用越聪明。这篇论文给出的答案是把策略从权重里搬到文本里用自然语言规则库承载持续学习。这篇解读适合三类人一是正在做 Agent 产品、被上线后无法迭代困住的工程师二是想搞懂无梯度强化学习到底怎么落地算法同学三是预算有限、只有 API 额度没有 GPU 集群的小团队。我会把机制、公式骨架、可复现的代码流程、成本核算和踩坑记录都摊开讲能抄的部分直接抄。1. 先把结论摆在前面这个方案到底在改什么1.1 一句话拆解把梯度换成文本编辑传统强化学习微调 LLM更新的是权重矩阵里的浮点数。JitRL 更新的是一个文本文件——准确说是一个结构化的策略条目库。Agent 每跑完一批任务系统把轨迹按好坏分组让模型自己对比反思产出一批候选规则比如当工具返回空结果时不要立即重试同一参数应先换关键词再查一次。这些规则经过打分、去重、合并之后进入策略库下一轮推理时被检索出来拼进系统提示。所以整个学习过程是执行 → 打分 → 反思 → 改库 → 再执行。参数空间从几百亿个浮点数变成了几百条自然语言条目。这是一个典型的黑箱优化问题和进化策略、贝叶斯优化属于同一个家族——你把 prompt 当基因型把任务奖励当适应度用选择和变异代替梯度下降。我特别欣赏这个设计的一点是它把持续学习的工程门槛从有没有集群降到了有没有 API key。对绝大多数做应用层 Agent 的团队来说这才是能真正跑起来的东西。你在本地跑一个脚本接上模型 API睡一觉起来策略库就更新好了中间不需要碰任何训练框架。1.2 98 美元和 3500 美元差的是哪几笔账先把两边的成本结构摆清楚不然这个对比容易被误读。全参数 RL 路线的钱花在两处rollout采样和训练前向反向。以 8 卡高端 GPU 为例机器租用价约 2.5 美元/卡/小时一小时就是 20 美元跑满 7 天约 168 小时账单约 3360 美元加上存储和调试重跑3500 美元是个很实在的估计。这里面最贵的是反向传播——每一条轨迹都要过一遍完整的梯度计算。JitRL 路线只有 rollout 和反思没有反向传播。它把训练这一步整个删掉了剩下的全是推理调用。我在第 4 节会给出详细的成本表这里先给结论约 1200 个任务、3 轮外层迭代、平均 6 轮交互的规模下rollout 花了 58 美元上下反思不到 2 美元验证评分约 6.5 美元检索装配约 3.5 美元再乘上 40% 的重试与失败重跑系数总计 98 美元左右。这里有个关键点必须说清楚98 美元替代的不是预训练也不是基座模型的能力上限。它替代的是任务级策略适配这一段。换句话说基座模型本身的多步推理能力不会因为 JitRL 变强但它在你的具体业务场景里的表现——工具调用顺序、错误恢复策略、输出格式遵循——确实会肉眼可见地变好。1.3 什么场景该用它什么场景别浪费时间适合的场景有个共同特征任务分布会漂移但单任务的判断标准相对稳定而且你能拿到可自动化的奖励信号。典型比如工具调用型 Agent查库、下单、填表、代码修复 Agent跑测试就知道对错、客服对话 Agent有满意度或转人工率作为代理指标。这类场景奖励信号干净轨迹可回放规则可复用JitRL 的性价比极高。不适合的场景也很明确。第一你需要模型掌握全新的知识或语言能力那是继续预训练和 SFT 的活写多少条规则都没用。第二你的任务奖励极度稀疏且延迟比如一个销售线索三个月后才转化反思阶段拿不到有效对比样本规则提炼会变成瞎猜。第三任务之间几乎没有共性每条轨迹都是独立特例那策略库只会膨胀成一堆互相冲突的补丁。还有一个容易忽略的限制上下文预算。策略库最终要塞进系统提示而系统提示是有硬上限的。我在实测里给策略库留了 1500 token每条规则平均 40 token也就意味着同时生效的规则最多三十几条。这个物理约束直接决定了你必须做淘汰和压缩不是规则越多越好。2. 为什么不训模型还能叫强化学习2.1 把 RL 三要素重新落位到文本空间很多人第一反应是不更新权重凭什么叫强化学习这个问题值得掰开说因为它决定了你理解这套方法的深度。标准 RL 里有三样东西策略policy、奖励reward、更新算子update rule。JitRL 一个都没少只是换了个载体。策略 π 不再是 LLM 的权重 θ而是权重固定 上下文可变的复合体形式化写成 π(a|s) LLM(a | s, Retrieve(M, s))其中 M 是策略库Retrieve 是按状态检索相关条目的函数。奖励 R(τ) 完全不变还是环境给的标量。更新算子则从梯度下降换成了反思 选择的文本编辑算子输入是带奖励标注的轨迹集输出是新的库 M。优化目标也一字不改max_M E_{τ~π_M}[R(τ)]。区别只在于你在一个离散的、非欧几里得的文本空间里做搜索梯度不存在所以必须用无导数优化。这个视角一旦建立起来很多工程细节就顺理成章了——为什么需要探索多样性 rollout、为什么需要利用保留高命中率规则、为什么会有过拟合在训练任务上把库调得太窄。我在给团队做内部分享时用过一个类比这就像调音师调音传统微调是直接把钢琴拆了重新做音板JitRL 是听一遍演奏在小本子上记下第三段左手偏重下次演奏前提醒自己。前者彻底但昂贵且不可逆后者轻量、可回滚、可解释但受限于演奏者本身的水平。2.2 无梯度更新的形式骨架与伪代码把上面的话写成可执行的形式核心就四个式子采样D_t {τ_i} ~ π_{M_t}每条轨迹带奖励 r_i反思C_t Reflect(D_t)产出一组候选规则选择M_{t1} Select(M_t ∪ C_t)按效用排序并裁剪到预算内迭代t ← t1直到验证集指标不再提升关键在第三步的 Select。它不是简单拼接而是要做信用分配——判断某条规则到底有没有用。我倾向于给每条规则维护一个三元组 (n_used, n_success, avg_delta)n_used 是被检索进提示的次数n_success 是这些回合里奖励达标的次数avg_delta 是相对基线的平均增益。然后用 Beta 后验或 UCB1 打分决定下一轮谁上谁下。# 策略条目的效用打分示意 import math def ucb_score(item, total_pulls, c1.2): if item.n_used 0: return float(inf) # 未探索的条目优先试一次 p item.n_success / item.n_used bonus c * math.sqrt(math.log(total_pulls 1) / item.n_used) return p 0.5 * item.avg_delta bonus这段代码很短但解决了一个真问题新规则没有历史数据如果纯按成功率排它永远上不了场策略库就固化了。UCB 里的探索项保证了每条候选规则都有被验证的机会这跟多臂老虎机的思路完全一致。2.3 和 PPO、GRPO 路线摆在一起对比把三条路线放一张表里看取舍关系会非常清楚。下表是我根据自己的理解和实测经验整理的具体数字是量级估计而非精确基准。维度全参 PPO/GRPOLoRA 轻量微调JitRL 无梯度更新对象全部权重低秩适配器文本策略库是否需要反向传播需要需要不需要典型硬件8 卡以上集群1 至 2 卡无仅 API单轮成本量级数千美元数百美元数十美元迭代周期天级小时级分钟到小时级能力上限提升有有有限无可解释性差差极好规则可读可回滚性需存 checkpoint需存 checkpoint删几条记录即可灾难性遗忘风险有有低库可审计这张表最有价值的一行是可解释性。规则库是纯文本出问题时你能直接读到Agent 这轮为什么选择先查 A 再查 B而不是对着一堆 logits 猜。对线上业务来说这一点的价值经常超过几个点的分数提升。反过来能力上限提升那一行是 JitRL 的硬伤你得接受它只能在基座模型的能力范围内做调度优化不能凭空长出不会的技能。3. JitRL 的核心机制拆解3.1 经验池轨迹怎样被压缩成可复用条目原始轨迹是又长又脏的一次任务动辄几千 token里面八成内容是工具返回的无关字段。直接拿去做反思成本高且噪声大。JitRL 在中间加了一层压缩每条轨迹先被摘要成结构化的四元组任务描述、关键决策点、结果状态、奖励。这一步我认为是整个流水线里最容易被低估的环节因为它决定了后面反思的质量上限。摘要的粒度要拿捏。太粗反思阶段拿不到足够的因果信息产出的规则全是要更仔细地检查输入这种废话太细token 成本翻倍而且模型会抓不住重点。我的经验是保留三类信息一是失败点前后各两步的完整动作二是工具返回的关键字段不要全文三是最终结果与期望的差异。这个粒度下单条摘要大约 200 到 300 token一批 20 条也就 6000 token 左右成本可控。还有一个细节值得单独提奖励的离散化。连续奖励在反思阶段很难用模型不知道 0.73 和 0.78 的区别意味着什么。我的做法是先分档达标/边缘/失败三档反思时只做组间对比不做组内排序。这样反思提示里就是清晰的这些成功了那些失败了找出区别模型的表现会稳定很多。3.2 及时反思批量对比式反思怎么触发、提示怎么写Jit 这个词我理解是 Just-in-Time 的意思也就是策略更新发生在需要它的时刻而不是攒够了再离线批处理。落到实现上就是反思的触发条件设计每积累 B 条新轨迹触发一次或者当滑动窗口内的成功率跌破阈值时立即触发。前者保证吞吐后者保证响应速度。反思提示的结构我踩过不少坑最后稳定下来的模板是这样的先给任务背景和评分标准再给正例组3 到 5 条达标轨迹摘要再给负例组同样数量最后明确要求只输出可执行的动作级规则每条不超过 40 字不要输出要小心这类无法执行的建议最多 8 条。约束条数这个细节很关键。不加限制的话模型一次能吐 30 条其中 25 条是同义反复你还得花时间清洗。加了限制它反而会挑最重要的说。另外动作级这个限定也得写死否则产出全是提升理解能力加强验证这种听着对但没法落地的空话。我还试过让模型直接输出对比表而不是规则效果反而更好——先让它列出成功组和失败组在这个决策点上的差异再基于差异写规则。等于给它加了一步显式的中间推理规则质量肉眼可见地提升。3.3 策略库的增删改信用分配与冲突消解库的维护是最考验工程功力的地方。新增相对简单难的是改和删。改指的是合并近义条目。两条规则如果语义重合度超过阈值就合并成一条更通用的表述并继承两者的统计量。我一般用向量相似度做初筛再让模型判断是否真的等价两级过滤能省掉大量误合并。删指的是淘汰。三种情况要删连续多轮 n_used 为 0 的说明检索器根本不会选它占着预算没意义、成功率显著低于基线的负向规则留着有害、以及和更高优先级规则冲突的。冲突检测这块我建议别完全交给模型做一个简单的规则引擎扫关键词组合会更可靠比如同时存在先验证再执行和不要重复验证就是硬冲突直接进人工复核队列。条目生命周期我习惯分四态candidate刚生成待验证、active已验证可进提示、probation指标下滑降权观察、archived归档不再检索但保留记录。这个状态机让整个库的演进过程可追溯出问题时能回放哪一轮引入了哪条规则导致指标变化。这件事在事故复盘时的价值比任何监控指标都高。3.4 提示装配检索、排序与预算控制的取舍最后一步是把库里的条目塞回系统提示。这里有三个决策点选哪些、怎么排、留多少预算。选择用检索按当前任务描述做语义匹配取 top-k。但纯语义匹配有个陷阱它偏向选和任务字面相似的规则容易漏掉跨任务的通用规则。我的折中方案是混合排序语义分占七成效用分UCB占三成保证既相关又有效。排序上我把最关键的 3 条规则放在提示开头和结尾各一份中间放次要的。这不是玄学位置对模型注意力的影响在长上下文里非常明显实测同一批规则换个位置遵循率能差十几个点。预算控制是硬约束。我给自己定的红线是策略库不超过系统提示总长度的 40%剩下留给任务说明和工具定义。超了就按效用分从低到高裁裁下来的进 probation 而不是直接删避免误杀。这个机制的副作用是库的规模会稳定在一个平台期而不是无限膨胀长期看反而是好事。4. 实操从零搭一条能跑通的流水线4.1 环境与依赖最小可用栈这套东西对环境的依赖极低这是它最讨喜的地方。你不需要 CUDA不需要深度学习框架一台普通开发机加一个模型 API 就够了。我用的是 Python 3.11依赖只有四样模型 SDK、向量检索库、一个轻量数据库存策略条目、以及任务环境本身的执行器。pip install openai chromadb pydantic tenacity数据库我用的 SQLite够用且零运维。表结构很简单策略条目表加轨迹表两张表就能撑起整个流程。如果你要做多 Agent 并行换成 Postgres 加一个任务队列就行接口不用改。配置方面有几个参数必须先定下来它们是后面所有调优的基准参数含义我的取值取值理由BATCH_SIZE触发反思的轨迹数20太少反思没对比样本太多单批成本高且噪声大MAX_RULES策略库容量上限120对应 1500 token 预算留出淘汰空间TOP_K单次装配检索条数12再多遵循率反而下降注意力被稀释ROLLOUT_PER_TASK单任务采样次数3至少 2 次才能形成组内对比MAX_STEPS单轨迹最大交互轮数10防止死循环也控制单次成本TEMP采样温度0.8需要探索多样性不能太贪心温度这一项特别说一下。很多人习惯把 Agent 的温度设成 0 求稳定但在这套方法里rollout 阶段必须保留随机性否则同一任务三次采样结果完全一样你拿不到对比样本反思就退化成复述。我的做法是采样用 0.8评估用 0两套配置分开。4.2 一轮完整迭代的代码骨架下面这段是我压到最简的架子去掉业务细节之后大概长这样。它不追求性能追求的是把数据流走通你可以直接在上面加自己的环境和评测。import json, uuid from collections import defaultdict def run_one_iteration(env, llm, policy_store, batch_size20): # 1. 采样 trajectories [] for task in env.sample_tasks(batch_size): rules policy_store.retrieve(task.query, top_k12) traj env.rollout(task, system_promptassemble(rules), temperature0.8, max_steps10) trajectories.append(traj) # 2. 按奖励分档 buckets defaultdict(list) for t in trajectories: buckets[t.grade].append(summarize(t)) # 压缩成 200~300 token # 3. 批量对比反思 candidates llm.reflect( goodbuckets[pass][:5], badbuckets[fail][:5], max_rules8, max_chars40, ) # 4. 入库 去重 信用分配 for rule in candidates: policy_store.upsert(rule, statecandidate) # 5. 更新统计量并按效用裁剪 for t in trajectories: for rid in t.used_rule_ids: policy_store.record(rid, success(t.grade pass), deltat.reward - baseline_reward) policy_store.prune(max_rules120, budget_tokens1500) return evaluate(policy_store)几个实现细节值得补充。assemble 函数要处理 token 预算超了就截断别指望模型自己忽略超长提示。summarize 我建议单独用一次低成本调用做比在反思提示里塞原始轨迹便宜得多也干净得多。prune 的裁剪顺序是先按状态archived 优先出再按效用分最后按最近使用时间三级排序能避免误删刚上线的新规则。还有一点整个循环必须有 held-out 验证集。每轮迭代结束在一个完全不参与反思的固定任务集上评一次只有分数提升才提交策略库变更否则回滚。这个 gate 听起来啰嗦但它挡住的是最常见的一种翻车——训练集分数一路涨实际业务表现原地踏步。4.3 参数怎么调三个真正影响结果的旋钮调参这件事上真正影响结果的其实只有三个其他都是噪声。第一个是反思频率。BATCH_SIZE 设太小比如 5反思过于频繁规则碎且重复库迅速膨胀设太大比如 100反馈延迟高早期的错误策略会污染后面几十条轨迹。20 到 30 是我试下来比较稳的区间任务同质性高的话可以放大到 50。第二个是规则长度上限。40 字是我反复试出来的甜点。短于 20 字规则会退化成口号先检查再执行不带任何决策信息长于 80 字规则变成一段叙述模型在提示里读它的成本上升而且多条长规则会互相稀释注意力。第三个是探索率。表现在温度、采样次数和 top_k 的组合上。我的经验公式是任务分布越稳定探索越少新任务占比越高越要保证每条候选规则都被真实试过一次。这里可以用 UCB 的探索系数 c 来做单一旋钮c 从 1.2 起调涨得快就降到 0.8长期不动就升到 1.5。反过来说有几个参数我建议你别在上面花时间反思提示里的措辞微调、摘要的具体字段顺序、检索的相似度阈值。这几个我做过对照实验差异在噪声范围内有那功夫不如多跑两条轨迹。4.4 把 98 美元算给你看一份可核对的成本表这是全文最实的一段。下表按 1200 个任务、3 轮外层迭代、单任务平均 6 轮交互、批量反思 20 条一轮来算单价取某中端模型的公开价位输入 0.55 美元/百万 token输出 2.2 美元/百万 token。费用项调用次数输入 token输出 token小计美元rollout 交互7200×325.2M×32.52M×358.2批量反思60×30.72M×30.09M×31.8结果验证评分36009.0M0.72M6.5规则检索装配216006.5M03.6小计———70.1重试与失败重跑40%———28.0合计———98.1几个计算口径说明一下。rollout 的输入 token 按每轮 3500 算其中系统提示 1200含 12 条规则约 500 token、历史轨迹 1800、工具返回 500。输出按每轮 350 token 算Agent 的动作通常不长。反思按每批输入 12000 token20 条摘要加指令、输出 1500 token8 条规则加解释算。验证评分是每轮跑完对全部任务重评一次输入 2500、输出 200。40% 的重试系数不是拍脑袋实测里超时、限流、解析失败、格式不合规加起来差不多就是这个量级。想把这个系数压下去最有效的办法是给所有结构化输出加上强校验和自动修复一行重试逻辑能省下几百次无效调用。对边一下 GPU 那边8 卡 2.5 美元/卡/小时跑 168 小时是 3360 美元加存储和调试重跑约 3500。差距 35 倍。这里面最反直觉的一点是——JitRL 的成本几乎全部由任务数量决定和模型参数量无关。你换更大的基座模型token 单价涨一点但 GP U 那边的成本会涨一个数量级。规模越大这个方案的相对优势越明显。5. 踩坑记录那些文档里不会写的问题5.1 常见故障速查表下面这张表是我和几个同行交流后攒出来的覆盖了八成以上的翻车场景。建议直接存下来出问题时按现象查根因。现象大概率根因快速排查处理方式分数先涨后跌策略库过拟合训练任务画 held-out 曲线对照加去重、提高淘汰阈值、扩充任务多样性提示长度持续超限条目无硬上限统计每轮 token 分布设硬预算裁剪低效条目进 probation模型不遵守规则规则埋在提示中段做位置对照实验关键规则前置与末尾重复反思产出全是空话轨迹摘要信息不足抽 5 条看反思输入补充失败点前后动作、加对比表中间步成本远超预算上下文重复注入按调用拆分 token 账单开前缀缓存、轨迹压缩、减少无关工具定义同类任务反复失败检索没召回到相关规则打印 top_k 命中列表混合语义分与效用分、补充同义表述规则互相打架缺冲突检测关键词组合扫描合并或加优先级字段冲突进人工队列我重点讲三个表里最不好处理的。第一个是分数先涨后跌这个最折磨人。它通常在第二轮或第三轮迭代出现训练集分数稳步上升验证集在某个点之后掉头向下。根因几乎永远是库变窄了——反思只在当前批次里找差异产出的规则越来越贴合那批任务的表面特征。解法有两个一是强制任务采样分层保证每批里都有一定比例的历史任务和边缘任务二是给规则加适用范围字段反思时要求模型显式写出这条规则在什么条件下不适用检索时按适用范围过滤。第二个办法效果更好但会让反思成本涨三成左右。第二个是模型不遵守规则。这个坑我踩了整整两周。一开始以为是模型能力问题换了两家服务商都没用后来做位置对照才发现把同一条规则从提示中段移到末尾遵循率从六成跳到九成。长上下文里的注意力衰减是真实存在的规则写得好不好是一回事放对位置是另一回事。顺便说规则数量也不是越多越好我测过 12 条和 30 条两组前者遵循率反而更高因为模型面对太多约束时会开始挑着遵守。第三个是成本偷偷超标。这事最隐蔽因为单次调用看起来都很便宜。根因通常是重复注入——每轮交互都把完整的工具定义和全部规则重新发一遍实际有效信息只占三成。解法是前缀缓存加上动态裁剪把稳定不变的部分工具定义、任务说明放在提示最前面以保证缓存命中把每轮变化的部分放在后面。这一项调整在我的实测里省了四成左右的输入成本。5.2 策略库退化的三种形态与对症下药策略库退化是个缓慢过程等你从分数上发现时通常已经积累了几十轮坏数据。我总结了三种典型形态。第一种是膨胀。表现是条目数持续增长但有效条目占比越来越低。根因是新增没有配套淘汰而反思又倾向于生成近义表述。药方是提高合并阈值并且强制每轮淘汰固定比例的末位条目——哪怕它们的统计量看着还行。这个强制淘汰听着粗暴但它逼着系统只保留最有价值的规则长期效果比温和淘汰好。第二种是冲突。两条规则在特定场景下给出相反指令模型随机选一个表现为同一类任务时好时坏方差极大。这类问题靠分数很难定位得靠人工抽检提示内容。药方是入库前做一次语义冲突检测把潜在冲突的条目挂上互斥标签检索时同组只取一条。第三种是僵化。表现是所有新规则都上不了场老规则永远霸占提示位置。根因是纯利用的选择策略新规则没有历史数据效用分自然低。药方就是前面写的 UCB 探索项另外可以加一条硬规则每轮装配必须包含至少一条 candidate 状态的条目强制给它曝光机会。这一条我在三个不同项目里都验证过加上之后新规则的存活率明显提升。5.3 评估失真为什么离线涨了线上没动这个问题值得单开一节因为它决定了你这套系统到底有没有用。失真的第一个来源是评估集污染。如果你的验证任务和训练任务来自同一个池子只是随机切分那策略库实际上见过它们的近亲分数会虚高。正确做法是按任务类型或时间切分验证集必须是完全不参与反思的那部分而且最好在时间上晚于训练集模拟真实的分布漂移。第二个来源是单指标。只看成功率会漏掉很多问题比如成功率涨了但平均交互轮数从 4 涨到 9成本翻倍或者成功率涨了但工具调用错误率也涨了只是恰好被重试掩盖了。我建议至少盯四个指标任务成功率、平均交互轮数、工具调用错误率、规则遵循率。前两个看效果后两个看健康度。第三个来源是评估器本身不稳定。用 LLM 做裁判时同一个输出评两次可能给出不同结论。解法是固定评估提示、温度设 0、并且对关键指标做多次采样取多数。这件事成本不高但收益很大我见过因为评估器抖动导致整个迭代方向跑偏的案例。最后分享一个我觉得很实用的小技巧给策略库做消融评估。每轮迭代结束后除了正常评估再跑一次清空策略库的基线评估两个分数的差值才是这套方法真正贡献的增益。如果某轮迭代后这个差值在缩小说明规则库的边际价值在下降该考虑换基座模型或者扩充任务类型了而不是继续在这条路上硬堆规则。