用 GitHub Agentic Workflows 自动化跨仓库文档
Automating cross-repo documentation with GitHub Agentic Workflows
微软 Aspire 团队(10人分布式应用开发工具团队)使用 GitHub Agentic Workflows 实现了跨仓库文档自动化。工作流在 microsoft/aspire 仓库的 pull request 合并后触发,agent 读取 diff 和关联 issue,在 microsoft/aspire.dev 仓库自动创建文档草稿 pull request,由原功能工程师审阅。在 Aspire 13.3 和 13.4 版本中,82 个文档 pull request 在产品 pull request 之后的中位时间 44.8 小时内合并,100% 被合并。agent 使用受限的 GitHub App token,仅能向 main 或 release/* 分支创建草稿 pull request,不能修改 AGENTS.md 等受保护文件。
“文档在哪里?”这是产品团队里没人喜欢回答的问题。诚实的回答通常是某种形式的“滞后”。写作者盯着一个已关闭的 pull request,试图反向工程出发生了什么变化。而 pull request 的作者早已转向下一个任务。等到文档真正发布时,功能已经上线了,有时甚至不止一次。这曾经是我们 Aspire 团队(我们是一个 10 人小团队,为分布式应用构建开发工具)的常态。几个月前,我们试图弄清楚如何安全地将 AI 引入我们已经信任的自动化流程中。那时我们发现了 GitHub Agentic Workflows。我开始在 microsoft/aspire 中拼接原型。以下是它带来的成果,数据直接来自 GitHub:对于 Aspire 13.3 和 13.4,82 个功能文档 pull request 在产品 pull request 之后的中位时间 44.8 小时内合并,每一个都由发布该功能的工程师审阅。没有增加人手。没有流程再培训。只是换了一种方式问“谁来写这个?” 🔒 约束:跨仓库自动化是难点
我们的产品位于 microsoft/aspire,文档站点位于 microsoft/aspire.dev——不同的仓库、部署目标和审阅链。大多数团队很快就能搞定同仓库自动化;跨仓库自动化才是棘手之处。宽范围的仓库级 token 应该进博物馆,任何负责任的安全策略(包括我们的)都会相应限制它们。这是好事。但如果写文档的地方和写代码的地方不同,这也会成为真正的瓶颈。
多年来的默认工作流是:工程师在 microsoft/aspire 中发布功能。写作者几周后注意到。写作者打开 pull request,阅读 diff,然后联系工程师澄清变化。工程师已经在做下一个功能,模糊地记得,回复了部分信息。文档草稿发布,有时针对的是已经发布的版本。这就是反向工程税。我们需要一种跨仓库的自动化,而不必给 agent 一个可写任何地方的 token。GitHub Agentic Workflows 最终成了答案。 🤖 为什么是 GitHub Agentic Workflows
GitHub Agentic Workflows 是 GitHub Next 团队的一个项目,我经常向别人描述为“GitHub Actions,但用模型作为工作项处理器,并带有满足安全审查的护栏”。这有点简化,但很接近。它的形态是:你将工作流编写为一个 markdown 文件(.github/workflows/my-thing.md)。顶部是 YAML 风格的前置元数据,下面是英文提示。你运行 GitHub Agentic Workflows compile,它会生成一个同级的 .lock.yml(一个普通的 GitHub Actions 工作流),你将其一起提交。运行时,工作流使用受限制的工具集,根据你的提示运行一个 agent。关键是,agent 不直接写入 GitHub。它发出意图(一个描述它想创建的 pull request、issue 和评论的 JSON blob),然后一个独立的、范围狭窄的作业(safe-outputs handler)针对每个工作流的 GitHub app 实现该意图。
最后一点是关键。agent 获得读取权限和一个提示。写入操作通过一个带有显式允许列表的微小可验证管道进行。安全审查点头。我们发布。 💚 一个小插曲:同源技术栈
我喜欢当你用来构建的工具本身也是用你正在构建的工具构建的。GitHub Agentic Workflows 的文档是用 Astro 和 Starlight 构建的。aspire.dev 也是如此——Astro 搭配 Starlight,再加上更广泛的 Starlight 插件生态(astro-mermaid、starlight-llms-txt、starlight-sidebar-topics、starlight-image-zoom、漂亮的 @catppuccin/starlight 主题等。向 Chris Swithinbank 和 Starlight 维护者致敬,整个生态系统感觉是由真正关心的人设计的)。这里有一种真正的亲缘关系。我们用来自动化文档的工具和我们自动化的文档站点共享相同的基础。很方便,因为下一节中的 Mermaid 序列图在两个世界中渲染方式完全相同。
端到端管道
以下是我们最终确定的流程。主角是一个名为 pr-docs-check.md 的工作流,位于 microsoft/aspire 中。它在 pull_request: closed 针对 main 或 release/* 时启动,条件是 merged == true。从那里开始,工作流首先在 agent 启动之前,通过纯 bash 运行一个确定性的目标分支解析器:
- Pull request 里程碑标题(例如 13.4 → aspire.dev 上的 release/13.4)。
- 关联 issue 的里程碑标题(从正文中解析 Fixes/Closes/Resolves #N,获取每个 issue,取第一个非空里程碑)。
- Pull request 基础分支,如果它匹配 release/X.Y[.Z]。
- 回退到 main。
这是关键。产品仓库中的里程碑清晰地映射到文档仓库中的发布分支。当 agent 最终运行时,它确切地知道文档应该放在哪里,无需对目标分支进行任何创造性写作或猜测。agent 读取 diff,扫描关联的 issue,并决定:这需要文档吗?如果需要,它会在签出的 microsoft/aspire.dev 工作区中起草实际内容,遵循我们现有的文档编写技能(语气、MDX 约定、Starlight 组件)。然后它发出一个 create_pull_request 安全输出并移交。safe-outputs handler 接管:
- 标题前缀:[docs]
- 标签:docs-from-code
- draft: true(我们从不自动合并)
- 基础分支:agent 提供,限制为 main 或 release/*
- 目标仓库:microsoft/aspire.dev
- 审阅者:从源 pull request 的审阅中识别出的 SME——即产品团队信任批准该功能的人,现在被要求批准该功能的文档。
一个配套作业在源 pull request 上发布一个标记评论,包含文档 pull request 链接,并在重新运行时最小化任何旧的 pr-docs-check 评论。刚刚点击“合并”的工程师会在几分钟内收到通知:“这是文档草稿。看看?” 🔑 safe-outputs 契约
整个安全故事归结为一小段枯燥的前置元数据:
tools:
github:
toolsets: [repos, issues, pull_requests]
min-integrity: approved # 仅运行固定版本、完整性检查的操作
allowed-repos:
- microsoft/*
github-app:
app-id: ${{ secrets.ASPIRE_BOT_APP_ID }}
private-key: ${{ secrets.ASPIRE_BOT_PRIVATE_KEY }}
owner: "microsoft"
repositories: ["aspire.dev", "aspire"]
safe-outputs:
create-pull-request:
title-prefix: "[docs] "
labels: [docs-from-code]
draft: true # 人在回路中,始终如此
base-branch: main
allowed-base-branches: [main, release/*]
target-repo: "microsoft/aspire.dev"
protected-files: blocked # AGENTS.md、清单、安全配置:不碰
fallback-as-issue: true
这就是用纯文本达成的协议。agent 获得一个 GitHub App token,其安装范围仅限于两个仓库——产品仓库和文档仓库——组织中的其他任何东西都不可达。它只能针对 main 或 release/* 创建 pull request。AGENTS.md 和依赖清单根据策略禁止访问。如果 pull request 创建失败(网络故障、冲突等),框架会回退到提交 issue,因此不会静默丢失任何内容。这是安全审查真正喜欢的部分。agent 的推理是模糊的。但操作面不是。 📊 数据说话
以下是来自一个滚动 30 天窗口(2026 年 5 月 3 日至 6 月 2 日)的数据,涵盖了 Aspire 13.3 发布的尾声和 13.4 的筹备期:
| 指标 | 值 |
|---|---|
| 在 microsoft/aspire 中合并的产品 pull request | 396(338 main / 50 release/13.3 / 8 release/13.2) |
| pr-docs-check 工作流运行次数 | 396 |
| 在 microsoft/aspire.dev 上创建的文档草稿 pull request | 82 |
| – 已合并 | 82(100%) |
| – 未合并关闭 | 0 |
| – 仍打开 | 0 |
| 文档 pull request 目标分支 | 52 → release/13.3, 27 → release/13.4, 3 → main |
| 文档合并中位时间 | 44.8 小时 |
| 24 小时 / 7 天内合并 | 38% / 96% |
注意:数字在撰写时捕获;工作流持续运行,因此总数只会增加。
其中一些数字值得再看一眼:396 次运行 → 82 个 pull request 并非缺陷。工作流在每个合并的 pull request 上运行;大多数是内部重构、测试修复或依赖升级,没有用户可见的表面。agent 说“不需要文档”300 多次是一个特性。100% 的合并率表明 agent 的文档选择是正确的。我们在 v1 误报阶段之后发布的更精确提示正在见效。 ✅ 有效之处,❌ 无效之处(起初)
有效之处 ✅
- 里程碑 → 发布分支映射。这是我们做出的最高杠杆选择。工程师已经在 pull request 和 issue 上设置了里程碑;我们免费获得了准确的目标分支路由。
- 仅草稿,SME 作为审阅者。agent 从不合并。发布功能的工程师是确认文档正确的人。我们已经在文档层停止了反向工程功能。工程师只需在已有的地方告诉文档草稿该说什么。
- 每个工作流有范围的 GitHub app。每个工作流获得自己的 app token,具有显式的仓库和权限范围。安全审查批准了。我们也批准了;第一次需要轮换密钥时。
- protected-files: blocked。agent 不能触碰 AGENTS.md、包清单或仓库安全配置。绝对不行。
无效之处(起初)❌
- agent 的“这值得写文档吗?”门控在第一个版本中过于宽松。它为真正内部的更改起草了 pull request,例如 CI 调整或日志重构。结果是:69 个 pull request 中有 9 个被关闭(≈13%),因此我们收紧了提示中的用户可见更改定义,并添加了显式的负面示例(CI、内部辅助函数、仅测试)。现在,比率正在下降。
- 跨仓库 pull request 创建需要一个镜像签出模式,这在文档中并不明显。agent 在一个仓库中工作;safe-outputs 需要找到目标仓库来推送分支。我们通过两次签出 microsoft/aspire.dev 解决了这个问题——一次作为当前工作区,一次放在 _repos/aspire.dev 下——这样 safe-outputs handler 可以确定性地重新发现它。
- 大的 diff 会耗尽提示预算。我们在 agent 前步骤的 bash 中预先提取 pull request 元数据(关联 issue、里程碑、基础分支),这样 agent 获得一个小的结构化摘要,而不是一个巨大的负载。这是 GitHub Agentic Workflow 的设计模式,并且有效。
总结
我们做出的改变改变了我们的思维方式。一个功能在文档完成之前不被视为完成。文档不再像拴在绳子上的易拉罐一样跟在后面。工程师的审阅是门控;机器人负责打字。关键是,这并没有取代文档写作者;而是减轻了他们的负担。我们的写作者过去大部分时间都在反向工程功能。现在他们把时间花在只有人类才能做好的事情上:叙述性页面、示例程序、概念性教程、那些不会从 diff 中自动产生的文档部分。机器人处理机械性的“这个新选项已添加;这是参考页面更新”工作,这些工作对任何人来说都从未令人愉快。
衷心感谢 GitHub Next 团队提供了 GitHub Agentic Workflows(并将 safe-outputs 原语作为设计的一等公民),以及 Chris Swithinbank 和 Starlight 维护者提供了我们自动化的文档平台。也真诚感谢安全团队,他们的护栏迫使我们在第一时间以正确的方式设计。良好自动化的无聊秘密在于,强大的安全约束使系统更值得信赖、更正确。如果你在一个仓库中构建产品,在另一个仓库中发布文档——特别是如果你必须在任何非平凡的安全边界内完成——那么 GitHub Agentic Workflows 值得认真考虑。从一个工作流开始,比如 pr-docs-check,然后观察你的文档中位时间会发生什么。 🔗 其他工作流
pr-docs-check 是我写这篇文章所围绕的,但它并非单独运行。如果你对其他工作流感到好奇,源代码是公开的:
- milestone-changelog.md:每两小时运行一次,拾取活动里程碑中新合并的 pull request,并维护一个 13.x-Change-log wiki 页面(新功能、改进、显著 bug 修复),附带一个配套的编辑反馈 issue。运行 346 次。
- release-update-support-mdx.md:在稳定的 Aspire 发布时,在 aspire.dev 上起草一个 [support] pull request,更新支持政策页面(推广新版本,降级前一个版本,刷新“最后更新”徽章)。
- update-integration-data.md:位于文档仓库中;每天运行 pnpm update:all,刷新 NuGet 元数据 + GitHub 统计 + 示例数据,并打开一个 chore: Update integration data PR,带有针对陈旧运行的 supersede-and-close 逻辑。运行 27 次,合并了 8 个 pull request。
- repo-pulse.md:一个滚动的三天仓库仪表板,固定到一个 issue 并原地更新:最近的合并、等待审阅的 pull request、新 issue、讨论活动。一个 issue,始终新鲜。
祝自动化愉快,朋友们!🤖🚀
这篇文章《使用 GitHub Agentic Workflows 自动化跨仓库文档》最初出现在 GitHub 博客上。