Astro 团队在 GitHub Actions 中运行隔离 AI 子 Agent,自动复现 Bug、验证补丁并生成预览版本,将开放 Issue 数量减少了 85%。详细阐述了软件工厂的架构设计。
每个人都在谈论软件工厂:把 AI Agent 组装成流水线、自主产出可用软件的想法,就像工厂把原材料加工成成品一样。关于这是否真的可行、自动化能走多远、人们演示的那些"循环"是否有价值,争论从未停止。有些人已经断言这是失败的。
与此同时,还有一个更安静、更令人担忧的声音:开源维护者正在 burnout。AI 浪潮让生成 Issue、Pull Request 和安全报告几乎零成本,但对维护者来说,逐一阅读它们的成本却高得惊人。保持项目健康的老办法在海量数据面前正在崩塌。
每个人对这两个话题都有热门观点。我们认为自己能提供更稀缺的东西:真实的结果。过去几个月,我们一直在 Astro 仓库上运行自动化分类流水线。它读取传入的 Bug 报告、在沙箱中复现问题、诊断根本原因,并为报告者发布预览版本供其验证。支撑这套流程的引擎逐渐演变成了 Flue——一个用于构建此类 Agent 自动化的开源框架,也是你可以用来构建自己系统的同一套工具。

这不是一蹴而就的成功。但通过大量迭代,我们把开放 Issue 从 200 多个降到了大约 30 个,并有望在下个月内达到零开口。这将是该仓库 5+ 年历史上首次出现零开放 Issue。
我们没有通过宣布"Issue 破产"、自动关闭冷门工单或忽略报告来实现这一目标。我们是通过在 GitHub Actions 内部用隔离的 AI 子 Agent 团队自动化 Issue 分类来做到的。以下是我们如何做到这一点的故事,以及你可以如何将其应用到自己的项目中。
年初,我们专注于自动化一个特定的开发领域:Issue 分类。作为一个开源项目,手动分类 Issue 是工作中最耗时、回报最低的部分之一。一个 Issue 有时可能需要花费数小时才能复现,更别提修复了。这是我们自动化之旅中一个自然(但经常被忽视)的起点。
我们从开发一个 Agent Skill 开始。这让我们能够作为维护者本地开发和测试自动化,在自己的机器上运行编码工具链。然后我们可以在仓库的 GitHub Action 中运行相同的工具链,完完全全地复用同一个分类工作流 Skill。
分类 Skill 镜像了我们在手动解决 Issue 时采取的精确步骤:
复现(Reproduce):克隆提供的复现仓库以验证报告的问题。
诊断(Diagnose):对代码库进行插桩并引入日志,以查明 Bug 的根本原因。
验证(Verify):审查相关测试套件、代码注释和文档,以确定该行为究竟是 Bug 还是预期功能。
修复(Fix):将复现用例转化为失败的单元测试,通过架构指南找到合适的解决方案,并部署修复。
为了避免常见的 LLM 偏差——即当 Bug 可能并不真正存在时仍倾向于强制给出一个解决方案——每个阶段都由一个隔离的子 Agent 执行。这些子 Agent 通过将它们的发现编译成 report.md 文件来顺序传递信息。
在分类 Skill 完成初步内部测试后,我们的重点转向构建一个完全自动化的流水线。我们特别希望将这套逻辑直接集成到 GitHub Workflow 中,确保完全的透明度,让任何人都能轻松审计 Agent 的顺序推理和操作步骤。
在接线过程中,我们意识到整个流水线实际上就是一个由 Issue 标签驱动的状态机。每个新提交都从 triage needed 标签开始,一旦用户确认修复,它就会转到 fix verified。除了这些标签转换之外,流水线本身不保持任何状态;它只是回读 Issue 的现有评论,以确定当前处于什么状态、下一步应该做什么。

从那里开始,流程自行运行。当 Agent 确定了一个修复方案时,流水线会使用 pkg.pr.new 启动一个预览版本,并将所有信息发布回 Issue:它发现了什么的总结、完整日志,以及安装预览版的说明。原始报告者随后可以针对自己的项目尝试该补丁,如果他们确认有效,自动化系统就会创建一个链接到该 Issue 的 Pull Request。

在构建这个系统的过程中,我们不断注意到它没有任何部分真正特定于 GitHub。对事件作出反应、运行一系列隔离的子 Agent、将推理与它们被允许采取的行动分开——这只是 一种工作流。它可以像从 GitHub Issue 一样,同样好地从 Slack 消息、Cron 任务或 Webhook 运行。将这一认知泛化为一个无论部署在哪里、无论驱动它的模型是什么都以相同方式工作的运行时,就成为了 Flue:一个开放的、平台无关的框架,用于构建持久的 Agent 和工作流。
当我们首次推出这个自动化系统时,我们共同担心它的有效性以及它可能对我们的开发者社区产生的负面影响。有人合理地担心,依赖自动化机器人的回复可能会让人感到冷漠,并在我们作为维护者与用户群体之间制造更多隔阂。
这并没有发生。如果有什么不同的话,那就是我们现在与用户有更多的交流,只是发生在更有用的地方:
关于自动化补丁的质量,我们的核心哲学是:我们的 AI Agent 应该能够成功解决绝大多数传入的 Issue。当一个 Agent 未能找到正确的解决方案时,我们将该失败解读为代码库内部架构或文档问题的指示器,指向三个领域之一:
一个清晰的例子发生在一系列相关的热模块替换(HMR)Bug 上。分类 Bot 多次尝试修改一个特定的 if 条件来解决该问题。虽然这个更改修复了目标 Bug,但由于该特定条件缺乏测试覆盖,它在其他地方引入了回归。一旦我们添加了解释该语句确切逻辑的描述性注释,Bot 就适应了,并停止在该区域尝试不正确的修改。
每一次我们追查这些失败之一并添加缺失的注释、测试或更清晰的边界,Bot 在代码库的那部分就会明显变得更好,下一个在其上工作的人类开发者也会如此。
最初,我们的分类逻辑直接存在于 Astro 仓库内。这种耦合使得迭代变得困难;升级 Flue 或修改工作流感觉就像在没有安全网的情况下对正在运行的基础设施进行手术。为了解决这个问题,我们将逻辑解耦为一个独立的、可测试的仓库:triagebot-action。这种隔离使我们能够引入自动化测试,并在接触主代码库之前确保稳定性。
如今,这个 Action 为 Astro 的 Issue 管理提供动力,并已从那里传播开来。其他几个团队也采用了它,有些直接使用,有些则 fork 它来构建适合自己项目的自动化"工厂"。第二条路径才是真正的重点:triagebot-action 还很年轻且仍在积极发展中,所以我们分享它更多是作为一个可以阅读、学习和适应的参考,而不是作为一个成品。
Action 本身的接线看起来像这样:
- uses: withastro/triagebot-action@v1
with:
read-token: ${{ secrets.GITHUB_TOKEN }}
write-token: ${{ secrets.BOT_GITHUB_TOKEN }}
cloudflare-api-key: ${{ secrets.CLOUDFLARE_API_KEY }}
cloudflare-account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
triage-model: cloudflare-workers-ai/@cf/moonshotai/kimi-k2.7-code
verification-model: cloudflare-workers-ai/@cf/moonshotai/kimi-k2.6
triage-skill: .agents/skills/triage
或者让你的 Agent 指向该仓库,让它阅读设置说明,包括添加状态机所依赖的标签。
无论你选择哪条路径,底层的想法比我们具体的实现更重要:一种可持续的反馈循环,让维护者能够专注于框架本身而不是管理积压。代码是开放的。Fork 它、拆解它,或者只借用适合你项目的部分。
想要构建类似的东西吗?深入研究 triagebot-action 的代码来了解它的工作原理,或者 fork 它作为你自己仓库自动化的起点。如果你正在更认真地构建基于 Agent 的基础设施,那正是 Flue 的用武之地:深入了解 Flue 框架来构建你自己的系统。我们很乐意看到你构建的东西。来 Astro Discord 分享你的"工厂"故事吧。