Skip to main content
patch.py
plugin.yaml
这就是一个完整的 algorithm 插件。launcher import patch、调用 install, 你的改动在这个作业接下来的全过程中生效。

你的函数什么时候被调用

两种装载模式,选哪个只取决于一件事:你的补丁需不需要训练期的上下文。
由 launcher 在训练入口运行之前调用,参数是这次作业的超参。
params 就是 spec.hyperparams——本次提交摊平后的 --set 覆盖值和解析后的配置值。 补丁只需要替换一个函数时,用 eager。
传给 install_deferred 的名字是 manifest 里的 name,不是完整的 <owner>/<name>。 传一个没登记的名字会抛错,并列出已登记的有哪些。

launcher 做了什么

1

校验注入的包

重算 forge_plugins/<name>/ 的摘要,与 JobSpec 比对。不一致就停止作业。
2

检查 SDK 兼容性

manifest 声明了 requires.core 时,运行中的 starforge-core 必须满足它。
3

把包根加入 sys.path 并 import

这正是「顶层名不得遮蔽真实依赖」要在发布期就拒绝的原因。
4

调用或登记

eager → 立即调用 install(params)deferred → 按 manifest 里的名字登记,等训练入口来调。
集群侧只装载 kind: algorithm。其他代码类 kind 会打一行日志跳过—— environment 插件由环境机制装载,data-prep 插件根本不离开你的笔记本。

怎么写这个函数

下面几条值得明说,因为违反它们会在很难定位的地方出问题:
  • 出真问题就抛。 install 里抛异常会停止作业,这是对的: 一个悄悄没生效的补丁,会产出一个数字含义与实验声明不符的 run。
  • 保持幂等。 多节点或带重启的执行器下,你的模块可能被 import 多次。 防住「把已经包过一次的函数又包一次」。
  • 不要在模块 import 期 import 训练框架,除非你确定它一定在。 放进 install 里 import——那时你已经确定这是训练容器。
  • 配置从 params 读,不要从环境变量读。 params 会随作业记录下来, 读的人能看到你的补丁被告知了什么。环境变量不会。

为什么这里把 monkey-patch 当成一等机制

对于装不了新依赖的内网集群,一个零依赖、运行期生效的补丁, 相比分发一个 fork 过的框架镜像是决定性的优势。让它可接受而不是鲁莽的,是「补丁被声明、被版本化、被 digest 锁定」这件事: 平台说得出哪个作业用了哪个补丁的哪个版本。 一个埋在训练脚本里、没人声明过的 monkey-patch,风险一样大,但完全没有这份记录。

两个来源,一个优先级

一个作业可以从两个地方带补丁: 同名时插件包优先。显式锁定的版本必须压过隐式内置的。

确认成功

作业日志里每个插件一行:
两行都没有,说明实验根本没引用这个插件——检查 plugins.lock.json 后重新提交。