0x00 概要
本系列目的是通过解析两个强化学习框架(Uni-Agent,Miles)来梳理Agentic RL。

Uni-Agent 是 verl 社区推出的一个面向 Agent RL 的训练/推理一体框架,以同一套交互栈同时支撑大规模 Agent 推理和 RL 训练。它在 verl(字节跳动开源的 LLM RL 训练框架)之上构建 Agent 抽象层(Model/Tool/Env 三层),将 sandbox 执行委托给 SWE-ReX。

项目的核心主张可以概括为 “推理 = 训练,同一入口”——把"Agent 如何与环境交互并产出 token-level 训练数据"封装成一套可复用、可扩展、可训练的工程系统。无论你是跑 1000 个并行的 SWE-Bench 推理任务,还是进行 GRPO/GSPO 强化学习训练,底层走的是同一套 AgentInteraction 交互循环。这种设计使得从"模型推理验证"到"大规模 RL 训练"的切换成本趋近于零——只需换一个 YAML 配置,不需要重写任何交互逻辑。

注,因为:

可能本文参考的verl版本不够新,且 verl 社区本身就在突飞猛进,因此可能某些对verl的认知不够准确

本文为“从代码反推设计理念” & 时间仓促

所以本文肯定存在很多错误,还请读者不吝指出存在的问题,谢谢。

0x01 基本功能
1.1 竞品对比与定位
在正式进入架构分析之前,我们先回答一个关键问题:Uni-Agent 在现有的 Agent 框架生态中处于什么位置?

1.1.1 三者定位
Agent 抽象层次
高 ▲
│ ┌──────────────┐
│ │ OpenHands │ 完整 Agent 应用
│ └──────────────┘


│ ┌──────────────┐ ┌──────────────────────────────┐
│ │ SWE-Agent │ │ Uni-Agent │
│ │ (学术 Agent) │ │ 推理+训练一体化框架 │
│ └──────────────┘ │ 统一交互栈,大规模并发, │
│ │ RL 训练原生支持 │
│ └──────────────┬───────────────┘
│ │
│ ┌──────────────▼──────────────┐
│ │ verl (训练引擎) │
│ │ AgentLoopBase/Manager │
│ │ FullyAsyncRollouter │
│ └─────────────────────────────┘
└──────────────────────────────────────────────────────► 训练能力
从上图可以看出,OpenHands 定位在"完整产品"层,关注的是开箱即用的 Agent 体验;SWE-Agent 定位在"学术研究"层,侧重单任务的推理表现。而 Uni-Agent 选择了第三条路:向下集成 verl 的训练能力,向上提供可编程的 Agent 抽象。这一定位使得它成为目前唯一将 Agent 交互栈与 RL 训练引擎深度集成的开源框架。这一点也在其 README 中可以看到。

Uni-Agent: Build, Run, and Train Agents at Scale

Uni-Agent is a unified framework for general agents at scale.

  • All-in-one stack: one framework for building, running, and training agents.
  • Unified agent interface: unified abstractions for diverse and complex real-world agent scenarios.

The long-term vision is to build the backend infrastructure for next-generation agents across both inference and training, enabling them to perceive, act, and explore complex real-world tasks.
1.1.2 七维度对比表
维度 Uni-Agent OpenHands SWE-Agent
核心定位 Agent 推理+训练一体化 全栈 AI 软件工程师产品 学术研究 Agent
训练能力 原生 GRPO/GSPO RL,Fully Async + Partial Rollout 无 无
交互模式 ReAct Loop + Tool-as-Bash + 双 parser Agent-Controller 事件驱动 ReAct Loop + 自定义 DSL
工具机制 6 种内置 tool,脚本上传到容器 丰富 tool 生态 3 种 tool
环境管理 4 种部署 discriminated union + SWE-ReX Docker 为主 Docker 容器
并发规模 1000+ 并行,Ray + asyncio 单实例为主 单实例
社区生态 新生项目(2026),tool 生态早期 成熟社区 学术社区
底层依赖 verl(训练) + SWE-ReX(sandbox) 自研 Docker
1.2 Uni-Agent 架构全景
因为 Uni-Agent 深度依赖 verl,下文的一些架构图会连带着 verl 一起展示,以完整呈现二者的协作关系。

1.2.1 全景图
1-全景图

从全景图中可以清晰地看到 verl 和 Uni-Agent 的分工:

verl 负责"怎么训练"(调度、算法、参数同步)。
Uni-Agent 负责"训练什么"(交互逻辑、环境管理、奖励计算)。
二者的分界线是 AgentLoopBase.run() 这一个方法签名——verl 通过 hydra.utils.instantiate 创建 UniAgentLoop 实例,调用 run() 获取 AgentLoopOutput,然后将其喂入 PPO/GRPO 训练管线。

1.2.2 代码组织
Uni-Agent VeRL
───────────────────────────────── ───────────────────────────────────────
uni_agent/ verl/verl-main/verl/
├── agent_loop.py ├── experimental/agent_loop/
│ └─ UniAgentLoop(AgentLoopBase) │ ├── agent_loop.py
├── interaction/ │ │ ├── AgentLoopBase (ABC)
│ ├── interaction.py │ │ ├── AgentLoopOutput (BaseModel)
│ │ └─ AgentInteraction │ │ ├── AgentLoopWorker
│ ├── model.py │ │ ├── AgentLoopManager
│ │ ├─ AgentChatModel │ │ └── _agent_loop_registry
│ │ └─ OpenAICompatibleChatModel│ │ ├── tool_agent_loop.py
│ ├── env.py │ │ │ └─ ToolAgentLoop (verl内置)
│ │ └─ AgentEnv │ │ ├── tool_parser.py
│ ├── tools_manager.py │ │ │ └─ ToolParser, FunctionCall
│ │ └─ ToolsManager │ │ └── utils.py
│ └── tool_parser.py │ ├── fully_async_policy/
│ ├─ XMLToolParser │ │ ├── fully_async_main.py
│ └─ HermesToolParser │ │ ├── fully_async_rollouter.py
├── deployment/ │ │ └── fully_async_trainer.py
│ ├── config.py │ ├── tools/
│ │ └─ DeployConfig (union) │ │ ├── schemas.py
│ ├── local/, host/, modal/, │ │ │ ├── OpenAIFunctionToolCall
│ │ vefaas/ │ │ │ ├── ToolResponse
│ └── remote_runtime.py │ │ │ └── …
├── tools/ │ │ └── tool_registry.py
│ ├── base.py │ └── utils/
│ │ └─ AbstractTool │ ├── chat_template.py
│ ├── registry.py │ │ ├── apply_chat_template()
│ ├── execute_bash/ │ │ └── initialize_system_prompt()
│ ├── str_replace_editor/ │ ├── tokenizer.py
│ ├── finish/, submit/ │ │ └── normalize_token_ids()
│ ├── search/, search_arxiv/ │ └── profiler.py
└── reward/ │ └── simple_timer()
├── base.py └── workers/
│ └─ AbstractRewardSpec └── rollout/
├── registry.py └── replica.py
├── swe_bench.py └── TokenOutput
├── swe_rebench.py
├── r2e_gym.py
└── search.py
1.2.3 DeployConfig 四后端
deployment/config.py 使用 Pydantic v2 discriminated union 实现编译时类型安全 + 运行时自动反序列化:

后端 类型标记 底层 Runtime 适用场景
Local type: “local” Apptainer/Docker/Podman 容器 本地开发、单机训练
Host type: “host” 主机直接执行(无容器) 搜索等轻量任务
Modal type: “modal” Modal serverless sandbox 云端弹性扩缩容
veFaaS type: “vefaas” 字节跳动内部 FaaS 字节内部大规模部署
值得注意的是,RemoteRuntime(deployment/remote_runtime.py)是独立于四种后端之外的 HTTP 客户端层,所有后端都通过它与 SWE-ReX server 通信。它不在 DeployConfig 的 discriminated union 内,而是各后端的共享基础设施——这种设计意味着添加新后端时,只需新增一个 Config 类和一个 Deployment 类,无需修改 RemoteRuntime。

0x02 Agentic RL 的难点
在深入 Uni-Agent 的设计之前,我们需要先理解它要解决什么问题。Agentic RL 与传统 RLHF 的差异不是量变,而是质变。

2.1 Agentic RL vs 传统 RLHF
传统 RLHF 训练的是一问一答的对话模型:给定一个 prompt,模型生成一段 response,奖励模型打分。这是一个"单轮、短文本、无环境交互"的场景。

π_θ(y | x) → reward_model(x, y) → PPO update
单轮文本生成 单标量奖励 一次参数更新
Agentic RL 则完全不同:它训练的是一个"与环境持续交互"的 Agent 模型。模型在真实环境中(代码仓库、终端、浏览器)通过多步交互完成复杂任务,训练目标是让模型学会更好的决策策略——不仅包括"说什么",更包括"何时采取什么行动"。

π_θ(a_t | h_t) → env.step(a_t) → o_{t+1} → … → terminal reward
多轮决策 多步环境交互 稀疏、延迟奖励
两者的本质区别在于:Agentic RL 的 trajectory 是多轮交互序列,包含交替的 model 输出和 environment observation token;奖励信号是稀疏且延迟的(任务完成才给分),而非每步都有即时 reward;token 序列需要精确区分 model 生成段(参与 loss)和 tool 响应段(不参与 loss)。

2.2 Agentic RL 六大核心需求
从上述差异出发,可以归纳出 Agentic RL 框架必须满足的六项核心需求:

需求 说明 Uni-Agent 实现

1 多轮交互 Agent 与环境进行多步 ReAct 循环;模型需要多次推理,每次根据环境反馈调整行动 AgentInteraction.run()
2 Token 级对齐/归因 prompt/response/tool observation 的 token mask 精确对齐;RL 训练需要知道每个 token 的 log probability 的梯度归属 rollout_cache[“response_mask”]
3 异步大规模并发 训练需要大量轨迹数据;上千个 agent 同时与环境交互 asyncio.Semaphore + Ray worker pool
4 环境多样性 支持不同 sandbox 后端;每个 Agent 需要独立的 sandbox,执行命令并获取结果 4 种 DeployConfig discriminated union
5 异构奖励信号 不同 benchmark 的评估逻辑;不同任务有不同的评估方式 4 种 AbstractRewardSpec 实现
6 训练-推理统一 同一套代码跑推理和训练,避免训练/推理 gap AgentChatModel + OpenAICompatibleChatModel 共享 AgentInteraction
2.3 Agentic RL 十大难点
这六项需求背后是一系列工程和算法层面的难题。我们将它们归纳为十个主要难点,逐一分析 Uni-Agent 的应对策略。

难点 1: Token 对齐

┌─────────────────────────────────────────────────────────────────────────────────────┐
│ prompt [MASK=0] │ response₁ [MASK=1] │ obs₁ [MASK=0] │ response₂ [MASK=1] │ … |
└─────────────────────────────────────────────────────────────────────────────────────┘
核心问题:每次追加 tool response 时,应该重新 tokenize 整个对话历史,还是增量 tokenize?如果增量 tokenize,如何保证 token 序列格式与 model 训练时的格式完全一致?

Uni-Agent 的方案是增量 tokenize + message_boundary_tokens 探测,采用的差分对比法来发现 tokenizer 在消息边界插入的特殊 token。

难点 2: Token 流的混合属性

Agent 的 response 不再是纯模型输出,而是模型输出与环境反馈的交织:

Token 序列: [模型思考][模型动作][环境观察][模型思考][模型动作][环境观察]…
梯度归属: [需要] [需要] [不需要] [需要] [需要] [不需要]
这要求框架精确标记哪些 token 参与 RL 梯度计算(模型的选择),哪些只是上下文(环境反馈)。Uni-Agent 通过 response_mask(1=参与/0=不参与)来实现这一区分。

难点 3: 交互时间极长且方差巨大

传统 RLHF 中一个 rollout 约 2 秒(生成 200 tokens),但在 Agentic RL 中,一个 rollout 可能耗时 30 秒到 60 分钟(100 步交互 + 环境执行)。Batch 内样本的执行时间差异可能超过 10 倍,训练被最慢的 Agent 阻塞(长尾效应),GPU 在等待环境执行时处于空闲状态。

难点 4: 训练-推理 Gap

推理时你可能用 OpenAI API 调用模型,但训练时 verl 需要 token IDs + log probs 来计算 PPO loss。如何保证同一套交互代码在两种不同的数据格式下都能工作?

Uni-Agent 的方案是双 Model 后端共享 AgentInteraction。

难点 5: 环境资源的管理与隔离

每个 Agent 需要独立的执行环境。1000 个 Agent = 1000 个容器(内存、CPU、磁盘)。环境可能崩溃、超时、资源耗尽。不同任务可能需要不同的 Docker 镜像。容器的生命周期需要与 rollout 同步管理。Uni-Agent 通过分层错误处理 + mask_abnormal_exit_traj + timeout_budget + 探活机制来应对。

难点 6: 大规模并发稳定性

上千个 sandbox 同时运行会引发资源争抢和端口耗尽。Uni-Agent 的方案是 Semaphore 限流 + Ray worker pool + per-worker 隔离。

难点 7: Off-policy 与 Staleness(参数过期)

为了提高 GPU 利用率,推理和训练需要异步执行(Fully Async 模式下 rollout worker 和 training worker 异步运行)。但这导致 Agent 使用的模型参数可能已过期,Importance sampling ratio 的估计变得不准确,训练稳定性下降。Uni-Agent 借助 verl 的 staleness_threshold 三层防御来应对。

难点 8: Partial Rollout

慢 trajectory 不应阻塞整个 batch。verl 的 partial_rollout=True 允许部分完成的 rollout 先参与训练,Uni-Agent 对此完全透明——FullyAsyncLLMServerClient 在底层处理断点续传。

难点 9: Reward 的计算复杂性

传统 RLHF 的 reward 计算是毫秒级的(调用一次 reward model),但 Agentic RL 的 reward 计算需要在环境中跑测试套件、执行代码、对比结果,耗时为分钟级。Reward 计算本身需要环境支持,且必须在 Agent 交互完成后、环境关闭前完成。不同 benchmark 的评估逻辑完全不同。

难点 10: Credit Assignment 困难

一个 Agent 执行了 100 步,最终 reward 是 0(没解决 bug)。哪一步是关键错误?传统 RL 只有 trajectory-level 的标量 reward,无法精确归因到具体的 step 或 action。Token-level 的梯度无法区分"好的思考"和"差的行动"。这是当前整个 Agentic RL 领域尚未解决的开放问题。

0x03 verl 的能力与系统性不足
理解了 Agentic RL 要解决的难点之后,我们需要审视 Uni-Agent 的底层依赖——verl——能提供什么,不能提供什么。这决定了 Uni-Agent 必须自己构建哪些能力。

3.1 设计范式差异
verl 的定位是通用 RL 训练框架:它擅长分布式训练、GRPO/GSPO、模型并行、异步调度与推理引擎集成,但并不内建 Agent 与环境交互本身。Uni-Agent 则把注意力放在多轮交互、工具调用、环境生命周期、奖励评估时序和 token-level 轨迹构建上。两者的关系可以概括为:verl 提供骨架,Uni-Agent 负责把骨架变成可运行、可训练、可扩展的 Agent 系统。

3.1.1 本质矛盾
verl 的核心假设源自 RLHF 场景,为"单轮对话 RLHF"而生:

维度 RLHF Agentic RL
交互轮数 1 轮 10-500 轮
Response 时间 秒级 分钟到小时级
Response 长度 几百 tokens 万~十万 tokens
环境依赖 无 容器 / 沙箱 / 云
失败模式 只有生成问题 环境崩溃、超时、格式错误、资源耗尽
Reward 计算 调 reward model 在环境中执行验证
数据组成 纯模型输出 模型输出 + 环境反馈混合
可以看到,verl 的设计假设在 Agent 场景下被系统性打破——几乎每一个维度都发生了质变。这不是 verl 的缺陷,而是"单轮场景"和"多轮场景"之间的根本差异。

3.1.2 分工边界
因此,Uni-Agent 与 verl 的分工非常清晰:

verl = 训练引擎(“怎么训练”):分布式调度、GPU 管理、PPO/GRPO 算法、Fully Async 策略
Uni-Agent = Agent 抽象栈(“训练什么”):多轮交互逻辑、Tool 执行、Sandbox 管理、Reward 计算
分界线是 AgentLoopBase.run() + AgentLoopOutput——一个方法签名,一个输出结构。verl 提供 RL 训练引擎,Uni-Agent 提供 Agent 行为层(环境 + 交互 + 工具 + 奖励 + 胶水),两者通过 AgentLoopOutput 协议连接。

2-分工边界

3.1.3 详细分工表
关注点 verl 负责 Uni-Agent 负责 边界机制
Agent 实例创建 hydra.utils.instantiate YAML 中 target _agent_loop_registry
LLM 推理 LLMServerClient.generate() → TokenOutput 封装为 model.query() self.server_manager
Tokenizer AutoTokenizer 加载 + 注入 tokenize/decode/boundary探测 self.tokenizer
RL 算法 PPO/GRPO/GSPO loss + optimizer 不感知 AgentLoopOutput
Fully Async FullyAsyncRollouter 全模块 不感知(训练脚本配置) verl 内部
Partial Rollout FullyAsyncLLMServerClient resume 透传 max_global_steps TokenOutput.extra_fields
多轮交互逻辑 不提供 (ToolAgentLoop 是另一实现) AgentInteraction.run() run() 内部
Tool Schema verl.tools.schemas 数据类 6 种 tool + bash 脚本 使用 verl 数据类
Tool 执行(沙箱) 不提供 ToolsManager + AgentEnv 纯 Uni
Sandbox 管理 不提供 4 种 DeployConfig 纯 Uni
Token 对齐 AgentLoopOutput.response_mask rollout_cache 增量 + boundary AgentLoopOutput
Reward 计算 reward_score 字段消费 AbstractRewardSpec 4 种 reward_score 字段
Worker 调度 AgentLoopManager Ray pool 不感知 verl 内部
数据批次 DataProto 协议 填充 raw_prompt + tools_kwargs kwargs 透传
Padding _agent_loop_postprocess() 不感知 verl 内部
异常分类 不提供 9 种 exit_reason + 5 层错误 纯 Uni
Dashboard wandb/tensorboard dashboard/ Web UI 各自独立
Tool Parse verl 内置 ToolParser XMLToolParser+HermesToolParser Uni 使用自己的 parser
3.2 verl 为 Agentic RL 做了什么
尽管 verl 的设计范式源自 RLHF,但它确实为 Agentic RL 提供了关键的专用能力。这些能力可以分为四个维度:

训练架构
• Fully Async Pipeline rollout/train 解耦,最大化 GPU 利用率
• Partial Rollout 不等最慢轨迹,快速利用已完成数据
• Parameter Sync 定期同步 + staleness 控制
算法 / 损失
• GSPO 序列级 clip,适应长轨迹
• Token-Mean Loss 按 token 加权,公平对待不同长度轨迹
• Dynamic Batch Size 按 token 总量组批,平衡 GPU 负载
• DAPO Reward Manager overlong buffer + 长度惩罚
• N-Response/Prompt Group 内多采样 + advantage normalization
推理引擎优化
• Multi-Turn Mode 推理引擎感知多轮模式
• Chunked Prefill 超长 context 分块处理,防 OOM
• Free Cache Engine rollout 后释放显存给训练
• Preemption Tracking 监控请求抢占,优化并发
• Routed Experts MoE expert 路由追踪
Staleness 控制
• staleness_threshold 数据过旧直接丢弃
• clip_ratio (极小值) 限制 importance sampling 偏差
• trigger_sync_step 控制参数传播频率
这些功能对应的实体如下表:

功能 Uni-Agent 使用方式

1 AgentLoopBase ABC 继承,实现 run()
2 AgentLoopOutput 填充 9 字段
3 AgentLoopMetrics 填充 metrics
4 num_turns 字段 填充 turn 数
5 extra_fields 双端通道 注入 traj_masked,exit_reason
6 multi_turn rollout 配置 enable=True
7 max_parallel_calls 设为 1
8 FullyAsyncRollouter 直接使用
9 FullyAsyncLLMServerClient 直接使用
10 staleness_threshold 训练脚本配置
11 partial_rollout 训练脚本配置
12 trigger_parameter_sync_step 训练脚本配置
13 verl.tools.schemas 使用 ToolCall 等
14 ToolResponse (多模态) 不直接使用
15 apply_chat_template() 使用(带 tools=)
16 normalize_token_ids() 5 处调用
17 AgentLoopManager 训练+推理都使用
18 _agent_loop_registry 通过 config_path 注入
3.3 verl 的不足
在充分肯定 verl 提供的能力之后,我们需要诚实地审视它的不足。verl 的"留白"正是 Uni-Agent 存在的理由。

3.3.1 verl 没做什么(= Uni-Agent 自己构建)
几个主要缺失能力举例如下:

缺失能力 为什么 Agentic RL 需要 Uni-Agent 如何补充
多轮 ReAct 循环逻辑 verl 的 ToolAgentLoop 是状态机,Uni 需要更灵活的设计 AgentInteraction.run() while 循环
Sandbox/容器管理 verl 不管理执行环境 AgentEnv + 4 种 DeployConfig
Tool 的 bash 执行 verl tool 是 Python 函数/类,无法在容器内隔离 Tool-as-Bash-Script + 容器上传
Agent 异常分类 verl 不知道 bash 超时 vs 格式错误 9 种 exit_reason + 5 层错误处理
双 Model 后端 verl 只提供 LLMServerClient AgentChatModel(训练)+ OpenAICompatible(推理)
SWE 特定 reward verl 的 reward 是通用的 AbstractRewardSpec + swe_bench/r2e_gym
实时 Dashboard verl 只有 wandb/tensorboard dashboard/ Web UI
3.3.2 具体不足分析
以下我们对 verl 的十项不足进行逐项深入分析。这些分析的目的不是批评 verl,而是帮助理解 Uni-Agent 的设计动机。

不足 1: 没有 Multi-Turn 交互的一等公民支持

verl 通过 AgentLoopBase.run() 提供了一个空接口——它的态度是"用户自己搞定多轮交互"。multi_turn.enable=True 只是一个开关,告诉引擎"这个 request 会多次追加 tokens",但不提供循环框架。Token 流的 prompt/response 分割完全由用户负责。这意味着每个 Agent RL 项目都要从头实现 multi-turn 循环,没有标准的 “step → observe → append” 模式可复用。

Uni-Agent 的补充方式:AgentInteraction 类 + rollout_cache 增量维护。

不足 2: 不理解"环境"概念

verl 的世界观里只有 Model(Actor/Critic/Ref),没有 Environment 抽象——它不知道需要启动容器、管理资源、安装工具。没有环境生命周期管理(start/run/close),也没有环境并发控制。verl 的 AgentLoopManager 只管"给 worker 派活",不管 worker 上跑了多少容器。1000 个 rollout 同时调用 env.start() 会导致资源爆炸。

Uni-Agent 的补充方式:AgentEnv + Deployment 多后端 + asyncio.Semaphore。

不足 3: Rollout 时间分布假设不成立

verl 的 batch 机制(包括 asyncio.gather 等待全部完成的模式)假设所有 rollout 时间接近。但在 Agent RL 中,某些 bug 简单(3 步 submit,30 秒),某些 bug 复杂(跑满 100 步,30 分钟),batch 被最慢的 rollout 阻塞。虽然 partial_rollout=True 在 async mode 中部分解决了这个问题,但 Sync mode 中无解——必须等全部完成。

更深层的问题是:Agent 的执行时间不可预测(取决于任务难度 + 模型能力),传统 RL 的"固定步数"假设完全不适用。

不足 4: Token Credit Assignment 不够精细

verl 的 response_mask 只有 0/1 两档,能区分模型输出和环境输出,但不能区分 thought 和 action(都是 mask=1),不能提供 per-step reward(只有一个标量 reward_score),不能做时间衰减(所有 mask=1 的 token 权重相同)。GRPO 的 advantage 是 trajectory-level 的标量,所有 mask=1 的 token 共享同一个 advantage,无法告诉模型"你的第 3 步是关键错误"。

verl 目前的 workaround 是通过 loss_agg_mode=“token-mean” 让不同长度的轨迹贡献正规化,但本质上还是 trajectory-level reward。

不足 5: 不支持 Action-Level Policy Optimization

verl 的 GRPO/PPO 工作在 token-level(loss = Σ_t [mask[t] * ratio[t] * advantage]),但 Agent 的决策单元不是 token,而是 action(一个 tool call 可能包含 50+ tokens)。Token-level ratio 不等于 action-level ratio;一个 action 中的 token 共享相同的"意图",但 log prob 分别计算;如果模型生成了正确的 function name 但参数有 typo,所有 token 被同样惩罚。

理想的 action-level 方案是将一个 action 中所有 token 的 logprob 求和作为一个整体来计算 ratio,但 verl 目前不支持。

不足 6: 推理引擎不为 Multi-Turn 优化

verl 的推理引擎(vLLM/SGLang)每次 generate() 调用本质上是一个独立请求,每次都传完整序列。100 步交互 = 100 次 prefill。即使有 prefix caching,cache miss 时也需要完整重算,且没有"session"概念——引擎不知道同一个 Agent 的多次 generate 是相关的。

理想的方案是 session-based generation:创建 session → 每步只传增量 → append observation,但 verl 的接口没有显式利用这种模式。

不足 7: 训练数据不均匀

verl 的 DataLoader 假设样本大小大致均匀,但 Agent 轨迹长度差异极大(2K ~ 128K tokens)。GPU 内存由最大的 sample 决定,这浪费了大量 padding。Dynamic batch size 部分缓解,但需要 per-sample padding,极长轨迹可能 OOM,但是,截断则意味着模型永远不会对长轨迹中后期的 token 计算梯度。

不足 8: 无法优雅处理 Rollout 失败

verl 的 AgentLoopManager 期望每个 rollout 都返回 AgentLoopOutput。如果失败,需要用户自行构造"empty output"(如 Uni-Agent 的 _build_empty_agent_output),没有"重试"机制,没有"替代 sample"机制。失败的 rollout 产生 garbage data(全 0 的 token ids + mask),占用了 batch 位置但不产生训练信号,高失败率 = 低训练效率。

不足 9: 参数同步对 Agent Rollout 的干扰

Fully Async 模式下,parameter sync 需要推理引擎加载新参数。如果 sync 恰好发生在 Agent 交互中间——Agent_A 正在第 50 步,推理引擎暂停 10-30 秒加载新参数,Agent_A 的环境一直在等(浪费容器时间),恢复后 Agent_A 继续第 51 步时用的是新参数。

结果:同一个 rollout 中前 50 步用参数 θ₀,后 50 步用参数 θ₁,response_logprobs 是混合的,importance sampling ratio 计算不准确。这是 async Agent RL 的固有困境,verl 对此无解。

不足 10: 缺少 Agent 特有的 Metrics

verl 的 training logger 跟踪的是通用 RL 指标(reward_score mean/std、response_length、KL divergence、loss),但 Agent RL 需要更细粒度的指标:per-task success rate、average number of turns、exit reason distribution、environment setup time vs interaction time、tool call distribution、format error rate 等。Uni-Agent 通过 extra_fields 传递了部分信息,但 verl 的 logger 不会自动展示这些,需要用户在 wandb/tensorboard 中 custom track。

3.4 小结
回顾整个分析,我们可以清晰地看到 verl 的设计范式和 Agent RL 需求之间的根本张力:

verl 的设计范式(RLHF-centric):

Rollout 是短的、确定性时间的
所有 token 都是模型生成的
不需要外部环境
Reward 由 reward model 即时返回
失败是少见的
Batch 内样本大致等长
一次 generate 调用 = 完整 response
Agent RL 的实际需求:

Rollout 时间跨度大(30 秒~1 小时)
Token 流是模型 + 环境交织的
需要管理容器 / 云环境的生命周期
Reward 需要在环境中执行验证(耗时)
失败是常态(环境崩溃、超时、格式错误)
轨迹长度差异 >10x
需要 100+ 次 generate 调用 per rollout
verl 选择的策略是务实的:提供最小化的扩展接口(AgentLoopBase),让上层框架(如 Uni-Agent)处理所有 Agent 特有的复杂性。这让 verl 保持通用性,让专业框架处理专业问题。

verl vs Uni-Agent 能力矩阵如下:

3-能力矩阵

0x04 Uni-Agent 设计理念与核心功能
4.1 核心设计哲学
在理解了 verl 的边界之后,我们可以深入 Uni-Agent 自身的设计。Uni-Agent 的设计哲学是 “推理 = 训练,同一入口”,具体体现在:

同一套 AgentInteraction 代码驱动纯推理(OpenAI API)和 RL 训练(verl vLLM/SGLang)两种场景
同一个 rollout_cache 数据结构在两种场景下承载不同的信息密度:训练侧有 token IDs + logprobs + mask,推理侧只有 API messages
同一套配置体系(YAML → Pydantic)覆盖从单机调试到千卡训练的规模跨度
这个哲学可以进一步拆分为五大设计理念:

理念 1: 推理即训练(Inference = Training)

同一套代码和交互逻辑,既用于大规模推理/验证,也用于 RL 训练的 rollout 阶段。不存在两套系统、两份代码。技术保障:rollout_cache 始终记录 token IDs 和 log probs,推理时忽略、训练时直接用。

理念 2: 三层解耦(Model / Tool / Env)

Agent 的三个核心要素独立定义、通过配置组合。换模型不改工具,换环境不改交互逻辑——这是"可扩展性"的工程保障。三层抽象如下:

4-三层抽象

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐