Skip to main content
recipe 包声明一种后训练方法:跑哪个入口、哪些超参可调、支持哪些框架版本和镜像、 控制台该画哪些指标。它不含任何平台会执行的代码。

目录结构

plugin.yaml
template/ 之外,任何地方出现可执行文件都会被拒。那个目录是交给用户、在用户容器里跑的脚手架; 根层是平台要解析的,不该出现任何让人期待平台去 import 的东西。

recipe.yaml

recipe.yaml

超参声明

params: 下的每一项,都是 sf validate 能在你笔记本上(而不是在集群上)拦下拼写错误的依据。
int | float | str | bool | enum
必填
写别的会在加载时被拒,并点名是哪个参数。
dot.path
这个值落在训练框架自己配置里的哪个位置。有了它,平台才能把扁平的 --set length_norm_power=1.2 翻译成框架原生的 override。
string
控制台和 CLI 里的展示分组,不参与校验。
mixed
校验契约。min/max 默认闭区间,除非设了 exclusive_minimum
{version: path}
上游在不同框架版本之间挪了配置键时用它。把这件事声明在这里, 而不是在 adapter 代码里写版本分支。

指标契约

metrics.primary 是有序列表,前两个进总览图,诊断阈值读的也是同一批 key。 aliases 把规范 key 映射到某个框架版本实际发出的名字,这样上游改名不会让一张图变空。

双语展示文案

manifest 用英文写,翻译放在一个 i18n: 块里。控制台按读者语言取,缺翻译时回退到 manifest 原文。
参数翻译放在 locale 底下,而不是挂在每个参数上。一个 recipe 会声明几十个参数, 每个都挂一个 i18n: 会把读者真正来找的契约(path / type / range)埋掉。 给一个没声明过的参数写翻译是错误,所以改名不会留下一条指向空处的翻译。 只有展示文案可翻译。名字、path、指标 key 是契约,任何语言下都一样。

命名

已发布方法的 id 永远是 <framework>/<owner>.<name>
多出来的这一段让「和内置方法撞名」在结构上不可能发生——你没法发布一个遮蔽 nemo-rl/grpo 的东西。

镜像

recipe 声明作业跑哪个容器镜像。这是声明包唯一能表达的真正危险的事: 一份纯 YAML 本来可以让集群去拉任意镜像。因此镜像必须通过部署的仓库允许列表(FORGE_ALLOWED_IMAGE_REGISTRIES)。 在向用户开放 recipe 发布之前,先把它配好。

确认成功

sf validate 不碰集群就能验你的参数声明。如果一个不合理的值在那里也通过了, 说明你的声明缺了范围限制。

版本

recipe.yaml 里的 version 对齐上游框架的发布号。包的内容身份是另一个东西—— 覆盖 manifest 加 template 的 bundle digest。所以改一个默认值或修一个模板会更新 digest, 而不必假装框架变了。 实验在 recipe.lock.json 里锁住 digest。你发布新版本后,已有实验照常工作, 直到它们的主人执行 sf recipe upgrade