☰
端侧LLM部署实战:模型选型、量化压缩与推理引擎优化指南
2026/10/2 11:12:09 网站建设 项目流程

端侧 Agent 这件事,真正落到工程上,第一个绕不开的坎就是:模型到底怎么塞进设备里。我见过太多团队在云端把 Agent 跑得风生水起,一到端侧就卡在部署环节——显存不够、量化掉点、推理延迟飙到没法用。这一篇就专门聊端侧 LLM 部署这件事,从模型选型、量化压缩、推理引擎到内存调度,把我自己踩过的坑和验证过的方案完整摊开讲。不管你是刚接触端侧 AI 的新手,还是已经在 RK3588、Jetson Orin 这类板子上折腾过的老手,下面这些内容应该都能帮你少走几段弯路。

1. 端侧 LLM 部署到底难在哪

1.1 端侧和云端的本质差异不是"小一点"

很多人第一次做端侧部署,脑子里想的是"把云端那套缩小版搬过来就行"。这个认知会让你在第一个月就撞墙。端侧和云端的差异不是规模问题,是约束条件完全不同。

云端部署 LLM,你关心的是吞吐、并发、GPU 利用率,显存不够就加卡,带宽不够就加节点。端侧呢?内存是焊死的,算力是固定的,功耗有硬上限,散热靠被动方案。你面对的是一个封闭系统,所有资源都是零和博弈——模型多占 100MB 内存,留给 KV Cache 的就少 100MB,直接影响能支持的上下文长度。

更关键的是,端侧设备通常没有独立的显存。CPU、GPU、NPU 共享同一块物理内存,这意味着模型权重、激活值、KV Cache、系统进程全在抢同一池子。你在云端习惯的"显存不够就 offload 到内存"这套玩法,在端侧直接失效,因为内存本身就是瓶颈。

1.2 三个硬约束:内存、算力、功耗

我把端侧部署的约束归纳成三条线,任何一条踩线都会导致方案不可用。

内存墙是最先撞上的。一个 7B 参数的模型,FP16 精度下光权重就要 14GB,这还没算 KV Cache 和运行时开销。而主流端侧设备的可用内存通常在 4GB 到 16GB 之间,还要分给操作系统和其他应用。所以模型压缩不是可选项,是必选项。

算力墙决定了你的推理速度上限。端侧 NPU 的算力通常标称几十 TOPS,但实际能跑 LLM 的效率要打很大折扣,因为 LLM 是访存密集型任务,不是纯计算密集型。很多 NPU 标称算力很高,但内存带宽跟不上,实际 token 生成速度惨不忍睹。

功耗墙是最容易被忽略的。设备跑起来发热,一发热就降频,一降频延迟就上去。我实测过某款开发板,冷机状态下能跑到 15 tokens/s,连续跑十分钟后掉到 6 tokens/s,就是因为温控降频。所以做端侧部署,散热设计必须和模型选型一起考虑。

1.3 一个真实的部署失败案例

说个我自己的经历。早期做一个端侧语音助手项目,选了个 13B 的模型,想着量化到 4bit 应该能塞进 8GB 内存。理论计算:13B × 0.5 字节 ≈ 6.5GB,加上 KV Cache 和运行时,8GB 勉强够。

实际部署上去,模型加载就失败了。排查发现几个问题叠加:量化后的模型实际占用比理论值高 15% 左右,因为有些层没法量化到 4bit,得保留 8bit 甚至 FP16;运行时框架本身有 500MB 到 1GB 的开销;KV Cache 在长上下文场景下能吃掉 1GB 以上。三项一加,直接爆内存。

最后降到 7B 模型才跑通。这个教训让我明白:端侧部署的内存预算,理论值至少要留 40% 的余量,否则一定翻车。

2. 模型选型:不是越小越好,也不是越大越强

2.1 参数量、量化精度、内存占用的三角关系

选模型本质上是在参数量、量化精度、内存占用之间找平衡点。我整理了一个实用的对照表,基于实际部署经验,不是理论值。

参数量FP16 内存8bit 内存4bit 内存适用设备内存
1.5B3GB1.5GB0.8GB2GB+
3B6GB3GB1.6GB4GB+
7B14GB7GB3.8GB8GB+
13B26GB13GB7GB16GB+
34B68GB34GB18GB32GB+

注意这里的 4bit 内存是含运行时开销的实测值,比纯权重大概多 10% 到 20%。选型时先看设备可用内存,再倒推能上多大的模型。

2.2 小模型的能力边界在哪里

很多人对小模型有误解,觉得 3B 以下就是玩具。实际上在特定任务上,小模型经过微调后完全可用。关键是要认清小模型的能力边界。

我实测下来,1.5B 到 3B 这个区间的模型,适合做这几类任务:意图识别和分类、简单的信息抽取、固定格式的文本生成、作为 Agent 的 router 层做任务分发。不适合做:复杂推理、多步规划、长文本理解、需要世界知识的问答。

7B 是个分水岭。7B 模型在量化到 4bit 后,能在 8GB 设备上跑,同时具备基本的推理能力和指令遵循能力,可以作为端侧 Agent 的主模型。13B 以上在端侧就比较尴尬了,要么设备内存够大,要么只能跑很低的量化精度,掉点严重。

2.3 选型时容易忽略的隐性成本

除了内存,还有几个隐性成本必须算进去。

Tokenizer 的开销。不同模型的 tokenizer 效率差异很大,同样一段中文,有的模型切成 50 个 token,有的切成 80 个。token 数直接决定推理时间和 KV Cache 大小。选型时一定要用你的真实业务语料测一下 tokenizer 效率。

上下文长度。标称支持 32K 上下文,不代表端侧能跑 32K。KV Cache 大小和上下文长度成正比,7B 模型在 4bit 量化下,32K 上下文的 KV Cache 能吃掉 2GB 以上内存。端侧实际能用的一般是 2K 到 8K。

推理框架的适配程度。有些模型架构新,推理框架还没做好优化,跑起来效率很低。选型时优先选社区支持好、有成熟端侧部署案例的模型架构。

3. 量化:端侧部署的核心技术

3.1 量化到底在做什么

量化的本质是用更少的比特表示权重和激活值。FP16 用 16 位表示一个数,INT8 用 8 位,INT4 用 4 位。位数越少,内存占用越小,但精度损失越大。

用一个生活化的类比:FP16 像是用一把刻度很细的尺子量东西,INT4 像是用一把只有几个刻度的尺子。大部分时候够用,但遇到需要精确测量的场景就会出问题。

量化的核心挑战是:如何在压缩的同时,尽量保留模型的能力。这里的关键是找到权重分布中的"重要区域",对这些区域用更高的精度,不重要的区域大胆压缩。

3.2 主流量化方案对比

目前端侧常用的量化方案有这么几类,我按实际使用体验做个对比。

GPTQ是训练后量化,用校准数据集来最小化量化误差。优点是压缩率高,4bit 下效果不错;缺点是需要校准数据,量化过程比较慢,而且对校准数据的选择敏感。

AWQ的核心思路是保护"重要权重",通过激活值分布识别出对输出影响大的权重通道,对这些通道保留更高精度。实测下来 AWQ 在 4bit 下的效果通常比 GPTQ 好一点,尤其是对指令遵循能力的保留。

GGUF是 llama.cpp 生态的格式,支持多种量化等级,从 Q2 到 Q8。它的优势是灵活,可以根据设备内存选不同等级,而且 CPU 推理优化做得好。端侧如果 NPU 支持不好,用 GGUF 走 CPU 推理是个稳妥选择。

动态量化是在推理时实时量化激活值,权重保持较高精度。这种方式精度损失小,但推理时有额外计算开销,端侧不一定划算。

方案压缩率精度保留量化速度端侧适配
GPTQ高中慢好
AWQ高较好中好
GGUF灵活好快很好
动态量化中很好快一般

3.3 量化掉点的真实表现和补救

量化一定会掉点,关键是掉在哪里。我的经验是:量化对模型的影响不是均匀的,有些能力掉得厉害,有些几乎不受影响。

掉得厉害的是:数学计算、代码生成、需要精确记忆的任务。这些任务对权重的细微变化敏感,量化后错误率明显上升。

掉得少的是:文本分类、情感分析、简单的信息抽取。这些任务对精度要求没那么高,量化后基本能用。

补救手段有几个。一是混合精度量化,对敏感层保留 8bit,其他层用 4bit。二是量化后做轻量微调,用少量数据把掉的能力找回来一部分。三是 prompt 工程补偿,在提示词里加更多约束和示例,引导模型输出正确格式。

我实测过一个 7B 模型,4bit 量化后在数学题上准确率从 65% 掉到 42%,但经过 500 条数据的 LoRA 微调后恢复到 58%。这个恢复程度在端侧场景下已经够用了。

4. 推理引擎:选对了省一半力气

4.1 端侧推理引擎的几种路线

端侧 LLM 推理引擎大致分三条路线,各有适用场景。

通用推理框架比如 ONNX Runtime、TensorFlow Lite,优势是跨平台、生态成熟,缺点是针对 LLM 的优化不够深,KV Cache 管理、注意力计算这些没有专门优化。

LLM 专用框架比如 llama.cpp、MLC-LLM、MNN,这些是专门为 LLM 设计的,在内存管理、量化支持、注意力计算上做了大量优化。端侧部署优先考虑这类。

厂商 NPU 工具链比如各家芯片厂商提供的推理 SDK,能充分利用 NPU 算力,但适配成本高,模型转换麻烦,而且不同厂商的工具链差异很大。

4.2 llama.cpp 在端侧的实战配置

llama.cpp 是我在端侧用得最多的方案,这里给一份实测可用的配置。

编译时关键选项:

cmake -B build \ -DCMAKE_BUILD_TYPE=Release \ -DLLAMA_CURL=OFF \ -DGGML_OPENMP=ON \ -DGGML_BLAS=ON \ -DGGML_BLAS_VENDOR=OpenBLAS

运行时的关键参数:

./llama-cli \ -m model-q4_k_m.gguf \ -c 4096 \ -n 512 \ -t 4 \ --mlock \ --no-mmap \ -ngl 0

几个参数的解释:-c 4096是上下文长度,端侧建议不要超过 8K;-t 4是线程数,一般设成物理核心数;--mlock锁定内存防止被换出,端侧内存紧张时慎用;--no-mmap禁用内存映射,加载慢但运行时更稳定;-ngl 0表示不用 GPU 层,纯 CPU 推理,如果有 GPU 可以调大。

4.3 NPU 加速的坑与收益

用 NPU 跑 LLM 听起来很美,实际有不少坑。

第一个坑是算子支持不全。LLM 里有些算子 NPU 不支持,会 fallback 到 CPU,导致频繁的数据搬运,反而比纯 CPU 还慢。部署前一定要确认模型的所有算子都能在 NPU 上跑。

第二个坑是量化格式不匹配。NPU 通常要求特定的量化格式,比如 INT8 对称量化,而你在 PC 上量化好的模型可能不兼容,需要重新量化。

第三个坑是动态 shape 支持差。LLM 推理时序列长度是变化的,很多 NPU 对动态 shape 支持不好,要么固定长度浪费算力,要么频繁重编译。

收益方面,如果算子适配好、量化格式对,NPU 相比 CPU 能有 2 到 5 倍的加速。但这个收益需要投入大量适配工作,项目周期紧的话,先用 CPU 方案跑通,再逐步优化 NPU 是更稳妥的路径。

5. 内存管理与 KV Cache 优化

5.1 KV Cache 为什么是内存杀手

KV Cache 是 Transformer 推理时缓存的历史键值对,避免重复计算。它的存在让自回归生成成为可能,但也带来了内存问题。

KV Cache 的大小计算公式:2 × 层数 × 头数 × 头维度 × 序列长度 × 精度字节数。以一个 7B 模型为例,32 层、32 头、头维度 128,序列长度 4096,FP16 精度:2 × 32 × 32 × 128 × 4096 × 2 ≈ 2GB。这 2GB 是纯 KV Cache,还没算模型权重。

端侧设备总共就 8GB 内存,模型权重占 4GB,KV Cache 占 2GB,系统和其他应用占 1GB,只剩 1GB 余量。这就是为什么端侧上下文长度通常限制在 2K 到 4K。

5.2 几种 KV Cache 压缩策略

针对 KV Cache 的内存压力,有几种优化策略。

量化 KV Cache。把 KV Cache 从 FP16 量化到 INT8,内存直接减半。实测下来对生成质量影响很小,是性价比最高的优化。llama.cpp 里可以用--cache-type-k q8_0 --cache-type-v q8_0开启。

滑动窗口注意力。只保留最近 N 个 token 的 KV,更早的丢弃。Mistral 系列模型用的就是这个方案。优点是内存恒定,缺点是丢失长距离依赖。

分页注意力。把 KV Cache 分成固定大小的页,按需分配,减少内存碎片。vLLM 用的就是这个方案,端侧也有框架在借鉴。

KV Cache 驱逐。根据注意力权重,驱逐不重要的 KV 对。这个方案实现复杂,端侧框架支持还不多。

5.3 内存预算的实操分配方法

我总结了一个端侧内存预算的分配方法,按这个来基本不会爆。

先确定设备可用内存,比如 8GB 设备,系统和其他应用占 2GB,留给推理的 6GB。然后按比例分配:模型权重占 60% 到 70%,KV Cache 占 20% 到 30%,运行时开销占 10%。

6GB 的预算下,模型权重最多 4GB,对应 7B 模型 4bit 量化;KV Cache 留 1.5GB,对应 4K 上下文;运行时留 0.5GB。这个配置实测能稳定跑。

如果内存更紧张,比如 4GB 设备,那就得上 3B 模型,或者把上下文压到 2K。不要试图在 4GB 设备上跑 7B 模型,即使量化到 4bit 也很勉强,运行时容易 OOM。

6. 部署流程与实测调优

6.1 从模型到设备的完整链路

端侧 LLM 部署的完整链路是这样的:原始模型 → 量化 → 格式转换 → 部署到设备 → 运行时调优。

每一步都有坑。量化阶段要选对方案和校准数据;格式转换要确保目标框架支持;部署阶段要处理依赖和权限;调优阶段要平衡速度和内存。

我建议的实操顺序是:先在 PC 上用目标框架跑通量化模型,确认效果可接受;再交叉编译到设备架构;最后在设备上做性能和内存调优。不要一上来就在设备上折腾,调试效率太低。

6.2 首 token 延迟和生成速度的平衡

端侧部署有两个关键指标:首 token 延迟(TTFT)和生成速度(tokens/s)。这两个指标往往互相矛盾。

首 token 延迟取决于 prompt 处理速度,prompt 越长延迟越高。生成速度取决于单 token 的计算和访存效率。

优化首 token 延迟的手段:prompt 缓存、prefix sharing、更激进的量化。优化生成速度的手段:KV Cache 量化、算子融合、NPU 加速。

实际场景下,如果是对话类应用,首 token 延迟更重要,用户等 2 秒没反应就跑了。如果是批量生成任务,生成速度更重要。根据场景选优化方向。

6.3 实测数据与调优记录

分享一组我在某款 8GB 内存开发板上的实测数据,模型是 7B 的 4bit 量化版本。

配置首 token 延迟生成速度内存占用
纯 CPU,4 线程1.8s8 tokens/s5.2GB
纯 CPU,8 线程1.2s11 tokens/s5.4GB
CPU + NPU 部分层0.9s16 tokens/s5.6GB
上述 + KV Cache INT80.9s15 tokens/s4.3GB

可以看到,KV Cache 量化后生成速度略降,但内存省了 1.3GB,这个 trade-off 在内存紧张时非常值得。NPU 加速收益明显,但适配成本高。

调优过程中发现一个反直觉的点:线程数不是越多越好。8 线程相比 4 线程提升有限,但功耗和发热明显增加,长时间跑反而因为降频导致速度下降。最终稳定在 6 线程是个平衡点。

7. 端侧 Agent 场景下的部署特殊考量

7.1 Agent 对模型调用的特殊需求

端侧 Agent 和单纯的对话应用不一样,它对模型的调用模式更复杂。

Agent 通常需要多次调用模型:一次做意图理解,一次做工具选择,一次做结果总结。每次调用都有延迟,累加起来用户体验就很差。所以端侧 Agent 的模型部署要考虑多轮调用的总延迟,而不只是单次推理速度。

另一个需求是结构化输出。Agent 需要模型输出特定格式的 JSON 或函数调用,这对模型的指令遵循能力要求高。量化后模型的结构化输出能力容易掉点,需要额外验证。

7.2 多模型协同的部署策略

端侧 Agent 常见的一个优化是大小模型协同。用一个小模型(1.5B 到 3B)做 router,判断任务类型;简单任务小模型直接处理,复杂任务交给大模型。

这种策略下,两个模型都要部署在设备上,内存压力更大。解决方案是模型分时加载:router 模型常驻,大模型按需加载。但加载模型本身有延迟,7B 模型从存储加载到内存要几秒,这个延迟要算进用户体验里。

另一个方案是模型共享。如果两个模型架构相同,只是参数量不同,可以共享部分层。这个方案实现复杂,端侧框架支持有限。

7.3 端侧 Agent 的降级与容错

端侧环境不稳定,内存可能被其他应用挤占,温度可能过高,这些都会影响推理。Agent 必须有降级策略。

我的做法是设置三级降级:正常状态下用 7B 模型跑完整流程;内存紧张时切换到 3B 模型,牺牲部分能力;极端情况下只跑规则引擎,不调用 LLM。

降级触发条件要提前定义好:可用内存低于阈值、推理延迟超过阈值、连续推理失败次数超过阈值。这些监控逻辑要集成到 Agent 框架里,不能等到 OOM 了才处理。

8. 一些踩坑之后的经验

部署端侧 LLM 这几年,有几个经验是文档里不会写、但实际很重要的。

第一,永远在真实设备上测,不要在 PC 上模拟。PC 的内存带宽、散热条件、调度策略和端侧设备完全不同,PC 上跑得好不代表设备上能跑。我吃过好几次亏,PC 上流畅的配置,到设备上直接卡死。

第二,量化模型要重新验证能力,不能假设和原模型一致。尤其是你的业务场景涉及特定领域知识时,量化可能把相关能力压没了。上线前一定要用业务测试集跑一遍。

第三,内存监控要常态化。端侧内存是动态变化的,其他应用可能随时占用。部署时要加内存监控,接近阈值时主动降级,而不是等系统杀进程。

第四,散热设计要和模型选型一起做。被动散热的设备,持续推理能力比峰值性能更重要。选模型时按持续性能算,不要按峰值算。

第五,留足调试时间。端侧部署的调试效率远低于云端,交叉编译、日志抓取、性能分析都更麻烦。项目排期时,部署调试的时间要按云端的两到三倍来估。

端侧 LLM 部署这件事,没有一劳永逸的方案,只有针对具体设备和场景不断调优的过程。上面这些是我在实际项目中验证过的思路和方法,具体参数还需要根据你的设备实测调整。如果遇到奇怪的性能问题,先查内存和温度,这两个是最常见的元凶。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询