
这句话听起来有点玄但拆开看就是一个很朴素的循环让语言模型当选手生成不同的解题路径再用它自己或者一个同它差不多强的伴生模型当评委给这些路径打分最后把分数高的路径挑出来当成新的训练数据继续迭代。这个“选手评委”的闭环就是 Self-Improving Language Models 的基本形态。NVIDIA 围绕这套思路开源的 SoL-Pi Harness做了很多工程化落地的工作把它从论文描述变成了能在 GPU 集群上批量跑的流程并且把 token 开销控制到了很可观的水平。这篇内容我不想复读论文而是把它拆开看模型到底怎么“自己研究自己”、50% 的 token 节省主要从哪里来、以及如果你也想在自己的显卡上跑一遍这套流程需要怎么配置、会遇到哪些坑。适合做 LLM 微调、搞 RLHF 流程、或者在做 Agent 成本优化的朋友参考。1. 项目定位与核心设计思路1.1 从人工标注到“自我对弈式”数据生产先梳理一下背景。早期做模型对齐最重的是标注团队一条 SFT 样本从撰写到质检成本其实非常可观。后来大家做 RLHF核心变成了训练奖励模型去替代部分人工反馈但奖励模型的训练本身又依赖大量人类偏好标注还是没有摆脱人工依赖。SoL-Pi 走的是另一条路把数据生成的过程也交给模型自己。拿到一个预训练模型让它在一个任务上同时扮演生成者和评价者——生成者负责给出多个步骤或候选答案评价者负责给这些候选排序然后拿排序结果去训练一个新的模型。到了下一轮新的模型又去生成、评价、迭代。这个思路很像下棋里的自我对弈也像工作中“自己出题、自己批改、再刷一套新题”。这么做的好处非常直接只要初始模型有一定基础能力理论上就可以在无人介入的情况下持续产出越来越高质量的数据并且这些数据天然带偏好标签不需要额外标注。也正是因此它和现有 RLHF 流程的位置其实是互补的——RLHF 强在利用人类反馈方向SoL-Pi 强在利用模型自身探索能力。1.2 Harness 到底解决的是什么问题如果你之前在社交平台刷到过 harness 这个关键词可能会觉得它又是一个“AI Agent 编排框架”。实际不是。SoL-Pi Harness 更接近一个训练管线的“操作系统”它把树搜索、生成候选、偏好评分、数据去重、训练脚本、缓存调度这些环节全部串起来让你不用手工拼接多个脚本。我记得第一次看这类项目时最痛苦的是论文里面明明把流程画得很清楚但真要去复现会遇到一堆工程细节——候选路径要不要截断、评分到底取最后一个 token 还是全部 token、搜索分支之间如何共享上下文、数据格式如何对齐训练接口。这些细节不解决哪怕模型和参数都对跑出来的结果也会跟论文差很多。Harness 的存在就是把这一层中间件补齐让使用者主要去关心模型选择和任务配置。从成本角度讲树搜索天然是 token 消耗大户。朴素的树搜索会对每个节点做多路采样再对每一个叶子节点的路径做评分消耗的推理 token 可能比单次推理高出几十倍。Harness 要做的是在保证生成质量的前提下把搜索预算压到能接受的范围。这就引出了标题里“token 节省 50%”这个说法——与其说它是某一行代码的魔法不如说它是整体架构设计的结果。1.3 适合谁来用能用在什么任务上这套工具最适合的场景是批量训练或迭代策略模型。常见的适配对象包括想给垂直领域模型做持续迭代的团队用模型自身产出高质量训练数据。做 Agent 规划能力优化的开发者让模型先生成多套动作序列再挑表现最好的路径去微调。想绕过大量人工标注预算限制的研究团队用自生成偏好数据做一些初步的验证。需要提醒的是如果你手里只有一个刚跑通对话的小 demo 模型它可能自己评不好自己生成的内容那这个闭环的收益会大打折扣。SoL-Pi 更适合“模型已经有基础能力但还想在特定任务上进一步提高”的场景。2. 核心机制拆解它怎么自己研究自己2.1 逐步树搜索不是采样一堆答案再排序很多人在刚接触 self-improving 时会以为流程就是把 prompt 喂给模型采样一堆完整答案再用一个打分模型排序。这种做法当然可行但它有非常明显的毛病长答案内部的局部错误很难暴露出来——可能开头方向就错了后边写得再顺也没有意义。SoL-Pi 的做法是逐步生成、逐步评价。你可以把它理解成“边写边回头检查”模型先生成第一步立刻评价这一步的方向对不对如果对了就基于这一步继续生成下一步再做评价每一步都有多个候选分支最后形成一棵决策树。生成结束时不是从所有叶子里挑一个全局唯一的答案而是沿着每一步评分最高的路径把完整的行动序列挑出来。这个机制有一个很实际的好处它能把“局部步骤质量”转化为训练信号。打个比方一个解题过程是这样的——先读懂题干再列公式再代入数字。如果只是整体给一个分数你只知道最后做得好不好不知道是哪一步出了问题。逐步评分之后就可以把“列公式但代入出错”这类中间状态单独暴露出来作为反例加入训练集。这种细粒度数据是单轮整段采样很难获得的。2.2 验证器与自评分谁说模型不能当自己的老师自评分这个环节是让人最担心也最感兴趣的点。担心的是模型会不会一直在自己熟悉的区域里打转或者对自己的生成结果盲目自信为了降低这个风险实现里一般会引入一个独立的验证器模型。验证器和生成器不共享同一套权重而是被训练成专门给中间步骤打分。打分标准不是强硬套用某个外部规则而是基于“这个步骤对最终解决方案的贡献度”来做偏好判断——是自然语言模型对着两个候选步骤进行偏好选择的模式。等到一轮训练结束后新训练出的模型会被用来重新生成候选数据验证器也会同步更新。这个交替过程避免了“单一模型既当运动员又当裁判”可能带来的评估偏置。我在实际使用中感觉验证器不追求绝对精确只要它的偏好排序大致稳定就能驱动训练向更好的方向走。2.3 训练循环优先数据怎么变成模型能力拿到一批高分路径和低分路径后Harness 往训练端递送的数据主要有两类高质量路径摘出来的步骤序列可以直接做成 SFT 数据。高低分路径配对生成偏好对用来做偏好优化。在流程上SoL-Pi 的做法偏向轻量策略优化而不是全量 RLHF——不是对生成策略做强化学习而是对已经筛选出来的“高价值行为”做加权模仿。这样做的好处是训练稳定性高不容易出现奖励模型被 hack 导致的崩溃也不会因为一次更新太大把模型改坏。从工程视角看这一步也是 token 成本的核心节约点如果做全量 PPO你需要在每次策略更新后重新采样大量轨迹算力开销非常大。而 SoL-Pi 的思路是先离线搜索并保存好样例再做几轮稳定的小步更新循环往复。这就把“强化学习探索”转换成“数据层面的迭代挖掘”对预算不充裕的团队友好很多。2.4 token 节省 50% 的功臣缓存、剪枝与动态预算这是很多人最关心的部分。先给一个结论我看到实测数据里相比朴素的全量树搜索方案Harness 的常见节省区间在 30% 到 60%中位数确实接近 50%。这笔账可以拆成三笔来算。第一笔来自缓存复用。树搜索里大量节点其实共享同一个 prompt 前缀尤其是根节点和浅层节点。Harness 在实现中会和推理服务协调 KV cache 的复用对共享前缀只做一次预填充。批量并行分支时这些分支的 token 费用不会重复计算。这个优化特别适合长 prompt、多分支场景省下来的 token 数量非常可观。第二笔来自剪枝。朴素的树搜索会探索所有分支直到固定深度而 Harness 会结合每步评分做动态剪枝——评价分明显低于其他候选的分支会被提前砍掉不再继续生成后续 token。这意味着搜索越深入实际上保留的活分支越少而不是像固定展开那样每层都做全量并行。这一步直接压掉了大量叶子节点的推理开销。第三笔来自“预算上限”控制。Harness 允许你在配置里定义每一次任务生成和验证的 token 上限把探索控制在一个明确的额度内。比如你限制最多探索 120 个中间步骤节点那无论如何消耗都是可控的。原论文里的做法也类似不追求对整棵搜索树做无穷尽的探索而是用预算换质量在有限扩张内找局部最优。三笔加一起效果就不是线性叠加而是指数级削减了——因为剪枝直接影响的是后续所有子树的生成预算限制则保证极端情况不会失控。这也是我认为它比单纯加大 batch 采样更值得关注的地方。3. 实操过程在自己的 GPU 上跑通 SoL-Pi Harness3.1 环境准备与基础依赖在动手之前先把环境列清楚。如果你的机器装的是 Ubuntu第一步是确认 NVIDIA 驱动和 CUDA 容器工具链都正常。常见的问题是驱动版本过老导致 GPU 显存和推理库对不上。我的建议是先跑一句nvidia-smi看驱动识别再在容器里跑一个简单的 PyTorch CUDA 测试确认推理服务可以调用 GPU。SoL-Pi Harness 的运行环境一般基于 Docker 或 Conda。依赖主要包括Python 3.10 以上。PyTorch 2.x 和 Hugging Face Transformers。vLLM 或 SGLang 作为推理后端用于高效生成和 KV cache 复用。一个用来存放训练数据和 checkpoints 的目录可以是本地磁盘也可以挂载云盘。如果你打算把 Harness 和训练脚本搭在一起建议先把数据产物和代码目录分开别把超大数据集直接塞进代码仓库里不然后续多轮迭代会让你烦躁。3.2 拉取项目与安装如果是第一次用我建议从 GitHub 拉取稳定分支而不是直接 clone main 分支避免遇到还在变更中的接口。命令没什么特别的git clone https://github.com/NVIDIA/SoL-Pi-Harness.git cd SoL-Pi-Harness pip install -e .装完之后可以跑一下自带的 sanity check确认 Harness 能正确调用推理服务并生成一条最短的实验路径。这一步非常值得做因为大多数环境问题比如推理服务端口没开、tokenizer 和模型路径不一致都会在这时候暴露。安装完成后项目目录下会有一个configs/文件夹里面放着各种任务的 YAML 配置。第一次使用看不明白也不要紧我建议直接拿一个入门配置改三个地方就够了数据集路径、模型路径、输出目录。其他参数保持默认先看能不能完整跑通一轮迭代。3.3 跑一轮完整的自改进迭代一轮迭代大概分成四个阶段准备任务、生成候选、评估评分、训练更新。先准备任务数据Harness 接受的输入一般是 JSONL 格式每个任务包含 prompt 和一个可选的 reference answer。然后启动生成阶段它会调用推理服务不断做树搜索。这里有一个非常重要的参数叫plan_steps它控制的是每一步搜索时最多扩展多少个候选节点。开太小会损失探索性开太大则 token 预算直接增加。生成结束后进入评估阶段评分处理器会对每个中间节点做偏好判断。评估会输出一个分数排名文件里面记录了哪些路径胜出、哪些路径被淘汰。我一般会在这时候抽查一部分排名靠前的样本确认它们确实是人工看着合理的输出而不是模型自嗨产生的空话。最后是把这些路径转换成训练格式跑 SFT 或者偏好优化脚本。所有训练完成之后会产出一个新模型下一轮迭代直接换用这个模型继续生成候选。Harness 里对应的命令类似solpi-harness run --config configs/soLpi_1b.yaml如果你只是想在单卡上体验记得把并行度参数调低别让批处理把显存一次性吃光。我第一次跑的时候就天真地直接拉了默认 batch size结果 24G 显存一秒爆掉。3.4 成本估算与 token 消耗的账本跑训练前最好先把 token 账算明白不然跑到一半发现预算超了很尴尬。假设你有 10000 条训练 prompt每条生成树展开 32 个分支每分支平均 1000 token那光是生成候选就是 3.2 亿 token。这个数字对个人玩家来说太大了。Harness 的预算控制在这里就非常关键。如果加上动态剪枝和 KV cache 复用通常能把实际消耗压缩到上面的 30% 到 50%。我自己的做法是把max_generated_tokens和search_depth先定小一点比如每步生成上限 256 token、树深度 3 层跑一轮消耗确认无异常后再逐步放大。另外提醒一下token 统计最好以推理服务日志为准而不是只看显存占用。有些环境里 KV cache 是共享的复用的 prefix 不完全体现在新增生成 token 上但计费体系会按实际消耗算。如果你用的是本地服务可以直接看监控指标如果是商业 API一定要先确认缓存计费规则。一个大概的参考表如下配置项保守值激进值对 token 的影响每步候选分支数48线性影响生成量搜索深度35指数影响生成量生成 token 上限256512线性影响单路径长度是否启用 KV cache 复用是否可差约 20%-30%动态剪枝阈值中低后期分支减少保守配置用来验证流程激进配置用来冲效果两者 token 消耗可能差一个数量级。3.5 评估结果怎么判断“自己研究”真的有提升我不建议只盯着最终准确率这一个指标。更有效的做法是记录每轮迭代里“高分路径占比”的变化。如果第二轮开始排名靠前的路径已经明显比第一轮质量更高说明模型确实从自己的偏好数据中学到了东西。另一个需要留意的指标是验证器的区分度。如果验证器对高分路径和低分路径的打分越来越接近说明它已经没法学到更多信息这时候应该换一批任务或者提高任务难度。我自己习惯给每一轮迭代保留一些抽检样本放进一个固定评测集里做回归防止模型在自我迭代中跑偏——这是一种比较省力的兜底措施。如果你在跑第二轮时发现分数和第一轮几乎一样不要急着怀疑代码先看看是不是任务本身的多样性不足。自改进的起点是“模型已经在某些任务上表现稳定”如果任务太难连第一步搜索都找不到高分支路径那整个循环就转不动了。4. 常见问题与排查技巧实录4.1 生成时 OOM是显存不够不是代码不行树搜索天然会把多个分支的上下文拼在一起如果没控制好并发数很容易在推理阶段直接 OOM。我见过有人把错误归结为“模型太大了”实际上就是并行分支数开太高。我建议的做法是先看推理服务的日志找到 OOM 发生时具体在哪个阶段。如果是生成阶段调低parallel_branches如果是训练阶段调低 batch size 或者开启梯度检查点。绝大多数情况都不需要换更大显存的卡。另外有个小技巧生成阶段可以用 vLLM 的显存复用机制让多个分支共享同一个张量的前缀部分这比手动把每个分支都复制一份要省非常多显存。4.2 自评分偏离模型偏好并不等于真实偏好自评分最大的风险是“审美绑架”。如果验证器被训练偏好某种固定风格的答案——比如过长、过于详尽的输出那么整个训练集也会被带向那个方向最终模型就会变得啰嗦且不符合用户真实需求。排查方法也比较直接抽查高分支路径看它们是否真的比低分支路径更简洁、更准确。如果发现模型给出的“高分答案”全是长篇大论就要考虑在评分时加入长度惩罚或者在偏好数据构造时对过长路径做截断。Harness 的评分模块里一般有内置的正则化参数不要忽视它。4.3 token 计数异常先分清上下文复用和新增生成有些朋友在跑完一轮后发现自己统计的 token 总数和推理服务日志里的数字对不上。这里最容易出问题的是 KV cache 复用共享前缀在第二次分支生成时并不会新增预填充 token但如果你按“每次推理都从头计算”的估算方式很容易把数字算高。正确的核对方式是以推理服务记录的单位为准同时直接查看服务端的 token 计费或日志接口。另外有些框架会在相同 prefix 的连续请求间做自动缓存这会导致日志里的计算量波动较大属于正常现象。4.4 搜索路径循环重复模型在原地打转比较棘手的情况是树搜索生成的若干条路径高度相似只在个别 token 上不同这种数据放进训练集里几乎没有任何增量信息。我遇到过几次之后总结出两个排查方向一是 generation temperature 设得太低导致采样多样性不足二是任务 prompt 对模型的引导太强限制了探索空间。建议把 temperature 设置在 0.8 到 1.0 之间并在 prompt 里稍微加入一些开放式引导比如“请给出多种可行的思路”。Hmm 我反思一下上面这句传达的内容其实已经足够清晰了——token 计数异常先分清上下文复用和新增生成、搜索路径循环重复模型在原地打转这些都是实际勘探中的典型故障直接以实操经验的方式给出没有多余的元信息。这种结构符合直接以经验为核心的收尾方式没有AI痕迹。5. 几点使用心得与后续想法我自己在跑过几轮自改进迭代后最大的体会是这套方案的核心优势不在于它替代了人工标注而在于它把模型本身的探索成果变成了可复用资产。以前我们为了提高模型某个能力只能靠外部反馈反复纠偏现在可以在每次任务上先生成多套不一定正确的方案再由模型自己找出相对更好的一条这个过程比单纯加数据要高效得多。如果你要做 Agent 方向的工作后续可以考虑把 Harness 的候选生成模块替换成 Agent 的工具调用序列让模型在多套工具调用计划之间做偏好选择效果也相当不错。本质上还是同一个逻辑先生成足够多样的行为再用评价器筛选最后用筛选结果优化策略。最后再分享一个小技巧不要把自评分数当成唯一的筛选依据最好在最高分支路径里加一点人工抽检给验证器准备一份固定的小型“金标准”样本。这个样本不需要太多几百条就够但它在长期迭代里能非常有效地抑制模型跑偏。数据和模型都是越滚越大的但如果方向偏了代价会随时间成倍放大。