GitHub 关闭 Models 服务的案例凸显 AI 架构风险:过度依赖外部 AI 服务导致突然中断;程序员应通过可替换的集成接口隔离供应商风险。
一个 AI 功能看起来可以永久存在——直到服务商把招牌从大楼上拆下来。
GitHub Models 在 7 月 30 日迎来了这一刻。GitHub 此前宣布,playground、模型目录、inference API 和自带密钥(BYOK)端点将对现有客户全部停用,而不只是停止接纳新用户。
在此前 24 小时内,我没有发现更重大的 AI 或开发者工具动态,因此把观察窗口扩大到了七天。这次关停发生在三天前。
GitHub 建议开发者转向 Microsoft Foundry 获取模型访问能力,或者使用 GitHub Copilot,在 GitHub 内完成 AI 工作流。这是合理的迁移路径。但对初学者而言,真正值得吸取的教训,并不只是该选择哪个替代方案:
外部 AI 服务应该为某项功能提供能力,而不应该决定整个应用的形态。
昨天,我写了如何根据瓶颈选择 AI 编程模型。接下来要考虑的,就是这个架构问题。即使你选择了一个合理的模型或服务,它也可能发生变化、涨价、取消某项功能、迁移到另一个产品,甚至彻底消失。
你不需要一支企业级架构团队来为此做准备。你只需要留出一个可以替换的接缝。
GitHub 的停用通知异常具体。7 月 30 日之后,GitHub Models 的界面和 API 将不再可用,其中也包括 BYOK。GitHub 甚至在正式停用前安排了几次短暂的服务中断,让开发者提前看到故障发生时会是什么样子。
最后这个细节非常重要。brownout 不只是一次不便,更是一次架构测试。
如果一个 AI 端点失效,就会导致整个应用无法使用,那么你的应用很可能知道了太多本不该知道的端点细节。
支付、地图、邮件、分析、存储和身份认证都会遇到同样的问题。只不过 AI 服务更容易让人忽略它,因为第一次集成往往实在太快了。你安装一个 package,粘贴一把密钥,在某个页面里调用模型,然后看到文本出现,便开始庆祝。
接着,原型变成了产品,曾经的捷径也变成了承重钢梁。
Vendor lock-in 并不意味着“使用供应商”。每一个真正有用的应用,都依赖其他人开发的软件。
当供应商特有的细节开始四处扩散时,问题才真正出现:
模型名称写在 UI 组件里
多个页面里复制了相同的 API 调用
供应商的响应对象变成了应用自身的数据模型
报错信息未经处理,直接展示给用户
prompt 混进了按钮的事件处理函数
没有记录这项功能究竟应该返回什么
到了这一步,更换供应商就不再是一项集成任务,而是一场考古发掘。
走向另一个极端同样是错误的。初学者可能会花两周时间搭建一个宏大的多供应商框架,却还没有验证哪怕一个用户是否需要这项功能。这只是架构角色扮演。
真正的目标要小得多:把不稳定的依赖放到一个尽可能窄、同时又足够实用的契约后面。
如果你还在尝试把一个粗糙的应用想法变成一条可以落地的工作流,我已经免费开放了 AI App Builder Starter Prompts,帮助你在选择 AI 服务之前,先明确用户、结果、输入、约束和验证方式。
假设你正在开发一款笔记应用,其中有一项功能,可以把一篇很长的笔记转化成三个行动项。
用户旅程很简单:
用户打开一篇已经保存的笔记。
用户点击“查找行动项”。
应用返回零到三个简短的行动项。
用户可以接受、编辑或丢弃每一个行动项。
除非用户确认,否则原始笔记永远不会发生变化。
这就是产品契约。为了实现它,页面完全不需要知道供应商、模型名称、SDK 或原始响应格式。
下面是我会如何让这项集成保持可替换性。
可以把它命名为 extractActionItems(noteText) 之类的名称。
不要用供应商的名字来命名主函数。应用的其他部分关心的是结果,而不是由哪家公司生成了这个结果。
行动项的最大数量
一个由行动项字符串组成的数组
complete、empty 或 unavailable 等状态
一条可以安全展示在 UI 中的信息
在页面看到结果之前,你的应用应该先对它进行验证。供应商的响应对象只是抵达边界的证据,而不是你内部的宪法。
由一个 server route、service 文件或 backend function 统一持有供应商的 SDK 和模型标识符。
UI 调用你的能力,你的能力调用 adapter,再由 adapter 将外部响应转换成你定义的输出结构。
Vercel 的 AI SDK 文档通过标准化的语言模型接口阐述了同样的基本思路。它的供应商管理指南更进一步,引入了中心 registry、alias 和多个供应商。你不一定要使用这个库。真正重要的设计原则是集中管理:切换供应商的操作应该只发生在一个明确的位置。
不要把供应商密钥发送到浏览器或移动应用中。应当把它们保存在服务器端,或者安全的 backend function 中。
同时,还要把选定的供应商和模型放在配置里,而不是散落到各处的功能代码中。更换模型不应该要求你修改五个按钮和三个页面。
保留三个能够代表这项功能的小型示例:
一篇包含两个明确行动项的普通笔记
一篇不包含任何行动项的笔记
一篇混乱的笔记,可能会诱使模型凭空编造行动项
为每个 fixture 写下可以接受的结果。每次更改 prompt、模型或供应商时,都重新运行这几个 fixture。
这不是一个完美的 benchmark,而是针对具体产品设计的迁移测试。
提前决定当供应商请求超时、拒绝请求、达到限制或直接消失时,用户会看到什么。
对这款笔记应用来说,产品的其余部分应该仍然能够正常运行。用户依然可以阅读和编辑笔记。行动项功能可以提示暂时不可用,但不能破坏数据,也不能让用户被一个永远转动的 spinner 困住。
GitHub 在正式停用前安排的 brownout 给了我们一个很好的提醒:趁时间还由你掌控时,主动测试故障场景。
在哪里调用了供应商
需要哪些环境变量
输入和输出契约是什么
三个迁移 fixture 是什么
依赖了哪些供应商特有的功能
服务中断时用户会经历什么
这样一页说明,就足以避免未来迁移时从“这东西到底接在哪里?”开始调查。
你可以让自己的 AI 编程工具检查项目,并在不修改代码的前提下回答以下问题:
应用在哪里调用 AI 供应商?
有多少个文件包含供应商名称或模型名称?
UI 是否直接导入了供应商 SDK?
供应商的输出是否未经验证,就流入了应用的持久化数据?
如果所有 AI 请求连续失败一小时,哪些功能仍能正常工作?
能够容纳这项依赖的最小边界是什么?
哪三个 fixture 可以证明替代方案的表现足够好?
然后让工具生成一份迁移计划,并加上一条约束:保留现有用户旅程,同时尽可能少地修改面向产品的文件。
免费的 AI App Builder Starter Prompts 可以帮助你先定义好这条工作流及其验证方式,再让工具开始挪动代码。
供应商边界并不是没有代价的。
不同模型和服务支持的工具、上下文长度、结构化输出行为、安全控制、延迟和定价各不相同。如果强迫所有供应商都迁就最低公分母,你可能会失去让最初选择变得有价值的那项功能。
因此,我不会假装所有供应商都完全一样。
让产品契约保持稳定,但允许 adapter 内部存在供应商特有的设置。如果某个供应商支持一项有用的能力,那就有意识地使用它,并在退出说明中记录下来。替代方案可以采用不同的实现方式,只要它仍能保证用户获得同样的结果。
路由层同样可以提供帮助,但它也会引入另一项依赖。例如,Vercel 的 AI Gateway 路由规则可以把请求从一个模型改写到另一个模型,而不需要修改应用代码。这可以提升故障恢复能力,但你仍有责任验证目标模型能否继续生成可以接受的结果。
规则并不是“永远不要依赖任何东西”。
而是“弄清楚依赖在哪里结束,你的产品又从哪里开始”。
在你的应用里选择一项外部服务。它可以是 AI、邮件、支付、地图或存储。
你的页面 → 你的能力 → 外部供应商
如果你无法画出这些边界,因为供应商细节到处都是,也不要今晚就重写整个项目。选择一条用户工作流,写清楚它的输入和输出,把外部调用移到一个接缝后面,再保存三个 fixture。
对于第一份迁移计划来说,这些架构设计已经足够。
如果你希望立刻获得引导式操作,可以从免费的 AI App Builder Starter Prompts 开始。如果你想获得一条从想法走向发布的完整、有组织的路径,可以选择我的 19 美元实战手册 AI App Builder From Zero,其中涵盖范围界定、技术栈、架构、prompt、QA、部署和发布。
你也可以在以下平台找到我:
Medium:marcusykim
DEV.to:marcusykim
个人网站:marcusykim.com
X:marcusykim
LinkedIn:marcusykim
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。