> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuneplane.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 对着 agent 环境训练

> 把作业指向一个任务集让模型去练，由判定器决定奖励。

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
tp env ls
tp submit my-agent --profile h200:8 --environment alice/calculator-tasks@1.0.0
```

平台解析这个版本、确认你有权使用它，然后把它送进作业。你的训练代码从不持有一个自己选的路径或
URL。

<Info>
  这一页讲怎么用一个环境。怎么写一个 —— manifest、任务集、协议 —— 见
  [编写环境](/zh-Hans/extend/environments)。
</Info>

## 作业收到什么

三个环境变量，由控制面设置：

| 变量                                | 是什么            |
| --------------------------------- | -------------- |
| `TUNEPLANE_JOB_ENVIRONMENT_DIR`   | 物化协议下环境被写到哪    |
| `TUNEPLANE_JOB_ENVIRONMENT_URL`   | 自服务或远端协议下它在哪应答 |
| `TUNEPLANE_JOB_ENVIRONMENT_SPLIT` | 这个作业能看到任务集的哪一半 |

<Warning>
  不要在实验里硬编码其中任何一个。路径是平台给的，直接写死一个路径的实验绕过了解析它的那道权限
  检查。
</Warning>

## split 不由你选

`TUNEPLANE_JOB_ENVIRONMENT_SPLIT` 由**操作本身**决定：训练作业拿 `train`，评测拿 `eval`。没有参数
能覆盖它。

这就是全部的安全属性，而它为什么是一个状态而不是一个设置，值得说白。留出的数据在"选它"变成一件
方便事的那一刻就不再是留出的了。分数最好的那次运行会变成在自己训练任务上评测的那次 —— 而下游没有
任何东西能看出这件事。数字看起来很好，模型并不好，而这个错误在那次运行产出的每个产物里都是隐形的。

让操作来决定，意味着泄漏不是一个有人会设错的设置。它是一个系统到不了的状态。

一次评测索要环境从未声明过的 split 会被拒绝，而不是被悄悄喂上训练任务。

## 作业能走的三条路

<Tabs>
  <Tab title="自服务（openenv）">
    平台运行环境服务端。你的训练器通过 openenv-core 的客户端 —— `reset`、`step`、`state` —— 对着
    `TUNEPLANE_JOB_ENVIRONMENT_URL` 驱动 episode。

    TRL、SkyRL、Unsloth 和 Axolotl 原生消费这种。没有额外要写的东西。
  </Tab>

  <Tab title="物化（nemo-gym）">
    平台把环境按 NeMo Gym 期望的文件形态写进作业，放在 `TUNEPLANE_JOB_ENVIRONMENT_DIR`，Gym 从它们
    启动自己的服务端。

    环境必须声明一个 harness 插件，因为得有人来跑轨迹循环，而平台不写它。
  </Tab>

  <Tab title="远端（openenv-remote）">
    有人已经在跑这个服务了。平台决定你的作业能否访问那台主机，并把 URL 交给你。它从不代理流量。
  </Tab>
</Tabs>

一份 manifest 还可以声明 `openenv-image`，即别人的 OpenEnv 容器。没有作业能到达它：托管另一方的
容器是执行器的活，而这个平台不做，所以这种引用会在准入时被拒绝，而不是在 launcher 里才发现。

## 奖励来自判定器

你不为环境写奖励函数 —— 环境声明由什么决定完成，而那永远是一个引用：

| 判定器 kind   | 谁来判                                                 |
| ---------- | --------------------------------------------------- |
| `rubric`   | 平台裁判，按你们团队写的一份 [rubric](/zh-Hans/guides/rubrics) 打分 |
| `plugin`   | 环境自己插件里的一个入口                                        |
| `endpoint` | 环境声明的一个服务                                           |

答不出来的判定器会**抛异常**，不会上报零。这个区别比听起来重要得多，原因见
[判定器](/zh-Hans/extend/verifiers)。

## 沙箱

harness 要跑模型生成代码的环境会声明 `sandbox.required`。在没有配置沙箱提供方的部署上，这种作业
会**在准入时被拒绝** —— 它不会退回到在训练容器里跑那些代码。

你需要沙箱却被拒绝时，让管理员设 `TUNEPLANE_SANDBOX_IMAGE`。这里有意没有默认值：跑模型生成的代码
不该是能被顺手打开的事。

## 确认成功

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
tp job logs
```

launcher 会把它解析到的环境和走的那条路打进日志：

```text theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
environment: alice/calculator-tasks@1.0.0 (openenv) served at http://127.0.0.1:8931
environment: split=train
```

如果 reward 对每条 rollout 都平在同一个值上，先怀疑判定器，再怀疑模型 —— 一个返回常数的插件判定器
和一个模型完全做不到的任务，从曲线上看是一模一样的。

## 下一步

[编写环境](/zh-Hans/extend/environments)讲 manifest 和任务集 ·
[判定器](/zh-Hans/extend/verifiers) · [评分标准](/zh-Hans/guides/rubrics)
