标题:为 AI SDK 打造软件工厂
原文:
Building a software factory for AI SDK
AI SDK 是全球最热门的开源 AI 项目之一,每周 npm 下载量超过 2000 万次,仓库 Stars 数超过 26,000。维护这样一个代码库,意味着要同时盯住四个不断变化的目标:
- 模型提供商:新供应商、新能力、新 Bug
- UI 框架:React、Next.js、Svelte、Vue 等框架的绑定
- 沙箱:智能体运行代码的执行环境
- 适配器:面向 Codex、Claude Code、Pi 等工具的适配层
经过几年的增长,仓库每月新增 issue 超过 100 个。等到 Anthropic 发布 Opus 4.6 模型时,PR 数量开始急剧攀升。到了 6 月底,积压的 issue 超过 1000 个,待处理的 PR 也接近 800 个。这个积压不是纪律问题——再厉害的核心维护者也不可能靠加班把它清零;而且代码生成太便宜了,积压只会越来越多。
所以,我们没有选择“把自己逼得更紧”,而是建了一座软件工厂。上线四周后,它已经能产出我们合并 PR 的 25%–35%,并关闭 70%–80% 的 issue。
建什么样的工厂,先想清楚三个问题
在动手之前,我们必须回答三个问题:
- 为什么现有的 agent 方案不够用?
- 什么样的自动化程度适合 AI SDK 这种项目?
- 如何把自动化、人力投入和风险对应起来?
为什么不多加几个 agent?
最优秀的核心维护者其实已经在大量使用 agent。Mitchell Hashimoto 运营 Ghostty 时就一直保持有一个 agent 在干活,并把 agent 每次的失败都写进 AGENTS.md,防止它重复犯同样的错误。Simon Willison 会并行跑四个编码 agent,而 Vercel Agent、CodeRabbit 这类审查机器人也部署在数百万个仓库里。当然也有维护者走另一个方向,比如 Daniel Stenberg 选择在 curl 项目中屏蔽 AI 生成的提交。
这些做法都有帮助,但都解决不了核心瓶颈:无论哪种方案,最终每个改动都要过一次人工审核。我们相信,在智能体工程里,人的责任承担依然是信任的基础。因此从一开始就知道,工厂的第一原则必须是提高审核者的效率。
什么样的自动化适合 AI SDK?
软件工厂本身也有不同的形态。
一端是完全自动化:智能体(agent)负责写代码、发布、部署,整个过程人连代码都不会看一眼。中间一档是 Codex、Claude Code 这类辅助工具,由人来指挥一个或一群智能体干活。而另一端,是几乎不敢自动化的软件,因为风险太高,比如心脏起搏器或自动驾驶汽车里的固件。AI SDK 的定位更贴近“谨慎”这一端。它是底层 AI 基础设施,上面跑着数以百万计的应用程序,质量和安全没有妥协的余地,发布什么必须由人来掌控。于是,我们希望软件工厂能把开发流程大量自动化,但始终保留人的角色。
问题来了:如何让自动化程度和工作量匹配风险?对一次具体改动而言,需要的人工审查深度应当随风险高低而变化。集中式的路线图加上详细的功能规格,可以在开工前把风险界定清楚,从而直接影响进入软件工厂的工作内容。但像 AI SDK 这样的开源项目还能收到社区提交的 issue 和 pull request,你没法保证这些贡献符合项目目标,也没法保证改动本身安全。风险越高,人为判断就越重要。为了让工厂更好地服务于这种判断,我们认为智能体不能只照着需求生成代码,还必须站在整个项目的上下文里,评估一个个完整的工作单元。我们的目标就是:让工厂对每项改动都给出全面的评估,既看它是否契合项目,也看它带来多大风险,并附上一整条可追溯的文档证据链,这样审查者就能轻松掌握该投入多少精力:
- 文档修正,扫一眼核实即可;
- 定义明确的 provider 改动,做针对性验证;
- 新增公共 API,则要做深度审查。
我们构建的成果是 ai-sdk-factory——一个能自动处理 AI SDK 社区进来的 issue 和 pull request 的软件工厂。工厂里的智能体会执行具体、可审查的任务,比如复现 bug、实现功能、为旧版 SDK 做反向移植(backport)。在整个流程中,人始终掌握控制权,包括合并每项改动。这款工厂不是一蹴而就的。
这套工厂是逐步搭建起来的。整个流程的起点,是先对 issue 做分类,判断它属于 bug、功能需求,还是文档更新。这一步不仅让我们对 backlog 的整体构成有了更清晰的认识,也为后来构建的其他专用 agent 提供了有用的上下文。我们为每一类新功能都做了多种原型方案,并在这个过程中逐渐形成了一套指导原则,最终决定了上线版工厂的架构。
一个任务对应一个 agent
当分类 agent 的准确率达到较高水平后,我们把重点转向自动化:重现 bug、修复 bug,以及审查修复结果。起初我们尝试构建一个能胜任所有步骤的单一 agent,但很快就发现,长期来看这种做法会带来不小的维护和排障负担。
于是我们改为每个具体任务对应一个独立 agent。这样一来,每一项新能力都更容易理解,也方便单独测试和调试。每个 agent 只负责一项明确的工作,拥有自己独立的提示词(prompt)、上下文和评估集(evals)。
如今,工厂里每个环节都有专职的 agent:
- Bug 重现
- Bug 修复
- PR 审查
- Backport(将修复移植到旧版本)
- 文档更新
- 功能分析
- 功能实现
安全,从第一步就做起
我们从第二个 agent 开始引入安全机制,原因是 bug 重现是工厂第一次需要根据自身无法控制的内容来执行代码。一个运行在公开仓库上的工厂,必须默认所有输入都可能来自攻击者:每一条 issue、每一个 PR、每一条评论,以及其中的链接,都不可信。
成功的开源项目往往是高价值的攻击目标,面临的威胁既包括恶意代码改动、供应链攻击,也包括资源耗尽、API 密钥窃取、提示词窃取等。沙箱是我们防御体系的基石。
ai-sdk-factory 中的每个 agent 都运行在相互隔离的 Vercel Sandbox 里,里面只包含该 agent 的代码、运行时,以及它完成特定任务所必需的密钥。有了这层护栏,不受信任的内容充其量只能左右 agent 提出的方案,而任何一个任务可能造成的破坏,都被限制在沙箱之内。
先在本地跑通,再迁移到云端
我们还在沙箱外围加了一层网络防护,用来限制智能体能访问的网络范围,堵住攻击者可能把机密信息从隔离环境里带出去的通道。最后一道防线是人工审核:没有 AI SDK 团队成员的人工批准,任何改动都不会被合并。
我们最初给工厂写的几个智能体,都是先跑在本地 CLI 上的。这样团队可以快速迭代——遇到识别不准、流程不畅、想试验不同思路,都能立刻调整。等好几个步骤都能在 CLI 上稳定运行了,我们才把整个系统搬到托管基础设施上。
ai-sdk-factory 的构成如下:
- Vercel Functions:负责 API、worker 和 webhook 接入
- Vercel Queues:负责任务执行
- Vercel Blob:存储日志
- Vercel Sandbox:提供智能体运行的工作区
- Neon Postgres:保存工厂数据
现在,GitHub 的 webhook 会把 issue 推进任务队列;一旦有新 issue 到达,worker 就会自动拉取,并在沙箱里启动智能体运行。我们还做了一个监控界面,可以并行追踪每次运行的状态,并可视化展示队列,方便审核团队查看。
软件工厂如何交付一个功能
7 月 24 日,一位社区成员在 OpenAI Web Search 里提出希望支持屏蔽域名(blocked-domain),这条请求变成了 issue #17898。下面我们看一套完整的流程:软件工厂是如何处理这个 issue、提交实现该功能的 PR,并最终把合并后的功能 backport 到 SDK 的 v5 和 v6 版本。
分类
工厂里第一个运行的智能体负责给 issue 和 PR 分类。在这个案例中,ai-sdk-factory bot 在 issue 下留了评论并打了标签,以很高的置信度判断这是一个 Feature(功能需求),还在评论里写明了分类依据。
分析
分类完成之后,分析智能体上场。工厂里的智能体不会对功能请求或 bug 的技术合理性做任何预设判断,所以分析智能体写了一个探针脚本,用来确认当前确实不支持屏蔽域名。它生成了 issue-17898-type-probe.ts 并运行,脚本在查找 blocked-domains 相关内容时没有找到,于是报错退出。
失败的探测证明该功能确实缺失于 main 分支,代理把这一结果作为证据写进了分析。随后,分析代理根据调查结果整理出功能规格:在现有网络搜索工具中增加一个可选的 blockedDomains 过滤器,并映射到提供商的 blocked_domains 字段。代理还确认,这一规格符合 SDK 的 provider-adapter(提供商适配器)架构,且向后兼容,连文档改动范围也一并规划好了。
实现
另一个代理随后按规格实现了功能,并提交了拉取请求。实现代理跑了一次真实的端到端测试:用屏蔽 wikipedia.org 的配置执行 OpenAI 网络搜索,确认该域名确实无法访问。这次测试结果也作为补充证据附在拉取请求上。
自动审查
接下来,审查代理对这次改动打分,没有发现任何问题,于是予以通过。它给出的评级是:功能已完整实现,且——
- 副作用风险:低
- 性能风险:无
- 向后兼容风险:低
人工审查
最后,Lars 通读了各代理留下的证据链,审查了代码改动,把 PR #18033 合并进了 main 分支。
向后移植
Lars 合并初始 PR 后,ai-sdk-factory 又开了两个向后移植的 PR:#18035(针对 v6)和 #18036(针对 v5)。v5 的移植没能干净地应用,工厂代理便标记并提交了冲突状态,随后定位并验证了修复方案,17 分钟后推送了修复。Lars 审查后,把两个向后移植的 PR 都合并了。
结果
软件工厂投入生产运行刚过四周,这期间的成绩如下:
合并到 main 的 PR:我们每周合并的 PR 中,有 25%–35% 出自 ai-sdk-factory 代理之手。
向后移植:工厂生成的 PR 占每周合并到 v6 版本线的一半以上,v5 的情况也差不多。过去,向后移植是我们常跳过不做的活儿,因为处理合并冲突实在不划算。如今 v5 和 v6 得到的支持比以往好得多。
问题处理:7 月份,超过 75% 的已关闭 issue 是由工厂关闭的。开放 issue 数量从 6 月底的峰值 1,022 个降到了 8 月初的 844 个,未解决的 bug 也减少了大约 25%。
ai-sdk-factory 是公开运行的,所以你在仓库里能看到它提交的每一个 pull request。改进工厂本身,就是这个工作的核心。运营这个工厂最有趣的部分,是看它失败时会发生什么。
每次运行只有四种结局:成功(success)、有缺陷(flawed)、阻塞(blocked)、人工处理(manual)。只有成功的结果会发布上线,其余三种都会作为反馈信号重新进入系统:
- 有缺陷:说明智能体产出了错误的结果。修复方式是改进提示词(prompt)、补充上下文,或者新增一条评测(eval)用例,让同样的错误下次能被自动发现。
- 阻塞:说明环境里缺了东西,比如某个凭证、服务或依赖。修复方式是把缺的资源补齐。
- 人工处理:这是我们刻意画下的一条边界,它会逼着我们反思:工厂改进到一定程度后,这条边界是否还值得保留。
每修复一类问题,自动化边界就向外扩展一步。每个星期,工厂都能接手一些之前还不敢交给它的工作。
运营工厂这件事,和团队平时维护测试套件、构建流水线是同一套纪律,只是对象从「检查工作的系统」变成了「执行工作的系统」。当智能体开始定义软件开发生命周期(SDLC)时,改进工厂将成为工程师的标准工作。
阅读更多