1. 为什么要在RK3588上跑本地大模型1.1 边缘侧跑大模型的真实动机把大模型塞进一块巴掌大的开发板这件事在两年前还属于“想想就好”的范畴。但RK3588这颗芯片出来之后情况变了。它自带6TOPS算力的NPU配上8核CPU4核A764核A55和最高32GB内存的配置已经具备了在端侧跑通中小参数对话模型的硬件基础。我最初动这个念头是因为手上有个离线场景的需求设备部署在没有稳定外网的环境里但又需要具备自然语言交互能力。云端API方案首先被排除延迟和可用性都不可控。于是开始研究在RK3588上做DeepSeek模型的本地部署。这里说的“本地部署”指的是把模型权重文件下载到开发板本地存储通过推理框架加载后直接在板子上完成对话生成整个过程不依赖任何外部网络请求。DeepSeek系列模型之所以适合这个场景核心原因是它提供了多个参数规模的版本其中1.5B到7B这个区间的模型经过量化压缩后刚好能塞进RK3588的内存和算力预算里。而且DeepSeek在中文对话上的表现相比同参数量的其他开源模型有明显优势这对于国内应用场景来说很关键。适合读这篇内容的人我大致分三类一是手里已经有RK3588开发板想找个实际项目练手的嵌入式开发者二是做边缘计算产品需要评估端侧AI对话可行性的方案工程师三是对大模型本地部署感兴趣想从低成本硬件入门的AI爱好者。不管你属于哪一类接下来的内容都会从硬件准备、系统配置、模型选择、推理框架搭建到实际对话测试一步步走完整个流程。1.2 先搞清楚RK3588的算力账本在动手之前有必要先把RK3588的算力账算清楚。这颗芯片的NPU标称6TOPS指的是INT8精度下的理论峰值算力。注意关键词INT8和理论峰值。实际推理时模型量化到INT8甚至INT4才能充分利用这个算力如果用FP16跑NPU的利用率会打折扣。另外6TOPS是NPU单独算力CPU和GPU的算力是另外计算的。RK3588的Mali-G610 GPU虽然支持OpenCL但在大模型推理上效率远不如NPU所以我们的重点是把模型跑在NPU上。内存方面RK3588支持LPDDR4/4x/5常见开发板配置有4GB、8GB、16GB、32GB几个档位。跑DeepSeek模型我的建议是至少8GB起步16GB会比较从容。以DeepSeek-R1-Distill-Qwen-1.5B为例FP16精度下模型权重大约3GBINT8量化后约1.5GBINT4量化后不到1GB。加上推理时的KV Cache和系统占用8GB内存跑1.5B模型是够的但如果想跑7B模型16GB内存是底线。存储方面eMMC的速度直接影响模型加载时间。我实测下来一个1.5GB的模型文件从eMMC加载到内存大约需要15-20秒如果放在SD卡上会更慢。所以建议把模型文件放在eMMC或者NVMe SSD上部分开发板有M.2接口。网络方面虽然推理不需要联网但下载模型权重和安装依赖包时需要稳定的网络连接建议用有线网口而不是WiFi速度更稳定。2. 部署前的环境准备与系统配置2.1 系统镜像选择与烧录RK3588开发板出厂时通常预装了Android系统但我们要跑大模型Ubuntu是更合适的选择。目前RK3588的Ubuntu支持已经比较成熟官方和社区都有维护的镜像。我推荐使用Ubuntu 22.04 LTS版本原因是它的软件包生态最完善Python版本和各类推理框架的兼容性最好。虽然网上有关于Ubuntu 26的讨论但截至我写这篇内容时RK3588平台上的Ubuntu 26支持还不够稳定不建议在生产验证阶段使用。烧录工具方面瑞芯微官方的RKDevTool是标配。操作流程是先用Type-C线连接开发板的OTG口和电脑按住Recovery键再上电进入Loader模式然后在RKDevTool中加载固件包点击升级即可。这里有个细节需要注意不同开发板的Recovery键位置不同有的在板子正面有的在背面烧录前先确认好。另外烧录完成后第一次启动会比较慢因为系统要做分区扩展和初始化耐心等3-5分钟。系统启动后第一件事是更新软件源和安装基础依赖。打开终端依次执行sudo apt update sudo apt upgrade -y sudo apt install -y python3-pip python3-dev cmake git wget curl sudo apt install -y libopenblas-dev libomp-dev这些包后面编译推理框架时会用到。libopenblas提供CPU端的矩阵运算加速libomp提供OpenMP多线程支持。虽然我们主要用NPU推理但框架编译时这些依赖是必须的。2.2 NPU驱动与RKNN Toolkit2安装RK3588的NPU要通过RKNN Toolkit2来调用。这是瑞芯微官方提供的推理工具链负责把训练好的模型转换成RKNN格式然后在NPU上执行。安装RKNN Toolkit2有两个途径一是通过pip安装预编译版本二是从源码编译。我建议先用pip试试pip3 install rknn-toolkit2如果pip安装失败或者版本不匹配就需要从官方仓库下载对应的whl包手动安装。注意RKNN Toolkit2的版本要和板子上的NPU驱动版本匹配版本不匹配会导致模型加载失败。查看NPU驱动版本的方法是cat /sys/kernel/debug/rknpu/version这个命令会输出当前NPU驱动的版本号比如“RKNPU driver version: 0.9.6”。然后去官方仓库找对应版本的rknn_toolkit2 whl包。安装完成后用以下Python代码验证是否正常from rknnlite.api import RKNNLite rknn RKNNLite() ret rknn.load_rknn(test.rknn) print(Load ret:, ret)如果输出“Load ret: 0”说明环境配置成功。这里要提醒一点RKNN Toolkit2在板子上运行时用的是rknnlite模块而在PC端做模型转换时用的是完整的rknn模块两者不要搞混。2.3 内存与存储的优化配置在跑大模型之前建议对系统做一些优化。首先是调整swap分区虽然swap会拖慢推理速度但在内存紧张时可以防止进程被OOM Killer杀掉。建议设置2-4GB的swapsudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile然后把swapfile写入/etc/fstab让它开机自动挂载。其次是调整CPU调度策略把CPU governor设为performance模式避免推理时降频echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor这个设置对推理速度有5%-10%的影响值得做。最后是清理不必要的后台服务比如蓝牙、打印服务等释放内存给模型用。用systemctl list-units可以查看当前运行的服务把不需要的disable掉。3. DeepSeek模型的选择与转换3.1 哪个DeepSeek版本适合RK3588DeepSeek家族模型不少但并不是所有版本都适合在RK3588上跑。我们需要考虑三个约束参数量、量化后的体积、以及NPU对算子类型的支持程度。目前经过实测比较适合RK3588的DeepSeek模型有以下几个模型版本参数量INT4量化后体积内存占用含KV Cache推理速度tokens/sDeepSeek-R1-Distill-Qwen-1.5B1.5B约0.9GB约2GB8-12DeepSeek-R1-Distill-Qwen-7B7B约4GB约8GB2-4DeepSeek-Coder-1.3B1.3B约0.8GB约1.8GB10-141.5B版本是甜点级选择速度和效果平衡得最好。7B版本效果更好但对内存要求高而且推理速度会明显下降。如果你的板子是16GB内存可以尝试7B版本8GB内存的话老老实实跑1.5B。另外要注意DeepSeek-R1系列是推理模型输出时会带思维链实际对话体验和普通对话模型略有不同。如果只是做日常对话DeepSeek-V2-Lite或者DeepSeek-R1-Distill-Qwen-1.5B都够用。3.2 模型下载与格式转换模型权重可以从HuggingFace或者ModelScope下载。考虑到网络因素国内用户建议用ModelScope。以DeepSeek-R1-Distill-Qwen-1.5B为例git lfs install git clone https://www.modelscope.cn/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B.git下载完成后得到的是PyTorch格式的模型文件。要跑在NPU上需要先转成ONNX格式再转成RKNN格式。转换过程在PC端完成因为RKNN Toolkit2的完整版只在x86 Linux上运行。转换脚本的核心逻辑是from rknn.api import RKNN rknn RKNN() rknn.config(mean_values[[0, 0, 0]], std_values[[1, 1, 1]], target_platformrk3588) rknn.load_onnx(modeldeepseek-1.5b.onnx) rknn.build(do_quantizationTrue, dataset./calibration.txt) rknn.export_rknn(deepseek-1.5b.rknn)这里的关键是量化校准数据集。do_quantizationTrue时RKNN会用校准数据集来统计激活值的分布从而确定量化参数。校准数据集的质量直接影响量化后的精度损失。我的经验是准备100-200条中文对话样本作为校准数据覆盖不同的句式长度和话题类型。如果校准数据太单一量化后的模型在遇到没见过的句式时会出现明显的质量下降。3.3 量化精度与速度的权衡量化是端侧部署绕不开的话题。RK3588的NPU对INT8和INT4都有支持但两者的取舍不同。INT8量化后精度损失较小通常只有1%-3%的下降但模型体积是INT4的两倍。INT4量化后体积大幅缩小但精度损失可能达到5%-10%而且不是所有算子都支持INT4。我的建议是如果内存充足16GB以上优先用INT8精度更有保障。如果内存紧张8GB用INT4但要做好对话质量下降的心理准备。另外混合量化也是个选择对精度敏感的层用INT8对精度不敏感的层用INT4。RKNN Toolkit2支持通过hybrid_quantization参数开启混合量化但配置起来比较麻烦需要对模型结构有深入了解。还有一个容易被忽略的点KV Cache的量化。对话模型推理时需要缓存历史token的Key和Value矩阵这部分占用的内存会随着对话轮数增加而增长。如果KV Cache用FP16存储跑多轮对话时内存会很快吃紧。把KV Cache也量化到INT8可以节省一半内存但对推理框架有额外要求。4. 推理框架搭建与对话功能实现4.1 基于RKNN的推理引擎搭建模型转成RKNN格式后下一步是在板子上搭建推理引擎。核心工作包括加载RKNN模型、初始化NPU运行时、实现tokenizer、管理KV Cache、以及构建对话循环。RKNNLite的API比较简洁加载模型和推理的代码大致如下from rknnlite.api import RKNNLite import numpy as np rknn RKNNLite() rknn.load_rknn(deepseek-1.5b.rknn) rknn.init_runtime(core_maskRKNNLite.NPU_CORE_0) # 构造输入 input_ids np.array([[1, 234, 567, 890]], dtypenp.int64) outputs rknn.inference(inputs[input_ids])但实际部署时远不止这么简单。DeepSeek模型是自回归生成的每生成一个token都需要把之前的KV Cache作为输入传进去。RKNNLite的inference接口支持多输入所以需要把input_ids、attention_mask、past_key_values等一起传入。这里有个坑RKNN对动态shape的支持有限如果每次输入的序列长度不同需要重新编译模型或者做padding。我的做法是固定一个最大序列长度比如512不足的部分用padding补齐这样只需要编译一次模型。4.2 Tokenizer与对话模板处理DeepSeek用的是自己的tokenizer需要从模型目录加载tokenizer.json和tokenizer_config.json。在板子上可以用transformers库的AutoTokenizer但transformers库比较重会占用不少内存。如果内存紧张可以用tokenizers库单独加载体积小很多from tokenizers import Tokenizer tokenizer Tokenizer.from_file(tokenizer.json)对话模板方面DeepSeek-R1系列有自己的chat template格式是|im_start|user 你的问题|im_end| |im_start|assistant如果模板用错了模型输出会变得很奇怪比如重复输出或者答非所问。这个模板定义在tokenizer_config.json的chat_template字段里部署前先确认一下。另外DeepSeek-R1是推理模型输出中会包含|thinking|标签包裹的思维链内容。如果不需要展示思维链可以在后处理时把标签之间的内容过滤掉。4.3 对话循环与流式输出实现对话循环的核心逻辑是接收用户输入 - 拼接对话模板 - tokenize - 推理生成 - detokenize - 输出。流式输出是指每生成一个token就立即显示而不是等整句话生成完再显示。这对用户体验影响很大尤其是RK3588上推理速度不快的情况下流式输出能让用户感知到模型在“思考”。实现流式输出的关键是维护一个生成状态机。每次推理只生成一个token然后把新token追加到输入序列中同时更新KV Cache。伪代码逻辑如下past_kv None generated_ids [] for _ in range(max_new_tokens): outputs rknn.inference(inputs[input_ids, past_kv]) next_token sample(outputs.logits) if next_token eos_token_id: break generated_ids.append(next_token) input_ids np.array([[next_token]]) past_kv outputs.past_kv print(tokenizer.decode([next_token]), end, flushTrue)采样策略方面可以用temperaturetop_p的组合。temperature控制随机性top_p控制候选集大小。对于对话场景temperature0.7、top_p0.9是比较通用的配置。如果希望输出更稳定可以把temperature降到0.3。5. 性能调优与常见问题排查5.1 推理速度优化实战RK3588上跑1.5B模型初始速度大概在5-8 tokens/s。经过优化后可以提升到10-15 tokens/s。优化手段主要有以下几个第一启用NPU多核。RK3588的NPU有三个核心可以通过core_mask参数指定使用哪些核心。对于大模型推理建议用RKNNLite.NPU_CORE_0_1_2开启全部三个核心速度能提升30%左右。但要注意多核推理需要模型支持并行不是所有模型都能受益。第二调整CPU亲和性。推理过程中有一部分算子在CPU上执行比如LayerNorm、Softmax等把这些算子绑定到大核A76上执行避免被调度到小核。可以用taskset命令绑定taskset -c 4-7 python3 chat.py这里4-7对应的是A76大核的CPU编号具体编号可以用lscpu查看。第三减少内存拷贝。RKNN推理时输入数据需要从CPU内存拷贝到NPU内存输出再拷贝回来。如果输入输出数据量大拷贝开销不可忽略。优化方法是尽量用零拷贝接口或者把多次推理合并成一次批量推理。第四模型层面的优化。比如把attention层的计算合并减少算子数量或者用FlashAttention替代标准attention减少内存访问。不过这些优化需要对模型结构做修改门槛较高。5.2 常见报错与解决方法部署过程中遇到的报错五花八门我整理了几个高频问题报错信息原因解决方法E RKNN: Invalid model file模型文件损坏或版本不匹配重新转换模型确认RKNN Toolkit版本与驱动匹配E RKNN: Failed to allocate memory内存不足减小模型量化精度或关闭其他占用内存的进程E RKNN: Unsupport op type模型中包含NPU不支持的算子用ONNX Simplifier简化模型或替换不支持的算子Segmentation fault输入shape不匹配检查输入tensor的shape和dtype是否与模型定义一致Tokenization errortokenizer文件缺失或版本不对重新下载tokenizer文件确认与模型匹配其中“Unsupport op type”是最常见的。RK3588的NPU对算子支持有限像一些自定义的激活函数、特殊的attention变体都可能不支持。解决方法是先用ONNX Simplifier做图优化把能合并的算子合并能消除的消除。如果还有不支持的算子就需要用CPU fallback把这部分算子放到CPU上执行。RKNN Toolkit2支持通过custom_op参数指定CPU fallback的算子。5.3 实操避坑经验汇总最后分享几个我在实操中踩过的坑都是文档里不会写的第一个坑模型转换时的校准数据集不能太少。我一开始只用了20条样本做校准结果量化后的模型在遇到长句子时输出乱码。后来增加到200条问题解决。校准数据的多样性比数量更重要要覆盖短句、长句、问句、陈述句等不同形式。第二个坑板子上的Python版本要和PC端一致。我在PC上用Python 3.10转换的模型板子上是Python 3.8结果rknnlite加载时报版本不兼容。后来统一用3.8才解决。建议在PC端用虚拟环境版本和板子保持一致。第三个坑散热问题。RK3588跑大模型时NPU满载发热量不小。如果开发板没有散热片连续跑10分钟以上会触发降频推理速度直接腰斩。建议加装散热片或者小风扇成本不高但效果明显。第四个坑电源要够。RK3588满载功耗可以到10W以上如果用的电源适配器功率不够会出现板子重启或者NPU初始化失败。建议用5V/3A以上的电源最好带独立供电的USB Hub。第五个坑不要用SD卡跑模型。SD卡的读取速度远低于eMMC模型加载时间会从20秒变成2分钟。而且SD卡的稳定性不如eMMC长时间读写容易出错。如果板子支持NVMe SSD把模型放在SSD上是最优解。5.4 对话效果调优与扩展方向模型跑起来之后对话效果调优是下一步。几个实用的调优方向一是调整system prompt给模型设定一个明确的角色和回答风格能显著提升对话质量。二是调整重复惩罚参数repetition_penaltyDeepSeek模型有时会陷入重复循环把repetition_penalty设为1.1-1.2可以有效缓解。三是限制max_new_tokens避免模型生成过长的无用内容。扩展方向方面如果想让对话系统具备联网搜索能力可以在本地部署一个轻量级的检索模块把检索结果作为上下文拼接到prompt里。如果想让模型支持多轮复杂对话可以引入对话历史管理把之前的对话摘要压缩后作为上下文。另外RK3588支持多路NPU并行如果板子上同时跑多个模型比如一个对话模型加一个视觉模型可以通过core_mask分配不同的NPU核心实现并行推理。我在实际使用中发现1.5B模型在RK3588上的对话体验已经可以满足基本的问答需求但复杂推理任务还是力不从心。如果对效果要求高建议上7B模型配16GB内存或者考虑用多块RK3588做分布式推理。这个方向后续还可以继续折腾比如尝试用RK3588的GPU做部分算子的加速或者探索更激进的量化方案。
