每周使用AI、开源工具并辅以人工审核发布huggingface_hub
摘要
Hugging Face 描述了如何利用AI、开源工具和人工监督,为其huggingface_hub库构建每周发布流水线,从而实现更快、更可靠的版本发布。
查看缓存全文
缓存时间: 2026/06/23 13:40
每周发布 huggingface_hub:借助 AI、开源工具与人在回路的协作
来源:https://huggingface.co/blog/huggingface-hub-release-ci 返回文章列表 (https://huggingface.co/blog)
Lucain Pouget 的头像 (https://huggingface.co/Wauplin)
Célina Hanouti 的头像 (https://huggingface.co/celinah)
- 我们的起点
- 两种类型的工作
- 设计原则:开放组件,人人可复用
- 流水线概览
- 信任但核实:人在回路的核心
- 让模型脚踏实地,避免编造
- 人工检查点
- 开放且安全的基础设施
- 那么,成本如何?
- 实际带来的变化
- 让它为你所用
- 下一步计划
- 总结
huggingface_hub 是 Hugging Face 生态系统底层的 Python 客户端。transformers、datasets、diffusers、sentence-transformers 以及其他数十个库都依赖它与 Hub 通信。每一个我们没有发布新版本的星期,都意味着修复和功能被卡在 main 分支上。
过去很长一段时间,我们每 4 到 6 周发布一次。现在,我们通过一个 GitHub Actions 工作流实现每周发布。我们使用开源工具和开放权重的模型来构建它,并在唯一需要判断力的地方保留了人类在回路中。这篇博文中的任何内容都不需要供应商合同、闭源模型或你无法自行运行的基础设施。这从一开始就是我们的设计目标,因为我们希望其他维护者能够拿来就用并进行改造。
读完这篇博文,你将拥有构建自己类似系统所需的一切。
我们的起点
旧流程部分自动化,但大部分仍依赖手动操作。
已经在 CI 中的步骤:
- 当标签被推送时发布到 PyPI。
- 在下游库中打开测试分支,并固定候选发布版本。
但以下步骤每次仍需要手动操作:
- 创建发布分支,更新
__init__.py中的版本号,提交,打标签,推送。 - 监控下游 CI 运行并排查失败原因。
- 阅读自上次发布以来合并的所有 PR,并手动编写发布说明:按主题分组,提供上下文,用避免像
git log转储的语言风格。 - 在 RC 阶段结束后发布稳定版。
- 起草内部 Slack 公告和社交媒体帖子。
- 打开发布后的 PR,将
main分支更新为下一个dev0版本。
编写好一个新版本的发布说明是最繁重的部分,需要汇总几十个不同主题的 PR。技术上并不难,但需要几小时的专注注意力。再加上公告,一个小版本的发布很容易变成分散在几天内的半天工作量。
两种类型的工作
所以我们决定精简整个流程。观察上面的列表,工作可以分为两类。
有些步骤是纯机械性的,可以自动化:更新版本号、提交、打标签、推送、打开下游测试分支、打开发布后的 PR。这些步骤不需要思考,只需要每次按正确顺序发生——这正是 CI 工作流擅长的。
其余的工作则不同。编写发布说明、决定强调什么、以面向人类受众的方式撰写公告——这是脑力劳动。正是这种判断力使得发布多年来一直需要手动操作。这正是 AI 发挥作用的地方,它可以在几秒钟内将一张白纸变成一份扎实的初稿。但这也是我们需要谨慎的地方,因为一份看起来自信但存在细微错误的初稿,比没有初稿更糟糕。
设计原则:开放组件,人人可复用
当我们决定解决这个问题时,我们事先设定了一个约束:每一个活动部件都必须能让任何维护者自行运行。没有闭源模型藏在不可替换的 API 后面,没有专有的发布平台,没有秘密配方。
以下是整个技术栈:
[技术栈图片/列表]
第二个原则:模型起草,人类决策。语言模型擅长将三十个简短的 PR 标题转化为可读的发布说明。但它们不适合被盲目信任。因此,工作流是人工监督的:模型做第一遍,确定性脚本检查其工作,然后人类在进行任何发布之前审查和编辑(详见下文)。
流水线概览
完整的工作流是一个单一文件 .github/workflows/release.yml (https://github.com/huggingface/huggingface_hub/blob/main/.github/workflows/release.yml),通过 Actions UI 手动触发。它只需要一个输入:
on:
workflow_dispatch:
inputs:
release_type:
type: choice
options:
- minor-prerelease # 从 main 分支创建 RC
- minor-release # 将 RC 提升为正式版
- patch-release # 在现有发布分支上修复 bug
从这里开始,任务大致按以下顺序运行:
- 准备。 计算下一个版本号,创建或复用发布分支,更新
__version__,提交,打标签,推送。 - 发布到 PyPI。 构建并上传
huggingface_hub。同时,构建并上传hfCLI 作为独立的 PyPI 包。 - 发布说明。 比较自上一个标签以来的提交范围,从 GitHub API 获取 PR 元数据,并让模型起草一份结构化的变更日志(这是最近的一份示例 (https://github.com/huggingface/huggingface_hub/releases/tag/v1.20.0))。保存为 GitHub 发布草稿。
- 下游测试分支。 对于 RC 版本,在
transformers、datasets、diffusers、sentence-transformers中打开一个分支并固定 RC 版本,以便它们的 CI 能快速告诉我们是否破坏了什么。 - Slack 公告。 阅读发布说明,以我们团队的风格生成内部公告。
- 存档说明。 将原始 AI 草稿和人工编辑后的版本并排上传到 Hugging Face Bucket。
- 发布后版本更新。 在稳定版发布后,打开一个 PR 将
main分支更新为下一个dev0。 - 在已发布的 PR 上添加评论。 在每个被包含在发布中的 PR 上留下“此改动已在 vX.Y.Z 中发布”的评论。
- 同步 CLI 文档。 打开一个 PR 到我们的 skills (https://github.com/huggingface/skills) 仓库,更新重新生成的
hfCLI 技能文档。 - 报告到 Slack。 每个步骤将其状态作为线程回复发布;最后一个任务更新根消息,显示 ✅ 或 ❌。
剩下的手动步骤是审查和发布草稿发布说明,以及审查和发布内部 Slack 消息。这两个步骤正是我们希望保留人类在回路的环节。
信任但核实:人在回路的核心
关于 AI 生成的发布说明,每个人都担心一种失败模式:模型悄悄漏掉一个 PR,或者虚构一个不属于本次发布的 PR。一份几乎正确但又不完全正确的变更日志,其危害比没有变更日志更糟糕,因为没人会再去核查。
我们不信任生成的发布说明在第一次尝试时就完整,我们通过确定性的方式进行验证。在模型运行之前,一个 Python 脚本会检索所有属于本次发布的 PR,并将其存储为事实依据。
# 确定性:从 squash-merge 的提交中提取 PR 编号。
PR_NUMBER_PATTERN = re.compile(r"\(#(\d+)\)$")
pr_numbers = [
int(m.group(1))
for commit in commits_since_last_tag
if (m := PR_NUMBER_PATTERN.search(commit.title))
]
save_manifest(pr_numbers) # 事实来源
然后模型根据这些 PR 起草发布说明。完成后,我们检查其输出是否与初始 PR 列表一致:
expected = set(load_manifest()) # 应该包含的
found = extract_pr_refs(notes_md) # 模型实际写了的 (#1234 -> 1234)
missing = expected - found # 被悄悄漏掉的
extra = found - expected # 属于其他发布的
如果发现任何遗漏或多余的内容,我们不会直接失败,也不会发布错误的文件。我们将差异反馈给智能体,要求它仅修复这些 PR:
for _ in range(MAX_ITERATIONS):
missing, extra = validate(notes)
if not missing and not extra:
break # 与事实清单完全匹配
run_agent_fix(missing_prs=missing, extra_prs=extra)
这就是让整个系统值得信赖的模式:一个非确定性的模型被确定性的护栏包裹。模型擅长撰写文章,但不擅长保证完整性。所以我们让它写作,让代码来强制执行一致性。
让模型脚踏实地,避免编造
完整性是一方面,准确性是另一方面。一个仅根据 PR 标题来总结的模型,会很乐意编造一个与真实 API 不符的代码示例。
为了防止这种情况,当我们在获取 PR 元数据时,也会拉取每个 PR 中的实际文档差异:PR 所修改的 docs/ 下所有 .md 文件的统一差异(unified diff)。
def fetch_doc_diffs(pr):
return [
{"filename": f.filename, "status": f.status, "patch": f.patch}
for f in pr.get_files()
if f.filename.startswith("docs/") and f.filename.endswith(".md") and f.patch
]
这些差异被放入模型的上下文中,这样当模型写“这里是新的 CLI 命令”时,它引用的就是 PR 作者在文档中实际写下的示例。这与之前的逻辑相同:给模型真实的原始素材和狭窄的任务。
提示本身以技能文件 (Skills) 的形式存在:存放在仓库中的小型 Markdown 文件(SKILL.md 加上参考模板)。发布说明技能文件详细说明了如何选择重点、如何组织章节、何时添加文档链接等。它读起来像入职指南——这正是正确的思维模型。
人工检查点
RC 发布后,GitHub 发布草稿中包含了 AI 的初稿。这时就需要人工介入了:
- 审阅者阅读草稿,调整语气和重点,修正模型过度强调或忽略的内容。
- 只有在这之后,他们才会触发
minor-release运行,将 RC 提升为正式版。
审阅者的时间用于打磨,将半天的写作时间变成十五分钟的编辑会议。
我们还保留了一份记录,以便持续改进。我们将两个文件并排存档到 Hugging Face Bucket:原始 AI 草稿(在 RC 发布时立即上传,无人修改)和人工编辑后的版本(在正式版发布时上传)。
# RC 发布时:直接从模型生成,未经修改
hf cp release_notes_raw.txt "hf://buckets/huggingface/releases/huggingface_hub/${V}/release_notes_raw.txt"
# 正式版发布时:经过人工审阅后
hf cp release_notes_edited.txt "hf://buckets/huggingface/releases/huggingface_hub/${V}/release_notes_edited.txt"
每周收集这两个文件,我们就能积累一个不断增长的“模型写了什么”与“我们希望它写什么”的数据集。这个数据集随后可用于更新智能体的技能。
开放且安全的基础设施
改造发布流程也是一个加强安全性的好机会,特别是针对供应链攻击。
没有 PyPI token。 发布使用可信发布 (Trusted Publishing):PyPI 验证由 GitHub 为这个特定工作流签发的一个短期 OIDC 令牌,并为每个制品签发 PEP 740 证明 / Sigstore 来源证明。没有需要泄露或轮换的长期密钥。
permissions:
id-token: write # 为 PyPI 签发 OIDC 令牌
attestations: write # 生成 Sigstore 来源证明
# ...
- uses: pypa/[email protected]
with:
attestations: true # 无需密码,无需 API 令牌,只需 OIDC
智能体运行时被固定并经过验证。 我们不会运行 curl | bash 来安装最新的 OpenCode 并指望其安全。我们固定一个版本,并在运行之前检查其 SHA256:
curl -fsSL https://opencode.ai/install | bash -s -- --version "${OPENCODE_VERSION}"
echo "${OPENCODE_SHA256} $(which opencode)" | sha256sum -c -
开放工具并不意味着可以粗心大意地使用工具。
那么,成本如何?
几乎可以忽略不计。一次完整的发布(发布说明加上 Slack 公告,涉及 20-40 个 PR 和几轮提示)在 Inference Providers 上花费大约 0.25 美元。使用按用量付费的开放权重模型,每周唯一真正的问题是“是否有值得发布的内容”——而答案总是“有”。
实际带来的变化
发布节奏从每 4 到 6 周一次变为每周一次。次要影响才是更有趣的:
- 发布说明变好了,而不是变差了。 初稿总是存在,所以审阅时间用于打磨。分组更一致,遗漏的内容更少。
- 问题暴露得更早。 每次 RC 的下游测试分支能在候选阶段就发现集成问题。
- 贡献者循环缩短了。 自动的“此改动已在 vX.Y.Z 中发布”评论带来的影响比我们预期的更大。当有人在已关闭的 PR 上报告问题时,每个人都能立刻看到修复包含在哪个版本中。过去这需要手动搜索标签。
让它为你所用
这是我们最关心的部分。工作流是为 huggingface_hub 量身定制的,但其结构是通用的。
几乎可以直接复用的部分:
- 触发器和版本更新逻辑(
minor-prerelease→minor-release→patch-release)。 - 信任但核实的循环:确定性清单、模型起草、验证、重新提示。这是可迁移的核心思想,与你生成的内容无关。
- OIDC 可信发布、固定且校验和验证的运行时、Slack 线程化。
- 基于技能文件的提示:替换模板,保留结构。
特定于我们的部分:
- 下游仓库列表及其依赖固定格式。
- 技能文件中具体的章节分类和语气。
- Slack 和存储桶的目的地。
要适配它:fork 工作流文件 (https://github.com/huggingface/huggingface_hub/blob/main/.github/workflows/release.yml) 和脚本 (https://github.com/huggingface/huggingface_hub/tree/main/utils/release_notes),将其指向你的包,重新编写技能 Markdown 文件 (https://github.com/huggingface/huggingface_hub/blob/main/.opencode/skills/hf-release-notes/SKILL.md) 以符合你项目的语气,设置两个仓库变量(模型 ID 和你的 OpenCode 版本),在 PyPI 上设置可信发布,然后删除下游测试分支的相关部分。
相似文章
huggingface/transformers 发布 5.8.0 版本
Hugging Face 发布了 Transformers 库 5.8.0 版本,这是一个广泛用于自然语言处理和深度学习的开源框架。
@vanstriendaniel: Hugging Face 是涵盖所有领域(包括生物医学)的 AI 与 ML 的家园!@NIH 刚刚将 @huggingface Hu…
NIH 已将 Hugging Face Hub 添加到其官方通用存储库列表中用于数据共享,允许 NIH 资助的研究人员在数据共享计划中使用它。
@RoundtableSpace:Hugging Face 用智能体把整个后训练团队自动化了。它会读论文、跑 GPU 实验、反复迭代……
Hugging Face 用自主智能体取代后训练团队,自动读论文、跑 GPU 实验并优化模型,不到 10 小时就在基准测试上提升 22 分,HealthBench 成绩比 Codex 高 60%。
@ClementDelangue:Hugging Face 正成为代理使用和构建 AI 的平台,现在它们可以调用 100 万个 HF Spaces,完成最新专用模型所能做的一切……
Hugging Face 现允许 AI 代理调用 100 万个 Spaces,把 Hub 变成可编程平台,代理可随手调用任何专用模型或应用。
@haofeiyu44:我们能否将 Hugging Face Hub——这个拥有海量工件的平台——转变为一个自我进化的发现机器?我们可以……
介绍 ArtifactLinker,这是一个将 HuggingFace 建模为工件图,并利用 GNN 和 LLM 代理自动发现最先进模型和研究见解的框架。