TRL documentation
Harbor 集成:在环境中训练 LLM
Harbor 集成:在环境中训练 LLM
Harbor 是一个用于在沙箱中运行智能体任务的框架。它将 任务(指令 + 沙箱镜像 + 验证器)、harness/agent(工具接口 + 循环)和 沙箱(docker、e2b、daytona、gke、……)解耦,使它们可以自由组合。这使其非常适合强化学习:同一套任务可以使用不同的工具接口进行训练,并运行在你偏好的任意沙箱后端上。
本指南介绍了如何将 Harbor 与 TRL 集成。有关 Harbor 本身的信息,请参阅Harbor 文档。
该集成位于
trl.experimental.harbor,并通过trl[harbor]附加组件进行控制(采用延迟导入——非用户无需承担任何额外开销)。
何时使用 Harbor 环境
GRPOTrainer 通过 environment_factory 插槽支持基于环境的训练——通用契约请参阅 OpenEnv。如果您希望针对 Harbor 任务套件 进行训练,请使用 Harbor:它是一棵任务目录树,每个任务都是一个自包含的沙箱 + 验证器(例如,一个数据分析智能体套件,其中模型在沙箱中探索文件并写出答案,由评分器进行检查)。
安装
pip install trl[harbor]
Harbor 通过 vLLM 驱动生成,并使用
environment_factory,这需要vllm和transformers>=5.2.0。pip install vllm
这将安装 harbor 框架(Python >= 3.12)。该集成会延迟导入 harbor 并在进程内运行它,因此未使用 trl.experimental.harbor 的用户不会受到影响。
在训练时,还必须安装并能够访问沙箱后端。Harbor 将云后端置于其自身的 extras 之后,因此请安装您打算使用的那个,并提供其凭据:
pip install "harbor[e2b]" # E2B cloud sandbox -> environment_type="e2b", needs E2B_API_KEY
# docker backend (environment_type="docker", Harbor's default) just needs a reachable Docker daemon快速入门
HarborSpec 将单个 Harbor 任务套件接入 TRL 训练器的三个插槽——train_dataset、environment_factory、reward_funcs——通过暴露与这些关键字参数名称一一对应的属性来实现:
from trl import GRPOConfig, GRPOTrainer
from trl.experimental.harbor import HarborSpec
spec = HarborSpec("AdithyaSK/data_agent_rl_environment_train", agent="bash", num_tasks=64)
trainer = GRPOTrainer(
model="Qwen/Qwen3-4B",
args=GRPOConfig(
num_generations=8,
max_steps=50,
max_tool_calling_iterations=25,
log_completions=True,
),
train_dataset=spec.train_dataset,
environment_factory=spec.environment_factory,
reward_funcs=spec.reward_funcs,
)
trainer.train()在底层,HarborSpec 会在首次访问时延迟执行以下三项操作:
spec.train_dataset:将任务套件解析为本地任务目录(如有需要则下载 HF 数据集),并构建一个datasets.Dataset,其中包含prompt(为空——环境的指令会在reset时追加)、task_dir、task_index,以及每个任务的task.toml元数据列。spec.environment_factory:返回一个无参可调用对象,用于生成每个 rollout 的全新 HarborEnv。在调用reset(task_dir)时,它会启动该任务的 Harbor 沙箱并返回其指令;工具方法会在沙箱中执行;env.reward会在 rollout 结束后运行一次验证器。spec.reward_funcs:一个结果奖励,用于读取 Harbor 验证器针对每次 rollout 的标量值。
数据集
dataset 可以是包含 Harbor 任务树的 Hugging Face 数据集仓库 ID,也可以是包含 tasks/ 子树的本地路径。每个任务都是一个目录:
tasks/<task_id>/
├── instruction.md # the task prompt (returned by reset)
├── task.toml # config + metadata (gold answer, difficulty, ...)
├── environment/ # Dockerfile (+ any pre-agent data hooks)
└── tests/ # test.sh / grader → writes the reward使用 num_tasks 或 indices(二者互斥)选择一个子集:
spec = HarborSpec("AdithyaSK/data_agent_rl_environment_train", num_tasks=10) # first 10
spec = HarborSpec("AdithyaSK/data_agent_rl_environment_train", indices=[0, 5, 13]) # specificAgents:外部与已安装
Harbor 支持两种由智能体驱动任务的方式,这种区别决定了哪些任务可以通过 RL 进行训练:
- 外部智能体在沙箱外部运行,并自行驱动循环,通过 Harbor 的环境接口向容器下发命令(“通常是通过
exec方法执行 bash 命令”)。智能体决定每个操作并解释每个结果;沙箱仅负责执行。 - 已安装的代理 会安装到容器镜像中,并作为无头子进程在其中运行(继承自
BaseInstalledAgent)。Harbor 会在沙箱内启动该代理,并在运行结束后解析其轨迹文件(populate_context_post_run);该代理会自主运行并执行自身的推理。
TRL 的集成采用外部智能体模式,目前仅支持该模式。强化学习训练要求训练器逐轮驱动 rollout:由正在训练的 policy model生成每一轮的内容,TRL 捕获其 token 和 log-probs 并应用环境掩码——这正是 environment_factory 针对黑盒 rollout_func 所提供的功能。已安装的智能体对此是不透明的:它在容器内部运行,使用其自身的模型,且仅在事后输出一条轨迹,因此训练器无法获取用于优化的 policy token 或 log-probs,正在训练的模型也从未被调用。因此,HarborEnv 是一个外部智能体——其工具方法通过 exec 进入沙箱,但循环以及正在训练的模型仍保留在 TRL 中。
选择基础智能体(框架)
基础智能体是框架——它决定了环境暴露哪些工具方法以及智能体如何提交。使用 agent= 进行选择:
HarborSpec(dataset, agent="bash") # built-in single-bash-tool harness
HarborSpec(dataset, agent="my_pkg.harnesses:JupyterEnv") # import path to your HarborEnv subclass
HarborSpec(dataset, agent="path/to/harness.py:JupyterEnv") # file path to your HarborEnv subclass
HarborSpec(dataset, agent=MyHarborEnv) # a HarborEnv subclass directly内置的 "bash" 测试框架(HarborBashEnv)暴露了一个 bash 工具,并通过写入 /workdir/answer.txt 来提交。两个功能更丰富的测试框架作为示例提供——每个都位于自己的文件夹中,并附有列出其工具的 README——位于 examples/grpo_harbor/harnesses/ 下:
jupyter/(JupyterEnv) — 有状态的 Python 内核(变量在单元格之间持久保留)+ 一个 shell 工具。terminal_notes/(TerminalNotesEnv) — 6 个 shell 工具(包括后台进程)+ 一个包含 4 个工具的持久化笔记工具包。
HarborSpec(dataset, agent="examples/grpo_harbor/harnesses/jupyter/env.py:JupyterEnv")
HarborSpec(dataset, agent="examples/grpo_harbor/harnesses/terminal_notes/env.py:TerminalNotesEnv")要编写自己的 harness,请继承 HarborEnv 并添加工具方法——每个公开方法都会成为一个工具(TRL 使用 inspect.getmembers 来发现它们),因此请为每个方法提供带类型的签名和 docstring(用于构建工具 schema)。辅助方法请以下划线开头。使用 self._exec(cmd) 在沙箱中运行 shell 命令,并设置 PROMPT_SUFFIX 以将 harness 指导追加到任务指令中:
from trl.experimental.harbor import HarborEnv
class GrepEnv(HarborEnv):
PROMPT_SUFFIX = "\n\nUse `grep` and `read_file`. Submit by writing /workdir/answer.txt."
def grep(self, pattern: str, path: str) -> str:
"""Search for `pattern` under `path`.
Args:
pattern: The regex to search for.
path: The file or directory to search.
"""
return self._exec(f"grep -rn {pattern!r} {path!r}")沙箱后端
environment_type 会直接传递给 Harbor(TRL 不会对其进行验证):
HarborSpec(dataset, environment_type="e2b") # cloud sandbox (offloads provisioning), needs E2B_API_KEY
HarborSpec(dataset, environment_type="docker") # default; needs a local Docker daemone2b 推荐用于集群训练:只有 environment.exec 会进入云端沙箱,因此 GPU 可以专用于策略,并且可以并发运行多个 rollout。
奖励函数
spec.reward_funcs 默认使用结果奖励——对于每次 rollout,它会读取 Harbor 验证器的标量值(env.reward),该值在 rollout 结束后通过在沙箱中运行任务的 tests/ 验证器计算一次。若要使用自定义奖励,请编写一个标准的 TRL 奖励函数:
def my_reward(environments, **kwargs) -> list[float]:
return [env.reward for env in environments]API
class trl.experimental.harbor.HarborSpec
< source >( dataset: stragent: str | type[HarborEnv] = 'bash'environment_type: str = 'docker'num_tasks: int | None = Noneindices: list[int] | None = Noneinclude_metadata: bool = True )
参数
- dataset (
str) — 一个 Hugging Face 数据集仓库 ID,其中包含 Harbor 任务树(例如"AdithyaSK/data_agent_rl_environment_train"),或者指向包含tasks/子树的本地目录路径。每个任务是一个目录,包含instruction.md/task.toml/environment//tests/。 - agent (
str或type,可选,默认为"bash") — 基础 agent / harness,即 env 暴露的工具接口。可以是以下之一:内置名称("bash")、导入路径"package.module:ClassName"、文件路径"path/to/file.py:ClassName",或直接传入 HarborEnv 的子类。 - environment_type (
str,可选,默认为"docker") — Harbor 沙箱后端,直接传递给 Harbor(支持其所有后端 —"docker"、"e2b"、"daytona"、"gke"、"modal"、"runloop"等)。此处不进行验证,由 Harbor 负责验证。"docker"是 Harbor 自身的 默认值;选择"e2b"可将沙箱功能卸载到云端。 - num_tasks (
int, 可选) — 限制拉取到数据集中的任务数量。None表示使用树中的所有任务。 - indices (
list[int],可选) — 特定任务的索引(指向排序后的任务列表)。与num_tasks互斥。 - include_metadata (
bool,可选,默认为True) — 将每个任务的task.toml元数据(gold_answer、difficulty 等)合并到数据集行中。
单个规格对象,用于将 Harbor 任务套件接入 TRL 训练器。
class trl.experimental.harbor.HarborEnv
< source >( environment_type: str = 'docker' )
基于 Harbor 沙箱 + 验证器的基础 TRL 环境。
子类定义了工具方法(即测试框架)。TRL 在每次 rollout 中驱动的生命周期为:reset(task_dir)(启动任务的沙箱并返回其指令)-> 工具方法(在沙箱中执行)-> reward(在 rollout 结束后,惰性运行一次验证器)。
单bash工具框架;通过写入/workdir/answer.txt来提交。
在沙箱中运行 shell 命令并返回其合并的 stdout+stderr。shell 在多次调用之间是无状态的。使用它来探索文件(ls, head, cat)、运行 Python(python3 -c "...")以及提交答案(echo -n "<value>" > /workdir/answer.txt)。
局限性
- 该集成位于
trl.experimental中 — API 可能会发生变化。设置TRL_EXPERIMENTAL_SILENCE=1可在 CI 日志中静默该警告。 - Harbor 的异步沙箱客户端绑定到单个事件循环,因此每个 env 都在其自身的事件循环上同步驱动 start/exec/verify;沙箱的创建在生成批次内是顺序执行的(像
e2b这样的云后端可以缓解单个沙箱的成本)。 - 单个
HarborSpec涵盖一个任务套件和一个测试框架;目前尚不支持多套件训练。