Prhub

#5978 [tool, rollout, cfg] feat: per-sample tool environment routing for ToolAgentLoop

原始 PR 作者 pull-ups 合并时间 2026-04-16 16:11 文件变更 1 提交数 1 评论 7 代码增减 +20 / -4

执行摘要

为 ToolAgentLoop 新增按样本选择工具子集的能力,支持多轮 rollout 中不同样本使用不同工具。

根据PR body描述,真实世界智能体训练中,不同场景需要不同工具(例如gsm8k计算器、sandbox_fusion代码执行器、geo3k几何工具)。目前批次中所有行共享相同的全局tool_config_path,这限制了灵活性。此PR通过简单的配置映射+数据集级路由键实现异构工具环境,无需自定义子类或新代理循环。

建议精读此PR以理解动态工具选择的设计,但需注意实现与描述的差异。关注run()方法中的工具过滤逻辑和状态机各处的getattr使用,这是核心变更。同时,可参考讨论中关于未来注册式工具定义的见解。

讨论亮点

主要讨论围绕实现方案与PR描述的差异展开:

  • wuxibin89建议:“只需在extra_info中添加tool_selection,保持rollout.yaml不变,从tool_config_path加载所有工具,然后通过tool_selection选择子集。”并提到正在开发基于注册的工具定义。
  • pull-ups回应已根据建议修改代码,以适应未来方向。
  • gemini-code-assist[bot]指出显著差异:PR描述提到使用extra_info.tool_env_name和预加载环境缓存,但代码使用extra_info.tool_selection过滤全局工具,且__init__无变更;回退逻辑不匹配描述——如果tool_selection提供但只包含未识别名称,代码会创建空字典而非回退到全局工具。

实现拆解

  1. 入口变更:在verl/experimental/agent_loop/tool_agent_loop.pyrun()方法中,从kwargs提取extra_info.tool_selection,根据工具名称列表过滤self.tools全局工具字典,将选中的工具和模式分别存入agent_data._active_toolsagent_data._active_tool_schemas
  2. 状态机适配:修改_handle_pending_state_handle_generating_state_call_tool方法,使用getattr(agent_data, "_active_tools", self.tools)getattr(agent_data, "_active_tool_schemas", self.tool_schemas)获取按样本选择的工具,替代硬编码的self.toolsself.tool_schemas
  3. 配置扩展:在verl/workers/config/rollout.pyMultiTurnConfig中添加tool_envs: Optional[dict[str, str]] = None字段,并在verl/trainer/config/rollout/rollout.yaml中补充默认值和文档说明。
  4. 向后兼容:当tool_selection未提供或为空时,回退到全局工具,行为与现有main分支一致。
文件 模块 状态 重要度
verl/experimental/agent_loop/tool_agent_loop.py 代理循环 modified 6.49
verl/workers/config/rollout.py 配置 modified 3.0
verl/trainer/config/rollout/rollout.yaml 配置 modified 2.0

关键符号

run _handle_pending_state _handle_generating_state _call_tool

关键源码片段

verl/experimental/agent_loop/tool_agent_loop.py core-logic

核心实现文件,修改了 run() 方法以支持按样本工具选择,并适配状态机各阶段使用活动工具。

async def run(self, sampling_params: dict[str, Any], **kwargs) -> AgentLoopOutput:
    # ... 其他初始化代码 ...
    agent_data = AgentData(
        messages=messages,
        image_data=images,
        video_data=videos,
        metrics=metrics,
        request_id=request_id,
        tools_kwargs=tools_kwargs,
        interaction=interaction,
        interaction_kwargs=interaction_kwargs,
    )
​
    # Per-sample tool selection: filter global tools by extra_info.tool_selection
    extra_info = kwargs.get("extra_info", {}) or {}
    tool_selection = extra_info.get("tool_selection")
    if tool_selection and self.tools:
        # 过滤工具字典,只保留 tool_selection 中存在的工具名称
        selected = {name: self.tools[name] for name in tool_selection if name in self.tools}
        agent_data._active_tools = selected
        agent_data._active_tool_schemas = [
            t.tool_schema.model_dump(exclude_unset=True, exclude_none=True) for t in selected.values()
        ]
    else:
        # 回退到全局工具
        agent_data._active_tools = self.tools
        agent_data._active_tool_schemas = self.tool_schemas
​
    # State machine loop
    state = AgentState.PENDING
    while state != AgentState.TERMINATED:
        if state == AgentState.PENDING:
            state = await self._handle_pending_state(agent_data, sampling_params)
        elif state == AgentState.GENERATING:
            state = await self._handle_generating_state(agent_data, sampling_params)
        elif state == AgentState.PROCESSING_TOOLS:
            state = await self._handle_processing_tools_state(agent_data)
        elif state == AgentState.INTERACTING:
            state = await self._handle_interacting_state(agent_data)
        else:
            logger.error(f"Invalid state: {state}")
            state = AgentState.TERMINATED
    # ... 输出处理 ...

评论区精华

实现方案与 PR 描述差异 设计

gemini-code-assist[bot] 指出代码使用 extra_info.tool_selection 过滤全局工具,而 PR 描述提到 extra_info.tool_env_name 和预加载缓存,且回退逻辑不匹配。

结论:未明确解决,但 PR 已根据 wuxibin89 的早期建议修改。 · partially_resolved

未来工具定义方向 设计

wuxibin89 提到正在开发基于注册的工具定义,以消除 agent_loop_config_path。

结论:此 PR 作为过渡方案,支持简单按样本工具选择。 · acknowledged

风险与影响

  1. 逻辑风险:在run()方法中,如果tool_selection包含未在self.tools中的名称,selected字典可能为空,导致agent_data._active_tools为空集,后续工具调用可能失败。根据gemini-code-assist[bot]的评论,这未按描述回退到全局工具。
  2. 兼容性风险:修改了AgentData对象,添加了_active_tools_active_tool_schemas属性,如果其他代码依赖AgentData结构,可能引入意外依赖。
  3. 配置风险:新增tool_envs配置字段,但实际代码未使用,可能导致配置与实际行为不一致,增加维护复杂度。
  1. 用户影响:允许用户在数据集级别指定工具子集,提升多场景训练灵活性,无需为不同工具集创建单独配置或批次。
  2. 系统影响:对ToolAgentLoop核心逻辑有中等影响,状态机各阶段现在支持动态工具选择,但性能开销可忽略(仅字典过滤)。
  3. 团队影响:为未来基于注册的工具定义铺平道路,但当前实现与PR描述存在差异,可能增加理解成本。
逻辑不一致风险 配置未使用 缺少测试覆盖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论