Hugging Face 发布 transformers 到 mlx-lm 移植 Skill 与测试框架
The PR you would have opened yourself
Hugging Face 发布一个 Skill 和配套测试框架,帮助贡献者把 transformers 中的语言模型移植到 mlx-lm,使模型加入 transformers 后能较快在 MLX 上可用。
使用 Skill 和测试框架让 transformers 模型可在 mlx-lm 中使用
简而言之
我们提供了一个 Skill 和一个测试框架,帮助将语言模型从 transformers 移植到 mlx-lm,使它们在加入 transformers 的那一刻就能(几乎)立即可用。该 Skill 旨在作为辅助工具支持贡献者和审阅者,而非自动化工具。我们解释了为什么这样做、如何做,并评论了在智能体时代如何有意义地为开源做贡献。
代码智能体的到来
2026 年,代码智能体开始真正发挥作用。过去编辑器旁的自动补全,如今变成了一个能根据简要规格一次性给出合理解决方案的系统。生成的代码通常开箱即用,覆盖了你的需求,并对你未指定的细节做出合理假设。这很棒。正如黄仁勋所说,我们瞬间从全球 3000 万程序员变成了 10 亿。创造力被释放了。
但这迫使我们必须重新思考开源。
以 transformers 库为例。它有数百名贡献者,被数千个项目使用,下载量超过十亿次。突然之间,任何拥有智能体的人都可以指示它找到某个未解决的 issue、修复它并提交 PR。而这正是正在发生的事情。这些人感到高兴,因为他们正在为一个伟大的库做贡献,但可悲的现实是,大多数时候他们并没有意识到自己其实没有。
为什么没有?智能体生成的 PR 通常会忽略两个前提。
像 transformers 这样的代码库非常在意代码本身。构建代码长什么样都无所谓的项目很酷,但 transformers 不是其中之一。由于被数千人使用,transformers 主要是作为一种人与人之间通过代码进行交流的方式而构建的。模型文件从上到下阅读,因为我们希望从业者无需在复杂的抽象之间跳转就能理解它们。这贯穿整个库的设计,也是我们倾向于扁平化层级结构的原因。
智能体没有这种上下文。由于设计决策并不明确,智能体会建议按照“最佳实践”进行重构来“改进”代码库,却没有意识到自己正在破坏库与其用户之间的隐性契约。它们冗长、过早泛化、注意不到某个改动会影响其他区域、引入细微 bug、破坏性能。它们还谄媚,接受任何想法并勤勉地执行,包括那些维护者本会用一句简短评论早早驳回的想法。
少数维护者仍然必须阅读每一个 PR、理解它、判断设计方向是否正确、识别副作用并撰写反馈。PR 数量增长了十倍,但维护者的数量没有(也不可能,因为团队协作无法扩展)。
这与 MLX 有什么关系?
由于数量庞大,transformers 是最早感受到这种压力的项目之一,但同样的动态正在各处发生。举一个不同领域的例子,App Store 的审核人员被淹没,因为现在任何人都可以构建并提交应用,所以很多人都在这么做。
同样的逻辑也适用于 MLX:其维护者非常关心代码,会仔细阅读每一个 PR。我们想看看 agent 能否帮助贡献者快速落地高质量的模型移植,同时支持审查者的工作。我们不仅希望产出看起来像是细心的人类提交的 PR,还提供额外的产物来增强信号:生成示例、数值对比,以及一个独立的非 agent 测试框架以保证可复现性。
transformers 与 MLX 之间的另一个联系是,大多数情况下,mlx-lm 模型都是从 transformers 实现移植而来的。由于 transformers 注重清晰性和可读性,它已成为模型定义的权威来源。下游贡献者会等到 transformers 实现就绪后,才将其移植到其他框架。作为一个副作用,这为 agent 提供了一个绝佳的环境,因为它天然地限制了范围:agent 无需从零开始创建实现,而是依赖 transformers 代码作为权威来源。
这种方法支持我们的目标:当一个模型落地到 transformers 后,它应该很快就能在 MLX 上可用。
我们做了什么
我们构建了一个 Skill,mlx-lm 贡献者可以用它把模型从 transformers 移植到 MLX。给定类似“将 olmo_hybrid 架构转换为 MLX”的提示,该 Skill 会搭建一个虚拟环境来工作,从 Hub 发现并下载相关模型,阅读 transformers 建模代码,编写 MLX 实现,并运行一系列测试。如果结果看起来不对,它会调试并迭代,直到满意才会宣布成功。
我们设计它时,就让它对审查者和贡献者同样有用。
对于贡献者,该 Skill 当然会处理所有脚手架工作:在 Hub 上查找模型变体,对比它们的配置以找出在不同模型变体间变化的参数,下载检查点,为 mlx-lm 和 transformers 设置可编辑安装。但它也处理更困难的建模任务。它会关注显著的架构细节,并验证敏感区域,比如可能导致难以发现的 bug 的 RoPE 配置。当配置未声明 dtype 时,它会检测到并从 safetensors 元数据头中推断出来。它在 transformers 和 MLX 之间运行逐层比较,以精确定位分歧发生的位置。这些是只有具备移植经验的人才会想到去运行的检查。
对于审查者,该 Skill 产出的 PR 会坦承是 agent 辅助的,但看起来确实像一份细心的人类提交。审查者会看到代码遵循 mlx-lm 惯例:惯用解决方案、没有不必要的注释、没有推测性抽象、未经明确批准不修改共享工具。鉴于代码是 agent 辅助的,我们尝试包含比中位数 PR 更多的数据,以提供尽可能多的信号。PR 正文包含一份报告,其中有变体及其架构差异的摘要、生成示例、数值对比、dtype 验证、与 transformers 基线的逐层比较。PR 始终披露它是 agent 辅助的,并且在贡献者接受结果之前,该 Skill 不会打开它。
为了验证,Skill 会为一个独立的、非 agentic 的测试框架生成测试清单,该框架在设计上易于复现,且不受 LLM 幻觉或自满的影响(详见下文)。
我们是如何做到的
Skill 是给 agent 的配方:简单的文本文件,包含指导方针,引导模型完成复杂任务。它们并不神奇;你可以通过提示和迭代达到同样的结果。但它们提供了一致性(每次运行都遵循相同的流程,而不同的人会有不同的提示方式),最大限度地减少歧义,并充当文档:任何人都可以阅读 Skill 来了解它的作用、识别缺失的情况并提出改进建议。
我们通过与 Claude 对话,自己移植了一个模型来引导 Skill 的创建。我要求它将 GLM 4.7 从 transformers 移植到 mlx-lm,像在正常会话中一样给出指令。一个技巧:我让 Claude 指向一个 mlx-lm 的检出副本,其中我已经删除了已有的实现,这样我就可以将输出与基准真值进行比较。经过几次迭代,我得到了一个可用的实现、一段揭示 Claude 如何解决问题的对话,以及 Skill 的初稿,这是 Claude 作为该过程的总结而创建的。我对其进行了大量编辑,并融入了 @gabegoodhart 的经验,他慷慨地分享了他们为另一个模型进行的移植对话 🙌。
我们重复了这个循环几次,Skill 不断成长。在技术方面,我们涵盖了诸如 RoPE bug(可能产生看似合理但随长序列而退化的输出)、float32 精度污染会悄无声息地扼杀推理速度(你会惊讶于这些事情发生的频率!)、不同模型变体之间配置字段的差异,实现必须处理这些差异,以及为无法装入单台机器的超大模型进行分布式推理。我们教它如何调用 hf CLI 来发现和下载模型。最重要的是,我们指示它运行经验丰富的移植者会运行的测试,并且在测试通过之前不要宣布成功。
在文化方面,我们涵盖了更软性的特征,并解释了使 PR 易于审查的惯例:不要用注释来解释代码(审查者必须解析注释和代码 🤦♂️),永远不要提议重构,未经询问不要触碰共享工具。这些规则对 agent 来说没有成本,但为审查者节省了大量时间。
最终结果:贡献者输入一个提示,Skill 就会生成像这个这样的 PR,以及一个用于外部测试框架的测试清单。
测试框架
Skill 会在 PR 中分享一份全面的结果报告。所有这些都来自 agent 在转换过程中运行的测试,但我们不希望审查者盲目相信并接受它们。为了更进一步,我们创建了一个独立的、非 agentic 的测试框架,对转换后的代码运行系统性测试。这带来了几个好处:
- 消除了关于 LLM 幻觉结果或对其过于自满的不确定性。
- 保证了可复现性:任何人都可以下载测试框架仓库并运行测试。
- 文档与透明度。所有结果都以不同层级保存:摘要报告、各模型详情、原始输入/输出保存为 JSON 文件。测试也会复制到结果文件夹中,这样即使我们将来修改了测试框架,也能知道当时运行的是什么。
测试框架不是 CI 门禁。有些检查很直接(输出的 dtype 是否正确?),但大多数是定性的。预训练模型在长序列中重复自己是正常的吗?与 transformers 基线相比 4% 的相对 logits 差异可以接受吗?这些都是基于类似架构经验的判断。测试框架提供了有用的信号,但最终还是要由评审者和贡献者来做决定。
如何使用该 Skill
该 Skill 是为那些已经在提交 mlx-lm 模型 PR,或者会自己手动操作的人设计的。它并不面向大众,因为提交给 mlx-lm 的 PR 很少能一提交就被接受。典型的流程是:贡献者提交 PR,评审者指出改进之处,双方反复迭代直到达到质量标准。如果对专家提交来说都是如此,那么对 agent 辅助的提交来说也将如此。
如果你不准备参与这个流程,那你可能就不应该提交 PR。评审者会努力理解你的代码(即使知道它是 agent 辅助完成的),所以你也应该这样做。对代码负责,并准备好采纳他们的反馈。特别是,不要把评审者的评论丢回给 agent,然后把它产出的任何东西直接发出去。LLM 会固执己见、跑题,并且无法有效地反驳。一旦你与评审者互动,这就变成了人与人之间的对话,所以轮到你参与讨论,并尊重他们投入的时间。
你也可以用这个 Skill 来学习;在信心和经验积累起来之前,你不需要提交任何东西。阅读该 Skill,找出你之前没有意识到的问题领域:它在 skill 文件、参考文档和实用脚本中包含了近 1.5 万字。把它指向你自己的 mlx-lm fork,尝试一次转换,并在被接受的实现进入官方仓库后,将你的输出与之比较。如果你这样做几次,你会学到很多关于 transformers、MLX 和语言模型架构的知识。
如果你准备好了:
uv run https://raw.githubusercontent.com/huggingface/transformers-to-mlx/main/install_skill.py
uvx hf skills add --claude
我们使用 Claude Code 开发和测试了这个 Skill。同样的方法也适用于 Codex 或其他编码 agent,但我们还没有测试过它们。如果你在其他环境中尝试这个 Skill,请告诉我们效果如何!
后续步骤与已知不足
这个 Skill 对 mlx-lm 中的 LLM 效果很好,但仍有很大的成长空间。
下一步
- mlx-vlm。视觉语言模型位于一个单独的仓库中,有着不同的约定。除了建模代码之外,mlx-vlm 还需要处理器在 LLM 看到输入之前处理图像预处理。我们期待与 Prince Canuma 合作,帮助他做他所做的事。
- llama.cpp。一些相同的挑战也适用。处理器需要将图像处理算法用 C++ 重新实现,数值差异不可避免。这是一个范围界定严格的 agent 可能有所帮助的领域。
- 测试框架。我们希望扩展测试集,并可能探索安全的自动化方式,在我们的基础设施上自动运行测试。
目前尚不可用的功能
- mlx-lm 中的共享工具。与 transformers 相比,mlx-lm 在将常见模式提取为共享函数方面要求不那么严格。该 Skill 有意偏向于自包含的模型文件(与 transformers 相同),但审阅者经常要求重构,将重复代码移入共享模块。
- VLM 及其他架构,如上所述。
- 量化模型上传。该 Skill 会测试量化,但不会将量化模型上传到 Hub。我们认为在 PR 审查期间上传没有意义,但我们可以创建一个流程稍后再做。
- 思考测试。目前尚未设计针对思考的专门测试。该 Skill 会转换并验证这些模型的生成结果,但不会验证思考结构。
结论
开源中的瓶颈不是打字速度:而是理解代码库,以便在不破坏与用户之间显式和隐式契约的情况下进行修改。如果我们教会智能体什么才是重要的,它们就能在这一过程中提供帮助。我们探讨了这在 mlx-lm 背景下的具体形态,并希望它能帮助贡献者和审阅者更快地落地高质量的模型转换!
资源
贡献:
相关库:
背景:
致谢!
非常感谢 Ben、Shaun、Aritra 阅读本文的早期版本并使其大为改进 🙌
我们无比感激 Apple 将 MLX 作为开源项目发布,也感激社区立刻认识到它的价值并热情贡献 🙏
来源:Hugging Face Blog · huggingface.co
来源: