1. 手机跑大模型这件事,到底靠不靠谱
先说结论:能跑,但别指望它替代云端服务。我前后在骁龙8 Gen 2的Android机和iPhone 15 Pro上折腾了差不多两个月,从最初的“这玩意儿真能跑?”到后来把本地模型接进自己的笔记工作流,中间踩的坑比想象中多得多。这篇文章就把整个路径完整拆一遍,包括模型怎么选、量化怎么做、推理框架怎么挑、内存怎么省,以及那些文档里不会写的坑。
所谓“手机本地部署LLM”,本质是把一个已经训练好的大语言模型,经过压缩和格式转换后,塞进手机的运行内存里,用手机芯片做推理计算。它解决的核心问题是:在没有网络、不想把数据传到云端、或者单纯想省API费用的场景下,依然能用到语言模型的能力。适合谁来参考?三类人:一是对隐私敏感、希望数据不出设备的开发者;二是想学习端侧推理原理的技术爱好者;三是需要在离线环境下做文本处理(比如摘要、翻译、分类)的工程人员。
但这里有个前提认知必须先建立:手机端能跑的模型,参数量通常在0.5B到7B之间,而且必须经过量化压缩。一个7B模型在FP16精度下大约需要14GB内存,手机根本扛不住。量化到4-bit之后,体积能压到3.5GB到4GB左右,这才勉强进入旗舰机的可运行范围。所以你在手机上跑的那个“大模型”,和云端动辄几百B参数的模型,完全不是一个量级的东西。它的定位更像是一个随身携带的离线小助手,而不是全能型AI。
我实测下来,Android端的生态明显比iOS端成熟。原因也简单:Android允许侧载应用、允许直接访问文件系统、允许后台长时间运行计算任务,而iOS对这些限制严格得多。所以如果你是第一次尝试,我建议从Android开始,成功率会高很多。iOS不是不能做,但路径更窄,后面会详细说。
2. 模型选型与量化:不是越小越好,也不是越大越强
2.1 手机端模型的参数甜点区在哪里
很多人一上来就想跑7B模型,觉得参数越大效果越好。理论上没错,但手机端有个硬约束:内存带宽和散热。我做过一组对比测试,在同一台骁龙8 Gen 2设备上,分别跑Qwen2.5-0.5B、Qwen2.5-1.5B、Llama-3.2-3B和Mistral-7B的4-bit量化版本,结果如下:
| 模型 | 量化精度 | 模型体积 | 加载时间 | 生成速度(tokens/s) | 手机发热情况 |
|---|---|---|---|---|---|
| Qwen2.5-0.5B | Q4_K_M | 约400MB | 1-2秒 | 25-35 | 几乎不热 |
| Qwen2.5-1.5B | Q4_K_M | 约1GB | 2-4秒 | 15-22 | 轻微温热 |
| Llama-3.2-3B | Q4_K_M | 约2GB | 4-8秒 | 8-14 | 明显发热 |
| Mistral-7B | Q4_K_M | 约4GB | 10-20秒 | 3-6 | 烫手,会降频 |
从这张表能看出来,1.5B到3B是手机端的甜点区。0.5B虽然快,但理解能力有限,复杂一点的指令就开始胡言乱语;7B虽然效果最好,但生成速度慢到你会失去耐心,而且手机很快就会因为过热而降频,速度进一步下降。
我个人的建议是:中文场景优先选Qwen2.5-1.5B或Qwen2.5-3B的量化版,英文场景可以考虑Llama-3.2-3B或者Phi-3.5-mini。这些模型在各自参数量级上的表现都比较均衡,不会出现某个能力特别短板的情况。
2.2 量化到底在做什么,为什么必须做
量化这个词听起来很专业,但用生活化的方式解释就很好理解。假设你原来用一把精确到毫米的尺子量东西,每个数据都要存成16位浮点数;量化相当于换了一把精确到厘米的尺子,每个数据只存4位整数。精度损失了一些,但存储空间和计算量都大幅下降。
具体到技术层面,常见的量化方法有GPTQ、AWQ、GGUF等格式。手机端最常用的是GGUF格式配合Q4_K_M量化,原因是GGUF是llama.cpp生态的标准格式,支持CPU推理,对硬件要求最低,而且Q4_K_M在精度和体积之间取得了很好的平衡。
注意:不要盲目追求Q2或Q3级别的极致压缩。我试过Q2_K量化的7B模型,体积确实压到了2.5GB左右,但输出质量下降非常明显,经常出现重复、断句错误、逻辑混乱的问题。省下来的那点内存,不值得用效果来换。
量化的具体操作通常在电脑上完成,需要用到llama.cpp提供的量化工具。流程是:先下载原始模型(通常是HuggingFace上的safetensors格式),转换成GGUF格式,然后再做量化。这个过程我在后面实操章节会详细展开。
2.3 模型来源与格式选择
模型下载渠道主要是HuggingFace和ModelScope。国内访问HuggingFace有时候不太顺畅,ModelScope上的模型镜像比较全,速度也快,建议优先考虑。
格式方面,手机端基本就认GGUF这一种。如果你看到的是safetensors或者PyTorch的.bin文件,都需要先转换。有些模型作者会直接提供已经量化好的GGUF文件,省去自己转换的步骤,优先选这种。
选模型的时候还要注意对话模板的问题。不同模型用的对话格式不一样,比如Qwen用的是ChatML格式,Llama用的是自己的特殊token格式。如果模板搞错了,模型会把用户输入当成普通文本续写,而不是当成指令来执行,输出结果会非常奇怪。好在现在主流的推理框架都内置了常见模型的模板,选对模型名称一般就能自动匹配。
3. Android端部署实操:从零到跑通
3.1 推理框架怎么选:llama.cpp还是MLC-LLM
Android端目前主流的本地推理方案有两个:llama.cpp和MLC-LLM。两者思路不同,适用场景也不一样。
llama.cpp是纯C++实现的推理引擎,核心优势是CPU推理效率高、依赖少、移植简单。它不需要特定的GPU加速,在骁龙芯片上通过NEON指令集优化就能跑出不错的速度。缺点是纯CPU推理时功耗较高,长时间运行发热明显。
MLC-LLM则是基于TVM编译器的方案,支持GPU加速(Android上通过OpenCL或Vulkan),理论上有更好的能效比。但它的部署流程更复杂,需要针对特定设备编译,而且对模型格式有额外要求。
我两个方案都试过,最后长期用的是llama.cpp。原因很实际:MLC-LLM的编译环节太容易出错了,不同手机芯片的兼容性差异很大,有时候编译通过了跑起来也会崩。llama.cpp虽然速度不是最快的,但胜在稳定,基本上只要模型文件没问题,就能跑起来。
如果你只是想快速体验,不想折腾编译环境,可以直接用现成的App。比如ChatterUI、LM Playground、PocketPal这几个,都内置了llama.cpp的推理能力,下载模型文件导入就能用。但如果你想自己控制推理参数、集成到自己的应用里,那就需要自己编译llama.cpp的Android版本。
3.2 编译llama.cpp的Android版本
编译环境准备是第一步。你需要:
- Android Studio(最新稳定版即可,主要用于获取NDK和CMake)
- Android NDK(建议用r26或r27版本)
- CMake 3.22以上
- Git
具体编译命令如下,这是我在Ubuntu环境下实测通过的流程:
# 克隆仓库 git clone https://github.com/ggerganov/llama.cpp cd llama.cpp # 创建构建目录 mkdir build-android && cd build-android # 配置CMake,注意替换NDK路径 cmake .. \ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ -DANDROID_ABI=arm64-v8a \ -DANDROID_PLATFORM=android-28 \ -DCMAKE_BUILD_TYPE=Release \ -DLLAMA_CURL=OFF # 编译 make -j$(nproc)编译完成后,你会得到libllama.so、libggml.so等动态库文件,以及llama-cli和llama-server两个可执行文件。把这些文件推到手机上,就可以通过adb shell运行了。
实操心得:
-DANDROID_PLATFORM建议设成android-28或更高。我试过设成android-24,编译能过但运行时会报缺少某些系统符号。另外-DLLAMA_CURL=OFF是关掉网络请求功能,手机端本地推理用不到,关掉能减少依赖。
3.3 把模型跑起来:完整命令行操作
编译产物推送到手机:
adb push build-android/bin/llama-cli /data/local/tmp/ adb push build-android/lib/*.so /data/local/tmp/ adb push qwen2.5-1.5b-instruct-q4_k_m.gguf /data/local/tmp/ adb shell chmod +x /data/local/tmp/llama-cli然后进入手机shell运行:
adb shell cd /data/local/tmp LD_LIBRARY_PATH=. ./llama-cli \ -m qwen2.5-1.5b-instruct-q4_k_m.gguf \ -n 512 \ -t 6 \ -c 2048 \ --temp 0.7 \ -p "你好,请用一句话介绍你自己"参数解释一下:-n 512是最大生成token数,-t 6是使用6个线程(骁龙8 Gen 2有1个X核+4个性能核+3个能效核,设成6比较均衡),-c 2048是上下文窗口大小,--temp 0.7是温度参数控制随机性。
实测在骁龙8 Gen 2上,Qwen2.5-1.5B Q4_K_M的生成速度大约在18-22 tokens/s,首token延迟在1秒左右。这个速度用来做文本摘要、翻译、简单问答是完全够用的。
3.4 集成到Android应用的关键点
如果你想在自己的App里集成,核心是通过JNI调用llama.cpp的C接口。主要涉及几个步骤:
第一,在CMakeLists里链接编译好的动态库。第二,写JNI桥接层,把Java/Kotlin的字符串传成C的char指针。第三,管理模型加载和推理的生命周期,避免内存泄漏。
这里有个容易忽略的点:模型加载应该在后台线程做,而且要做好内存回收。一个1.5B的Q4模型加载后大约占用1.2GB到1.5GB内存,如果Activity销毁时没有正确释放,下次加载就会OOM。我的做法是把模型实例放在Application级别的单例里,全局只加载一次,所有页面共享。
另外,Android 12以上对后台进程限制更严,如果推理时间较长,建议用Foreground Service加通知的方式保活,否则系统可能在推理过程中把进程杀掉。
4. iOS端部署:限制更多,但并非不可能
4.1 iOS端的特殊约束
iOS端做本地LLM部署,最大的障碍不是硬件性能——A17 Pro的神经网络引擎其实很强——而是系统限制。iOS不允许JIT编译,不允许动态加载未签名的可执行代码,后台运行时间也严格受限。这意味着llama.cpp那种“编译一个可执行文件直接跑”的路子在iOS上行不通。
iOS上可行的方案主要有两个:一是用Core ML把模型转换成Apple自己的格式,利用Neural Engine加速;二是用MLX框架,这是Apple专门为自家芯片做的机器学习框架,支持统一内存架构,推理效率不错。
Core ML的优点是能吃到Neural Engine的加速,功耗低;缺点是转换流程复杂,对模型结构有要求,不是所有LLM都能顺利转。MLX的优点是灵活,支持动态图,转换相对简单;缺点是生态还在建设中,文档不够完善。
4.2 用MLX跑通第一个模型
MLX的安装需要Python环境,建议用conda创建一个独立环境:
pip install mlx mlx-lm然后直接从HuggingFace拉取MLX格式的模型:
mlx_lm.generate \ --model mlx-community/Qwen2.5-1.5B-Instruct-4bit \ --prompt "请用一句话解释什么是量化" \ --max-tokens 200这个命令在Mac上就能跑,验证模型没问题后,再考虑往iOS设备上部署。iOS端需要把MLX的推理代码集成到App里,通过Swift调用。Apple官方有一个MLX Swift的示例项目,可以作为起点。
注意:iOS端跑模型对设备内存要求很高。1.5B的4-bit模型大约需要1GB左右的内存,iPhone 15 Pro的8GB内存勉强够用,但如果是iPhone 14或更早的6GB机型,跑起来会比较吃力,系统可能会因为内存压力杀掉App。
4.3 iOS端的替代思路:用快捷指令调用本地服务
如果你不想折腾App开发,还有一个取巧的办法:在电脑上跑一个本地推理服务(比如用Ollama),然后手机通过局域网访问。这样手机端只负责发送请求和展示结果,计算全在电脑上完成。
这个方案的好处是手机端零负担,模型可以随便选大的;缺点是必须和电脑在同一个网络下,失去了“随时随地离线使用”的意义。但如果你主要在家里或办公室用,这个方案其实很实用。
具体做法是在电脑上启动Ollama服务,然后iPhone上用快捷指令的“获取URL内容”功能,向电脑的IP地址发送POST请求。请求体是JSON格式,包含prompt和参数。返回的结果解析后展示出来就行。
5. 性能调优与省电策略
5.1 线程数怎么设才合理
线程数不是越多越好。手机芯片通常是大小核架构,比如骁龙8 Gen 2是1+4+3,天玑9300是4+4。如果把线程数设成8,系统会把任务分配到所有核心上,包括能效核。但能效核的主频低,参与计算反而会拖慢整体速度,因为推理是同步的,最慢的那个核心决定了整体速度。
我的经验是:线程数设成性能核的数量。骁龙8 Gen 2设6(1个X核+4个性能核+1个能效核做调度),天玑9300设8(4个X4+4个A720),A17 Pro设6。这样能保证所有计算都落在高性能核心上,避免被能效核拖后腿。
你可以通过adb shell cat /proc/cpuinfo查看CPU核心信息,然后根据实际情况调整。
5.2 上下文长度与内存的权衡
上下文窗口(context window)直接决定了模型能“记住”多少内容。设得越大,内存占用越高。以Qwen2.5-1.5B Q4_K_M为例,2048上下文大约占1.2GB内存,4096上下文就要1.5GB左右。
手机端我建议上下文不要超过4096。一方面内存吃不消,另一方面上下文越长,首token延迟越高,因为模型需要处理更多的输入token。如果你只是做短文本处理,2048完全够用。
如果确实需要处理长文档,可以采用分块处理的策略:把长文档切成若干段,每段单独送给模型处理,最后把结果拼接起来。虽然会损失一些跨段落的上下文关联,但内存压力小很多。
5.3 散热与持续性能
手机跑LLM最大的敌人是散热。我实测过,骁龙8 Gen 2在连续推理10分钟后,机身温度会升到42度左右,然后系统开始降频,生成速度从20 tokens/s降到12 tokens/s左右。如果继续跑,温度会稳定在45度上下,速度维持在10-12 tokens/s。
缓解办法有几个:一是限制单次生成的最大token数,比如设成256,生成完就停,让手机有时间散热;二是避免边充电边推理,充电本身就在发热,叠加推理的热量会加速降频;三是如果条件允许,摘掉手机壳,裸机散热会好一些。
实操心得:如果你需要长时间批量处理文本,建议把任务拆成小批次,每批之间间隔30秒到1分钟,让芯片有时间降温。我试过连续跑1小时,不做间隔的话,后半段速度只有前半段的一半。
6. 常见问题与排查技巧实录
6.1 模型加载失败或崩溃
这是最常见的问题,原因通常有三个:模型文件损坏、内存不足、格式不兼容。
排查步骤:先用md5sum校验模型文件的完整性,对比下载页面提供的哈希值。如果文件没问题,检查手机剩余内存是否足够,1.5B的Q4模型至少需要1.5GB可用内存。如果内存也够,那可能是GGUF版本和推理框架版本不匹配,尝试更新llama.cpp到最新版重新编译。
6.2 输出乱码或重复
这种情况通常是对话模板不匹配导致的。模型没有正确识别指令格式,把用户输入当成了普通文本续写。解决办法是在推理时指定正确的chat template,llama.cpp用--chat-template参数,比如--chat-template chatml对应Qwen系列。
另一个可能的原因是温度参数设得太低或太高。温度太低(比如0.1)会导致输出过于确定,容易陷入重复循环;温度太高(比如1.5)会导致输出过于随机,出现乱码。建议设在0.6到0.8之间。
6.3 速度突然变慢
如果之前跑得好好的,突然速度掉了一半,大概率是手机降频了。检查手机温度,如果背面明显发烫,那就是散热问题。停一会儿等温度降下来再跑。
另一个可能是后台有其他应用在抢资源。Android的后台管理比较宽松,有些应用会在后台偷偷跑计算任务。建议推理前清理一下后台,或者开飞行模式减少网络相关的后台活动。
6.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 加载模型时崩溃 | 内存不足 | 查看logcat中的OOM信息 | 换更小的模型或更低的量化精度 |
| 输出乱码 | 对话模板错误 | 检查模型文档确认模板格式 | 指定正确的chat template |
| 输出重复 | 温度参数不当 | 尝试调整温度值 | 温度设在0.6-0.8之间 |
| 速度突然下降 | 芯片降频 | 检查手机温度 | 暂停推理等待降温 |
| 首token延迟高 | 上下文过长 | 查看context设置 | 减小上下文窗口 |
| 推理中途中断 | 后台被杀 | 查看系统日志 | 使用Foreground Service |
7. 开源项目推荐与选型建议
7.1 推理框架类
llama.cpp是目前最成熟的端侧推理框架,社区活跃,更新频繁,支持几乎所有主流模型架构。缺点是纯CPU推理功耗较高,但胜在稳定可靠。
MLC-LLM支持GPU加速,理论能效比更好,但编译部署门槛高,适合有编译经验的开发者。
MLX是Apple生态的专属方案,在iPhone和Mac上表现优秀,但只支持Apple设备,跨平台性差。
Ollama虽然主要是桌面端方案,但它的API设计很简洁,可以作为手机端App的后端服务,手机通过局域网调用。
7.2 现成App类
ChatterUI是我用得最多的Android端App,界面简洁,支持导入GGUF模型,可以调整推理参数,还支持多轮对话历史管理。
PocketPal的UI更现代一些,内置了模型下载功能,不需要自己找模型文件,适合新手快速体验。
LM Playground偏向开发者向,可以实时看到推理速度、内存占用等指标,方便调优。
iOS端的话,MLX Chat是一个不错的起点,基于MLX框架,支持在iPhone上直接跑量化模型。
7.3 模型资源类
ModelScope上的模型镜像比较全,国内下载速度快,推荐优先使用。
HuggingFace上的模型更新更及时,但国内访问可能不稳定,可以作为备选。
选模型的时候注意看模型卡片上的说明,确认是否支持GGUF格式、是否有现成的量化版本、对话模板是什么格式。这些信息决定了你能不能顺利跑起来。
8. 我踩过的几个坑和最后的小建议
第一个坑是盲目追求大参数。一开始我非要跑7B模型,结果加载慢、生成慢、手机烫,体验极差。后来换成1.5B,速度上来了,日常用完全够。模型大小和体验之间要平衡,不是越大越好。
第二个坑是忽略了对话模板。有次跑一个Llama模型,输出全是重复的“好的好的好的”,查了半天才发现是模板没设对。现在养成了习惯,拿到新模型先看文档确认模板格式。
第三个坑是没做内存回收。在App里反复加载模型测试,结果跑了十几次之后OOM崩溃。后来改成全局单例,只加载一次,问题就解决了。
如果你刚开始折腾,我的建议是:先用现成App跑通流程,再考虑自己编译集成。ChatterUI加一个Qwen2.5-1.5B的GGUF文件,十分钟就能体验到手机跑大模型的效果。有了直观感受之后,再决定要不要深入折腾编译和集成。
另外,手机端LLM目前的定位是“离线小助手”,适合做文本摘要、翻译、简单分类、格式转换这类任务。别指望它写长文、做复杂推理、或者替代云端大模型。把它当成一个随身携带的、不联网也能用的文本处理工具,心态就对了。
最后分享一个实用技巧:如果你经常需要处理同类任务,可以给模型写一个固定的系统提示词(system prompt),把任务要求、输出格式、注意事项都写进去。这样每次只需要输入待处理的内容,模型就会按照预设的格式输出,省去了重复描述需求的麻烦。我在做文本分类的时候就是这么干的,效率提升很明显。