Shipping huggingface_hub every week with AI, open tools, and a human in the loop

Shipping huggingface_hub every week with AI, open tools, and a human in the loop

每周利用 AI、开源工具和人工干预发布 huggingface_hub

huggingface_hub is the Python client at the base of the Hugging Face ecosystem. transformers, datasets, diffusers, sentence-transformers and dozens of other libraries depend on it to talk to the Hub. Every week we don’t ship a new release is a week of fixes and features stuck on main. huggingface_hub 是 Hugging Face 生态系统的基础 Python 客户端。transformersdatasetsdiffuserssentence-transformers 以及其他数十个库都依赖它与 Hub 进行交互。如果我们每周不发布新版本,就意味着修复和功能会被积压在主分支上。

For a long time we released every 4 to 6 weeks. We now release every week from a single GitHub Actions workflow. We built it using open-source tools and open-weights models and kept a human in the loop at the one place where judgment matters. Nothing in this post requires a vendor contract, a closed model, or infrastructure you can’t run yourself. That was a design goal from the start since we wanted a workflow other maintainers could pick up and adapt. By the end of this post, you’ll have everything you need to build your own. 长期以来,我们每 4 到 6 周发布一次。现在,我们通过一个 GitHub Actions 工作流实现每周发布。我们使用开源工具和开放权重模型构建了该流程,并在需要判断的关键环节保留了人工干预。本文提到的所有内容都不需要供应商合同、闭源模型或你无法自行运行的基础设施。这是我们从一开始就设定的设计目标,因为我们希望其他维护者能够直接采用并适配这一工作流。读完本文,你将掌握构建自己发布流程所需的一切。

Where we started

起点:我们曾经的流程

The old process was partly automated, mostly manual. 旧流程部分自动化,但大部分仍需手动完成。

Already in CI: Publishing to PyPI once a tag was pushed. Opening test branches in downstream libraries with the release candidate pinned. 已实现 CI 的部分: 推送标签后自动发布到 PyPI;在下游库中创建并锁定候选版本(RC)的测试分支。

Still manual, every single time: Creating the release branch, bumping the version in __init__.py, committing, tagging, pushing. Watching the downstream CI runs and triaging failures. Reading through every PR merged since the last release and writing release notes by hand: grouped by theme, with context, in a voice that didn’t read like a git log dump. Cutting the stable release after the RC period. Drafting an internal Slack announcement and social posts. Opening the post-release PR to bump main to the next dev0. 仍需每次手动完成的部分: 创建发布分支,更新 __init__.py 中的版本号,提交、打标签、推送。监控下游 CI 运行情况并处理失败。阅读自上次发布以来合并的每一个 PR,并手动撰写发行说明:按主题分组、添加背景信息,并确保语气自然,而不是简单的 git 日志堆砌。在 RC 期结束后发布稳定版。起草内部 Slack 公告和社交媒体帖子。提交发布后的 PR,将主分支版本号提升至下一个 dev0。

Writing good notes for a new version was the heavy part, aggregating tens of PRs on different topics. Nothing technically hard but a few hours of focused attention. Add the announcements on top and a minor release was easily a half-day of work spread over several days. 为新版本撰写高质量的说明是最繁重的工作,需要汇总数十个不同主题的 PR。虽然技术上不难,但需要几个小时的专注。再加上公告撰写,一个小版本的发布很容易耗费分散在几天里的半天工作量。

Two kinds of work

两种工作类型

So we decided to streamline the whole thing. Looking at that list, the work splits in two. Some steps are purely mechanical and can be automated: bumping the version, committing, tagging, pushing, opening downstream test branches, opening the post-release PR. Nobody needs to think about those. They just have to happen in the right order, every time, which is what a CI workflow is good at. 因此,我们决定简化整个流程。审视上述列表,工作可以分为两类。有些步骤纯属机械性,可以自动化:更新版本号、提交、打标签、推送、开启下游测试分支、提交发布后的 PR。这些步骤无需人工思考,只需按正确顺序执行即可,而这正是 CI 工作流的强项。

The rest is different. Writing release notes, deciding what to highlight, phrasing an announcement for a human audience: that’s brain work. It’s the kind of judgment that kept the release manual for years. This is where AI comes in, turning a blank page into a solid first draft in seconds. It’s also where we have to be careful because a draft that looks confident and is subtly wrong is worse than no draft at all. 其余部分则不同。撰写发行说明、决定重点内容、为人类读者润色公告:这些需要动脑。正是这种判断力使得发布流程多年来一直依赖人工。这正是 AI 的用武之地,它能在几秒钟内将空白页面变成一份扎实的初稿。但这也是我们需要谨慎的地方,因为一份看起来自信却存在细微错误的草稿,比没有草稿更糟糕。

The design principle: open parts, reusable by anyone

设计原则:开放组件,人人可用

When we decided to fix this, we set one constraint up front: every moving part had to be something any maintainer could run themselves. No closed model behind an API we couldn’t swap, no proprietary release platform, no secret sauce. 当我们决定解决这个问题时,预先设定了一个约束:每一个环节都必须是任何维护者都能自行运行的。没有无法替换的闭源 API 模型,没有专有的发布平台,也没有所谓的“秘方”。

Here’s the entire stack: 以下是完整的技术栈:

PartWhat it does
GitHub ActionsOrchestrates the whole release
OpenCode AgentRuntime that drives the model
An open-weights model (currently GLM-5.2 from Z.ai)Drafts the release notes and Slack announcement
HF Inference ProvidersServes the model
PyPI Trusted PublishingPublishes the package
组件功能
GitHub Actions编排整个发布流程
OpenCode Agent驱动模型的运行时
开放权重模型 (目前使用 Z.ai 的 GLM-5.2)起草发行说明和 Slack 公告
HF Inference Providers提供模型推理服务
PyPI Trusted Publishing发布软件包

The second principle: the model drafts, a human decides.

第二原则:模型起草,人工决策。

Language models are good at turning thirty terse PR titles into readable release notes. They are not good at being trusted blindly. So the workflow is human-supervised: the model does the first pass, a deterministic script checks its work, and a human reviews and edits before anything ships. 语言模型擅长将三十个简短的 PR 标题转化为可读的发行说明,但不值得盲目信任。因此,该工作流采用人工监督:模型进行第一轮处理,确定性脚本进行校验,最后由人工在发布前进行审查和编辑。

A tour of the pipeline

流水线概览

The full workflow is a single file, .github/workflows/release.yml, triggered by hand from the Actions UI. It takes exactly one input: 整个工作流位于单个文件 .github/workflows/release.yml 中,通过 Actions UI 手动触发。它仅需一个输入:

on:
  workflow_dispatch:
    inputs:
      release_type:
        type: choice
        options:
          - minor-prerelease # cut an RC from main
          - minor-release    # promote the RC to final
          - patch-release    # bugfix on an existing release branch

From there, the jobs run roughly in this order: 此后,任务大致按以下顺序运行:

  1. Prepare: Compute the next version, create or reuse the release branch, bump __version__, commit, tag, push.

  2. 准备: 计算下一个版本号,创建或复用发布分支,更新 __version__,提交、打标签、推送。

  3. Publish to PyPI: Build and upload huggingface_hub. In parallel, build and upload the hf CLI as its own PyPI package.

  4. 发布到 PyPI: 构建并上传 huggingface_hub。同时,构建并上传 hf CLI 作为独立的 PyPI 包。

  5. Release notes: Diff the commit range since the last tag, pull PR metadata from the GitHub API, and have the model draft a structured changelog. Saved as a draft GitHub release.

  6. 发行说明: 对比上次标签以来的提交范围,从 GitHub API 拉取 PR 元数据,并让模型起草结构化的变更日志。保存为 GitHub 发布草稿。

  7. Downstream test branches: For RCs, open a branch in transformers, datasets, diffusers, sentence-transformers with the RC pinned, so their CI tells us fast if we broke something.

  8. 下游测试分支: 对于 RC 版本,在 transformersdatasetsdiffuserssentence-transformers 中开启分支并锁定 RC 版本,以便它们的 CI 能快速反馈我们是否引入了破坏性更改。

  9. Slack announcement: Read the notes and produce an internal announcement in our team voice.

  10. Slack 公告: 读取说明并以我们团队的口吻生成内部公告。

  11. Archive notes: Upload both the raw AI draft and the human-edited version to a Hugging Face Bucket, side by side.

  12. 归档说明: 将 AI 原始草稿和人工编辑后的版本并排上传到 Hugging Face Bucket。

  13. Post-release bump: After a stable release, open a PR on main bumping to the next dev0.

  14. 发布后更新: 稳定版发布后,在主分支开启 PR,将版本号提升至下一个 dev0

  15. Comment on shipped PRs: Leave a “this shipped in vX.Y.Z” comment on every PR in the release.

  16. 在已发布的 PR 上评论: 在本次发布涉及的每个 PR 上留下“已在 vX.Y.Z 中发布”的评论。

  17. Sync CLI docs: Open a PR to our skills repo with the regenerated hf CLI skill docs.

  18. 同步 CLI 文档: 向我们的技能仓库提交 PR,更新重新生成的 hf CLI 技能文档。

  19. Report to Slack: Every step posts its status as a thread reply; a final job updates the root message with ✅ or ❌.

  20. 报告至 Slack: 每一步都将状态发布为线程回复;最终任务会用 ✅ 或 ❌ 更新根消息。

The remaining manual steps are reviewing and publishing the draft release notes, and reviewing and posting an internal Slack message. Those two steps are where we want a human in the loop. 剩下的手动步骤是审查并发布草稿说明,以及审查并发送内部 Slack 消息。这两个环节正是我们需要人工介入的地方。

Trust but verify: the human-in-the-loop core

信任但要验证:人工介入的核心

Here’s the failure mode everyone worries about with AI-generated release notes: the model quietly drops a PR or invents one that isn’t in this release. A changelog that’s almost right is worse than no changelog because nobody re-checks it. We don’t trust the generated release notes to be complete on the first try, we verify it deterministically. 这是每个人对 AI 生成发行说明所担心的故障模式:模型悄悄漏掉一个 PR,或者编造一个本次发布中不存在的 PR。一份“几乎正确”的变更日志比没有日志更糟糕,因为没人会去复核它。我们不相信生成的发行说明在第一次尝试时就是完整的,我们通过确定性方式进行验证。