> ## 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.

# Python SDK

> starforge.report —— 让任何训练脚本都能把曲线打进控制台。

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
from starforge.report import init, log, finish

init(hparams={"lr": 1e-6, "kl_coef": 0.05})

for step, batch in enumerate(loader):
    loss = train_step(batch)
    log({"loss": loss, "reward": batch_reward}, step=step)

finish()
```

三个函数。不 import 任何训练框架，不需要继承任何东西，只要镜像里装了 `starforge-core` 就能用。

## 安装

catalog 里的镜像都自带。自定义镜像里：

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
pip install starforge-core
```

## 三条设计约束——它们会影响你的用法

<Columns cols={3}>
  <Card title="绝不抛异常" icon="shield-check">
    回传是旁路。采集挂了，训练照常跑。你不需要给这些调用套 `try`。
  </Card>

  <Card title="没凭据就是空操作" icon="plug">
    同一个脚本在本机跑什么都不做，也不产生任何网络请求，所以不需要维护一个单独的「本地模式」分支。
  </Card>

  <Card title="哪都能 import" icon="package">
    只依赖标准库。不会因为镜像里没装 `requests` 而 import 失败。
  </Card>
</Columns>

## `init()`

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
init(
    hparams: Mapping[str, Any] | None = None,
    monitor_hardware: bool = True,
    monitor_interval: float | None = None,
) -> bool
```

启动回传会话。返回值表示回传是否真的开启了——在本机是 `False`，这不是错误。幂等：调两次是安全的，
第二次传 `hparams` 会把新的补进去。

<ParamField path="hparams" type="Mapping">
  给控制台「配置」面板用的超参。嵌套字典会用点号摊平，`{"policy": {"lr": 1e-6}}` 变成 `policy.lr`。
</ParamField>

<ParamField path="monitor_hardware" type="bool" default="True">
  启一个后台线程采集 GPU 利用率、显存和网络，供「系统」页展示。
  如果作业里已经有别的东西在上报硬件，设成 `False`。
</ParamField>

<ParamField path="monitor_interval" type="float" default="10">
  硬件采样间隔（秒）。`STARFORGE_MONITOR_INTERVAL` 可以覆盖默认值。
</ParamField>

## `log()`

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
log(metrics: Mapping[str, Any], step: int | None = None, prefix: str = "") -> None
```

发送一批标量。

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
log({"loss": 0.42, "reward": 0.71})                    # step 自动递增
log({"loss": 0.41}, step=121)                          # 显式指定 step
log({"loss": 0.41}, prefix="eval")                     # 变成 eval/loss
log({"grad": {"norm": 1.2, "clip": 0.8}}, step=121)    # 变成 grad.norm、grad.clip
```

非标量值在能取均值时折算成均值，折算不出来的直接丢弃——逐 token 的 loss 张量会变成一个数，字符串会被丢掉。
不传 `step` 时用内部计数器递增，这正是奖励函数里想要的行为：那里根本没有全局 step 的概念。

<Tip>
  没先 `init()` 时 `log()` 会替你调。在奖励函数或环境代码里，
  一行 `from starforge.report import log` 就够了——不用初始化，也不用把对象一层层传进去。
</Tip>

## `log_hparams()` 与 `finish()`

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
log_hparams(params: Mapping[str, Any]) -> None
finish() -> None
```

`log_hparams` 在 `init` 之后往配置面板里补内容。`finish` 停止硬件采集并把缓冲区刷干净；
它是幂等的，也注册进了 `atexit`，所以正常退出的脚本严格来说可以不调用它。
还是调一下：进程在 `atexit` 执行前被杀掉时，缓冲区里剩的东西就丢了。

## Hugging Face 与 TRL

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
from starforge.report import StarForgeCallback
from trl import GRPOTrainer

trainer = GRPOTrainer(..., callbacks=[StarForgeCallback()])
```

它按 Trainer 自己的生命周期完成 `init`、每个 log step 的 `log` 和结束时的 `finish`。
对任何 `transformers.Trainer` 以及所有基于它的 TRL trainer 都适用。

```python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
StarForgeCallback(monitor_hardware: bool = True, prefix: str = "")
```

它没有继承 `transformers.TrainerCallback`——Hugging Face 是按方法名调用回调的，鸭子类型就够了；
不继承还能让 `starforge.report` 在没装 `transformers` 的镜像里照样 import。

## 确认成功

提交作业，打开 Charts 页。第一次 `log()` 之后几秒内就会出现数据点。

如果日志在滚而曲线一直是空的，说明回传代码没跑到。进容器里确认：

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
echo $STARFORGE_ENABLED   # 必须是 1
```

如果是 `1` 但仍然没有点，说明 `init()` 根本没被执行到——在它旁边加一行 `print` 重新提交。

## SDK 的其余部分

`starforge.report` 是公开接口。这个包同时导出 JobSpec 契约类型（`JobSpec`、`Recipe`、`ResourceSpec` 等）
以及 `Reporter`——平台自己的框架桥所用的底层客户端。它们分别记录在
[ingest 契约](/zh-Hans/api-reference/ingest)和 [JobSpec](/zh-Hans/reference/jobspec)：
写框架适配器时才需要，给训练脚本加埋点时不需要。
