让 Agent 边跑边学:一套在线强化学习训练架构

本文只讨论通用的工程方法与架构取舍,不涉及任何具体业务、代码、数据与效果指标。

一、为什么要走到"训练"这一步

Agent 项目的早期形态几乎都一样:拿一个通用大模型,靠 Prompt Engineering 把业务逻辑塞进去。这个选择在早期是完全正确的——不需要标注数据,不需要训练资源,改一版 prompt 半小时就能上线,迭代速度是压倒性优势。

但这条路会撞上三堵墙:

  1. 稳定性与时延不由自己掌控。通用模型服务的可用性和 P99 时延是外部变量,要保证用户体验就得靠预留算力兜底,成本随规模线性上涨。
  2. 效果上限由基座模型决定。Agent 的效果本质上是基座模型指令遵循能力和 function call 能力的函数。prompt 调到某个程度就会进入平台期,再怎么改也只是在天花板下面挪动。
  3. 框架重、链路长。一次任务往往要多次调用大模型,每一跳都有时延。如果能用一个针对性训练过的小模型替代通用大模型,反而可能同时拿到更好的效果和更短的链路。

所以自研 Agent 模型不是"更酷",而是"必要"——它是把上限、成本、稳定性三个变量重新拿回自己手里的唯一方式。

二、真正的难点不是训练,是闭环

想清楚要训练之后,痛点立刻换了一批:

  • 局部最优陷阱。Agent 的不同阶段(规划、检索、生成……)通常各自挂一个模型分别调优,每个环节都调到最好,端到端不一定最好。真正要优化的目标是"用户最终看到的那个回复好不好",而不是"规划节点的输出像不像标注答案"。
  • 框架异构。开源 Agent 框架五花八门,业务自研的框架更是各家一套。训练框架如果要求 Agent 按它的接口重写,那这个方案在落地第一天就死了。
  • 离线训练成本高、数据组织复杂。人工攒数据集、离线跑训练、人工评估、人工上线,一个循环走完,业务需求已经变了。

第三点是最关键的:如果模型更新不能自动化,训练就永远是一次性的"项目",而不是持续生效的"能力"。目标应该是让模型能从日常的真实使用和环境反馈中自主学习,形成流式的自动更新。

三、核心抽象:把 Agent 当黑盒

这个问题上,微软的 Agent LightningTrain ANY AI Agents with Reinforcement Learning)给了一个非常漂亮的解法,开源实现在 GitHub

image.png

它的核心洞察只有一句话:

Agent 完成一次任务会多次调用大模型。把每次调用的输入输出抽出来,配上这次任务整体拿到的 reward,就得到了一组 (input, output, reward)——这就是 RL 训练数据。

这一句话解开了"框架异构"的死结。训练框架不需要理解 Agent 的内部结构,不关心它是 ReAct 还是多智能体编排,不关心它用什么语言写的。它只需要在模型调用这一层做拦截,Agent 对训练框架来说是一个完全的黑盒。

对应的训练流程被拆成 Server / Client 两侧:

Train Server                                Train Client
    │  ①加载训练集 [input]
    │  ②分 batch 下发            ──────────▶   ③把 input 喂进真实 Agent
    │                                          得到 [input, output]
    │                                       ④送 Reward Model 打分
    │  ⑥输出更新后的 model       ◀──────────   ⑤回传 [input, output, reward]

Server 管训练,Client 管"驱动真实 Agent 跑一遍"。两者之间只有数据契约,没有框架耦合。这个边界划得非常干净——它意味着 Agent 团队和训练团队可以并行演进,各自的技术选型互不污染。

四、落地时的工程架构

论文给的是骨架,把它接到一个已经在跑的线上系统上,需要补足四段链路。

在线推理链路训练闭环评估与上线 用户Agent 服务编排层Agent 执行器LLM Proxy模型服务平台Train ClientReward ModelTrain Server在线采集库离线数仓训练 / 验证集Judge Server评估集Reward Model ① 埋点采样上报② 流式同步③ 筛选 + 预处理④ 加载 [id, input]⑤ 下发 batch⑥ 按 id 回查原始请求⑦ rollout 重放真实链路⑧ 打分⑨ [input, output, reward]⑩ 新模型权重固定评估集打分、对比基线⑪ 达标后上线按 model 参数路由到训练中的模型

整体数据流:实线为主链路,虚线为埋点采样与模型路由;编号对应下文各小节

4.1 数据采集:从线上真实流量里长出训练集

训练数据的来源不应该是人工构造的题库,而应该是线上真实发生过的请求。这就要求在两个位置埋点:

  • 模型代理层(LLM Proxy):所有对大模型的调用统一收口到一个代理,代理按比例采样,记录 [input, output, trace_id]
  • 对话/编排层:任务结束时(流式场景是流结束时)上报端到端的 [request, response, trace_id]

trace_id 是把这两份数据串起来的唯一钥匙——它让"用户问了什么、最终看到了什么"和"过程中某个模型节点具体输入输出是什么"能被关联到同一次决策过程上。

先落到在线库,再由流式同步任务实时写入离线数仓。这里刻意分成两跳:在线库承担写入和按 id 随机读取,数仓承担大规模筛选和分析,各司其职。

采集表的 schema 大致是这样的(已泛化):

字段 类型 说明
id bigint 主键
app varchar 业务线标识,用于数据筛选
trace_id varchar 串联一次完整决策过程
process_node varchar 决策链路上的节点名,如 planner / retriever / end2end
model_name varchar 被调用的模型名
input / output mediumtext JSON 序列化的模型输入输出
reward_score double Reward Model 给出的奖励分
attributes mediumtext 预留的扩展字段,JSON
request_time / response_time varchar 请求与响应时间

process_nodeapp 两个字段是可扩展性的关键:有了它们,同一套采集链路可以同时服务多条业务线、多个待训练节点,筛数据时一个 where 条件就能切出想要的子集。attributes 这种预留字段容易被批评为"不够规范",但在这种早期快速演进的系统里,它是避免频繁改表的必要妥协。

4.2 数据准备

策略同学从数仓用 SQL 筛出自己想要的数据,写成 parquet 放到分布式存储,形成训练集和验证集。注意这里落盘的只有 [id, input]——完整的上下文不需要提前物化,因为 rollout 阶段会用 id 回查在线库把原始请求捞回来。这样训练集本身很轻。

4.3 Rollout:让训练跑在真实链路上

这是整套架构里最有意思的部分。

Train Client 拿到一条 [id, input] 之后,不是在沙盒里模拟,而是用 id 回查到当时的原始请求,重新向线上 Agent 发起一次真实调用,把整条 trajectory 跑出来。请求里额外带两个参数:

  • model 参数:模型代理识别到它之后,把这一跳的请求转发到 Train Server 上正在训练的那个模型,而不是线上默认模型。
  • invariant 参数:保证这次 rollout 中,不属于当前训练目标的其他模型节点,输出与原始请求保持不变

第二个参数是精髓。Agent 链路上通常有多个模型节点,如果 rollout 时每一跳都重新随机采样,那么最终 reward 的变化到底来自"被训练的这个模型变好了"还是"别的节点这次运气好"就无法归因了。把其他变量钉死,reward 的差异才干净地归因到当前被训练的模型上——这本质上是把线上链路改造成了一个可控变量的实验环境。

为此,Agent 服务需要提供一个 rollout 接口。接口设计上有个原则值得强调:用一个透明的 string 承载原始请求,而不是把原始请求的结构展开进 rollout 的接口定义

RolloutRequest {
    originRequest : string   // 原始请求的序列化结果
    trainMeta     : string   // 训练侧透传的元信息
}
RolloutResponse {
    originResponse : string  // 原始响应的序列化结果
}

这样 rollout 接口和业务接口是解耦的,业务请求结构演进时不需要动 rollout 这一层。但代价是:业务接口必须保证向前兼容——新版本服务要能正确处理历史版本的请求结构,否则昨天采集的数据今天就 rollout 不了了。这个约束应该写进接口规范,而不是靠自觉。

4.4 评估与上线:闭环的最后一环

训练出新模型不等于可以上线。需要一个独立的 Judge Server:

  1. 从评估平台拉取固定的高质量测试集;
  2. 把 input 打给新模型拿到 output;
  3. 送 Reward Model 打分,与基线对比;
  4. 达标才推送到模型服务平台上线。

这一步是整个"自动更新"叙事能否成立的关键。没有自动化的评估门禁,所谓自动训练只是把风险自动化了。

4.5 Reward 设计

Reward 决定模型往哪个方向走,是整套系统里唯一无法工程化解决、必须靠业务理解的部分。通常两条路并用:

  • LLM 生成 reward:用一个更强的模型做 judge,适合开放式、主观的质量评价;
  • 规则函数生成 reward:适合有客观标准的场景,如格式是否合法、工具调用参数是否正确、结果是否匹配 ground truth。

我的判断是:能用规则的地方尽量用规则。LLM judge 自身的噪声会直接变成训练信号里的噪声,而且它的偏好会被模型学去——你最终得到的是一个"擅长讨好 judge 的模型",而不一定是"用户觉得好的模型"。

五、已知的取舍与遗留问题

一个诚实的方案设计必须写清楚它现在还不能做什么:

  • 训练期间线上不能随意变更。因为 rollout 跑在真实链路上,训练过程中线上代码或配置一变,采样分布就漂了。当前只能靠流程约束(训练期间冻结变更),正确的做法是用预发环境做隔离——这是明确要补的一课。
  • 同时只能训练一个模型。当前架构是串行的,多模型并行训练需要在数据、调度、代理路由几层都做改造。前面 schema 里预留 app / process_node 字段,就是为这一天做的铺垫。
  • 回放不等于在线。用历史请求重放,本质仍是 off-policy 的近似,与真正的在线交互式学习还有距离。

六、写在最后

回头看,这套架构真正的价值不在于用了 RL,而在于它把"模型效果"从一个靠人推动的项目变成了一条自我运转的流水线:线上流量自动变成训练数据,训练自动产出新模型,评估自动决定是否上线。人的位置从"每一环都要推一把",退到"定义 reward 和评估标准"。

这也是我认为这个方案里最长期正确的一点——它没有试图去优化某一次的模型效果,而是把优化能力本身做成了基础设施。前者是一次性收益,后者是持续复利。

关键词: LLM agent 架构