没人讨论的端侧 LLM 问题:模型更新传播
大多数构建端侧 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 变体,就使用那个;如果两者都无法运行,则回退到云端推理。
Google 的 LiteRT-LM 通过其 Engine/Session 分离实现了这一点的实用版本。单个基础模型引擎同时服务多个应用功能,具有会话级隔离。上下文切换和写时复制(copy-on-write)KV 缓存共享允许功能共享已加载的模型,而无需为每个请求重新初始化。引擎暴露应用层可以在调度前查询的能力元数据。
回退到云端不是失败——它是让端侧 AI 可以全面部署的安全阀。在实践中有效的架构:端侧处理常规的、低敏感度的、高频的请求;云端处理复杂推理、长上下文操作,以及超出本地能力的请求。切换对用户应该是透明的。路由决策应该是确定性且可测试的,这样你就能推断哪个用户群使用哪个后端。
增量更新:带宽与一致性
如果模型更新传播是问题,增量更新似乎是显而易见的解决方案。不推送完整的 2GB 模型下载,只推送变化的参数。DeltaLLM 等类似方法利用注意力稀疏性——观察到跨连续模型版本,大多数权重变化量很小——来将更新大小减少 60-80%。
带宽计算很有说服力。一个 4 位量化的 7B 模型大约是 4GB。微调版本之间的增量更新可能是 400-800MB。对于使用按量计费连接或存储有限的用户,这是功能可用和被禁用之间的区别。
但增量更新引入了一个新的一致性问题。增量只对特定基础版本有效。如果用户 A 有版本 1.0,用户 B 有版本 1.2,那么从 1.2 到 1.3 的增量对用户 B 有效,但对用户 A 无效。你需要从 1.0 到 1.3 的增量(更大)或者为旧基础版本的用户提供完整模型下载。在碎片化的用户群中管理这个增量图,需要大多数团队在数百万设备上运行之前都没有构建的基础设施。
实践方法:对前一两个版本的用户使用增量,对其他所有人使用完整下载。实施分阶段发布,优先针对增量符合条件的用户群,在 扩展到完整下载群体之前验证质量指标。这将增量图的复杂性限制在可管理的深度,同时获取大部分带宽节省。
隐私:你在不知情的情况下同意的权衡
每次端侧部署都会做出隐私权衡,但不是大多数团队所想的那种。
显而易见的权衡:用户数据永远不离开设备,所以它永远不会出现在云端日志中,永远不会被保留用于训练,永远不会在云端泄露中暴露。对于医疗、金融和受监管行业,这通常是决策标准。当数据不移动时,GDPR 和 HIPAA 合规性在结构上变得更简单。
不那么明显的权衡:隐私保证只与更新机制一样强。如果你通过与应用更新相同的渠道推送模型更新,用户可以检查变化并审计行为差异。如果你通过动态资产交付系统推送模型更新——大多数团队都这样做,因为这将模型迭代与应用商店审核周期解耦——用户对自己设备上运行的内容能见度有限。模型更新机制成为用户隐式授予执行权限的可信但不透明的渠道。
这是一个值得进行明确架构审查的设计选择。处理得好的团队会精确记录动态资产交付系统能够和不能更新什么,实施模型完整性验证(对下载的权重进行哈希,加载前验证),并给用户一个退出路径,优雅降级到云端推理或完全禁用该功能。
