AI 工具

DeepSeek-R1 本地部署:GGUF 校验导入、性能测试与 WebUI

在自己的电脑或小主机上跑 DeepSeek-R1 蒸馏模型,数据不出本机。ollama pull 不通时(公司代理、DNS 拦截等),改用“从 Hugging Face 下载 GGUF、校验 sha256、导入 Ollama”的办法。再测一下本机速度,最后用 Open WebUI 给家人或同事一个网页界面。

BINBHO · 图文教程

在自己的电脑或小主机上跑 DeepSeek-R1 蒸馏模型,数据不出本机。ollama pull 不通时(公司代理、DNS 拦截等),改用“从 Hugging Face 下载 GGUF、校验 sha256、导入 Ollama”的办法。再测一下本机速度,最后用 Open WebUI 给家人或同事一个网页界面。

先看清成品

  • 在 box 上实测(8 核 Intel Xeon 虚拟机,没有 GPU,16GB 内存;Ollama 0.40.7):

    • ollama pull 失败(见调试示例),改用 import_gguf.sh 导入成功,sha256 校验通过。
    • 故意截断文件后再导入,被 sha256 校验拦下。
  • 速度:

    模型 生成速度 读入提示
    deepseek-r1-distill:1.5b 43.6 tok/s 646.4 tok/s
    qwen2.5 1.5b 48.8 tok/s 1853.3 tok/s
    qwen3 0.6b 123.3 tok/s 1950.7 tok/s

    (之前另一次运行的生成速度是 41.0 / 40.6 / 143.2,说明每次结果都有波动)

  • 没有测过: Open WebUI 的 compose 文件只做了 docker compose config 校验,没有启动;GPU 部分也没有测(box 没有 GPU)。

说明:“DeepSeek-R1 蒸馏版”是用 R1 的输出训练出来的小模型(基座是 Qwen),能力和官方 API 背后的大模型差距很大。本机跑的是 1.5B 参数、Q4_K_M 量化的版本。许可证(Hugging Face 标签):deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B 是 MIT,unsloth 的 GGUF 转换仓库是 apache-2.0。

合规提醒:API Key 只放在环境变量里,不要写进代码或提交到 Git。不要把身份证号、客户资料、公司机密发给云端 API;这类数据用 B 篇的本地部署处理。如果要把它做成面向公众的服务,需要按《生成式人工智能服务管理暂行办法》《人工智能生成合成内容标识办法》等规定履行相应义务。API 价格以 DeepSeek 官网“模型 & 价格”页为准,本文不列价格。

安全提醒:Ollama 的 11434 端口没有鉴权。不要映射到公网,也不要在路由器上开端口。局域网共享请通过 Open WebUI(它有账号体系),远程使用参考 38-jellyfin-C 的 Tailscale 方案。

做完之后你会得到什么?

成果 说明
import_gguf.sh 用 HF API 取 sha256 → 下载 → 校验 → ollama create
bench.py 用 Ollama 返回的 eval_count / eval_duration 计算 tok/s,第一次运行(包含加载时间)不计入
docker-compose.yml Ollama + Open WebUI,Ollama 不对外开放端口

需要准备哪些环境?

项目 要求 说明
内存 1.5B Q4 模型文件约 1.1GB;建议 8GB 以上内存 7B 以上的模型需要更多内存,或者用显卡
Ollama Linux 用官方安装脚本;macOS / Windows 用安装包 安装脚本需要 zstd(box 上缺少时安装脚本会报错提示)
工具 curl、python3、sha256sum

文件结构

41-deepseek-B-src/
├── import_gguf.sh
├── bench.py
└── docker-compose.yml

第 1 步:导入模型

import_gguf.sh:

#!/bin/sh
# 从 Hugging Face 下载 GGUF,核对 sha256,再导入 Ollama。
# 适用场景:ollama pull 不通(公司代理、内网镜像、DNS 拦截等),或者想用指定的量化版本。
# 用法:sh import_gguf.sh 仓库 文件名 本地模型名
#   sh import_gguf.sh unsloth/DeepSeek-R1-Distill-Qwen-1.5B-GGUF DeepSeek-R1-Distill-Qwen-1.5B-Q4_K_M.gguf deepseek-r1-distill:1.5b
set -eu
REPO=$1; FILE=$2; NAME=$3; DIR=${GGUF_DIR:-$HOME/gguf}
mkdir -p "$DIR"; cd "$DIR"
# Hugging Face 的 API 会给出 LFS 文件的 sha256
WANT=$(curl -fsSL "https://huggingface.co/api/models/$REPO/tree/main" |
  python3 -c "import sys,json; print(next(f['lfs']['oid'] for f in json.load(sys.stdin) if f['path']=='$FILE'))")
[ -f "$FILE" ] || curl -fL --retry 3 -C - -o "$FILE" "https://huggingface.co/$REPO/resolve/main/$FILE"
GOT=$(sha256sum "$FILE" | cut -d' ' -f1)
[ "$GOT" = "$WANT" ] || { echo "✗ sha256 不一致:$GOT ≠ $WANT,删除后重新下载"; exit 1; }
echo "✓ sha256 校验通过 $GOT"
printf 'FROM ./%s\n' "$FILE" > "Modelfile.$NAME"
ollama create "$NAME" -f "Modelfile.$NAME"
ollama show "$NAME" | sed -n '1,12p'
$ sh import_gguf.sh unsloth/DeepSeek-R1-Distill-Qwen-1.5B-GGUF DeepSeek-R1-Distill-Qwen-1.5B-Q4_K_M.gguf deepseek-r1-distill:1.5b
✓ sha256 校验通过 f3bdf9cf31dee4b57ae4e455a1cb0d01b5c2c1b50d72d3112141c195506c2840
using existing layer sha256:f3bdf9cf…  writing manifest  success
  Model
    architecture        qwen2
    parameters          1.8B
    context length      131072
    quantization        Q4_K_M
    template source     gguf_chat_template
  Capabilities
    tools
    thinking
    completion

template source: gguf_chat_template 表示 Ollama 直接使用了 GGUF 文件里自带的对话模板,所以 Modelfile 只需要一行 FROM。截断文件后的校验结果:

✗ sha256 不一致:<截断文件的哈希> ≠ f3bdf9cf…2840,删除后重新下载

第 2 步:测速度

bench.py:

"""在本机测本地模型的速度:用 Ollama 原生接口返回的 eval_count / eval_duration 计算生成速度(tokens/s)。
用法:python bench.py 模型1 模型2 ...    环境变量 OLLAMA_URL 默认 http://127.0.0.1:11434"""
import os, sys, requests

URL = os.environ.get("OLLAMA_URL", "http://127.0.0.1:11434")
PROMPT = "用三句话解释什么是二分查找。"

def run(model, think=None):
    body = {"model": model, "prompt": PROMPT, "stream": False, "options": {"num_predict": 256, "temperature": 0}}
    if think is not None: body["think"] = think
    d = requests.post(f"{URL}/api/generate", json=body, timeout=600).json()
    if "error" in d: raise SystemExit(f"{model}: {d['error']}")
    return d

for m in sys.argv[1:]:
    run(m)                                  # 第一次包含加载时间,丢掉
    d = run(m)
    gen = d["eval_count"] / d["eval_duration"] * 1e9
    pp = d["prompt_eval_count"] / max(d["prompt_eval_duration"], 1) * 1e9
    print(f"{m:28} 生成 {gen:5.1f} tok/s  读入提示 {pp:6.1f} tok/s  本次输出 {d['eval_count']} tokens")
$ python bench.py deepseek-r1-distill:1.5b qwen2.5-local:1.5b qwen3-local:0.6b
deepseek-r1-distill:1.5b     生成  43.6 tok/s  读入提示  646.4 tok/s  本次输出 256 tokens
qwen2.5-local:1.5b           生成  48.8 tok/s  读入提示 1853.3 tok/s  本次输出 29 tokens
qwen3-local:0.6b             生成 123.3 tok/s  读入提示 1950.7 tok/s  本次输出 256 tokens

这是 box 上的实测数字,你的机器会不一样,请在自己的机器上跑一遍。

第 3 步:网页界面(未在 box 上启动)

docker-compose.yml:

# Ollama + Open WebUI:在局域网里给家人或同事一个网页聊天界面
# 注意:Ollama 的 11434 端口没有鉴权,不要映射到公网;这里只让 Open WebUI 在容器网络内访问它
services:
  ollama:
    image: ollama/ollama
    volumes:
      - ./ollama:/root/.ollama
      - ./gguf:/gguf:ro            # 放 import_gguf.sh 下载好的文件,在容器里 ollama create
    restart: unless-stopped
    # 有 NVIDIA 显卡时取消注释(需要先安装 NVIDIA Container Toolkit)
    # deploy:
    #   resources:
    #     reservations:
    #       devices: [{driver: nvidia, count: all, capabilities: [gpu]}]
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    environment:
      OLLAMA_BASE_URL: http://ollama:11434
    volumes:
      - ./open-webui:/app/backend/data
    ports:
      - "3000:8080"
    depends_on: [ollama]
    restart: unless-stopped

启动后打开 http://主机:3000,第一个注册的账号就是管理员。

调试示例:ollama pull 报“non-public”

在 box 上直接 ollama pull deepseek-r1:1.5b,会长时间卡在 “pulling manifest”,等不到结果时会报错。报错的关键信息是(节选并整理):Ollama 下载模型时会跳转到 *.r2.cloudflarestorage.com,而这个域名被解析成了 198.18.0.1;Ollama 判定这是非公网地址,拒绝跳转。

原因是 box 的网络把这个下载域名解析到了 198.18.0.1(198.18.0.0/15 是保留地址段,常见于代理或 DNS 拦截环境)。Ollama 认为这是非公网地址,拒绝跳转。这不是 Ollama 坏了,而是网络环境的问题。解决办法有两个:换一个网络;或者像本文这样从 Hugging Face 下载 GGUF 再导入。导入时一定要校验 sha256,避免文件下载不完整或被篡改。

常见问题

现象 原因 处理
安装脚本提示缺 zstd 新版安装包是 zstd 压缩的 apt-get install zstd
速度很慢 内存不够,模型被换到了磁盘上 换更小的模型或更低的量化
局域网其他电脑连不上 11434 默认只监听本机 用 Open WebUI 访问,不要直接开放 11434

模板规则

  • 导入的模型文件一律校验 sha256。
  • 速度以自己机器的实测为准。
  • 无鉴权的推理端口不对外开放。

项目资源

用途 地址
Ollama 导入模型 https://docs.ollama.com/import
Ollama Linux 安装 https://docs.ollama.com/linux
DeepSeek-R1-Distill-Qwen-1.5B(Hugging Face) https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
GGUF 量化版(unsloth) https://huggingface.co/unsloth/DeepSeek-R1-Distill-Qwen-1.5B-GGUF
Open WebUI 文档 https://docs.openwebui.com/

本地部署的价值在于数据不出门。代价是模型小、能力有限,所以要先测清楚它能做什么,再决定哪些任务交给它。