DeepSeek本地部署+API调用实战:从Ollama到vLLM,我踩过的坑全在这

去年底DeepSeek V3发布的时候,我第一反应是"又一个大模型"。等我真正跑起来,发现这东西确实有点东西——671B参数的MoE架构,实际推理只激活37B,性能逼近GPT-4但成本低了一个量级。

这篇文章记录我把DeepSeek从"跑起来玩玩"到"真正用在生产项目里"的全过程。不讲理论废话,直接上手操作,踩过的坑一个不落。

一、先搞清楚你要什么:V3还是R1?

很多人上来就问"DeepSeek怎么部署",但连V3和R1的区别都没搞清。简单说:

V3是通用模型,采用MoE(混合专家)架构,总参数671B但每次推理只激活37B个参数。适合日常对话、写作、代码生成这类通用任务。它的核心创新是Multi-head Latent Attention(MLA),把KV Cache的显存占用压缩到了传统MHA的5-13%。

R1是推理模型,走的Dense架构路线,专门针对数学、逻辑、代码调试做了优化。它会先"思考"一段内部推理链,然后给出答案。思考过程用户看不到,但能显著提升复杂问题的准确率。

我的选择标准很简单: - 日常写代码、处理文本 → V3 - 解数学题、做逻辑推理、调复杂bug → R1 - 本地资源有限 → R1的蒸馏版(7B/14B/32B参数量可选)

二、Ollama本地部署:5分钟跑起来

Ollama是我推荐新手的第一选择。不用折腾Python环境、不用配CUDA,一行命令就能跑。

安装

macOS和Linux直接一行搞定:

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

Windows去官网 https://ollama.com/download 下载安装包,双击就行。

下载并运行模型

# DeepSeek R1 7B蒸馏版(适合入门,约4.7GB)
ollama run deepseek-r1:7b

# DeepSeek R1 32B版(需要至少20GB内存,推荐有显卡的机器)
ollama run deepseek-r1:32b

# DeepSeek V3(完整671B,需要企业级硬件)
ollama run deepseek-v3

第一次执行会自动下载模型文件。下载完成后直接进入交互式对话,出现 >>> Send a message... 就是成功了。

实测结果

我在两台机器上测试了DeepSeek R1不同版本的表现:

测试机器A:MacBook Pro M2 Pro,32GB内存,无独立显卡

模型版本 文件大小 加载时间 生成速度 回答质量
R1 1.5B 1.1GB 2秒 42 tokens/s 能对话,但经常跑题,不推荐
R1 7B 4.7GB 5秒 18 tokens/s 日常够用,代码生成准确率约70%
R1 14B 9.0GB 11秒 9 tokens/s 明显更聪明,性价比最高
R1 32B 19.5GB 28秒 4 tokens/s 接近满血,但生成太慢

测试机器B:Ubuntu服务器,64GB内存,RTX 4090 24GB显存

模型版本 生成速度 并发能力
R1 7B 85 tokens/s 可同时处理5个请求
R1 14B 52 tokens/s 可同时处理3个请求
R1 32B 28 tokens/s 单请求流畅

结论:个人笔记本跑7B或14B就够了;有GPU的服务器推荐32B。1.5B别浪费时间,降智严重。

踩坑记录

坑1:内存不足直接卡死

32GB内存跑32B模型,系统会把剩余内存用完。我第一次跑的时候Chrome还开着20个标签页,直接把机器卡到重启。解决方案:跑大模型前关掉吃内存的应用,或者用OLLAMA_MAX_LOADED_MODELS=1限制同时加载的模型数。

export OLLAMA_MAX_LOADED_MODELS=1
export OLLAMA_NUM_PARALLEL=1
ollama run deepseek-r1:32b

坑2:模型下载中断后无法续传

网络不好的话,几个G的模型下载到一半断了。Ollama不支持断点续传,只能重新下载。我的解决方案是用代理或者换个网络好的时段下载:

# 设置代理后再下载
export HTTPS_PROXY=http://127.0.0.1:7890
ollama pull deepseek-r1:14b

坑3:Ollama的API端口和其他服务冲突

Ollama默认监听11434端口。如果你机器上跑着其他服务占了这个端口,启动会报错但没提示。手动指定端口:

export OLLAMA_HOST=0.0.0.0:11435
ollama serve

三、vLLM部署:生产环境的正确选择

Ollama跑个人项目没问题,但要接入生产系统——比如我需要同时给8个平台的内容生成提供API服务——就需要vLLM了。

为什么选vLLM?

核心区别一句话:Ollama是个人电脑的桌面应用,vLLM是服务器上的推理引擎。

vLLM用了PagedAttention技术来管理显存,原理类似操作系统的虚拟内存分页。传统方法给每个请求预分配一大块连续显存,很多时候用不完,浪费严重。vLLM把显存切成小块按需分配,显存利用率能到95%以上。

实际效果:同样的RTX 4090,Ollama跑7B模型处理5个并发已经很勉强,vLLM能轻松处理20个并发请求。

安装和启动

# 前提:Python 3.8+,CUDA 11.8+,NVIDIA GPU
pip install vllm

# 启动API服务(兼容OpenAI接口格式)
python -m vllm.entrypoints.openai.api_server \
    --model deepseek-ai/DeepSeek-V3 \
    --tensor-parallel-size 1 \
    --max-model-len 4096 \
    --gpu-memory-utilization 0.9 \
    --port 8000

几个关键参数说明: - --tensor-parallel-size:多GPU并行数,单卡就写1 - --max-model-len:最大上下文长度,显存不够就调小 - --gpu-memory-utilization:显存使用比例,留一点给系统

调用测试

vLLM启动后暴露的是OpenAI兼容接口,直接用openai库调用:

from openai import OpenAI

client = OpenAI(
    api_key="not-needed",  # 本地部署不需要key
    base_url="http://localhost:8000/v1"
)

response = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V3",
    messages=[
        {"role": "system", "content": "你是一个Python专家"},
        {"role": "user", "content": "写一个递归实现的快速排序,要求处理重复元素"}
    ],
    temperature=0.7,
    max_tokens=1024
)

print(response.choices[0].message.content)

踩坑记录

坑1:CUDA版本不匹配

vLLM对CUDA版本很敏感。我一开始装的CUDA 12.4,vLLM某些算子编译不过。降到CUDA 12.1就好了。检查方法:

nvcc --version  # 查看CUDA版本
nvidia-smi      # 查看驱动版本
pip show vllm   # 查看vLLM编译依赖的CUDA版本

坑2:模型太大加载失败

DeepSeek V3完整版671B,需要至少8张A100 80GB才能跑。大部分人用不上。我退而求其次用了R1 32B版本,单卡4090就能跑得很顺畅。

四、DeepSeek API调用:不想自己部署就用官方

自己部署不现实的话(比如没有GPU),直接调DeepSeek的官方API是最省事的方案。

申请API Key

  1. 去 https://platform.deepseek.com 注册账号
  2. 充值(目前价格:V3输入¥1/百万tokens,输出¥2/百万tokens,比GPT-4便宜10倍以上)
  3. 在"API Keys"页面创建密钥

基础调用

from openai import OpenAI

client = OpenAI(
    api_key="sk-your-api-key",
    base_url="https://api.deepseek.com"
)

# 普通对话
response = client.chat.completions.create(
    model="deepseek-chat",  # 对应V3
    messages=[
        {"role": "user", "content": "解释一下Python的GIL是什么,为什么它让多线程变慢"}
    ]
)
print(response.choices[0].message.content)

# 推理模式(R1)
response = client.chat.completions.create(
    model="deepseek-reasoner",  # 对应R1
    messages=[
        {"role": "user", "content": "证明:对任意正整数n,n^3 - n 能被6整除"}
    ]
)
# R1会返回reasoning_content(思维链)和content(最终答案)
print("思考过程:", response.choices[0].message.reasoning_content)
print("最终答案:", response.choices[0].message.content)

Function Calling实战

Function Calling是我用得最多的功能——让模型不只是"聊天",而是能调用外部工具完成实际任务。

from openai import OpenAI
import json

client = OpenAI(
    api_key="sk-your-api-key",
    base_url="https://api.deepseek.com"
)

# 定义工具
tools = [
    {
        "type": "function",
        "function": {
            "name": "search_articles",
            "description": "搜索技术文章数据库",
            "parameters": {
                "type": "object",
                "properties": {
                    "keyword": {
                        "type": "string",
                        "description": "搜索关键词"
                    },
                    "platform": {
                        "type": "string",
                        "enum": ["zhihu", "juejin", "csdn", "all"],
                        "description": "指定搜索平台"
                    },
                    "limit": {
                        "type": "integer",
                        "description": "返回结果数量",
                        "minimum": 1,
                        "maximum": 20
                    }
                },
                "required": ["keyword"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "publish_article",
            "description": "发布文章到指定平台",
            "parameters": {
                "type": "object",
                "properties": {
                    "title": {"type": "string", "description": "文章标题"},
                    "content": {"type": "string", "description": "文章内容(Markdown格式)"},
                    "platform": {
                        "type": "string",
                        "enum": ["zhihu", "juejin", "csdn"],
                        "description": "发布平台"
                    },
                    "tags": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "文章标签"
                    }
                },
                "required": ["title", "content", "platform"]
            }
        }
    }
]

# 第一轮:用户请求,模型选择工具
messages = [{"role": "user", "content": "帮我搜一下掘金上关于MoE架构的最新文章,找3篇"}]
response = client.chat.completions.create(
    model="deepseek-chat",
    messages=messages,
    tools=tools
)

message = response.choices[0].message
print("模型选择了工具:", message.tool_calls[0].function.name)
print("参数:", message.tool_calls[0].function.arguments)
# 输出: search_articles, {"keyword": "MoE架构", "platform": "juejin", "limit": 3}

# 第二轮:返回工具执行结果,模型生成最终回答
messages.append(message)
messages.append({
    "role": "tool",
    "tool_call_id": message.tool_calls[0].id,
    "content": json.dumps([
        {"title": "DeepSeek V3的MoE架构深度解析", "url": "https://juejin.cn/post/xxx1", "likes": 234},
        {"title": "MoE vs Dense:大模型架构选型指南", "url": "https://juejin.cn/post/xxx2", "likes": 189},
        {"title": "从零实现一个简单的MoE层", "url": "https://juejin.cn/post/xxx3", "likes": 156}
    ], ensure_ascii=False)
})

final_response = client.chat.completions.create(
    model="deepseek-chat",
    messages=messages,
    tools=tools
)
print(final_response.choices[0].message.content)

这段代码的实际效果:用户说"帮我搜文章",模型自动判断该调search_articles函数,提取出关键词、平台、数量等参数。你只需要实现真正的搜索逻辑,模型负责理解意图和组织答案。

踩坑记录

坑1:R1模型不支持Function Calling

deepseek-reasoner(R1)目前不支持tools参数。我一开始没注意,传了tools进去直接报500错误,日志里也没有明确提示。记住:Function Calling只能用deepseek-chat(V3)

坑2:API高峰期限流

DeepSeek API在工作日下午(14:00-18:00)经常限流,返回429错误。我的处理方案是加指数退避重试:

import time
import random

def call_with_retry(func, max_retries=5):
    for attempt in range(max_retries):
        try:
            return func()
        except Exception as e:
            if "429" in str(e) and attempt < max_retries - 1:
                wait = (2 ** attempt) + random.random()
                print(f"限流,等待 {wait:.1f} 秒后重试...")
                time.sleep(wait)
            else:
                raise

坑3:长文本输出被截断

max_tokens默认值比较小,长文章生成到一半就停了。API调用时务必手动设一个够大的值:

response = client.chat.completions.create(
    model="deepseek-chat",
    messages=messages,
    max_tokens=4096  # 根据需要调大
)

五、Ollama vs vLLM vs API:我该选哪个?

跑了两个月之后,我的实际使用分配是这样的:

场景 方案 原因
日常写代码、问问题 Ollama + R1 14B 本地跑不花钱,响应快
批量生成内容(8个平台分发) DeepSeek API V3 需要高并发和Function Calling
复杂推理、数学证明 DeepSeek API R1 本地跑不起满血版
压测/基准测试 vLLM + R1 32B 需要精确控制推理参数

如果你刚入门,我建议从Ollama开始——零成本,5分钟上手。等你发现本地模型不够用了,再申请API key补充。vLLM等你确实有生产级需求再碰。

六、总结

DeepSeek的出现让"本地跑大模型"从极客玩具变成了实用工具。V3的MoE架构在保持高性能的同时把推理成本砍到了传统Dense模型的几分之一。R1的推理链机制在复杂任务上表现让人惊喜。

我每天实际在用的组合:笔记本上Ollama跑R1 14B处理日常开发问题,云端API V3处理多平台内容生成任务。两个月下来API费用不到50块钱。

如果你也在做AI相关的开发,DeepSeek值得认真试试。不一定要替代GPT-4,但作为高性价比的补充方案,已经足够好了。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐