在大多数多轮大语言模型智能体项目里,最让人头疼的问题之一不是模型不会调用工具,而是模型明明跑完了整条轨迹,最终答案也正确,但你无法确定究竟是哪一轮推理、哪一次工具调用真正决定了这个结果。CREST 论文提出的方向,是把验证器(verifier)作为外部约束引入多轮智能体的信用分配过程,让最终奖励不再被简单摊平到每一步,而是先经过验证器对中间状态的判断,再决定哪些动作应该被加强、哪些动作应该被减弱。换句话说,它想解决的不是“模型能不能完成任务”,而是“任务成功后,功劳应该记在谁头上”。
这篇文章会围绕多轮智能体训练中最容易被低估的信用分配问题展开,先说明什么是多轮智能体、为什么最终奖励不够用,再拆解 CREST 中“验证器约束信用分配”的设计思路,然后给出一套便于复现的最小实现框架,最后讨论验证数据、训练稳定性、常见报错和工程化建议。如果你正在做工具调用智能体、Agent 强化学习微调、过程监督相关的研究或工程,下面这些内容会比较实用。
1. 先理解多轮智能体为什么需要信用分配
1.1 多轮智能体不是“回答一道题”,而是“执行一条任务链”
普通大模型评测通常只关心一轮输入和一轮输出,模型给出最终答案,任务结束。多轮智能体则完全不同。它面对一个用户目标后,需要自己规划步骤,生成思考内容,决定调用搜索、计算器、数据库、外部 API 或代码执行器等工具,然后读取工具返回的观察结果,再决定下一步动作。这个循环可能要重复多次,直到模型认为信息足够,才输出最终答案。
这类结构在工程里通常被称为 Agent 轨迹(trajectory)。一次完整的轨迹可以由下面的数据对象表示:
from dataclasses import dataclass from typing import Optional @dataclass class Turn: step_id: int # 第几轮 thought: str # 模型内部推理 action: str # 动作类型,例如 search / python / db action_input: str # 动作参数 observation: str # 工具返回的观察 final_answer: Optional[str] # 如果本轮结束,记录最终答案 @dataclass class Trajectory: query: str # 用户请求 turns: list[Turn] # 多轮动作列表 final_reward: float # 整体奖励,通常只有 0 或 1为什么需要这个结构?因为后续所有信用分配计算,都要以“每一轮转换”为基本单位。如果训练数据里只保留最终答案,而丢弃中间动作,那么即使采用再复杂的强化学习算法,也没有办法把成功或失败归因到具体步骤上。
1.2 只看最终结果,无法回答“哪一步真正导致失败”
假设一个模型要完成下面这条任务链:
- 用户提问:某公司某年的营收是多少。
- 模型第一步调用搜索,但检索关键词写错了。
- 工具返回了一个错误实体的结果。
- 模型根据错误结果继续推理,中途发现数字明显不合理。
- 模型重新调整关键词,第二次检索成功。
- 模型输出正确答案。
从最终结果看,这条轨迹成功了,所以奖励为正。但仔细看内部结构,第一次检索动作本身是错误的。如果没有过程信号,强化学习会把最终成功的正奖励均匀地传播给每一步,导致“错误的关键词”也可能被增强。更危险的是,如果模型在错误检索之后很快通过某种巧合修正了方向,那么错误动作反而会被当成有效动作来学习。
反过来也存在另一个问题:模型前几轮推理和工具调用完全正确,但最后一轮回答时格式不满足要求,最终奖励为负数。此时如果对整条轨迹做反向传播,前面正确步骤的概率也会被整体压低。
这在强化学习里叫稀疏延迟奖励问题。最终奖励只告诉模型“结果好坏”,不告诉模型“过程哪一步好坏”。多轮智能体链条越长,中间动作数量越多,这个问题越严重。
1.3 信用分配要同时处理时间和动作两个维度
多轮智能体的信用分配并不只是在时间维度上推迟奖励这么简单。它还要处理两个更复杂的问题。
第一个是时间维度。奖励发生在轨迹末尾,模型在步骤 t 采取的决策,可能要等到几步之后才能看到影响。错误的动作可能来自很远的前缀,也可能来自最近一次观察的误判,不能简单地把最后一步当成罪魁祸首。
第二个是动作维度。模型每一步可能同时包含思考、工具选择和参数拼接。同样是一次工具调用,选择“调用哪个工具”和“传入什么参数”会影响后续结果;而“如何解读工具返回的 observation”又会影响下一步决策。如果只对整个动作给同一个 credit,就很难定位是检索策略出了问题,还是工具参数出了问题。
所以在多轮智能体训练里,真正需要的是一个更细粒度的过程信号,而不是只在大结局后做一次全局审判。CREST 解决的核心问题正在这里。
2. CREST 的方法骨架:验证器如何成为信用分配约束
2.1 验证器不是普通奖励模型
在主流 LLM 对齐方案里,奖励模型(reward model)通常对整条序列或一个最终状态打分,例如用户上一轮提问、模型回答了一长串内容,奖励模型输出一个总分。这种打分天然是粗粒度的。
验证器(verifier)更接近“过程监督器”。它不直接回答“这条轨迹最终好不好”,而是回答“当前这个中间状态或这一小步转换是否合理”。例如在某个工具调用后的 observation 上,验证器可以判断这一步得到的信息是否与问题相关、是否包含明显矛盾、是否偏离了目标。
在 CREST 的思路里,验证器的作用不是额外给一个过程奖励就结束,而是为信用分配提供边界。它告诉训练系统:这一步从局部看是可靠的,还是不可靠的;如果不可靠,那么即使在最终成功轨迹里,这一步骤也不能获得过高的正向 credit。
2.2 “约束信用”到底约束了什么
这里需要先把“最终奖励如何传播到每一步”这个问题形式化。一种简单做法是认为每条动作都拿到相同的回报。另一种是使用蒙特卡洛回报,即把从当前步到轨迹结束之间的累计奖励当作当前步的回报。还有一种是用 Critic 网络估计状态价值,从而计算优势函数。
但上述方法都缺少一个外部监督来回答“当前这一步在局部是否真的正确”。CREST 用验证器把这个缺失信息补了进来。用便于理解的示意公式可以写成:
credit_t = lambda_t * final_reward lambda_t = verify_score_t / sum_i(verify_score_i)这里verify_score_t不是某一个模型凭空生成的,而是结合了验证器对当前步骤的局部判断。如果验证器认为第 t 步的工具调用和观察结果存在明显错误,那么verify_score_t会被压低。即使 final_reward 为正,该步骤得到的credit_t也很小,不会导致错误动作概率被错误提升。
如果最终奖励为负,同理,验证器分数高的步骤不应该承担过大的负面责任,因为它们局部是正确的,问题可能出在后面几步。因此验证器不是简单地在最终奖励上再加一层筛选,而是在“整条轨迹的最终奖惩”和“每一步该承担多少责任”之间建立一道闸门。
方法名里的“约束”二字,强调的是验证器不会直接替策略模型做动作,也不会直接把局部分数当作最终反馈,而是把局部正确性作为信用分配的上界或下界,限制最终奖励的不合理扩散。
2.3 与几种常规信用分配方法做对比
为了理解 CREST 的定位,可以把主流信用分配方式放进一张表里对比。
| 方法 | 监督信号来源 | 是否使用中间状态 | 典型问题 |
|---|---|---|---|
| 整条轨迹 REINFORCE | 最终奖励 | 否 | 对每个动作给同样 credit,稀疏且噪声大 |
| Monte Carlo 回报 | 从当前步到轨迹结束的累计奖励 | 否 | 方差高,无法区分错误动作出现的具体位置 |
| GAE + Critic | 最终奖励 + 学到的价值函数 | 弱 | Critic 自身误差会污染优势估计 |
| 结果奖励模型 | 对整条回答打分 | 否 | 无法给中间工具调用步骤细粒度反馈 |
| 过程奖励模型 | 对每一步打分 | 是 | 每步分数本身可能不准,缺少与最终回报的融合 |
| CREST 思路 | 最终奖励 + 验证器约束 | 是 | 验证器的局部判断决定了最终奖励如何分配给每一步 |
这张表不是要说明前几种方法没有价值,而是要说明它们各自解决的粒度不同。CREST 最值得关注的地方在于,它没有抛弃最终奖励,而是把最终奖励当作总预算,把验证器当作预算分配规则。局部正确的步骤可以拿到更多贡献,局部可疑的步骤必须降权。
这里给出的公式是便于理解方法思想的抽象写法,实际论文中的实现可能包含更复杂的归一化、时间折扣和约束条件。工程复现时要结合自己的轨迹结构来设计,不能把示意公式原样当作最终的损失函数。
3. 用最小实现说明 credit 计算过程
3.1 第一步:准备带中间状态的数据集
无论使用什么算法,多轮智能体的训练数据都不能只保存最终答案。至少要保存每一步的思考、动作、动作输入、工具返回的 observation、最终奖励,以及可选的验证器分数。
一条带验证器标注的轨迹可以设计成如下 JSON 结构:
{ "query": "查询某公司2023年营收并对比前一年变化", "final_reward": 1, "turns": [ { "step_id": 1, "thought": "需要先找到公司的财报数据", "action": "search", "action_input": "某公司 2023 年营收", "observation": "返回了该公司的新闻页面", "verifier_score": 0.9, "verifier_label": "correct" }, { "step_id": 2, "thought": "从新闻页提取数据,再查找前一年数据", "action": "search", "action_input": "某公司 2022 年营收 财报", "observation": "返回了包含同比增速的报告", "verifier_score": 0.4, "verifier_label": "uncertain" }, { "step_id": 3, "thought": "增速与前一页数据矛盾,需要再核实", "action": "python", "action_input": "计算2023与2022的同比", "observation": "计算出差异超过5%", "verifier_score": 0.8, "verifier_label": "correct" } ] }这段 JSON 的核心信息是,每一步不仅有动作内容,还带了一个verifier_score和verifier_label。verifier_label可以是correct、uncertain、incorrect等离散标签,verifier_score可以是由验证器模型或规则得到的连续分数。后续信用分配主要依赖这些内容。
在实际项目里,这一步最容易犯的错是只给每条轨迹准备一个最终答案文本,而没有把 action、observation 映射成可计算的字段。到训练阶段才发现需要重放历史数据,成本会很高。
3.2 第二步:让验证器对每一轮转换打分
验证器可以有多种实现形态。如果希望工程落地简单,可以用一个大模型作为在线判断器,给每一步生成一个评分;如果希望训练和推理成本可控,可以用一个较小的序列分类模型,输入当前 query、历史步骤和当前 observation,输出分数。
一个简化版的验证器打分函数可以写成:
def verify_step( query: str, past_turns: list[dict], current_turn: dict, verifier_model, ) -> tuple[str, float]: """ 返回 (label, score)。 label 建议使用 correct / uncertain / incorrect。 score 是连续值,范围建议保持在 0 到 1。 """ prompt = build_verifier_prompt(query, past_turns, current_turn) result = verifier_model.predict(prompt) label = result["label"] score = result["score"] if label == "incorrect": score = score * 0 # 局部错误时强制降低 credit elif label == "uncertain": score = score * 0.5 # 不确定时打一个折中 return label, float(score)这里的关键是,验证器不应该只给“与最终答案是否一致”评分,而应该独立判断当前步骤是否合理。比如工具返回数据与待求问题无关,即使后续模型靠其他步骤成功了,这一步也应该被标记为incorrect。
incorrect时把 score 压到很低,是实现“约束”最直接的一种方式。最终奖励为正时,它不能被扩散到这一步;最终奖励为负时,这一步也不该承担主要责任。
3.3 第三步:把最终奖励拆成每个动作的 credit
在拿到每一步的验证器分数后,就可以计算 credit 序列。为了降低随机噪声,可以加入时间折扣因子,让靠近最终结果的步骤拥有更高的时间敏感度,但局部错误仍然由验证器负责降权。
def compute_credit( total_reward: float, verify_scores: list[float], gamma: float = 0.95, ) -> list[float]: """ 根据验证器分数和折扣因子,将最终奖励分配到每一步。 返回的 credit 序列满足:credit 的总和约等于 total_reward。 """ n = len(verify_scores) raw_weights = [] for i in range(n): score = verify_scores[i] # 越靠近最终答案的步骤,时间折扣越小 time_weight = gamma ** (n - 1 - i) raw_weights.append(score * time_weight) total_weight = sum(raw_weights) + 1e-6 credits = [total_reward * (w / total_weight) for w in raw_weights] return credits如果某一步验证器分数为 0,它的权重也会变成 0,最终奖励会自动分配到其他步骤上去。这比平均分配更合理。
假设某条轨迹有 3 步,final_reward 为 1,验证器分数分别是 0.9、0.4、0.8,折扣因子为 0.95。那么第 2 步因为验证器分数低,获得的 credit 会明显小于第 1 步和第 3 步。如果第 1 步是incorrect被压到 0,最终的正向 credit 就会主要落在第 3 步上。
这一步最重要的目的是观察 credit 序列是否与人工判断一致。可以先抽几十条轨迹,把计算结果打印成对照表,不要直接进入训练。
3.4 第四步:用 credit 更新策略模型
拿到每一步的 credit 后,可以采用类似策略梯度的方式更新模型,只是这里不使用整条轨迹的单一优势,而是使用验证器约束后的逐步优势。
一个最小损失函数可以参考下面这段伪代码:
import torch def policy_gradient_loss( policy_logprobs: torch.Tensor, # shape: [num_steps] credits: list[float], # shape: [num_steps] ) -> torch.Tensor: advantages = torch.tensor(credits, dtype=torch.float32) # 可选:减去均值,降低方差并保持稳定性 advantages = advantages - advantages.mean() loss = -(advantages * policy_logprobs).mean() return loss这个损失函数的含义是:如果某一步的 credit 为正,就提高这一步动作的 log probability;如果 credit 为负,就降低它。
需要注意的是,直接对每一步都做梯度更新,会增加样本效率风险,因为每一步之间并不独立。工程上更稳妥的做法是引入 KL 惩罚,防止策略在单次更新中偏离参考策略太远。常见写法是在原损失上加上beta * kl_divergence,其中beta可以按训练进度动态调节。
在多轮任务中,轨迹长度差异较大,建议对不同长度轨迹分开记录 loss。如果发现长轨迹普遍训练不稳定,则需要在归一化时按轨迹长度调整,或者使用截断后的固定窗口来限制依赖范围。
3.5 可调参数与影响
上面伪代码中涉及几个参数,实际项目里要理解它们各自的作用。
| 参数 | 含义 | 推荐起点 | 调大影响 | 调小影响 |
|---|---|---|---|---|
verify_score | 验证器分数 | 0 到 1 | 更强调过程正确性 | 更容易被最终奖励带偏 |
gamma | 时间折扣 | 0.95 | 强调早期步骤也很重要 | 只关心靠近结尾的动作 |
KL beta | KL 惩罚系数 | 0.01 | 策略更新更保守 | 策略可能快速漂移 |
advantage_mean | 优势去均值 | 是 | 方差更低 | credit 正负比例不稳定 |
verifier_label | 离散标签 | correct/uncertain/incorrect | 控制约束强度 | 过少则无法约束 |
这里没有标准答案,需要根据轨迹平均长度、验证器准确率和任务复杂度做实验。最忌讳的是所有参数都直接照搬某个 benchmark 项目,那通常只在特定数据分布下有效。
4. 训练过程怎么设计,以及怎么证明 credit 分配有效
4.1 推荐的训练管线
在实际实验里,验证器约束信用分配不太适合一上来就端到端跑完整 RL。建议按下面这个顺序推进。
第一步,先做监督微调基线。用一批人工标注或模型生成的高质量多轮轨迹训练一个基础策略,确保模型本身已经具备基本任务能力。这样后续强化学习阶段主要做偏好优化和错误修正,而不是从零学工具调用。
第二步,训练验证器。验证器可以独立于策略模型训练,输入格式是“用户问题 + 历史步骤 + 当前步骤的 observation”,输出是correct / uncertain / incorrect和连续分数。这里要有独立的验证集,不能只使用训练轨迹做评测,否则无法判断验证器是否过拟合。
第三步,用当前策略采样一批新轨迹。对每条轨迹记录最终奖励和所有中间状态,然后调用验证器打分,生成 credit 序列。
第四步,用第 3.4 节的损失函数更新策略,然后回到第三步继续采样。
为了让实验可复现,每次迭代都要保存固定版本。对多轮智能体来说,数据分布会随策略更新而变化,如果不同时记录策略版本、验证器版本、采样温度、credit 计算参数,后面很难定位是模型问题还是数据处理问题。
4.2 离线的过程正确性评估
训练过程中不能只看最终成功率,还要看过程层面的变化。如果最终成功率没变,但成功轨迹里的中间错误步骤明显减少,这也是一种有效提升。
建议记录一组过程指标:
- 每条轨迹中
verifier_label = incorrect的比例。 - 在最终成功轨迹中,仍被验证器标记为
incorrect的步骤数量。 - 在最终失败轨迹中,被验证器标记为
correct的步骤数量。 - 每个步骤的验证器分数与最终奖励之间的相关性。
其中最后一个指标很有意思。如果验证器分数与最终奖励几乎不相关,说明验证器给的是与结果无关的局部噪声,用它约束信用分配会很危险。
对于少量关键轨迹,还需要人工复核验证器分数是否正确。CREST 这类方法有一个隐含假设:验证器比最终奖励更能反映中间步骤质量。如果验证器本身不准确,那么加再多约束也只是把噪声换成另一个方向的噪声。
4.3 在线评估要看哪些维度
在线评估要与离线计算对齐。每次策略更新后,在固定评测集上测试新的策略,可能需要多次采样取 pass@k,而不是只取一次 greedy 结果。多轮智能体本身具有随机性,单次采样容易受偶然因素影响。
在线评估至少要覆盖三个维度:
- 任务最终成功率,以及达到成功所需的平均步数。
- 工具调用错误率,例如调用了不该调用的工具,或参数不完整。
- 在成功轨迹中,是否存在可观测的“绕路修复”现象。即模型先犯了错,后来又在后面的步骤里被迫修正,这种轨迹要单独统计。
如果模型成功率没有提升,但“绕路修复”明显减少,说明 credit 分配让模型开始避免早期错误;如果二者都没有变化,应该优先检查验证器分数和 credit 归一化逻辑。
4.4 一套可复用的实验记录清单
要判断新方法是否有效,最有效的方法是提前列一份实验记录清单,每次改动只动一个变量。
| 记录项 | 示例 | 说明 |
|---|---|---|
| 实验编号 | exp-014 | 唯一标识 |
| 策略模型版本 | policy_v3 | 模型 checkpoint |
| 验证器版本 | verifier_v2 | 如果换过验证器,结果不可直接比较 |
| 采样温度 | 0.7 | 影响轨迹分布 |
| 采样轨迹数 | 2000 | 决定梯度噪声 |
| credit 计算参数 | gamma=0.95, score_weight=1.0 | 核心参数 |
| KL beta | 0.01 | 策略更新步长约束 |
| 评估集 | eval_hard_50 | 固定测试集 |
| 最终成功率 | 62% | 最终结果指标 |
| 过程错误比例 | 8.4% | 过程质量指标 |
| 备注 | 第二次 retry 成功后奖励仍然过大 | 记录影响判断的现象 |
这份清单不只是给论文实验用,工程团队做模型迭代时同样需要。很多 Agent 训练项目结果忽好忽坏,最后查出来的原因经常不是算法写错,而是验证器换了一个版本,或者 credit 参数被人改动后没有同步记录。
5. 常见问题与排查路径
5.1 训练曲线平稳但最终效果不提升
现象是 loss 看起来在正常下降,greedy 评测成功率也稳定,但多轮任务成功率没有明显升高。
优先检查 credit 序列是否产生了有效差异。直接把一条成功轨迹和一条失败轨迹分别打印出来,看每步 credit 是不是“全为正”或“全为负”。如果几乎所有成功轨迹中每一步 credit 都接近同一个正数,那么验证器约束实际上没有起作用,模型收到的仍然是一个平均信号。常见原因包括验证器分数区分度太低、归一化权重把差异抹平、或者大部分轨迹里步骤标签都被标记为correct。
此时应当先看验证器在轨迹上的分数分布。如果分布过于集中在 0.8 到 1.0,建议先增强困难负例,或降低correct的判定阈值。
5.2 最终成功率上升,但中间错误动作也被增强
这种问题比“不提升”更难发现。表现为最终成功率提高,但模型产生了更多早期错误,然后依靠后面步骤强行纠错。如果只看最终结果,会误以为训练是成功的。
需要将成功轨迹按“是否出现过 verifier_label = incorrect 的步骤”分组,分别统计这些错误步骤所在位置的 credit。如果错误步骤在成功轨迹中仍然拿到较高正 credit,说明约束没有通过验证器生效。可能原因有三个:验证器没有真正把错误步骤判为错误;在计算raw_weights时错误步骤 score 没有被压到足够低;时间折扣因子过大,导致位置靠前的高错误步骤获得了过高的权重。
5.3 验证器准确率不低,但训练中逐渐失真
验证器在静态数据集上可能很准确,但策略更新后,模型生成的动作分布会发生变化,出现验证器没有见过的中间状态。此时验证器会产生系统性偏差,甚至把本来正确的新动作误判为incorrect。
常见表现是策略逐步趋向保守,不敢调用工具,或反复输出同一句验证器认为安全的中间话术。处理方式不是立刻换一个更大的验证器,而是让验证器在训练过程中定期用新采样的负例做增量校准。同时要监控每个训练 batch 中incorrect标签占比。如果这个占比在几个迭代周期内突然升到异常值,说明策略漂移已经超出验证器覆盖范围,建议回滚到上一个 checkpoint。
5.4 数据集里没有中间步骤标签怎么做 starter
真实业务数据很难一开始就具备完美的过程标签。可以采用由粗到精的弱监督流程。
第一步,用规则判断明显错误。例如工具返回状态码异常、检索结果为空、代码执行报错,都可以直接标记为incorrect。
第二步,用大模型作为旁路验证器,对每条轨迹逐步骤打分。为了减小过拟合,可以把用户请求和整条历史拼接后让模型给出结构化输出。
第三步,人工抽检一批结果,计算验证器与人工的一致率。一致率达到 85% 以上再开始做训练,否则先修正验证 prompt 或补充标签样本。
弱监督只适合启动阶段。随着模型能力提升,最终还要逐步引入人工标注高质量负例,否则验证器会停留在“能识别明显错误”的粗粒度水平,无法对 subtle 的错误步骤施加约束。
5.5 一个可以直接照着查的顺序
当训练结果异常时,按下表顺序排查能省不少时间。
| 检查顺序 | 检查对象 | 判断方法 | 处理建议 |
|---|---|---|---|
| 1 | 输入轨迹 | 是否有 action、observation、step_id 等字段 | 字段缺失时无法做细粒度归因 |
| 2 | 验证器分数 | 打印所有轨迹的 score 分布 | 分布单一则提高数据多样性或更换验证器 |
| 3 | credit 序列 | 同一轨迹是否出现明显正负区分 | 如果全部同号,检查归一化逻辑 |
| 4 | 梯度方向 | 对比错误步骤和正确步骤的 logprob 变化 | 错误步骤 logprob 不应持续上升 |
| 5 | 训练稳定性 | KL 散度和 reward variance | beta 太小或 advantage 没去均值 |
| 6 | 评测方式 | 单次采样还是多次采样 | 多轮任务建议用 pass@k 评估 |
这六步就是把上面所有问题统一成一条排查链路。遇到任何异常,先不要急着改网络结构,先确认数据是否支持“过程级归因”。
6. 工程实践建议与后续方向
6.1 研究阶段建议从小规模“可解释环境”开始
如果你刚开始理解 CREST 这类方法,不建议直接在一个复杂的真实 Agent 系统上做实验。真实工具返回的 observation 太杂,问题也无法穷举,很难判断 credit 分配到底是否正确。
更稳妥的做法是先用一个 step 数量可控、成功条件明确的多轮环境做实验。例如设计 5 到 8 步的检索与计算任务,让环境能明确告诉模型当前步骤的工具返回是否符合目标。此时验证器可以先保持简单,甚至用手工规则替代。等规则版验证器能稳定提升过程质量,再替换成学习的验证器,并对比两者在训练样本效率上的差异。
这个方法的好处是你能准确区分方法的收益来源:是“过程监督信息本身有用”,还是“特定验证器实现有效”。如果刚开始就把验证器、信用分配、策略更新、真实工具全部耦合在一起,出了问题很难定位。
6.2 生产环境要补齐哪些工程保障
生产环境与实验环境相差很大。实验环境可以手工重启任务,生产环境则必须考虑数据版本、监控、回滚和异常保护。
第一,验证器和策略必须分开部署并固定版本。不要在生产训练任务中偷偷更新验证器模型,否则历史 rollout 数据与新验证器分数之间会出现不可控偏差。
第二,所有 rollout 数据要完整落盘。即使当前只计划训练一个很小的策略,也应该把 query、每步 thought、action、observation、工具返回 metadata、final_reward 都保存下来。以后改动验证器时,可以用同一批历史轨迹重放对比。
第三,设置安全回滚策略。如果观察到训练后的策略在某类任务上最终成功率下降,要能快速切回上一版策略,而不是等待下一次训练迭代把问题修好。
第四,对最终奖励本身要谨慎。在多轮 Agent 中,很多最终奖励不是环境天然给出的,而是由结果评测模型产生的。如果这个结果评测模型本身有偏好,那整个信用分配都会被污染。生产环境至少要保留人工抽检最终奖励的机制。
6.3 下一步可以扩展的方向
CREST 所代表的思路并不局限于“用验证器做奖惩分配”。它可以往几个方向继续扩展。
一个方向是让验证器具备“前瞻性”。当前验证器往往只基于已有轨迹判断当前步是否正确,但真正的中间状态质量,还要看它对后续动作的帮助。例如某一步工具调用返回的全是无关信息,但碰巧包含一个能引发正确搜索的线索,局部验证器可能给出低分,实际却是有价值的。引入前瞻性验证器时,需要把未来是否成功的信息也作为弱约束进入训练。
另一个方向是把 credit 分配扩展到工具调用参数级别。现在很多工作只对 action 级别做奖励归因,但同一个 action 里 query 拼接、top-k 选择、温度参数都值得细粒度建模。如果 trajectory 数据结构足够精细,这部分也能纳入验证器约束。
还有一个方向是与偏好优化的结合。传统 RL 使用最终奖励,DPO 等偏好优化方法使用成对轨迹偏好。如果把验证器约束后的过程质量融入偏好对构建,可能比单纯使用最终答案胜负更稳定。
多轮智能体训练真正有价值的地方,不是把模型输出调得越来越像某个人工答案,而是让模型在复杂工具链中学会自己判断哪一步是关键的、哪一步是危险的。验证器约束信用分配提供了一条新的路径:在最终结果之外,给训练过程加一个状态级解释器。对做 Agent 训练和评测的团队来说,真正值得投入的也不是堆更多算力跑更多轨迹,而是先把“每一步为什么对、为什么错”这个信号做强、做细、做到可回滚。