本地部署DeepSeek并开放API

在本地电脑部署DeepSeek,并开放API给局域网内其它设备调用,如树莓派。

1. 基础

1.1 平台

  • Ubuntu 22.04
  • Ollama
  • DeepSeek-R1-1.5B

Note: 在Windows平台部署步骤类似。

1.2 整体规划

  1. 只是开发测试,而不是生产环境部署,所以部署快速模型进行开发,消耗资源越少越好;
  2. 我会使用DeepSeek-R1-1.5B的4bit量化版本,实测体积减少70%;
  3. 使用Ollama进行部署,并使用Ollama的API调用DeepSeek。

2. 安装开发环境

$ sudo apt install build-essential flex bc gawk bison texinfo libssl-dev libelf-dev libncurses-dev cmake git ssh curl

另外需安装cuda, cudnn,pytorch.

3. 安装Ollama

$ curl -fsSL https://ollama.com/install.sh | sh

3.1 新手看这里,老司机跳过

新手执行以下命令,之后,直接跳过步骤4~步骤7,直接从步骤8开始执行:

$ ollama run deekseep-r1:1.5b

并把后面步骤的 "deepseek-r1-q4" 替换成 "deepseek-r1:1.5b",如果有变化,则运行以下命令:

$ ollama list

以结果中的NAME的实际名称为准。

4. 下载DeepSeek模型

从huggingface下载(国内网络无法直连,设置环境变量:"HF_ENDPOINT=https://hf-mirror.com"),安装一些python库:

$ pip install transformers huggingface_hub sentencepiece

通过huggingface-cli(上面的python库会产生这个软件)下载:

$ cd ~
$ mkdir -p models/deepseek-r1
$ mkdir -p models/output
$ cd models/deepseek-r1
$ huggingface-cli download deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --local-dir . --local-dir-use-symlinks False

目录如下:

$ ls
.cache
figures
.gitattributes
config.json
generation_config.json
LICENSE
model.safetensors
README.md
tokenizer.json
tokenizer_config.json

5. 下载编译llama.cpp

$ cd ~
$ git clone https://github.com/ggml-org/llama.cpp.git
$ cd llama.cpp
$ mkdir build
$ cmake -B build
$ cmake --build build --config Release -j8

编译完成后,验证编译是否成功:

$ cd ~/llama.cpp/
$ ./build/bin/llama-cli --help

如果有非错误信息打印,说明成功。

6. 转换模型

6.1 转为FP16精度的GGUF文件

Note: 注意下方命令参数中的路径改为实际存放路径.

$ cd ~/llama.cpp/
$ python convert_hf_to_gguf.py ~/models/deepseek-r1 --outfile ~/models/output/deepseek-r1-1_5b-fp16.guff --outtype f16

查看存储占用:

$ cd ~/models/
$ du -sh deepseek-r1
3.4G    deepseek-r1

$ du -sh output/deepseek-r1-1_5b-fp16.guff
3.4G    output/deepseek-r1-1_5b-fp16.guff

可以看出,转换为GGUF后,文件尺寸并没有改变。

产生的`~/models/output/deepseek-r1-1_5b-fp16.guff`, 就可以部署使用了,它的精度是fp16.

不过我们使用它的4-bit量化版本,以进一步减少存储空间占用和减少资源使用量.

6.2 转为Q4精度的GUFF文件

$ cd ~/llama.cpp/build/bin
$ llama-quantize ~/models/output/deepseek-r1-1_5b-fp16.guff ~/models/output/deepseek-r1-1_5b-q4.guff Q4_0

转换完成后,我们查看存储占用:

$ cd ~/models/output/
$ du -sh *
3.4G    deepseek-r1-1_5b-fp16.guff
1017M   deepseek-r1-1_5b-q4.guff

$ du -s *
3476976 deepseek-r1-1_5b-fp16.guff
1041244 deepseek-r1-1_5b-q4.guff

可以看出, 体积减小 ((3476976 - 1041244) / 3476976 * 100%) ≈ 70%.

7. 部署模型

$ cd ~
$ mkdir -p .ollama/models
$ cp ~/models/output/deepseek-r1-1_5b-q4.guff ~/.ollama/models/
$ cd ~/.ollama/models/
$ vim Modelfile

在Modelfile中添加如下内容:

FROM ./deepseek-r1-1_5b-q4.guff
PARAMETER temperature 0.6
PARAMETER num_ctx 4096

使用ollama安装模型:

$ cd ~/.ollama/models/
$ ollama create deepseek-r1-q4 -f Modefile
$ ollama run deepseek-r1-q4

如果正常,就可以使用本地deepseek-r1-q4了(一般而言,准确度相较于原始模型下降)。

8. 局域网使用API

$ sudo vim /etc/systemd/system/ollama.service

在其中的Enviorment追加一个端口11434(ollama默认端口),把此处:

[Service]
...
Enviorment="..."

改为:

[Service]
...
Enviorment="OLLAMA_HOST=0.0.0.0:11434"

然后执行:

$ sudo systemctl daemon-reload
$ sudo systemctl restart ollama
$ sudo ufw allow 11434/tcp

先来个本地简单测试:

$ curl http://localhost:11434/api/tags

如果部署成功,这个本地网络请求,会返回ollama已安装的模型列表信息。

9. 通过api调用deepseek

9.1 生成式

$ curl http://localhost:11434/api/generate -d '{"model": "deepseek-r1-q4", "prompt": "今天天气很好", "stream": false}'

9.2 对话式

$ curl http://localhost:11434/api/chat -d '{"model": "deepseek-r1-q4", "messages": [{"role": "user", "content": "讲个笑话"}]}, "stream": false'

根据电脑性能,回复的快慢可能不同。正常情况下可以根据关键字生成一些内容。
局域网内其它设备把localhost换成部署电脑的IP,如家用路由器的常见形式是"192.168.XXX.XXX",之后,局域网其他设备比如电脑,树莓派,或者一些其它的设备,就可以调用这个api进行交互了。

10. 代码调用

以Python为例:

import requests

def call_deepseek(prompt, model="deepseek-r1-q4", api_url="http://localhost:11434/api/generate"):
    payload = {
        "model": model,
        "prompt": f"<|You are a helpful assistant|>{prompt}",
        "stream": False,
        "options": {
            "temperature": 0.7,
            "max_tokens": 1000
        }
    }
    try:
        response = requests.post(api_url, json=payload)
        response.raise_for_status()
        return response.json()["response"]
    except Exception as e:
        return f"API failed for {str(e)}"

result = call_deepseek("今天天气很好")
print(result)

更多的自行探索。

posted @ 2025-03-31 20:26  this毛豆  阅读(769)  评论(0)    收藏  举报