面试官追问:GRPO 不是调用一个函数,Agent rollout 为什么总把系统拖垮?
GRPO 的公式并不神秘,难的是把一组可比较、可复现、成本可控的 Agent 轨迹真正采出来。
“我们用 GRPO 训练了一个 Agent。”
这句话放在简历上很有气势。面试官通常不会先问公式,而是问一句很朴素的话:
“一组 rollout 是怎么来的?”
如果你的回答是“把 prompt 复制几份,然后生成几次”,下一问马上会来:工具返回不一样怎么办?有的轨迹三步结束,有的跑到三十步怎么办?八张卡在等一个慢网页时,GPU 算力算谁的?
👔 面试官 GRPO 和 PPO 的关键差异是什么?
🙋♂️ 常见回答 GRPO 不训练 value model,用同一问题采样的一组结果计算相对优势,省显存。
👔 面试官 那 Agent 里的“同一问题”是什么?如果每条轨迹拿到的搜索页面不同,还能比较吗?
公式回答到这里就不够了。GRPO 的相对优势依赖一组样本之间的可比性。rollout 质量不稳,后面再漂亮的 loss 也只是在给噪声加速。
先把 GRPO 摆回它该在的位置
DeepSeekMath 介绍的 Group Relative Policy Optimization,核心思路很直接:对同一个输入采样多条输出,用组内奖励的均值和方差构造相对优势,不必像 PPO 那样单独维护一个 value model。形式可以写成:
A_i = (r_i - mean(r_group)) / (std(r_group) + ε)
再配合旧策略比率、裁剪和 KL 约束更新策略。DeepSeek-R1 将这类方法用于大规模推理训练,引发了很多“只要上 GRPO 就能涌现”的误读。真正可迁移的经验不是一个神奇开关,而是:同题多采样、奖励可比较、更新受约束。
对 Agent 来说,一条 output 不再只是文本。它可能包含思考 token、工具调用、工具观察、下一轮思考和终止答案。组内比较的对象,应该是同一个任务、同一套环境契约下的完整决策轨迹。至少要记录:
- 输入问题和任务版本;
- 初始环境状态或可复现的快照;
- 模型生成的动作 token;
- 工具名、参数、返回摘要和耗时;
- 终止原因、奖励分解和验收结果。
这些字段看上去像日志工作。实际上,它们决定了你是否真的在做 group relative,而不是拿几条互不相干的故事算平均数。
一组 rollout,到底该怎么采
最小可行流程可以拆成六步。
第一步,固定问题批次。不要每轮都从动态数据源随机抓 prompt,否则这轮的提升可能只是题目变简单。
第二步,为每个问题建立环境副本。文件系统、数据库、网页快照、随机种子都要有边界。若工具必须联网,至少缓存响应和版本,让失败可以重放。
第三步,用当前策略生成一组轨迹。组大小不是越大越好。小组方差估计抖,大组则把采样成本和尾部延迟一起放大。先从 4 或 8 条做基线,再根据奖励分布和显存调整。
第四步,执行工具并把观察回填。工具返回的内容是 observation,不是策略动作;训练时对这部分 token 做 mask。Search-R1 对检索 token 的处理就是一个清晰例子:更新模型自己生成的 token,别让它去拟合搜索引擎吐出来的原文。
第五步,统一验收。数学题用答案检查,代码任务跑测试,检索任务查引用是否支持结论。不同任务可以有不同 verifier,但同一组样本必须经过同一版本的验收器。
第六步,计算组内优势,过滤明显环境故障,再做策略更新。生成和更新之间的队列边界要清楚,否则失败重试会混入下一轮样本,造成样本年龄不可控。
为什么长轨迹会拖垮 rollout
语言模型生成本来就有长短差异,Agent 再叠加工具延迟,尾部样本会更长。一个批次里,七条轨迹三步结束,第八条卡在网页超时二十秒,整批 padding 和等待都由它决定。
常见故障有三个。
其一,GPU 等 CPU。工具调用在进程外执行,模型服务却同步等待,卡上没有 token 可以生成。
其二,短轨迹被长轨迹 padding。为了凑成张量,三步轨迹被补到三十步,显存和计算都花在空白位置。
其三,重试放大流量。一次超时如果在 worker、网关、环境三层各重试一次,就不是一次失败,而是最多八次请求。训练曲线没涨,账单先涨。
工程上要把 rollout 当作分布式数据生产,而不是一个 for 循环。把策略生成、工具执行、验收和写盘拆成可观测阶段;为每条轨迹设置总步数、单步超时、工具预算和 wall-clock 上限;超过上限要有明确终止原因,不要让 worker 永久挂起。
同一组样本,环境真的一样吗
GRPO 依赖组内相对比较,环境差异会直接污染优势。举个小例子:同一个搜索问题,A 轨迹拿到的是刚更新的页面,B 轨迹拿到的是缓存旧页。A 答对、B 答错,模型可能把“调用搜索”学成“碰到新缓存就赢”。
解决办法取决于工具性质。
对可缓存工具,保存请求参数和完整响应摘要,训练时从快照回放。对有随机性的工具,固定种子或把随机源当显式环境变量。对必须实时调用的服务,记录时间窗口、返回状态和速率限制,并把“不可比较”的样本打上标签。
这里不追求绝对确定性。网络不可能永远像实验室一样安静。你要做的是知道哪些差异属于策略探索,哪些差异只是环境晃了一下。前者进入奖励,后者进入诊断或重试。
奖励全相同或全不同,GRPO 都会难受
组内奖励全是 1,标准差为 0,优势没有方向;全是 0,情况一样。可以跳过这组、积累到下一组,或使用带温度的软评分,但不能假装相对优势仍然提供了信息。
另一头是奖励尺度混乱。一条轨迹答案对但调用了 30 次工具,另一条答案也对只调用 3 次。如果奖励把“正确”设成 1,再用很小的成本惩罚,组内差异几乎看不出来;惩罚过大,又会把模型推向不敢行动。
我的做法是先画奖励分布,再选权重。把最终结果、硬约束、工具成本、格式检查分开记录,展示每项在组内的方差。若某个分量长期为常数,它不是一个有效的相对信号;若某个分量支配全部方差,要确认这是不是产品真正要优化的目标。
rollout 版本和更新版本要对得上
Agent 训练经常使用推理服务单独生成轨迹,再回到训练框架做更新。生成模型、训练模型、tokenizer、工具协议只要有一个版本错位,重要性比率就不再对应同一策略。
至少要在轨迹里写入 policy version、tokenizer revision、prompt template revision 和 environment version。更新时检查版本,不匹配就拒绝进入 batch。这个检查会让一些样本被丢弃,短期看像浪费;但把错版本样本混入梯度,通常更难排查。
还要处理样本年龄。若生成队列堆积几分钟,训练更新了很多轮后才消费,旧策略采的轨迹会变得过时。可以限制队列长度、周期性清空,或明确采用异步训练并监控 policy lag。不要一边使用 on-policy 的公式,一边让样本在仓库里过夜。
代码任务的 rollout:通过测试不等于轨迹好
代码 Agent 是最容易让人误会的场景。最终测试全绿,轨迹可能包含危险的文件操作、无关依赖安装和大量重复运行。只看 outcome,模型会学会“把测试跑绿”,而不是“写出可维护的修复”。
反过来,测试环境偶发失败,也不能立刻把策略判成坏。需要把编译器、测试框架、依赖安装的状态分开记。对于外部副作用,沙箱要限制网络、文件和进程;对每次执行记录 patch、stdout 摘要和测试版本。
rollout 的质量最终由验收器决定。验收器只检查一个脆弱的样例,GRPO 就会把策略往样例漏洞上推。这个问题会在下一篇 reward hacking 里展开。
给 rollout 做一张体检表
我通常把 rollout 指标分成四组,而不是只报 samples per second。
第一组是可比性:同一 prompt 的环境快照命中率、verifier 版本一致率、奖励标准差为零的组占比。可比性差,组内优势就没有解释力。
第二组是效率:每条轨迹的 token 数、工具次数、p50/p95/p99 时延、GPU 等待时间和重试率。p50 很漂亮、p99 爆炸时,集群仍然会被尾部拖住。
第三组是质量:最终正确率、硬约束通过率、引用支持率、代码测试通过率。把这些指标和 reward 分开画,才能看出刷分。
第四组是新鲜度:轨迹生成时的 policy version、进入更新时的版本、队列等待时间。样本年龄一旦和训练步数相关,loss 下降也不代表策略更新有效。
每轮抽几条“最高优势”和“最低优势”轨迹人工看一眼。最高优势轨迹如果只是碰巧撞上一个脆弱页面,应该先修数据,而不是庆祝模型学会了搜索。
在资源受限时,可以先降低组大小,再做更长的离线回放;不要为了凑满一组而无限等待慢样本。一个明确标记为 incomplete 的小组,比一组混入超时重试的伪完整数据更适合调试。
同步、异步和离线回放的边界
同步 rollout 好理解:一轮生成完,统一算奖励,再更新策略。它的优点是样本关系清楚,缺点是被最慢轨迹卡住。异步 rollout 可以让 worker 持续生产,吞吐更高,但样本年龄、版本漂移和奖励延迟要额外监控。两者不是谁先进,而是任务能否容忍旧策略样本。
如果工具延迟不可控、任务又必须实时交互,可以先采用“异步生成、周期性冻结策略”的折中:冻结一个 policy version 生成一段时间,达到队列上限后统一更新,再切换版本。这样仍有等待,却能把样本新鲜度控制在一个可解释的窗口内。
离线回放适合做 verifier、mask、奖励权重和超时策略的回归,不适合证明实时环境里的最终收益。回放里工具响应固定,模型学不到新页面变化;实时训练则反过来会受网络噪声影响。报告里把两种结果分开写,别用离线吞吐去宣称线上交互能力。
2026 年关于异步 RLHF 的研究把这种“样本年龄”进一步写成了 staleness 与学习率的关系。采样策略落后越多,旧轨迹对当前策略的偏差越大,更新就越不能激进。落到工程上,不是背一个缩放公式,而是同时监控 policy lag、队列等待时间、importance ratio 和有效样本率;一旦超过设定窗口,就降学习率、丢弃过旧样本或切回冻结版本采样。
另外,长轨迹可以按 turn 截断,但截断必须作为终止事件进入奖励。若直接丢掉尾部 token,模型会以为任务自然结束,逐渐学会提前收尾。截断样本可用于诊断“预算不足”,但不要和真正成功样本混在同一奖励桶里。
报告 rollout 时,最好把“每秒生成多少 token”和“每个正确任务花多少成本”同时给出。前者方便看系统吞吐,后者才接近产品约束。一个靠重复采样把正确率抬高的系统,可能在第二个指标上已经不可用。资源报告还应注明并发度、每条轨迹的平均工具等待和失败重试次数;否则换一台更快的机器,数字会变好,却无法说明算法本身有了提升。
60 秒面试回答
GRPO 的核心是同一输入采样一组轨迹,用组内奖励计算相对优势,避免单独训练 value model。Agent 场景中,一条轨迹包含模型动作、工具观察和终止结果,所以 rollout 首先是数据生产问题。
我会固定 prompt、环境快照、随机性和 verifier 版本,记录 policy、tokenizer、环境版本。生成、工具执行、验收、更新分阶段排队,设置步数、超时、工具预算和样本年龄上限。工具返回的 observation 不参与 loss,只更新模型自己生成的 token。组内奖励方差为零或来自环境故障时,跳过或重试,不把它们当成有效优势。
评价 rollout 不只看吞吐,还看轨迹可复现、奖励可比较、尾部延迟和 verifier 稳定。GRPO 省掉的是 value model,不是工程复杂度。
参考资料
- DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models
- DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning
- Search-R1: Training LLMs to Reason and Leverage Search Engines with Reinforcement Learning
- verl: Volcano Engine Reinforcement Learning for LLMs
- Staleness-Learning Rate Scaling Laws for Asynchronous RLHF
AgentAlpha 大模型 Agent 训练营
AgentAlpha 的路线从 RAG、记忆系统、单 Agent、多 Agent、DeepSearch、高效推理、Code Agent、自进化编码,推进到第 9 阶段的 Agentic RL 和最后的综合项目。
Agentic RL 阶段已经确认的内容包括 Search-R1、GRPO / PPO、奖励函数和搜索触发;阶段交付是一份小规模问答或推理任务上的 RL 微型实验报告。课程按周任务、作业检查、代码 Review 和项目验收推进,完成项目后再继续打磨 README、技术报告、简历项目段落和面试讲法。
如果你只想先看路线图,发「路线」;想判断自己适合从哪个项目开始,发「项目」;正在准备面试,发「追问」。
先让每条轨迹在同一个世界里发生,再谈相对优势。下篇见。