news 2026/9/13 14:22:09

在 verl + SGLang 中为多轮 RL 集成搜索工具(Search Tool Integration):从本地检索服务到端到端训练完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 verl + SGLang 中为多轮 RL 集成搜索工具(Search Tool Integration):从本地检索服务到端到端训练完整指南

在 verl + SGLang 中为多轮 RL 集成搜索工具(Search Tool Integration):从本地检索服务到端到端训练完整指南

【免费下载链接】verlverl/HybridFlow: A Flexible and Efficient RL Post-Training Framework项目地址: https://gitcode.com/GitHub_Trending/ve/verl

verl(HybridFlow)为多轮强化学习(Multi-Turn RL)增加了搜索工具调用能力:模型可以在 Actor rollout 阶段主动发起检索请求,并将检索结果直接用于训练。本文基于仓库中的 search_tool_example.rst 官方指南,完整覆盖"本地稠密检索器(local dense retriever)搭建 → 检索服务启动 → 数据预处理 → 8×H20 端到端训练 → 自定义搜索配置"的全流程,并结合仓库源码(工具抽象基类、注册机制、奖励函数、数据预处理脚本)讲解底层实现,帮助你掌握在 verl 多轮 RL 管线中接入任意本地检索引擎的完整集成模式。

版本提示:本指南所描述的端到端配方(配置、检索服务、训练脚本)当前仍然有效,用于说明搜索工具与 verl 多轮 RL 的集成模式;但仓库中内置的参考实现verl.tools.search_tool.SearchTool类已被移除,SearchTool现在需要由用户基于verl.tools.base_tool.BaseTool自行提供。

一、背景:为什么要在多轮 RL 中接入搜索工具

verl 为 Multi-Turn RL 新增了搜索工具调用功能,核心价值在于:

  • 模型自主检索:在 Actor rollout 阶段,模型可以根据自身知识缺口主动发起检索请求(retrieval request),无需人工干预;
  • 检索结果直接参与训练:检索返回的文档被拼入对话轨迹,作为后续轮次的上下文,直接参与策略梯度训练;
  • 两种检索接入方式:既支持使用本地稠密检索器(local dense retriever)作为检索工具,也支持对接你自己的本地检索引擎(local retrieval engine)。

从整体架构看,一次完整的搜索式多轮 rollout 流程为:

  1. 模型在某个轮次判断"缺乏相关知识",通过工具调用协议(sglang tool-calling)发出搜索意图;
  2. verl 的工具执行层将查询参数(queries、topk 等)转发给检索服务;
  3. 检索服务返回 top-k 文档;
  4. 检索结果以tool角色消息的形式回到对话历史,模型据此继续推理并最终给出答案;
  5. 奖励函数(如 EM 精确匹配)对最终答案打分,驱动策略更新。

二、快速复现:从零搭建端到端搜索 RL 环境

官方文档给出了一套完整的快速复现流程。需要注意的是,训练进程与本地检索服务运行在两个独立的 Python 环境中:训练环境使用 uv(verl-multiturn-rollout),检索器环境使用 conda 安装faiss-gpu

2.1 创建 Docker 容器

使用 SGLang 官方镜像启动容器:

docker run \ -it \ --shm-size 32g \ --gpus all \ -v {Huggingface-Cache-Path}:/root/.cache \ --ipc=host \ --network=host \ --privileged \ --name sglang_{your-name} \ lmsysorg/sglang:dev \ /bin/zsh

退出容器后如需重启,执行:

docker start -i sglang_{your-name}

2.2 安装 Python 3.10 并配置 uv 虚拟环境

apt update apt install -y python3.10 python3.10-venv # 创建虚拟环境 python3 -m venv ~/.python/verl-multiturn-rollout # 激活虚拟环境 source ~/.python/verl-multiturn-rollout/bin/activate # 安装 uv python3 -m pip install uv

2.3 安装 verl 及其依赖

cd ~ git clone https://github.com/verl-project/verl.git cd verl # 安装 verl python3 -m uv pip install . python3 -m uv pip install -r ./requirements_sglang.txt # 手动安装 flash-attn python3 -m uv pip install wheel python3 -m uv pip install packaging python3 -m uv pip install flash-attn --no-build-isolation --no-deps

三、搭建本地稠密检索引擎(Local Dense Retriever)

如果你已有自己的本地检索服务,可以跳过本小节。官方指南采用 search-R1 示例中提供的本地稠密检索器(详细说明见 search-R1 的 retriever 文档),要点如下:

  • GPU 版本:精度和速度更高,每块 GPU 约占用 5–7 GB 显存;
  • CPU 版本:可用于简单测试,但检索精度较低,会拉低训练效果;
  • 安装建议:推荐使用 conda 安装faiss-gpu=1.8.0;使用 venv 可能出现错误。

3.1 安装 Miniconda 并创建检索器环境

# 下载 Miniconda 安装脚本 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh # 以批处理模式安装到 $HOME/miniconda3 bash ~/miniconda.sh -b -p $HOME/miniconda3 # 仅在当前 shell 激活 conda eval "$($HOME/miniconda3/bin/conda shell.bash hook)" # (可选)将 conda 加入默认 shell 启动项 conda init # 重新加载 shell 配置 source ~/.bashrc # 创建并激活 Python 3.10 的检索器环境 conda create -n retriever python=3.10 -y conda activate retriever # 安装 PyTorch(GPU 版)及相关库 conda install pytorch==2.4.0 torchvision==0.19.0 torchaudio==2.4.0 pytorch-cuda=12.1 -c pytorch -c nvidia -y # 安装其他 Python 包 pip install transformers datasets pyserini huggingface_hub # 安装 GPU 版 faiss conda install faiss-gpu=1.8.0 -c pytorch -c nvidia -y # 安装 API 服务框架 pip install uvicorn fastapi

3.2 下载索引与语料库

本地检索文件较大,请预留充足磁盘空间:下载约 60–70 GB,解压后约 132 GB

conda activate retriever save_path=/the/path/to/save python examples/sglang_multiturn/search_r1_like/local_dense_retriever/download.py --save_path $save_path cat $save_path/part_* > $save_path/e5_Flat.index gzip -d $save_path/wiki-18.jsonl.gz

3.3 启动本地 flat e5 检索服务

启动注意事项:

  1. 首次启动会下载模型并加载索引;
  2. 除下载外,启动过程约需 1–2 分钟;
  3. 启动后每块 GPU 约占用 5–7 GB 显存,其余显存留给多轮 RL 训练。
conda activate retriever index_file=$save_path/e5_Flat.index corpus_file=$save_path/wiki-18.jsonl retriever_name=e5 retriever_path=intfloat/e5-base-v2 python examples/sglang_multiturn/search_r1_like/local_dense_retriever/retrieval_server.py \ --index_path $index_file \ --corpus_path $corpus_file \ --topk 3 \ --retriever_name $retriever_name \ --retriever_model $retriever_path \ --faiss_gpu

路径说明examples/sglang_multiturn/...下的download.pyretrieval_server.py以及后文的训练脚本属于被移除的参考配方。在当前仓库树中,这些示例文件已不存在(与内置SearchTool一并移除),上述命令作为官方文档记录的集成配方保留;实现你自己的检索服务时,需提供与 5.3 节 I/O 契约兼容的 HTTP 接口。

四、数据预处理与端到端训练

4.1 设置 WANDB_API_KEY

export WANDB_API_KEY={YOUR_WANDB_API_KEY} # 定义时间戳函数 function now() { date '+%Y-%m-%d-%H-%M' }

4.2 预处理数据集

注意:以下数据预处理与训练命令必须在verl-multiturn-rollout环境中运行。

python3 examples/data_preprocess/preprocess_search_r1_dataset.py

该脚本(preprocess_search_r1_dataset.py)的核心逻辑是:从 HuggingFace 下载train.parquet/test.parquet(默认仓库PeterJinGo/nq_hotpotqa_train,支持通过--hf_repo_id--local_dir--hdfs_dir覆盖),逐行转换为 verl 训练所需的格式:

  • 构建 system/user 两轮 prompt,system 提示词要求模型"先在<think>中推理,缺少知识时通过<tool_call>发起搜索,搜索结果显示在<tool_response>之间,可直接给出<answer>格式的答案";
  • reward_model.ground_truthgolden_answers提取标准答案;
  • 为每个样本生成extra_info.tools_kwargs,将ground_truthquestiondata_source注入搜索工具的create_kwargs
  • 可选将处理后的 parquet 拷贝到 HDFS(--hdfs_dir)。

4.3 在 8 × H20 上测试

# 确保已定义 now() 函数 # 创建日志目录 mkdir -p logs # 设置 GPU 并使用合适的日志路径 export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 nohup bash examples/sglang_multiturn/search_r1_like/run_qwen2_5_3b_search_multiturn_fsdp.sh \ trainer.experiment_name=qwen2.5-3b-it_rm-searchR1-like-sgl-multiturn-$(now) \ > logs/searchR1-like$(now).log 2>&1 &

该命令以 Qwen2.5-3B-Instruct 为策略模型、FSDP 为并行后端、SGLang 为 rollout 引擎,通过命令行覆盖trainer.experiment_name的方式启动一次带搜索的 search-R1 风格多轮 RL 训练,日志写入logs/目录。

五、自定义搜索配置:参数详解与 I/O 契约

5.1 开启多轮推理

在训练配置中设置以下字段以启用多轮 rollout(同时参见 multiturn.rst 中的multi_turn: True写法):

actor_rollout_ref: rollout: name: "sglang" multi_turn: enable: True

5.2 声明搜索工具

你必须在工具配置文件中指定retrieval_service_url,并正确配置并发参数。并发配置的详细设计可参考 Sandbox Fusion 示例:

tools: - class_name: verl.tools.search_tool.SearchTool config: retrieval_service_url: http://127.0.0.1:8000/retrieve num_workers: 120 rate_limit: 120 timeout: 30

各字段含义:

参数说明
retrieval_service_url本地检索服务的 HTTP 端点,训练时工具通过该地址发起检索请求
num_workers每个 DP 上请求检索服务的并发 worker 数
rate_limit全局并发检索请求上限,用于保护检索服务、避免 429 等过载错误
timeout单次检索请求的超时秒数

在此基础上,还需要在 rollout 配置中通过tool_kwargs.tools_config_file指定该工具 YAML 文件的路径(详见 multiturn.rst 的 Custom Tool Configuration 小节):

actor_rollout_ref: rollout: tool_kwargs: tools_config_file: <path_to_tool_yaml_file>

源码印证:工具 YAML 的解析与实例化在 tool_registry.py 的initialize_tools_from_config中实现——它通过OmegaConf.load读取 YAML,按class_name动态导入工具类(get_tool_class),并将config字段转为 dict 后实例化;当前代码要求config.typenativeToolType.NATIVE枚举),同时支持可选的tool_schema字段(构造OpenAIFunctionToolSchema)。也就是说,自定义工具的 YAML 需要包含type: native字段。

5.3 检索服务 I/O 契约

如果检索服务的输入输出与下列格式匹配,只需要修改retrieval_service_url;否则可以在search_r1_like_utils.py中自定义适配逻辑。

输入格式(POST JSON):

{ "queries": ["What is Python?", "Tell me about neural networks."], "topk": 3, "return_scores": true }

输出格式return_scores=True时返回相似度分数,result为每个 query 的结果列表):

{ "result": [ [ # 每个 query 的结果 { "document": doc, "score": score }, # ... 更多文档 ], # ... 其他 query 的结果 ] }

六、源码级原理:工具抽象、注册机制与奖励函数

6.1 工具生命周期:BaseTool 抽象基类

所有接入 verl 多轮 RL 的工具(包括搜索工具)都需要继承 base_tool.py 中的BaseTool。该抽象类定义了完整的工具生命周期:

  • get_openai_tool_schema():返回 OpenAI 格式的工具 schema,用于向模型描述可调用工具;
  • create(instance_id, **kwargs):为一条对话轨迹创建工具实例(默认生成 uuid);
  • execute(instance_id, parameters, **kwargs):执行工具,返回(ToolResponse, tool_reward_score, tool_metrics)——ToolResponse支持文本、图片、视频等多模态内容;
  • calc_reward(instance_id, **kwargs):根据工具状态计算奖励(默认返回 0.0);
  • release(instance_id, **kwargs):rollout 结束后释放工具实例(默认空操作)。

对于搜索工具,execute即负责将模型发出的 query 转发到retrieval_service_url,并把返回的 top-k 文档封装为工具响应文本。由于仓库中的参考实现verl.tools.search_tool.SearchTool已移除,你需要按上述接口自己实现一个SearchTool(BaseTool)子类,并保持 YAML 中class_name指向你的实现。

6.2 无状态工具:@function_tool 装饰器

如果检索工具是无状态的(无需create/release生命周期),也可以使用 function_tool.py 提供的@function_tool装饰器,把一个普通 Python 函数注册为工具,schema 由transformers.utils.get_json_schema依据函数签名和 Google 风格 docstring 自动推断。两种方式(function_tool_pathtool_config_path)可以同时配置,AgentLoopWorker启动时会合并注册表,重名工具会报错。

6.3 奖励函数:Search-R1 风格 EM 打分

训练效果的奖励信号来自 search_r1_like_qa_em.py:

  • extract_solution:用正则从模型输出中提取<answer>...</answer>之间的最终答案(取最后一个匹配);
  • normalize_answer:对答案做小写、去标点、去冠词、规整空白等标准化;
  • em_check/subem_check:分别做精确匹配(EM)与子串包含匹配(Sub-EM);
  • compute_score:提取不到答案得 0;匹配成功得满分score;若<answer>标签数量超过 10 个(防止模型刷标签),分数降为score/4;否则返回format_score

该奖励函数由 reward_score/init.py 中的分发逻辑按data_source路由:searchR1_nqsearchR1_triviaqasearchR1_popqasearchR1_hotpotqasearchR1_2wikimultihopqasearchR1_musiquesearchR1_bamboogle等数据集均走search_r1_like_qa_em.compute_score。这意味着你可以直接用上述数据源标识复用这套奖励机制。

七、注意事项与运维要点

  1. 训练耗时:该配方的总训练时间约 27 小时;
  2. 验证集开销:验证集非常大(51k 条),每次验证约需 6000 秒,因此默认val_before_train=False,即训练前不做验证,避免在训练开始前就消耗大量验证时间;
  3. 双环境隔离:训练(uv +verl-multiturn-rollout)与检索服务(conda +retriever)必须分离,检索器环境的faiss-gpu建议用 conda 安装;
  4. 磁盘与显存规划:语料下载 + 解压约需 200 GB 量级磁盘;检索服务每 GPU 占用 5–7 GB,需为多轮 RL 训练预留足够显存;
  5. 参考实现已移除:当前仓库不再内置SearchTool类与examples/sglang_multiturn/示例脚本,请基于BaseTool自行实现,并确保与 5.3 节检索服务 I/O 契约兼容。

八、延伸阅读

  • 多轮 rollout 总指南:多轮配置、@function_tool、delta 分词策略、Qwen 系列推理内容裁剪特例处理
  • Sandbox Fusion 工具集成:基于 Ray Global Actor + 信号量的分布式令牌桶限流设计(对应num_workers/rate_limit参数的底层实现)
  • 搜索式 RL 数据预处理脚本:Search-R1 风格训练数据的完整构造逻辑
  • Search-R1 风格 EM 奖励函数:精确匹配/子串匹配打分实现
  • 工具注册与实例化:YAML 工具配置的解析、动态导入与名称冲突检查
  • 工具抽象基类:create/execute/calc_reward/release生命周期接口定义

【免费下载链接】verlverl/HybridFlow: A Flexible and Efficient RL Post-Training Framework项目地址: https://gitcode.com/GitHub_Trending/ve/verl

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 14:22:06

Nebius AI Builder免费计划深度实测:400美元GPU算力如何加速RAG开发

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 14:17:35

数据库SQL优化指南:从慢SQL定位到索引策略与查询重写

SQL优化这事&#xff0c;说小也不小。很多团队一遇到慢SQL就急着加索引&#xff0c;结果加了索引还是慢&#xff0c;又去翻配置调参数&#xff0c;折腾一圈发现根本没动到根子上。我做了十几年数据库优化&#xff0c;接手过的慢SQL案例少说也有几百个&#xff0c;核心其实就两条…

作者头像 李华
网站建设 2026/9/13 14:17:18

HTML基础语法详解:从文档骨架到语义化实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 14:16:40

多模态开发实战指南:从视觉大模型微调到RAG与Agent

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华