☰
多轮强化学习实战:训练LLM智能体长程决策
2026/10/17 8:18:32 网站建设 项目流程

做LLM智能体的人,十有八九都遇到过一个场面:模型单轮问答、单步工具调用表现都很好,可一旦让它自己拆解任务、连续调用好几轮工具、中途还要根据反馈调整策略,就开始犯糊涂——工具用错、步骤跳过、绕远路最后还回不到正题。这种“长程决策”能力,恰恰是智能体从“会聊天”走向“会办事”的分水岭。AgentGym-RL这个名字里的“Gym”已经暗示了思路:把LLM扔进一个模拟环境里,用多轮强化学习(Multi-turn Reinforcement Learning)让它在反复试错中学会长程规划与决策。这篇文章不聊表层概念,直接把它的环境设计、训练回路、奖励机制、关键参数和踩过的坑拆开讲,适合正在做LLM Agent训练、或者想从单轮RLHF往多轮RL方向走的开发者参考。

1. 从单轮对齐到长程决策——AgentGym-RL想解决的问题

1.1 传统RLHF为什么管不住“长程”

传统RLHF做的是“偏好对齐”:给模型一个prompt,让它生成一段response,再用奖励模型打分,优化模型。这套逻辑在对话场景下非常好用,因为输入输出都短,反馈信号明确,一个回合就能评价好坏。但你把它搬到智能体任务上,问题就来了。

以“帮用户查资料并整理成表格”为例,完整流程是:理解需求→构造搜索关键词→调用搜索工具→阅读多篇结果→抽取信息→对比筛选→生成表格。中间任何一个环节出错,最终结果都会崩。可如果只拿最终结果训练,模型根本不知道是哪一步错了,也不知道每一步好坏对结果的影响程度——这就是**信用分配(Credit Assignment)**难题。单轮RLHF的奖励信号是“整段文本”级别的,到了多步任务里就成了一个极其稀疏的全局信号,模型很难从中学到逐层的决策能力。

更麻烦的是,长程任务里模型经常要面对一个巨大的动作空间组合爆炸。每一步可以选择调哪个工具、传什么参数、要不要继续搜索还是直接作答,每个选择都会影响后续所有步骤。这种问题用单轮监督学习(SFT)也好、单轮RL也好,都会让模型在训练时看到一个“静态快照”,学不会动态纠错——环境变了、反馈变了,它不知道该怎么调整。

1.2 长程决策场景下“多轮”意味着什么

AgentGym-RL这类框架的核心变化,是把“单轮生成”扩展成“多轮轨迹(Trajectory)”训练。所谓轨迹,就是智能体在环境里从任务开始到结束的完整行为序列,格式大致如下:

观察 → 思考 → 动作 → 环境反馈 → 新的观察 → …

跟单轮RLHF的关键区别在于:训练对象不是“一个回答”而是“一整条行为链”。每一步动作都会影响后续状态,每一轮都需要决策,而强化学习算法要做的就是在这个行为链上评估和优化策略——让“好排列”更可能出现,“坏排列”更少出现。

多轮RL

的优势在于它能处理部分可观测性:智能体一开始并不知道完整环境,只能通过观察收集信息。比如网页检索任务,模型第一步搜到的结果可能偏题,但看到了搜索结果后可以调整关键词再搜一次——这种“根据反馈修正策略”的能力,只有通过多轮交互训练才能习得。

2. 核心机制拆解:多轮强化学习的训练回路

2.1 第一层:环境模拟器与轨迹采样

AgentGym-RL训练体系的最底层是一个环境层。它把各种任务包装成OpenAI Gym风格的接口,让LLM像强化学习里的Agent一样与环境交互。环境不只有一个,而是覆盖多种任务类型的一个任务集合(Task Suite),常见的有这么几类:

  • 网页/工具类:模拟浏览器页面或API接口,模型需要调用搜索、点击、读取等工具完成任务。
  • 代码执行类:模型生成代码、执行、查看结果,根据报错再修改(比如写一个数据处理脚本跑通并输出正确统计结果)。
  • 问答推理类:模型可以主动选择是否查资料,多轮检索后给出最终答案。
  • 对话类:多轮对话中需要追问澄清、提供信息、推进任务完成。
  • 数学/逻辑类:按步骤推理,每步产生中间结论,并可以被检查正确性。

这些环境统一封装成两个核心方法:reset()(初始化新任务)和step(action)(执行动作、返回观察与奖励)。统一的接口意味着训练代码可以跟具体任务解耦——换任务只需要换环境注册,策略网络、奖励模型、RL算法都不用动。

轨迹采样过程是:给模型一个任务描述作为初始观察,模型输出动作(文本或工具调用),环境执行动作后返回新的观察和奖励,循环往复直到出现终止信号(任务完成/失败/最大步数耗尽)。一条轨迹长的可能几十轮甚至上百轮,训练数据量比单轮对话大了一个数量级。

2.2 第二层:奖励信号与过程奖励

长程决策最棘手的问题不是“没有奖励”,而是“奖励太稀疏”。最终答对了给1分,失败了给0分——中间几十步动作的好坏模型完全无从判断。所以这类框架里一定离不开**过程奖励(Process Reward)**设计。

过程奖励可以有多种来源:

  • 规则型奖励:工具调用是否合法、代码是否通过编译、是否访问了禁止页面,这类信号可以通过人工规则直接判断,准确且零成本。
  • 结果型子奖励:任务被拆成几个子目标,每完成一个子目标给一个奖励(比如“找到相关文档”给0.3分,“提取出正确字段”给0.5分)。
  • 模型型奖励:用一个训练好的奖励模型(RM)对中间步骤评分,优点是通用性强,缺点是可能引入偏好偏差,需要跟规则型奖励配合使用。

训练时一般把这些奖励加总成综合奖励 = 过程奖励 + 终止奖励。关键原则是:过程奖励要设计成“稀疏但不罕见”——太密集了模型会学会刷奖励(比如反复调用无意义的工具);太稀疏了模型学不会中间步骤。后面第三节我会给出一个具体的配比案例。

2.3 第三层:策略更新算法与PPO变体

策略优化环节,主流选择还是PPO(Proximal Policy Optimization)。为什么不是Q-Learning、不是A2C?因为LLM的param量太大,值函数类算法样本效率虽高但对Exploration要求极高,不适合大模型的离线训练;PPO的重要性采样离线更新机制天然适合“先采轨迹、再批量更新”这种LLM训练范式。加上PPO用clip限制每次更新幅度,能有效防止策略在单次更新中崩坏——这对大模型来说特别重要,谁也不想辛辛苦苦训到一半,一口气更新过头让模型变成只会说重复话的“复读机”。

实现上,PPO部分包含两个网络:

  • Actor(策略网络):就是被训练的LLM,输入当前观察和上下文,输出下一步动作的概率分布。
  • Critic(价值网络):评估当前状态的价值,也就是“从这一步开始往后,平均还能拿到多少奖励”,用来计算优势函数。

优势函数用**GAE(Generalized Advantage Estimation)**计算,公式长这样:

A_t = δ_t + (γλ)δ_{t+1} + (γλ)²δ_{t+2} + … 其中 δ_t = r_t + γ·V(s_{t+1}) - V(s_t)

GAE的巧妙之处在于,它把“每步即时奖励”和“未来长期预期”加权融合。当λ靠近1时,更看重长期回报,适合长程任务;当λ靠近0时,更看重短期反馈。在AgentGym-RL这类长程决策场景,λ一般取值在0.95以上,γ(折扣因子)取0.99,意味着模型需要把几十步之后的回报也算进当前决策的评估里。

3. 实操指南:从头实现一个AgentGym-RL风格训练

3.1 环境搭建与任务集选择

我不建议一开始就上全家桶。实操经验是:先在大类任务里选1~2个做技术验证,跑通一条完整训练链路后再横向扩展。以最常见的“网页检索+问答”组合为例:

class WebSearchEnv: def __init__(self): self.tool_schema = {...} self.max_steps = 10 self.state = None def reset(self): # 从任务集里抽样一个query self.query = sample_task() self.state = {"turn": 0, "history": [], "result": None} return {"observation": self.query, "step": self.state["turn"]} def step(self, action): # action可以是search(query)、read(url)、finish(answer) if action["type"] == "search": self.state["result"] = search_api(action["query"]) reward = 0.2 # 搜索成功且返回有效结果 elif action["type"] == "read": self.state["result"] = read_page(action["url"]) reward = 0.3 # 读取到内容 elif action["type"] == "finish": reward = 1.0 if is_correct(action["answer"]) else -0.2 done = True ... return observation, reward, done, info

关键点在这个reward的分配。上面给“搜索返回有效结果”0.2、“读页面”0.3,数值是我自己定的一个配置。实际上“搜索有效”的定义可以进一步细化:返回结果跟query的相关性大于某个阈值才给奖励,否则奖励为0——奖励要给在“做对了什么”上,而不是“做了什么”上。无数失败的教训都源于模型发现“调用工具就有分”,于是开始疯狂调工具但不推进任务。

任务集建议自己维护一个JSON文件:

{ "tasks": [ {"id": "t001", "type": "search_qa", "query": "列出某地近五年人口变化并分析原因", "answer": "...", "tools": ["search", "read", "finish"]}, ... ], "max_steps": 10, "reward_weights": {"search_valid": 0.2, "read_valid": 0.3, "correct": 1.0, "wrong": -0.2} }

训练时每次从任务集里抽样,保证模型见到多样化的任务,避免在单一任务上过拟合。

3.2 奖励配比与归一化

奖励设计是整个训练里最难“调”的部分。我踩过最深的坑是奖励幅度不一致:搜索成功给0.2,但最终答案对了给10——结果模型发现只要死磕最终答案就能拿高分,完全忽略中间步骤的质量。正确做法是控制奖励在一个相对集中的量级里,并通过归一化消除量级差异。

给一个经过多轮实验验证的基线配置:

环节奖励事件基础分值说明
工具调用合法性非法调用/越权访问-0.1规则判断,防模型乱试
搜索关键词构造合理且返回有效结果+0.2有效=结果相关性Top-K包含目标信息
阅读成功读取并抽取到有效信息+0.3跟后续答案相关性联动
早期无用动作重复调用相同工具-0.05轻度惩罚,防止死循环
最终回答答案正确+1.0终止奖励
最终回答答案错误-0.2终止奖励
步数超限超过最大步数仍未完成-0.5终止奖励

这套配置的核心逻辑是:中间过程奖励加起来(一个任务大概经历3~5次搜索、2~3次阅读),总过程奖励约在0.9~1.5之间,跟最终奖励量级接近——模型不会觉得“过程只是过程的,结果才重要”。归一化放在advantage计算前的reward中,可以在每次iteration用所有轨迹的reward做z-score归一化。

3.3 关键训练参数与基线配置

LLM参数规模不同、任务复杂度不同,超参数需要调整。下面给的是我在7B~13B开源模型上实测过比较稳定的基线:

参数推荐值备注
rollouts per iteration512 ~ 1024每轮采样轨迹数,太少策略估计方差大
max trajectory length10 ~ 20超过这个长度强制截断
GAE λ0.95 ~ 0.99长程任务取高值
discount γ0.99让远期奖励影响当前决策
PPO clip ratio0.2标准值,大模型不需要太激进
actor lr1e-6 ~ 3e-6调大容易崩,调小学得太慢
critic lr3e-6 ~ 1e-5价值网络可以比actor稍快
entropy coefficient0.01 ~ 0.05防止策略过早坍缩
batch size64 ~ 128PPO更新时的mini-batch大小

这里特别提醒一个容易被人忽略的参数:max trajectory length。很多人为了“给模型充足探索空间”把这值设得很大,但惩罚是:一,每个样本的padding成本爆炸,训练速度骤降;二,路径太长后credit assignment问题加重,模型根本不知道几十步以前的哪个动作起了作用。我通常的做法是先用短轨迹(最大10步)跑通,再逐步加长。

3.4 完整训练循环示例

训练主循环的伪代码如下:

for iteration in range(max_iterations): # 1. 采样阶段:用当前策略跑一批任务,收集轨迹 trajectories = [] for task in sample_tasks(batch_size=512): traj = rollout(env=create_env(task), policy=actor) trajectories.append(traj) # 2. 奖励阶段:为每条轨迹的每个step计算奖励 rewards = compute_rewards(trajectories, reward_config) # 3. Advantage计算:用GAE估计优势值 advantages = compute_gae(rewards, values, gamma=0.99, lam=0.97) # 4. 更新阶段:PPO更新Actor与Critic for epoch in range(ppo_epochs): # 一般3~5遍 for batch in make_batches(trajectories, batch_size=64): loss = ppo_loss(policy_logp, old_logp, advantages, clip_ratio=0.2) value_loss = mse(critic_values, returns) entropy_bonus = -mean(entropy(policy)) total_loss = -(loss - value_loss_weight * value_loss + entropy_coef * entropy_bonus) total_loss.backward() clip_grad_norm(model.parameters(), max_norm=1.0) optimizer.step() # 5. 验证阶段:在验证集上评估成功率 eval_success_rate = evaluate(actor, eval_tasks) logging.info(f"Iter {iteration}: eval_success_rate={eval_success_rate}")

有一点必须说清楚:rollout阶段对于LLM来说非常贵,因为它要生成上千条完整轨迹。一般做法是在rollout时设置temperature为0.7~1.0,增加探索;而验证阶段用temperature=0,保证确定性。

4. 踩坑实录:训练长程LLM智能体的典型问题排查

4.1 稀疏奖励造成的“原地踏步”

第一次跑通训练后,我遇到的现象非常典型:模型学到的最优策略是“调用一次搜索工具,然后直接finish”——因为它发现搜索有0.2过程奖励,而finish无论对错都不会带来太大惩罚(当时wrong只给-0.05)。最终成功率一直上不去,但奖励曲线却在缓慢上升,看起来“模型在进步”,实际在钻奖励空子。

排查思路:

  1. 检查每轮迭代的平均轨迹长度。如果长度明显收敛到很小值,大概率模型在走捷径。
  2. 检查动作分布。如果finish动作频率异常高,说明终止奖励和过程奖励的比例有问题。
  3. 用过程指标监控,不要只看总奖励。这个建议很关键:每轮迭代记录“搜索动作占比”、“读取动作占比”、“完成任务数/步数比”、“中间子目标完成率”,比总奖励更能反映模型真实行为。

我的修复方案:加大wrong惩罚到-0.2,同时对finish加上“最少前置步骤”约束(必须在至少完成1次搜索+1次读取后才能finish),这个约束不在奖励里硬调,而是直接在环境层禁止,效果立竿见影——模型被迫走完整流程。能用环境约束解决的,就别用奖励去调,这是省时间的大智慧。

4.2 信用分配:模型分不清哪一步是胜负手

长程任务训练到中期,会出现另一个典型问题:final答案错了,模型不知道该改搜索关键词、还是改阅读逻辑、还是改最终生成方式。表现出来就是同一个错误反复犯,轨迹之间差异很小。

这个问题的根源在于GAE的方差太大。几十步的轨迹,每步的reward又只有0.1~0.3,优势估计的噪音会淹没“哪个动作更优”的信号。我试过两种有效解法:

第一,提高λ。从0.95提到0.99,让优势估计更依赖长期收益而不是即时奖励,缓解对单步噪音的过拟合。

第二,给关键子目标额外奖励。把“搜索关键词构造质量”作为一个可计算指标(比如用检索结果的embedding相似度打分),搜索质量高就额外加0.1~0.2。这就是把“模糊的步骤贡献”变成“可量化的步骤奖励”,本质是帮模型做信用分配。

4.3 策略崩塌与熵坍缩

训练到后半段,模型可能出现“复读机”现象:反复调用同一个工具,输出格式完全一样,动作熵降得极低。这是典型的熵坍缩(Entropy Collapse)。原因通常有两个:一是学习率过大导致策略过快收敛到局部最优;二是奖励分配不均匀,某个动作序列奖励特别高,模型就往那个方向“梭哈”。

应对手段:

  • 调高entropy_coef,从0.01慢慢调到0.05以上。
  • 降低actor的lr,回退到上一个checkpoint重新往上训练。
  • 在rollout阶段增加temperature,保证采样动作多样性。
  • 给重复动作施加惩罚,也就是我在第一节提到的“重复调用同一工具给-0.05”。

经验证明,前三种是治标,第四种往往才能真正让模型学会“换条路试试”。惩罚重复动作本质上是告诉模型:环境有记忆,你在原地打转是会被发现的。

4.4 训练-推理不一致问题

还有一个很多人忽略的坑:训练时模型用的是beam search / 概率采样,行为跟推理时用的greedy decoding差异非常大。训练好的模型在验证集上成功率不错,一上线换成greedy推理就掉点。

我的建议是训练最后阶段做decode策略对齐:在最终的few-shot训练阶段,rollout改成采样一组高概率动作,再用verifier挑最好的(Best-of-N),而不是纯让策略网络输出唯一动作。这个技巧带来的收益甚至比调奖励函数更明显。

5. 我的几点个人实操体会

项目做到后期,我最大的体会是:多轮RL训练LLM智能体,难点不在算法,在反馈信号。PPO、GAE这些算法本身已经很成熟,真正决定最终效果的是你如何定义“好的中间行为”、如何把任务拆解成可检查的子目标、如何设计环境约束。这也提醒我,做这类项目前,先用小规模实验验证“奖励信号是否有效”比直接上大规模训练经济得多——我在7B模型上先跑几百条轨迹来观察奖励分布是否合理,确认没问题再放量,整个过程省了很多无效GPU小时。

最后分享一个小技巧:训练过程中监控“步骤级成功率”(比如“搜索后正确点击率”、“读取后成功提取字段率”)比监控总体成功率灵敏得多。刚训完第一版时,总体成功率只有21%,看似很差,但步骤级成功率已经有70%以上,说明模型的底层能力已经起来了,只是决策链上某个环节在拖后腿。顺着这个逻辑查具体是哪个环节,比盲调超参高效得多。

AgentGym-RL这个方向还很新,工具调用会越来越多、任务会越来越长,多轮RL的训练范式也会持续演进。如果你正准备往这个方向踩一脚,我希望上面这些真实记录能帮你少走一些弯路。等我把更长任务的训练跑完,再来聊下一轮的教训。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询