我们如何构建一个软件工厂,将 Astro 的 GitHub 问题数降至零

每个人都在谈论软件工厂:即 AI 代理可以被组装成一条流水线,自主生产出可工作的软件,就像工厂将原材料转化为成品一样。关于这是否真的可能、自动化究竟能走多远,以及人们演示的“循环”是否有意义,存在着无休止的争论。有些人已经将其视为失败。
与此同时,还有一个更安静、更令人担忧的话题:开源维护者正在精疲力竭。AI 热潮使得生成问题、拉取请求和安全报告几乎零成本,而维护者阅读所有这些内容却代价高昂。维持项目健康的旧方法在如此大的数量下不堪重负。
每个人对这两个话题都有自己的看法。我们认为我们有一些更罕见的东西可以提供:实际结果。在过去的几个月里,我们在 Astro 仓库上运行了一个自动化的分类流水线。它读取传入的错误报告,在沙盒中复现它们,诊断根本原因,并发布预览版本供报告者验证。其底层引擎发展成了 Flue,一个用于构建此类代理自动化的开放框架,你也可以使用同样的工具来构建你自己的自动化。

这并非一蹴而就。但通过大量的迭代,我们已将其用于将未解决的问题从 200 多个减少到约 30 个,并预计在下个月的某个时候达到零。这将是该仓库在其 5 年多的历史中首次出现零未解决问题。
我们不是通过宣布“问题破产”、自动关闭冷门票或忽略报告来实现这一目标的。我们是通过在 GitHub Actions 中运行一组隔离的 AI 子代理来自动化问题分类来实现的。以下是我们如何达到这一目标的故事,以及你可以从中借鉴到自己的项目中的经验。
从代理技能开始
今年年初,我们专注于自动化开发的一个特定领域:问题分类。作为一个开源项目,手动问题分类可能是工作中最耗时、最无回报的部分之一。单个问题有时可能需要数小时才能复现,更不用说修复了。这是我们开始自动化之旅的一个自然(但经常被忽视)的地方。
我们首先开发了一个代理技能。这使我们作为维护者可以在本地开发和测试自动化,在我们自己的机器上运行编码框架。然后,我们可以在我们的仓库上的 GitHub Action 中运行相同的框架,并完全重用完全相同的问题分类工作流技能。
分类技能反映了我们在手动解决问题时采取的确切步骤:
复现:克隆提供的复现仓库以验证报告的问题。诊断:对代码库进行插桩并引入日志记录,以查明错误的根本原因。验证:审查相关的测试套件、代码注释和文档,以确定该行为是真正的错误还是预期功能。修复:将复现转换为失败的单元测试,通过架构指南确定适当的解决方案,并部署修复。
为了防止 LLM 在 bug 可能并不存在时频繁倾向于强行给出解决方案,每个阶段都由一个隔离的子代理执行。这些子代理通过将他们的发现编译到 report.md 文件中,按顺序向前传递信息。
将技能转化为自动化
在对分流技能进行初步内部测试后,我们的重点转向构建一个完全自动化的流水线。我们特别希望将此逻辑直接集成到 GitHub 工作流中,确保完全透明,以便任何人都能轻松审计代理的顺序推理和操作步骤。
当我们连接起来时,我们意识到整个流水线实际上只是一个由问题标签驱动的状态机。每个新提交都以标签“需要分流”开始,一旦用户确认修复,它就会变为“修复已验证”。除了这些标签转换之外,流水线本身不持有任何状态;它只是通过读取问题的现有评论来确定给定问题所处的位置以及接下来应该发生什么。

从那里,流程自行运行。当代理找到修复方案时,流水线会使用 pkg.pr.new 生成一个预览版本,并将所有内容发布回问题:它发现的摘要、完整日志以及安装预览的说明。原始报告者随后可以针对自己的项目尝试补丁,如果他们确认有效,自动化系统会打开一个链接到该问题的拉取请求。

从分流到框架
在构建过程中,我们不断注意到其中没有任何东西是特定于 GitHub 的。响应事件、运行一系列隔离的子代理,并将它们的推理与它们被允许采取的行动分开——这一切都只是一个工作流。这个工作流可以同样轻松地从 Slack 消息、cron 作业或 webhook 中运行,就像从 GitHub 问题中运行一样。将这一认识推广为一个运行时,无论部署在哪里,或驱动哪个模型,都以相同的方式工作,这就是 Flue 的由来:一个开放的、与平台无关的框架,用于构建持久的代理和工作流。
代理自动化的好处
当我们首次推出这个自动化系统时,我们对它的有效性以及可能对我们的开发者社区产生的潜在负面影响有所担忧。有一种合理的担忧是,依赖自动化的机器人回复可能会显得缺乏人情味,并在我们作为维护者与用户群之间造成又一层隔阂。
这种情况并没有发生。相反,我们现在与用户的交流更多了,只是在更有用的地方:
- 在 Discord 中直接与我们的社区成员互动。
- 积极参与 RFC 讨论并处理新的功能请求。
- 与贡献者密切合作,帮助将他们的想法整合到框架中。
关于自动化补丁的质量,我们的核心理念是,我们的 AI 代理应该成功解决绝大多数传入的问题。当代理未能找到正确的解决方案时,我们将这种失败解释为代码库中潜在架构或文档问题的指标,指向以下三个领域之一:
- 不透明抽象:如果代理无法解释组件之间的边界,人类开发人员很可能也会对代码结构感到困惑。
- 缺少文档:关键代码段缺乏解释其实现原理的明确注释。
- 测试不足:仓库缺乏全面的测试覆盖,尤其是单元测试。
一个明显的例子发生在一系列相关的热模块替换(HMR)错误中。分流机器人反复尝试修改特定的 if 条件以解决问题。虽然此更改修复了目标错误,但由于缺乏对该特定条件的测试覆盖,它在其他地方引入了回归。一旦我们添加了描述性注释,解释控制该语句的确切逻辑,机器人就适应了,并停止在该区域进行不正确的修改。
每次我们追查这些失败之一并添加缺失的注释、测试或更清晰的边界时,机器人都会在代码库的那部分明显变得更好,下一个处理它的人类也是如此。
将工作流转变为 GitHub Action
最初,我们的分流逻辑直接存在于 Astro monorepo 中。这种耦合使得迭代变得困难;升级 Flue 或修改工作流感觉就像在没有安全网的情况下对实时基础设施进行手术。为了解决这个问题,我们将逻辑解耦到一个独立的、可测试的仓库中:triagebot-action。这种隔离使我们能够引入自动化测试,并在触及我们的主要代码库之前确保稳定性。
如今,这个 action 为 Astro 中的问题管理提供支持,并且已经从那里传播开来。其他几个团队已经采用了它,有些直接使用,有些则分叉它来构建适合其项目的自动化“工厂”。第二条路径才是重点: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
或者,将你自己的代理指向该仓库,让它通读设置,包括添加状态机所依赖的标签。
无论你选择哪条路线,核心理念比我们的具体实现更重要:一个可持续的反馈循环,让维护者能够专注于框架本身,而不是管理积压的事务。代码是开放的。你可以分叉它、精简它,或者只借用适合你项目的部分。
想要构建类似的东西?深入研究 triagebot-action 的代码,了解它是如何工作的,或者将其分叉作为你自己仓库自动化的起点。如果你正在更认真地构建基于代理的基础设施,那正是 Flue 的用途:深入 Flue framework 来构建你自己的。我们很期待看到你的成果。来 Astro Discord 分享你的“工厂”故事吧。
