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

# 用 Agent 环境做训练

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

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

平台解析版本、检查你是否有权使用、把它送进作业。
你的训练代码从头到尾不会持有一个自己选定的路径或 URL。

<Info>
  这一页讲的是**使用**环境。要自己写一个——manifest、任务、四种协议——
  见[编写环境](/zh-Hans/extend/environments)。
</Info>

## 作业收到什么

三个由控制平面注入的环境变量：

| 变量                            | 是什么                   |
| ----------------------------- | --------------------- |
| `STARFORGE_ENVIRONMENT_DIR`   | 物化类协议下，环境被挂载在哪        |
| `STARFORGE_ENVIRONMENT_URL`   | 服务类或远程协议下，它在哪应答       |
| `STARFORGE_ENVIRONMENT_SPLIT` | 这个作业可以看到 taskset 的哪一半 |

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

## split 不是你能选的

`STARFORGE_ENVIRONMENT_SPLIT` 由**操作类型**决定：训练作业拿到 `train`，评测拿到 `eval`。
没有任何参数可以覆盖它。

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

让操作类型来决定，意味着这个泄漏不是某人可能配错的一项设置，而是系统根本到不了的一个状态。

评测去要一个环境从未声明过的 split 会被拒绝，而不是悄悄给它训练任务。

## 三条路径，从 trainer 的视角

<Tabs>
  <Tab title="服务式（openenv）">
    平台运行环境 server。你的 trainer 通过 openenv-core 的客户端驱动 episode——
    `reset`、`step`、`state`——打到 `STARFORGE_ENVIRONMENT_URL`。

    TRL、SkyRL、Unsloth 和 Axolotl 原生支持这条，不需要额外写东西。
  </Tab>

  <Tab title="物化式（nemo-gym）">
    平台把环境写进作业，写成 NeMo Gym 期望的那些文件，位置是 `STARFORGE_ENVIRONMENT_DIR`，
    Gym 再从它们启动自己的 server。

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

  <Tab title="远程（openenv-remote）">
    服务已经有人在跑。平台决定你的作业能不能够到那台主机，然后把 URL 交给你。
    它从不代理这些流量。
  </Tab>
</Tabs>

## 奖励来自 verifier

你不需要为环境写奖励函数——环境自己声明什么决定任务完成，而且那永远是一个引用：

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

答不出来的 verifier 会**抛异常**，不会报零分。
这个区别为什么比听起来重要，见 [verifier](/zh-Hans/extend/verifiers)。

## 沙箱

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

需要沙箱却被拒的话，让管理员配 `FORGE_SANDBOX_IMAGE`。
默认没有值是有意的：运行模型生成的代码，不该在无意中被开启。

## 确认成功

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
sf 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
```

如果每次 rollout 的 reward 都精确地停在同一个值上，先怀疑 verifier 再怀疑模型——
一个返回常量的 plugin verifier，看起来和「模型做不了这个任务」一模一样。

## 下一步

<Columns cols={2}>
  <Card title="编写环境" icon="joystick" href="/zh-Hans/extend/environments" arrow="true">
    manifest、taskset，以及四种协议。
  </Card>

  <Card title="Rubric" icon="ruler" href="/zh-Hans/guides/rubrics" arrow="true">
    rubric 类 verifier 据以打分的那份标准。
  </Card>
</Columns>
