← 返回信息流
技术博客Hugging Face Blog·10 小时前

AI与开源工具加持,Hugging Face实现每周发布huggingface_hub

原标题:Shipping huggingface_hub every week with AI, open tools, and a human in the loop

速览

Hugging Face通过引入AI辅助和开源工具,显著提升了其核心库huggingface_hub的发布效率。该实践展示了在开发流程中融入人工智能技术的可行性,实现了每周一次的自动化或半自动化发布周期。这一成果不仅提高了软件迭代速度,也为开源社区提供了高效协作的范例。

AI 深度解读

每周发布 huggingface_hub:AI、开源工具与人工介入的闭环

背景

huggingface_hub 是 Hugging Face 生态系统的 Python 客户端核心,transformersdatasetsdiffuserssentence-transformers 等数十个依赖库都通过它来与 Hub 进行交互。对于维护团队而言,如果一周没有发布新版本,就意味着所有的修复和新功能都积压在 main 分支上,无法触达用户。

长期以来,该项目的发布周期为每 4 到 6 周一次。然而,随着项目体量的增长,这种低频发布模式带来了维护压力。为了改善这一状况,团队决定将发布频率提升至每周一次,并构建了一个基于 GitHub Actions 的单一工作流来实现这一目标。

在采用新流程之前,发布过程是部分自动化但主要依赖人工的。虽然 CI(持续集成)环境已经能够自动执行“推送标签后发布到 PyPI”以及“在下游库中打开测试分支”等任务,但大量关键步骤仍需手动完成:

  • 创建发布分支、在 __init__.py 中提升版本号、提交、打标签、推送。
  • 监控下游 CI 运行结果并排查故障。
  • 撰写发布说明(Release Notes):这是最耗时的部分。维护者需要阅读自上次发布以来合并的所有 PR(Pull Request),按主题分组,提供上下文,并以非 git log 风格的自然语言撰写说明。
  • 在候选版本(RC)期结束后切割稳定版。
  • 起草内部 Slack 公告和社交媒体帖子。
  • 打开后续 PR 将 main 分支版本号提升至下一个 dev0

撰写高质量的版本说明是一项繁重的工作,需要聚合数十个不同主题的 PR。虽然技术上没有难点,但需要数小时的专注力。加上公告撰写,一次小版本的发布往往需要分散在几天内的半天工作量。

核心内容

为了解决上述痛点,团队对发布流程进行了重构,将其分为两类工作:纯机械性任务需要判断力的脑力劳动

1. 设计理念:开源、可复用、无供应商锁定

团队设定了一个核心约束:所有组件必须是任何维护者都能自行运行的。不使用无法替换的封闭 API 模型,不依赖专有的发布平台,没有“秘密配方”。整个技术栈完全基于开源工具和开源权重模型(Open-Weights Models),旨在让其他项目的维护者也能轻松采纳并适配此工作流。

2. 工作流架构:AI 起草,人工决策

工作流的核心原则是:模型负责起草,人类负责决策

  • 自动化机械步骤:版本提升、提交、打标签、推送、打开下游测试分支等,由 CI 工作流按顺序自动执行。
  • AI 介入环节:利用语言模型将数十个简短的 PR 标题转化为可读的发布说明初稿。
  • 人工审核环节:在发布前,由人类审查并编辑 AI 生成的草稿。这是唯一需要人类判断力的地方,也是防止 AI 产生“看似自信实则错误”内容的关键防线。

3. 流水线详解

整个工作流包含在一个文件 .github/workflows/release.yml 中,通过 GitHub Actions UI 手动触发。输入参数包括:

  • minor-prerelease:从 main 分支切割 RC。
  • minor-release:将 RC 提升为最终稳定版。
  • patch-release:在现有发布分支上进行 Bug 修复。

主要执行步骤如下:

  1. 准备(Prepare):计算下一个版本号,创建或复用发布分支,提升 __version__,提交、打标签、推送。
  2. 发布到 PyPI:构建并上传 huggingface_hub。并行地,构建并上传 hf CLI 作为独立的 PyPI 包。
  3. 生成发布说明
    • 计算自上一个标签以来的提交差异。
    • 从 GitHub API 获取 PR 元数据。
    • 让模型起草结构化的变更日志(Changelog),并保存为 GitHub 发布的草稿。
  4. 下游测试分支:对于 RC 版本,在 transformersdatasetsdiffuserssentence-transformers 等库中打开分支并锁定 RC 版本,以便快速发现回归问题。
  5. Slack 公告:读取发布说明,以团队特有的语气生成内部公告。
  6. 归档说明:将 AI 生成的原始草稿和人工编辑后的版本并排上传至 Hugging Face Bucket。
  7. 发布后版本提升:稳定版发布后,打开 PR 将 main 分支提升至下一个 dev0
  8. 评论已发布的 PR:在发布中包含的每个 PR 上留下“此功能已包含在 vX.Y.Z 中”的评论。
  9. 同步 CLI 文档:打开 PR 到 Skills 仓库,更新重新生成的 hf CLI 技能文档。
  10. 状态报告:每个步骤的状态作为线程回复发布到 Slack,最终任务更新根消息显示 ✅ 或 ❌。

4. 信任但验证:人工介入的核心机制

AI 生成发布说明的主要风险在于:模型可能会悄悄遗漏某个 PR,或者捏造一个不属于本次发布的 PR。一个“几乎正确”的变更日志比没有变更日志更糟糕,因为没人会去重新检查它。

为此,团队引入了**确定性验证(Deterministic Verification)**机制:

第一步:建立事实真相(Ground Truth)

在模型运行之前,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:应该存在的 PR 集合(来自 manifest)。
  • found:模型在笔记中引用的 PR 集合(从 #1234 解析出 1234)。
  • missing:预期存在但模型遗漏的 PR。
  • extra:模型提及但不属于本次发布的 PR。

如果存在缺失或多余项,系统不会直接失败或发送错误文件,而是将差异反馈给 Agent,要求它修复特定的 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)

这种模式使得整个过程变得可信:非确定性的模型被包裹在确定性的护栏中。模型擅长撰写文本,但不擅长穷尽列举;因此,让模型负责写作,让代码负责一致性校验。

5. 防止幻觉:基于文档差异的上下文 grounding

除了完整性,准确性同样重要。如果仅凭 PR 标题让模型总结,它可能会自信地编造一个与实际 API 不符的代码示例。

为了防止这种情况,在获取 PR 元数据时,团队还拉取了每个 PR 中实际修改的文档差异(Diff):即 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 作者实际在文档中编写的

查看原文 →huggingface.co