1. 项目概述:为什么要在Jetson Nano上折腾DeepSeek?

最近手头有个闲置的Jetson Nano开发板,看着它4GB的内存和相对羸弱的CPU,总觉得让它跑跑简单的视觉Demo有点大材小用,或者说,没把它的潜力榨干。正好DeepSeek这类开源大模型火得不行,我就琢磨着,能不能把这“老伙计”变成一个本地的、能跑起来的AI对话终端?毕竟,云端API调用有延迟、有费用,还涉及隐私,如果能在本地设备上跑通一个可用的模型,哪怕能力弱一些,对于学习、调试或者一些简单的离线任务,意义还是很大的。

这个项目的核心目标,就是在基于ARM架构的NVIDIA Jetson Nano开发板上,成功部署并运行DeepSeek大语言模型。这里说的“运行”,不是指调用云端API,而是指通过Ollama这类工具,将模型文件拉取到本地,并在Jetson Nano的硬件上完成推理。整个过程会涉及到ARM64环境的适配、CUDA的配置、Ollama的安装与模型拉取,以及最后在终端或通过API进行测试。对于拥有类似边缘计算设备(如树莓派、其他Jetson系列)的开发者来说,这是一次非常典型的“边缘AI”实践,能让你深刻理解从云端模型到边缘部署的全链路挑战和解决方案。

2. 环境准备与深度解析:Jetson Nano的“底子”与挑战

在开始动手之前,我们必须对Jetson Nano的硬件和系统环境有一个清醒的认识。这不是一台x86的PC,它的每一步操作都可能遇到ARM架构带来的“惊喜”。

2.1 硬件与系统基础盘点

我使用的是一台Jetson Nano 4GB开发者套件版。它的核心配置如下:

  • CPU : 四核ARM Cortex-A57 @ 1.43 GHz。这个性能大概相当于几年前的中端手机处理器,处理复杂编译任务时会比较慢。
  • GPU : 128核NVIDIA Maxwell架构GPU。这是我们的主力,所有AI推理计算都指望它了。虽然架构老,但支持CUDA,这就是价值所在。
  • 内存 : 4GB LPDDR4。这是最大的瓶颈!大模型动辄需要数GB甚至数十GB的内存,4GB意味着我们只能运行参数量较小的模型版本(通常是7B参数以下的量化版)。
  • 存储 : 我为其配备了一张64GB的microSD卡。系统、软件、模型都放在这里。读写速度会直接影响体验,建议使用Class 10或UHS-I以上规格的卡。

系统方面,我刷写了NVIDIA官方提供的JetPack 4.6.1镜像(具体版本号可能随时间更新,请以官网最新为准)。这个镜像包含了Ubuntu 18.04 LTS、CUDA 10.2、cuDNN 8.x等一整套为Jetson优化的软件栈。 非常重要的一点:请务必使用NVIDIA官方提供的镜像,而不是自己安装Ubuntu再配驱动,那会是一场灾难。 官方镜像已经做好了内核、驱动、CUDA的深度集成。

开机后,第一件事是检查基础环境:

# 查看系统版本和内核
cat /etc/os-release
uname -a

# 查看CUDA和GPU信息
nvcc --version # 如果提示命令未找到,可能需要将/usr/local/cuda/bin加入PATH
nvidia-smi

nvidia-smi 这个命令很关键,它能告诉你GPU是否被正确识别、驱动是否加载、以及当前GPU的内存使用情况。在Jetson Nano上,它的输出可能不像服务器显卡那样信息丰富,但只要能显示GPU型号和少量内存信息,就说明基础环境是OK的。

2.2 依赖安装与系统优化

Jetson Nano的默认镜像为了节省空间,很多开发工具没有预装。我们需要先补全一些基础依赖。

# 更新软件源并升级现有包
sudo apt-get update
sudo apt-get upgrade -y

# 安装编译、下载等基础工具
sudo apt-get install -y \
    curl \
    wget \
    git \
    build-essential \
    libssl-dev \
    zlib1g-dev \
    libbz2-dev \
    libreadline-dev \
    libsqlite3-dev \
    llvm \
    libncurses5-dev \
    libncursesw5-dev \
    xz-utils \
    tk-dev \
    libffi-dev \
    liblzma-dev \
    python3-openssl

接下来是Python环境。系统自带了Python 3.6,但有些新工具可能要求更高版本。我选择使用 pyenv 来管理多版本Python,这样更灵活,也不会破坏系统自带的Python。

# 安装pyenv
curl https://pyenv.run | bash

# 将pyenv初始化脚本添加到shell配置文件中(如 ~/.bashrc)
echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
source ~/.bashrc

# 安装一个较新的Python版本,例如Python 3.10.13
# 注意:在Jetson Nano上编译Python非常耗时,可能需要1-2小时
pyenv install 3.10.13

# 设置为全局默认版本
pyenv global 3.10.13

# 验证
python --version
pip --version

注意 :在ARM设备上从源码编译Python是一个极其漫长的过程,期间CPU会满载,开发板可能会比较热。请确保供电充足(最好使用桶形电源而非Micro USB供电),并耐心等待。如果中途失败,多半是内存不足,可以尝试增加swap空间。

系统优化项

  1. 交换空间(Swap) :4GB内存跑大模型很容易爆掉。增加Swap空间相当于用存储空间模拟内存,能防止进程因内存不足(OOM)被系统杀死。但SD卡速度慢,Swap用多了会卡顿,这是权衡。
    # 创建一个8GB的交换文件
    sudo fallocate -l 8G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    # 为了开机自动挂载,将下面一行添加到 /etc/fstab
    # /swapfile none swap sw 0 0
    
  2. 电源模式 :Jetson Nano有两种电源模式:5W和10W(Max-N)。10W模式能解锁CPU和GPU的更高频率,性能更好,但需要足够的散热。如果你使用了风扇散热片,建议设置为10W模式。
    sudo nvpmodel -m 0 # 0代表10W模式(Max-N),1代表5W模式
    sudo jetson_clocks # 启用风扇并设置静态时钟(性能模式)
    

3. Ollama的安装与配置:在ARM64上的特别之旅

Ollama是目前在本地运行大模型非常流行的工具,它简化了模型下载、加载和提供API的整个过程。但官方安装脚本主要针对x86_64架构,我们需要为ARM64(特别是Jetson的aarch64)进行手动安装。

3.1 手动安装Ollama

Ollama本身是一个Go语言编写的二进制文件,我们需要下载适用于ARM64的版本。

# 前往Ollama的GitHub发布页,找到最新的Linux ARM64版本下载链接
# 例如(链接可能过期,请检查最新版本):
curl -L -o ollama-linux-arm64 https://github.com/ollama/ollama/releases/download/v0.1.40/ollama-linux-arm64

# 赋予执行权限并移动到系统路径
chmod +x ollama-linux-arm64
sudo mv ollama-linux-arm64 /usr/local/bin/ollama

# 验证安装
ollama --version

如果 /usr/local/bin 不在你的PATH中,可以将其加入,或者直接使用绝对路径 /usr/local/bin/ollama

3.2 配置Ollama服务与国内镜像

为了让Ollama在后台持续运行并提供服务,我们将其设置为系统服务。

# 创建Ollama服务用户(可选,但推荐)
sudo useradd -r -s /bin/false -m -d /usr/share/ollama ollama

# 创建服务文件
sudo tee /etc/systemd/system/ollama.service << EOF
[Unit]
Description=Ollama Service
After=network-online.target

[Service]
Type=exec
User=ollama
Group=ollama
ExecStart=/usr/local/bin/ollama serve
Restart=always
RestartSec=3
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Environment="OLLAMA_HOST=0.0.0.0" # 允许非本地连接,方便其他设备访问
Environment="OLLAMA_ORIGINS=*" # 允许所有来源的CORS请求(开发环境,生产需限制)

# 可选:如果你配置了国内镜像源,可以在这里设置
# Environment="OLLAMA_MODELS=/path/to/your/local/models" # 自定义模型存储路径

[Install]
WantedBy=default.target
EOF

# 重新加载systemd配置
sudo systemctl daemon-reload
# 启用服务开机自启
sudo systemctl enable ollama
# 启动服务
sudo systemctl start ollama
# 查看服务状态
sudo systemctl status ollama

如果状态显示为 active (running) ,说明服务启动成功。默认情况下,Ollama的API服务会运行在 11434 端口。

关于模型下载 :直接从Ollama官方拉取模型对于国内用户可能非常慢甚至不可行。这里有两个解决方案:

  1. 使用国内镜像源(推荐) :一些社区维护了Ollama模型的镜像。你可以在运行 ollama pull 命令前,通过环境变量或修改配置来指定镜像站。例如(镜像站地址需自行寻找可用的):

    export OLLAMA_MODEL_SOURCE="https://mirror.example.com/ollama"
    ollama pull deepseek-coder:6.7b
    

    请注意,镜像站的可用性和完整性需要自行甄别。

  2. 手动导入模型文件 :先从其他网络环境好的机器下载模型文件(通常是 Modelfile 和多个二进制分片),然后传输到Jetson Nano上,使用 ollama create ollama run 来手动创建模型。具体步骤可以参考Ollama官方文档关于“从GGUF文件创建”的部分。这需要你对模型文件格式有一定了解。

实操心得 :在Jetson Nano上,我强烈建议先在其他电脑(比如x86的笔记本)上,用Ollama把需要的模型 pull 下来。模型文件通常存储在 ~/.ollama/models 目录下。然后将这个目录整个打包,通过SCP或者U盘拷贝到Jetson Nano的对应位置(注意用户权限,如果是 ollama 用户运行服务,则需要将文件放在 /usr/share/ollama/.ollama/models 或类似路径,并修改所有者)。这能节省大量时间和避免网络问题。

4. 拉取与运行DeepSeek模型:选择与适配的博弈

Ollama支持很多模型,但并非所有模型都适合Jetson Nano。我们需要考虑两个关键约束: 内存 架构

4.1 模型选择:量化版本是唯一出路

原始的DeepSeek Coder 6.7B或DeepSeek-V2等模型,仅FP16精度就需要超过13GB的GPU内存,这远远超出了Jetson Nano的4GB物理内存+8GB Swap的能力。因此,我们必须使用 量化模型

量化是一种模型压缩技术,通过降低模型权重(参数)的数值精度(例如从FP16降到INT4、INT8)来大幅减少模型大小和内存占用,同时尽可能保持模型性能。常见的量化格式有GGUF(llama.cpp社区推动)、GPTQ、AWQ等。Ollama主要支持GGUF格式。

对于Jetson Nano 4GB,我的经验是:

  • 7B参数模型 :可以尝试 q4_0 q4_K_M 等4位量化版本。加载后,GPU内存占用大约在3-4GB,会非常紧张,推理速度慢,且极易触发Swap导致卡顿。
  • 更小的模型(如1B-3B) :是更实际的选择。例如 deepseek-coder:1.3b phi 系列、 tinyllama 等。它们能在有限内存下提供更流畅的交互体验。

假设我们决定尝试 deepseek-coder:6.7b 的量化版。首先需要查看Ollama支持的该模型的标签(tag)。

# 搜索deepseek相关模型(需要网络)
ollama list | grep deepseek
# 或者去Ollama官网查看模型库:https://ollama.com/library

# 假设我们找到了一个合适的标签,例如 `deepseek-coder:6.7b-q4_0`
# 拉取模型(这将开始下载,耗时很长)
ollama pull deepseek-coder:6.7b-q4_0

重要提示 :在Jetson Nano上直接执行 ollama pull 很可能因为网络或内存问题失败。如前所述, 强烈建议在其它机器上拉取后拷贝过来

4.2 手动处理模型文件(备用方案)

如果Ollama官方库没有你想要的特定量化版本,或者你想使用自己转换的GGUF模型,可以手动操作。

  1. 获取GGUF模型文件 :从Hugging Face等社区平台下载对应模型的GGUF格式文件(例如 deepseek-coder-6.7b-instruct.Q4_K_M.gguf )。
  2. 创建Modelfile :这是一个告诉Ollama如何加载模型的配置文件。
    # Modelfile 示例
    FROM /绝对/路径/到/你的/deepseek-coder-6.7b-instruct.Q4_K_M.gguf
    
    # 设置一些参数
    PARAMETER temperature 0.7
    PARAMETER top_p 0.9
    PARAMETER num_ctx 2048 # 上下文长度,根据模型能力和内存调整,越小越省内存
    
    将上述内容保存为 Modelfile 文件。
  3. 创建并运行模型
    # 在Modelfile所在目录执行
    ollama create my-deepseek -f ./Modelfile
    # 运行模型
    ollama run my-deepseek
    

4.3 首次运行与性能观察

当你第一次执行 ollama run 时,Ollama会加载模型到内存。这是最紧张的时刻。

# 在终端中交互式运行
ollama run deepseek-coder:6.7b-q4_0
# 或者运行你自定义的模型
# ollama run my-deepseek

观察终端输出。你会看到加载进度条。同时,打开另一个终端,运行以下命令监控系统资源:

# 监控GPU使用情况
watch -n 1 nvidia-smi

# 监控内存和Swap使用情况
watch -n 1 free -h

# 监控整体系统负载
htop

如果模型成功加载并出现了提示符(例如 >>> ),恭喜你,最艰难的一步已经完成!你可以尝试输入一些简单的编程问题或对话。

性能预期管理 :在Jetson Nano上运行6.7B的4位量化模型,生成速度可能只有1-3个token/秒。对于简单的代码补全或问答尚可接受,但进行长文本对话会非常需要耐心。更小的模型(如1.3B)速度会快很多,可能达到10-20 token/秒。

5. 高级配置与优化:榨干每一分性能

基础运行只是第一步,要让体验更好,还需要一些优化。

5.1 调整Ollama运行参数

通过环境变量或在 ollama run 时传递参数,可以调整模型运行方式,以更好地适应Jetson Nano。

  • 限制运行线程 :默认Ollama可能会使用所有CPU核心,在ARM上有时反而会因调度开销降低效率。可以尝试限制使用的CPU核心数。

    # 通过numa控制,但Jetson Nano是单节点,更简单的方法是使用taskset
    # 首先,找到ollama serve进程的PID
    ps aux | grep ollama
    # 然后,用taskset绑定到特定CPU核心(例如核心0和1)
    sudo taskset -cp 0,1 <PID>
    

    更一劳永逸的方法是在systemd服务文件 [Service] 部分添加:

    Environment="OMP_NUM_THREADS=2" # 限制OpenMP线程数
    TasksMax=50% # 限制CPU使用率(systemd特性)
    
  • 调整模型加载参数 :在 Modelfile 或运行命令中,可以调整关键参数来平衡速度和内存。

    ollama run deepseek-coder:6.7b-q4_0 --num_ctx 1024 --num_batch 256 --num_gpu_layers 20
    
    • --num_ctx 1024 :将上下文长度从默认的2048减半,显著减少内存占用。
    • --num_batch 256 :处理提示时的批次大小,影响内存和速度。
    • --num_gpu_layers 20 :指定将模型的前20层放在GPU上运行,其余在CPU。这个数字需要反复试验,放太多GPU内存不够,放太少GPU加速效果差。对于6.7B模型,在4GB Jetson上,10-30层是一个可以尝试的范围。

5.2 使用API接口与外部工具集成

Ollama默认在 http://127.0.0.1:11434 提供与OpenAI兼容的API。这意味着你可以用任何支持OpenAI API的客户端来连接它。

使用curl测试API

curl http://127.0.0.1:11434/api/generate -d '{
  "model": "deepseek-coder:6.7b-q4_0",
  "prompt": "用Python写一个快速排序函数",
  "stream": false
}'

配置VS Code或Cursor等编辑器 :许多现代代码编辑器支持配置本地大模型作为补全或聊天助手。

  1. 在VS Code中安装 Continue CodeGPT 等插件。
  2. 在插件设置中,将API Base URL设置为 http://localhost:11434/v1 (注意 /v1 后缀)。
  3. API Key可以留空或随意填写。
  4. 模型名称填写你在Ollama中拉取的模型名,如 deepseek-coder:6.7b-q4_0

这样,你就可以在熟悉的编辑器环境中,获得由本地Jetson Nano提供的代码补全和建议了,虽然速度不快,但隐私性极佳。

5.3 编写自动化脚本与管理多个模型

当你有多个模型或需要定期执行某些任务时,脚本非常有用。

一个简单的对话脚本 ( chat_with_deepseek.py ):

import requests
import json

def ask_ollama(prompt, model="deepseek-coder:6.7b-q4_0", host="localhost", port=11434):
    url = f"http://{host}:{port}/api/generate"
    payload = {
        "model": model,
        "prompt": prompt,
        "stream": False,
        "options": {
            "num_ctx": 1024,
            "temperature": 0.7
        }
    }
    try:
        response = requests.post(url, json=payload, timeout=300) # 设置长超时
        response.raise_for_status()
        return response.json()["response"]
    except requests.exceptions.RequestException as e:
        return f"Error: {e}"

if __name__ == "__main__":
    while True:
        user_input = input("\nYou: ")
        if user_input.lower() in ['exit', 'quit']:
            break
        print("\nDeepSeek: ", end='', flush=True)
        answer = ask_ollama(user_input)
        print(answer)

模型管理脚本 :用于切换不同任务所需的模型。

#!/bin/bash
# switch_model.sh
MODEL_NAME=$1

# 停止当前可能运行的ollama服务(粗暴但有效)
sudo systemctl stop ollama
# 等待进程完全结束
sleep 3

# 这里可以做一些清理工作,比如清空GPU内存(如果有其他进程占用)
# 实际上ollama停止后,GPU内存会被释放

# 启动服务并运行指定模型
sudo systemctl start ollama
sleep 5 # 等待服务启动
ollama run $MODEL_NAME

6. 常见问题与排查实录:我踩过的那些坑

在这一路上,我遇到了不少问题,这里把典型的几个和解决方法记录下来,希望能帮你节省时间。

6.1 内存不足(OOM)问题

症状 :运行 ollama run 时,进程被杀死,终端显示 Killed ,或者系统变得极其卡顿,然后Ollama服务崩溃。 dmesg 日志中能看到 Out of memory 相关记录。

排查与解决

  1. 确认模型大小 :首先确保你拉的模型是量化版(q4, q5, q8等),并且参数规模(如6.7B)对于4GB内存来说已经是极限。优先尝试更小的模型(如1.3B, 3B)。
  2. 增加Swap空间 :如前所述,将Swap扩大到8GB甚至16GB(如果SD卡空间足够)。这不能提升速度,但能防止进程被直接杀死。
  3. 调整模型参数 :这是最有效的手段。在运行或创建模型时,强制减少上下文长度 num_ctx (例如从4096降到1024或512)。这能线性减少内存占用。
  4. 卸载无用进程 :关闭图形界面(如果不需要),进入纯命令行模式,可以节省不少内存。使用 sudo systemctl set-default multi-user.target 然后重启。
  5. 监控工具 :养成使用 htop nvidia-smi 的习惯,在运行模型前先看看空闲内存有多少。

6.2 模型加载失败或输出乱码

症状 :模型能拉取,但运行时报错,例如 unexpected tensor type ,或者生成的内容全是乱码、重复字符。

排查与解决

  1. 模型文件损坏 :这是最常见的原因,尤其是在网络不好时拉取的模型。解决方法是用 ollama rm <model-name> 删除模型,然后重新拉取(建议在稳定网络环境下进行)。或者使用 ollama pull --insecure 参数跳过某些校验(不推荐)。
  2. 量化格式不兼容 :Ollama的GGUF加载器可能对某些非常新的或特殊的量化格式支持不好。尝试换一个更通用的量化类型,例如从 q4_K_M 换成 q4_0
  3. Modelfile配置错误 :如果你是自己创建Modelfile,检查 FROM 指令指向的GGUF文件路径是否正确,文件是否有读取权限。

6.3 Ollama服务无法启动或端口占用

症状 :执行 sudo systemctl status ollama 显示失败,或者用 curl 测试API连接超时。

排查与解决

  1. 检查端口占用 11434 端口可能被其他程序占用。使用 sudo netstat -tlnp | grep 11434 查看。
  2. 检查服务日志 :使用 sudo journalctl -u ollama -f 实时查看服务日志,里面通常有具体的错误信息。
  3. 权限问题 :如果修改了模型存储路径,或者用不同用户运行过Ollama,可能导致权限混乱。检查 /usr/share/ollama 目录及其子目录的所有者和权限,确保运行Ollama服务的用户(如 ollama )有读写权限。
  4. 二进制文件兼容性 :确保下载的Ollama二进制文件是ARM64版本,而不是x86_64版本。可以用 file /usr/local/bin/ollama 命令检查。

6.4 推理速度极慢

症状 :模型能运行,但生成每个词都要等好几秒甚至十几秒。

排查与解决

  1. 检查是否在用GPU :这是最关键的一点。运行模型时,观察 nvidia-smi ,看GPU利用率(Volatile GPU-Util)是否在波动。如果一直是0%,说明模型完全运行在CPU上,速度必然极慢。这通常是因为 num_gpu_layers 参数设置为0,或者模型不支持GPU卸载。确保在运行命令或Modelfile中设置了合适的 num_gpu_layers (一个大于0的值)。
  2. Swap频繁使用 :如果 free -h 显示Swap使用量(used)很高,且 si / so (swap in/out)数值持续不为0,说明内存严重不足,系统在频繁使用低速的Swap,导致整体卡顿。此时只能换更小的模型或进一步降低 num_ctx
  3. 电源和散热 :确认Jetson Nano运行在10W模式( sudo nvpmodel -m 0 ),并且散热良好。过热会导致CPU/GPU降频,性能下降。可以加装风扇或散热片。
  4. 使用更高效的量化 :在模型精度可接受的范围内,使用更激进的量化。例如,从 q8_0 换到 q4_0 ,模型体积和计算量都会减小。

6.5 网络问题与镜像源配置

症状 ollama pull 速度极慢,或者根本连不上。

排查与解决

  1. 使用国内镜像 :这是最有效的解决方案。积极搜索可用的Ollama国内镜像站,并通过环境变量配置。
  2. 手动下载再导入 :如前面反复强调的,在PC端下载好模型文件(GGUF),然后通过SCP、U盘等方式拷贝到Jetson Nano。在Jetson上使用 ollama create 从本地文件创建模型。这是绕过网络问题最彻底的方法。
  3. 代理配置(需合规) :如果你有合规的网络访问方式,可以在系统或Ollama服务级别配置。但请注意,配置代理本身需要谨慎处理,确保符合所有相关规定。

整个项目折腾下来,最大的体会就是“妥协的艺术”。在Jetson Nano这样的资源受限边缘设备上部署大模型,你必须在模型能力、响应速度、内存占用和功耗之间反复权衡。没有完美的方案,只有最适合你当前场景的选择。对于教育演示、离线轻量问答、特定领域的代码补全,这个方案是可行且有趣的。但对于需要高响应、长上下文的生产环境,它显然力不从心。不过,这个过程本身带来的对模型部署、硬件性能、量化技术以及Linux系统调优的理解,是任何理论教程都无法替代的。最后一个小技巧,给你的Jetson Nano配一个主动散热风扇和一个可靠的5V 4A电源,它能让你在调试的路上走得更稳当。

更多推荐