Modal 发布开源训练服务器 Spindle,兼容 Tinker 接口
Introducing our Training API
Modal 发布开源、兼容 Tinker 的训练服务器 Spindle,可部署在用户的 Modal workspace 中,按 GPU 时间而非 token 计费。
原文给出了与 Tinker 兼容的开源训练服务器,并用多组 RL 工作负载对比了按 GPU 计费的成本差异。
Thinking Machines 的 Tinker 改变了人们进行后训练的方式。你在笔记本电脑上用纯 Python 编写训练循环,Tinker 则在其 GPU 上运行前向和反向传播。我们非常喜欢它,与我们合作的许多团队也是如此。
然而,随着这些团队扩大规模,他们不断提出同样的两个问题:
- 一旦你运行数十个实验,按 token 计费就会变得昂贵。
- 你只能使用提供商决定支持的模型和功能。
我们认为一个好的 API 值得不止一种实现。今天我们发布 Spindle,这是一个开源、兼容 Tinker 的训练服务器,运行在你的 Modal 工作区中。因为服务器归你所有,你可以自定义其中的任何内容,并且你支付的是 GPU 时间而不是 token 费用。我们的默认配置经过调优,开箱即可最大化 GPU 利用率,我们计划持续发布优化,进一步推高性价比。
部署服务器只需一条命令:
然后,针对该服务器运行你的训练脚本。
你的团队应该在什么时候使用 Spindle?
Modal 现在覆盖了整个后训练栈,从按需集群到为你运行训练循环的库。你该从哪里开始?

如果你不想编写训练循环,可以使用我们昨天发布的训练库 Modal Dojo。只需提供模型和数据集,Dojo 会处理其余部分。如果你想掌控直到集群的一切,Modal 提供原始原语:按需多节点集群和用于 RL rollout 的沙箱。
Spindle 介于两者之间。你用自己定义的损失、奖励和环境编写训练循环,Spindle 处理其下的分布式训练。它支持全参数训练,并在大量开源模型上支持多 LoRA。对于运行许多实验的团队,Spindle 支持数百个并发训练运行,性能相近,且与闭源 API 相比成本显著降低。
底层实现
Spindle 兼容 Tinker 的 API 由一个分布式控制平面支撑,该控制平面处理请求和会话管理,以及基于 Modal Functions 构建的容器自动扩缩容。
Spindle 的后端包含一组解耦的训练引擎和推理池。请注意,它们不必运行在相同的加速器或精度上!我们写过如何在这些情况下保持 RL 稳定,并利用固有的成本节省和更高的 GPU 可用性。
我们的整个系统构建在 Modal 原语之上:Modal Clusters 使大模型的传入请求能够被调度到动态可用的、通过 RDMA 连接的节点上,而无需预留集群;Modal Volumes 提供快速、持久的检查点;Modal Servers 提供快速推理层。在构建多 LoRA 训练的过程中,我们还向 Miles 和 SGLang 上游贡献了多项改进,并将继续投资于开源生态。
设计一个高性能的多租户训练系统需要克服各种挑战,我们必须仔细思考。这带来了许多令人兴奋的工作,如今支撑着 Spindle 的核心组件,包括多客户端批调度、异步检查点、增量权重同步,以及用于多 LoRA 和 KV 感知请求路由的自定义推理路由器。你可以在这里阅读更多关于我们设计的内容。
Spindle 实战
过去几个月里,我们在数学推理、智能体编程和搜索智能体方面运行了大量 RL 工作负载。以下是一些示例。
多轮搜索智能体的后训练
我们复现了 Jasper Lu 的用 GRPO 训练搜索智能体,该工作训练 gpt-oss-20b 在一批 SEC 文件语料上执行多轮智能体搜索,使用关键词匹配、grep 和读取工具。任务是整理出一组能够回答查询的文档。
我们拉取了他的开源代码,只把 BASE_URL 和 API_KEY 改为指向我们的 Spindle 部署,然后运行 uv run。就这样。
对比两个 Spindle 种子、我们在 Tinker 上对同一代码的重新运行,以及作者公布的训练结果,我们看到 Spindle 在所有更新步上都与两者保持在 0.01 奖励以内。

随后我们在相同的 32 条留出查询上对第 16、20 和 24 次更新的检查点进行评分,观察到类似的一致性:

将 Spindle 扩展到适配你的工作负载
如果你通过闭源 API 进行训练,你就只能使用提供商决定支持的模型和功能。当你需要他们没有的东西时,除了等待或寻找变通方法之外,你几乎无能为力。
由于 Spindle 是开源的,并且运行在你的 Modal 工作区中,你可以按需进行更改,而我们的配置层让这件事变得极其简单。例如,当我们想在长时程软件任务上训练 Qwen3.5-9B 时,当时我们只有默认的 16k 上下文配置。通过两处简单的更改,我们在配置中将其提升到了 256k:

这次运行在可抢占 GPU 上训练了大约 3 天,每当机器被回收时都会自动从检查点恢复。它还通过 multi-LoRA 让 8 个客户端共享同一批 GPU,这意味着你可以用一次的成本和时间完成 8 次长上下文消融实验。更多内容见下文。
复合成本节省
智能体 RL 的大部分时间都花在生成 rollout 上,这既需要较长的解码时间,也需要执行延迟。当一个客户端在等待长时间的多轮 rollout 时,其训练器 GPU 大多处于空闲状态。根据工作负载的不同,我们观察到,为单个客户端提供服务的训练器(即使运行异步 RL)只有不到一半的时间处于忙碌状态。
在完全异步 RL 中,应对训练器利用率不足的标准做法是扩展推理计算,并允许略微离策略的 rollout 始终为训练器提供数据。Multi-LoRA 与这种方法完美契合:在固定训练器规模下,你可以为单次运行扩展推理,也可以在固定推理预算下增加运行数量,或者两者兼做!
Spindle 的 multi-LoRA 后端让多个客户端共享同一个训练器,从而利用训练器的空闲时间。当一个客户端在等待 rollout 时,训练器会运行另一个客户端的训练步骤。当多个客户端共享同一批 GPU 时,每次运行的成本只是专用计算上的一小部分。
为了量化这一点,考虑同一个简单的 GRPO 任务(在 DAPO-math 上训练一个 27B 模型),让 1 到 8 个客户端共享同一个训练器和推理 GPU(训练用 4×H200,推理用 12×B200)。

观察训练器的利用率,我们可以看到成本收益来自哪里:

只有一个客户端时,训练器有很长的空闲期。当四个客户端交错执行训练步骤时,它保持约 88% 的忙碌状态。增加客户端会降低每次运行的成本,代价是每次运行完成得稍慢一些。请注意存在一个限制:在这里超过四个客户端后,我们观察到训练器发生抖动,这会显著降低每个客户端的吞吐量。
同样的效果也适用于智能体工作负载。以下是我们于 Spindle 上运行的一些工作负载,从单轮数学到长程智能体,每一项都与在 Tinker 上运行相同脚本的情况进行了对比:
| 工作负载 | 配置 | 客户端 | $/1M 输出 token | 相对 Tinker 的价格降幅 |
|---|---|---|---|---|
| DAPO-math,单轮(Qwen3.8-27B) | Tinker | 1 | $9.77 | — |
| Spindle:4×H200 训练,12×B200 推理 | 2 | $3.57 | −63% | |
| Spindle:8×H200 训练,8×H200 推理 | 8 | $1.99 | −80% | |
| 搜索智能体,最多 40 轮(gpt-oss-20b) | Tinker | 1 | $5.06 | — |
| Spindle:8×H200 训练,16×H200 推理 | 4 | $4.06 | −20% | |
| Spindle:8×H200 训练,16×H200 推理 | 8 | $3.80 | −25% | |
| SWE-Gym,256K 上下文(Qwen3.8-27B) | Tinker | — | $10.79(估算) | — |
| Spindle:8×B200 训练,8×B200 推理 | 4 | $6.17 | −43% | |
| Spindle:8×B200 训练,12×B200 推理 | 8 | $5.82 | −46% |
为 GPU 付费而非为 token 付费,意味着你从 GPU 中获得的每一点额外吞吐量都会降低你的每 token 价格。这些实验得出的更广泛结论是:如果你让 GPU 保持忙碌,例如同时运行多个实验,Spindle 提供的性价比远优于闭源 API。
立即试用
要开始使用,请按照设置说明在你的 Modal 工作区中部署 Spindle。
Spindle 是开源的,我们希望与使用它的人一起构建它。如果你遇到 bug,或者需要我们尚不支持的模型或功能,请提交 issue。对于新模型配置或现有模型的性能调优,你可以直接提交 PR。若要向上游贡献更大的改动,请来我们的 Slack 与我们交流,以便我们讨论你的想法!
我们仍处于 beta 阶段,正在打磨性能优化、改进的自动扩缩容、新功能和训练配方等大量内容。敬请期待,祝你 Spindling 愉快!🍽️
来源:Modal Blog · modal.com