跳到主要内容

没人讨论的端侧 LLM 问题:模型更新传播

· 阅读需 13 分钟
Tian Pan
Software Engineer

大多数构建端侧 LLM 功能的工程师,将时间花在解决那些显而易见的问题上:量化、延迟、内存限制。模型能装进手机,推理速度够快,演示效果也很好看。然后他们向数百万台设备发布,才发现一个更难的问题——从来没人提前告诉他们:你现在有数百万个独立的计算节点,运行着你 AI 模型的不同版本,而你根本没有可靠的方式知道任何一个用户运行的是哪个版本。

云端推理在最好的意义上是无聊的。你更新模型,重新部署服务器,几分钟内整个用户群就都在运行新版本了。端侧推理则彻底打破了这个假设。一个三个月前最后一次打开你应用的用户,仍在运行那时当前的模型——而且没有干净的方法强制更新,没有服务器端回滚,也没有简单的方法在没有你从一开始就构建的监控埋点的情况下检测到版本不匹配。

这种版本碎片化是端侧 AI 的核心运营挑战,其后果远不止缓慢的发布。它造成无声的能力漂移,使事故响应复杂化,并将你的"AI 功能"变成一个由独立运行的异构系统组成的庞大集群——你对其负责,却无法直接控制。

端侧更新为什么从根本上不同

移动应用更新和模型更新在纸面上看起来相似:一个新的二进制文件发布出去,设备最终会下载它,用户更新后获得新版本。但在实践中,其动态完全不同。

应用更新是二元的。用户要么拥有新版本应用,要么拥有旧版本。两个版本之间的行为差异在 UI 变化和发布说明中是可见的。用户和支持团队都能理解。

模型更新是持续且无形的。LLM 的"行为"不是一组离散的功能——它是关于输出的概率分布。两个模型版本对大多数输入可能产生表面上相似的响应,但在边缘情况、对抗性提示,或新版本经过微调的特定领域上却可能大相径庭。遇到这种漂移的用户无法诊断它。你的支持团队无法将其与版本关联。你的监控面板显示的是平均质量指标,这可能根本无法发现退化的用户群。

更新采纳曲线使这个问题更加严重。对于典型的移动应用,50% 的用户在发布后一周内更新;80% 在一个月内。对于嵌入应用中的模型,采纳率遵循应用的更新曲线,而非模型特有的曲线。如果你的应用每月发布而模型每周更新,大多数用户总是在运行至少落后几周的模型。对于那些选择退出自动更新的用户——iOS 和 Android 上这是一个相当大的比例——差距可能延伸到数月乃至数年。

Meta 在 Instagram、WhatsApp 和 Facebook 上部署 ExecuTorch 说明了这种规模:数十亿用户,设备从去年的旗舰机到六年前的中端机各不相同,每台设备可能运行着不同的量化变体。运营面不是一个模型版本——而是一个随着每次发布组合式增长的"模型版本 × 硬件能力 × 操作系统版本"矩阵。

制品集合问题

版本碎片化比最初看起来更糟,因为"模型"并非单一制品。在生产环境中,一个可工作的端侧 AI 功能是以下各项的组合:

  • 基础模型权重(量化为 4 位、2 位或特定硬件格式)
  • 叠加其上的任何微调 LoRA 适配器
  • 系统提示或提示模板
  • 分词器及其词汇表
  • 如适用,检索索引或向量存储
  • 推理运行时本身(llama.cpp、MLC-LLM、ExecuTorch、MLX)

当其中任何一个组件更新而其他组件未更新时,整个系统的行为可能以难以预测、更难调试的方式改变。一个在没有相应提示模板更新的情况下发布的基础模型更新,在更新后的提示上可能表现异常。针对模型版本 N 训练的 LoRA 适配器应用于模型版本 N+1 时,可能悄悄产生退化的输出——不是崩溃,只是错误的答案。

云端推理规避了这个问题,因为整个制品集合是原子式协同部署的:更新容器,一切都一起更新。在端侧,每个组件可能通过不同的渠道按不同的时间表交付。应用商店交付运行时和基础模型;动态资产交付系统可能单独推送更新的适配器;系统提示可能从远程配置服务获取。这些组件之间的一致性不是有保证的——它必须被刻意设计出来。

实践建议:将整个制品集合作为一个单元进行版本管理。为(模型检查点、适配器权重、提示模板、分词器、运行时版本)这个元组分配一个单一的语义版本。在发布任何组件之前,将兼容性作为一个包进行验证。在遥测数据中存储完整的版本元组,这样当质量回退出现时,你就能识别出是哪个制品集合负责。

能力协商与优雅降级

模型更新传播问题有两种需要不同应对措施的失败模式。

第一种是单一版本下的能力漂移:同一版本上的用户因为硬件差异(热节流、内存压力、NPU 可用性)产生不一致的输出。一台全新启动、处于凉爽环境、有 8GB 空闲内存的 iPhone 17 Pro,与同一款手机在经过 20 分钟高负荷使用后、热节流将持续吞吐量降低 40% 的状态下,运行同一模型产生的输出不同。

第二种是跨用户群的版本不匹配:不同版本上的用户产生的输出反映了不同的模型能力,而用户完全没有可见的信号表明这正在发生。

这两个问题都通过借鉴网络协议设计的一种模式来(不完美地)解决:能力协商。在模型运行之前,应用程序查询设备实际能做什么——不是它理论上支持什么,而是它在当前可用内存、散热状态和已安装模型版本下能持续做什么。然后应用程序路由请求以匹配。如果设备支持最新的 7B 模型,就使用它;如果只能可靠运行 1B 变体,就使用那个;如果两者都无法运行,则回退到云端推理。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates