这里是基于InternBootcampv1开发的InternBootcampv2,主要包含了针对具体专业性Bootcamp场景的multi-round toolcall的agentic RL 流程。
InternBootcampv2 深入绑定了verl的multi-round toolcall的流程,通过SGLANG-rollout的state control,实现对专业场景的toolcall调用、reward计算、模型训练及推理
为了支持更复杂的Bootcamp任务,我们需要多轮工具调用来处理。
(1)LLM-based workflow
prompt --> LLM rollout(decision) --> tooluse response --> LLM rollout(decision) --> tooluse response ...
(2)environment-based workflow
prompt --> LLM rollout --> tooluse --> env decision --> LLM rollout --> tooluse --> env decision ...
即,一个Bootcamp任务存在两种LLM与环境的交互形式
(1)single-round toolcall & 多轮对话,本质上都可以refine成single-round的交互
(2)multi-round toolcall 的调用在RL framework中,需要async的调用,导致rollout逻辑会更加复杂
流程包含了:
(1)模型的prompt Design,workflow的整个流程;
prompt Design,在verl里体现为数据构造,对应包含data-source来明确task的类型,
生成这种数据的流程,在Bootcamp中,参考InternBootcampv1的对应思路;
(2)对应需要调用的tool的toollist tool的描述;
verl中, toollist,在toolconfig里填写,并且会在chat-template中基于对应mcp协议,拼接在chat-template里,
tool的config中,直接绑定了对应的tool的实现;
(3)调用的tool的实现逻辑,对应的io;
verl中,tool的调用,是通过执行execute,在SGLANG的rollout中对应调用的,
其中,SGLANG的rollout,会根据对应的state,对rollout过程进行控制,这些state包含了toolcall 和terminate等信号,
同时,在这里会计算每一轮的toolcall返回的中间过程reward;
SGLANG的rollout中,需要传入的参数包含了
(4)基于tool的io的返回,模型的multi-round rollout;
整体rollout结束后,会通过reward score 处计算最终的reward
(5)基于toolcall返回 or 基于模型判断 or 基于max-step 等条件,任务workflow的最终终止;
verl中,state中控制了流程的终止
git clone https://example.com/openinternbootcamp.git --recurse-submodules
cd openinternbootcamp
pip install -e ./
# verl install
pip install -e ./verl/
# openevolve install
pip install -e ./openevolve/
# 一键安装所有父和子仓库依赖
pip install -r requirements-editable.txt
继承基类BaseInstructionGenerator
示例: example_instruction_generator.py
若需生成数据,须继承BaseInstructionGenerator基类,并实现以下两个抽象方法:(若无需生成数据则将数据规范为以下对应格式即可,无需实现InstructionGenerator)
from internbootcamp.src.base_instruction_generator import BaseInstructionGenerator
from typing import Dict, Any, Optional
import random
class CustomInstructionGenerator(BaseInstructionGenerator):
"""自定义指令生成器"""
def __init__(self, **kwargs):
super().__init__()
# 配置data_source,基类已如下实现,计算reward时会根据此信息匹配对应的RewardCalculator
self.data_source = f"bootcamp/{self.__class__.__name__.replace('InstructionGenerator', '').lower()}"
# 初始化自定义参数
for key, value in kwargs.items():
setattr(self, key, value)
def case_generator(self) -> Dict[str, Any]:
"""
生成任务案例,返回包含任务信息的字典
Returns:
Dict[str, Any]: 任务信息字典,包含ground_truth等关键信息;
这个任务信息字典将作为对应RewardCalculator的_verify_correction方法和对应Tool的create方法的identity参数传入
"""
# 实现任务生成逻辑
# 例如:生成数学题目、电路参数等
pass
def prompt_func(self, identity: Dict[str, Any]) -> str:
"""
根据任务信息生成提示语
Args:
identity (Dict[str, Any]): 任务信息字典
Returns:
str: 生成的提示词
"""
# 实现提示语生成逻辑
# 使用identity中的信息构建输入给语言模型的prompt
pass
关键要点:
- data_source属性用于标识数据来源,格式为"bootcamp/your_bootcamp_name"
- case_generator()方法生成能用来唯一确定任务且验证候选答案的参数集,以字典格式返回
- prompt_func()方法根据任务参数生成提示词
实践建议:
- Prompt模板:使用多个prompt模板,生成时随机选择,实现多样prompt
- 题目变种:使用参数data_type参数控制题目变种类型,实现多样的题型与prompt
示例: example_instruction_config.yaml
使用YAML配置文件来管理数据生成的参数和行为:
# custom_instruction_config.yaml
instruction_generators:
# 基础配置组
basic_config:
config:
min_value: 1
max_value: 100
operation_type: "simple"
generation_ratio: 0.1 # 占总生成数据的40%,所有generation_ratio会自动归一化为比例(如0.4和0.6会分别分配40%和60%的样本数)
# 高级配置组
advanced_config:
config:
min_value: 50
max_value: 500
operation_type: "complex"
generation_ratio: 0.7 # 占总生成数据的60%,无需手动保证所有ratio之和为1,系统会自动归一化
# 带默认tool的配置组
basic_config_w_tool:
min_value: 1
max_value: 100
operation_type: "simple"
generation_ratio: 0.1
yaml_tool_path: "path/to/tool.yaml" # 工具配置文件路径
# 带默认interaction的配置组
basic_config_w_tool:
min_value: 1
max_value: 100
operation_type: "simple"
generation_ratio: 0.1
yaml_interaction_path: "path/to/interaction.yaml" # 交互配置文件路径
# 全局配置
global_config:
# 指令生成器类的完整路径
class_name: "internbootcamp.bootcamps.your_bootcamp.your_instruction_generator.CustomInstructionGenerator"
# 随机种子配置
enable_random_seed: true
default_seed: 999
# 数据集划分配置
default_split_samples:
train: 10000
test: 1000
# 是否启用数据打乱
shuffle: true
# 是否生成parquet文件
gen_parquet: false
配置说明:
- instruction_generators: 定义多组配置,每组有不同的参数和生成比例
- global_config: 全局设置,包括类路径、随机种子、数据集划分、是否生成parquet格式数据等,也可于此配置tool或interaction config(全局配置会与单条generator配置合并)
- generation_ratio: 控制每组配置生成数据的比例,自动归一化
示例: example_multiturn_w_tool_grpo.sh
例如以下命令
# data_generate.sh
#!/bin/bash
python -m internbootcamp.utils.data_generation \
--instruction-config configs/your_instruction_config.yaml \
--output-dir data/your_bootcamp/ \
--tool-config configs/your_tool_config.yaml \ #全局配置,与单条配置合并
--interaction-config configs/your_interaction_config.yaml \ #全局配置,与单条配置合并
--split-samples train:10000,test:1000 \
--shuffle \
--global-config-overrides '{"gen_parquet": true}' \ #全局配置覆盖
--no-tool \ #开启则不使用任何工具配置
--no-interaction \ #开启则不使用任何交互配置
参数列表
| 参数名称 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
--instruction-config |
str | ✓ | - | 指令管理器配置文件路径,定义数据生成的核心逻辑 |
--output-dir |
str | ✓ | - | 输出文件目录,生成的数据集将保存在此目录下 |
--tool-config |
str | ✗ | None | 工具配置文件路径,相当于全局配置,生成时与单条配置合并(冲突时优先使用单条配置) |
--interaction-config |
str | ✗ | None | 交互配置文件路径,相当于全局配置,生成时与单条配置合并(冲突时优先使用单条配置) |
--split-samples |
str | ✗ | None | 数据集划分和样本数,格式为 train:10000,test:1000,val:500 |
--shuffle |
flag | ✗ | False | 是否对生成的数据进行随机打乱 |
--gen_parquet |
flag | ✗ | True | 是否生成parquet格式文件(除jsonl外) |
--global-config-overrides |
str | ✗ | None | 全局配置覆盖参数,JSON字符串格式,如 '{"enable_random_seed": true}' |
--no-tool |
flag | ✗ | False | 开启则不使用任何工具配置 |
--no-interaction |
flag | ✗ | False | 开启则不使用任何交互配置 |
执行脚本后会以split为后缀生成多个jsonl数据文件
{
"data_source": "bootcamp/Example",
"prompt": [
{
"content": "你是一位数学专家,擅长进行算术运算。\n\n任务:计算表达式 88086 ÷ 38856 - 34189 + 96429 ÷ 65083 × 2882 + 21625 × 99240 + 97985 × 61813 ÷ 6044 ÷ 79107 × 68650 + 89020 的结果,误差范围为 1e-4\n\n最终答案格式:请以``json\n{\n \"result\": your_result\n}\n``格式返回结果,且在必要时使用科学计数法(如1e-4、2.5E+3)。\n\n计算建议:\n1. 请在合适的时机运用算术工具,如需要计算大数等自信程度不高计算时,以避免计算错误和无意义的工具调用。\n2. 若需要计算的表达式较长,请在实际计算开始前,先进行计算规划,以避免计算错误和无意义的工具调用。\n下面请开始计算。",
"role": "user"
}
],
"reward_model": {
"ground_truth": {
"expression": "88086 ÷ 38856 - 34189 + 96429 ÷ 65083 × 2882 + 21625 × 99240 + 97985 × 61813 ÷ 6044 ÷ 79107 × 68650 + 89020",
"expected_result": 2146993745.4955528,
"tolerance": "1e-4"
},
"style": "rule"
},
"extra_info": {
"tools_kwargs": {
},
"need_tools_kwargs": false,
"index": 102,
"split": "test",
"generator_name": "medium_arithmetic_w_interaction",
"interaction_kwargs": {
"name": "example_interaction",
"identity": {
"expression": "88086 ÷ 38856 - 34189 + 96429 ÷ 65083 × 2882 + 21625 × 99240 + 97985 × 61813 ÷ 6044 ÷ 79107 × 68650 + 89020",
"expected_result": 2146993745.4955528,
"tolerance": "1e-4"
}
}
}
}
现支持批量并行数据生成:
# 批量数据生成
python -m internbootcamp.utils.batch_data_generation \
--bootcamp-registry configs/bootcamp_registry.jsonl \ # Bootcamp注册表
--max-workers 8 \ # 最大并行进程数
--output-dir data/batch_generated/ \
--split-samples train:1000,test:100 \ #每个Bootcamp配置生成1000个训练样本和100个测试样本
--concat-files \
--continue-on-error
bootcamp注册表作为批量生成配置文件(bootcamp_registry.jsonl): 单条注册表数据结构:
{"instruction_config_path": "internbootcamp/bootcamps/your_bootcamp/configs/your_instruction_config.yaml", "data_source": "bootcamp/YourBootcamp", "yaml_tool_path": "internbootcamp/bootcamps/your_bootcamp/configs/your_tool_config.yaml", "yaml_interaction_path": "internbootcamp/bootcamps/your_bootcamp/configs/your_interaction_config.yaml", "reward_calculator_class": "internbootcamp.bootcamps.your_bootcamp.your_reward_calculator.YourRewardCalculator"}
参数列表:
| 参数名称 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
--bootcamp-registry |
str | ✓ | - | Bootcamp注册表文件路径,jsonl格式,每条记录包含一个bootcamp的配置信息 |
--max-workers |
int | ✗ | min(16, CPU核心数) | 最大并行工作进程数,自动限制在CPU核心数范围内 |
--continue-on-error |
flag | ✗ | False | 遇到错误时继续执行其他配置,不中断整个批量生成流程 |
--log-level |
str | ✗ | INFO | 日志级别,可选值:DEBUG、INFO、WARNING、ERROR |
--output-dir |
str | ✗ | data/generated | 输出目录,所有生成的数据集将保存在此目录下 |
--split-samples |
str | ✗ | train:100,test:0 | 数据集划分和样本数,格式为 train:10000,test:1000,val:500 |
--concat-files |
flag | ✗ | False | 是否将所有生成的文件按split分别合并到文件中 |
--no-tool |
flag | ✗ | False | 是否不使用工具配置,开启则忽略所有工具相关配置 |
--no-interaction |
flag | ✗ | False | 是否不使用交互配置,开启则忽略所有交互相关配置 |
示例: example_tools.py
若自定义Bootcamp需支持工具训练,须继承BaseTool基类,并实现以下两个核心抽象方法:
# 示例代码结构
class CustomTool(BaseTool):
def __init__(self, config):
super().__init__(config)
async def create(self, instance_id: Optional[str] = None, identity: dict = None, **kwargs) -> str:
"""用于创建针对每条数据所需要的额外变量,在数据加载阶段被执行。
Args:
instance_id (Optional[str]): 针对每个instance的id,不指定时由类自动生成
identity (dict): 每条数据所需要的额外变量,data source应该有identity字段
Returns:
instance_id: str
"""
# 创建工具实例
pass
async def execute(self, instance_id: str, parameters: dict[str, Any], **kwargs) -> tuple[str, float, dict]:
"""工具的执行逻辑
Args:
instance_id (str):
parameters (dict[str, Any]): 执行工具所需的参数,parameters均有LLM的输出提供
Returns: tool_response, tool_reward_score, tool_metrics
tool_response (str): 工具的输出
tool_reward_score (float): 工具计算的reward结果,如有,否则返回0
tool_metrics (dict): 返回{}
"""
# 执行工具逻辑
pass
关键要点:
- create()主要用于实现预定义tool环境变量,或初始化tool环境需维护的变量,这些变量不会暴露给模型。
```yaml
tools: - class_name: "internbootcamp.bootcamps.your_bootcamp.your_tools.CustomTool" config: type: "native" tool_schema: # tool_schema会作为prompt被输入LLM type: "function" function: name: ""
$ claude mcp add InternBootcamp \
-- python -m otcore.mcp_server <graph>