1. 为什么本地跑 deepseek-r1 还需要一层“接入层”
很多人第一次在终端里跑通ollama run deepseek-r1:7b之后,会陷入一种微妙的失落:模型确实在回答,但只能对着黑底白字的命令行敲字,历史对话翻不回去,代码片段复制出来还带着一堆换行。更关键的是,它和你的 Vscode 是割裂的——你在编辑器里写代码,想让它帮忙看一段逻辑,只能切窗口、复制、粘贴、再复制回来。这个链路一旦超过三次,人就不想用了。
所以“本地部署 deepseek-r1”这件事,真正的分水岭不在模型能不能跑起来,而在于它能不能变成你日常工作流里顺手的一环。我自己的判断标准很简单:如果调用它需要我离开当前编辑器超过 5 秒,那它就不算落地。
这篇要做的就是把三个东西串成一条线:Ollama 负责把 deepseek-r1 拉起来并提供标准推理端点,web-ui 负责给你一个能管理对话历史的网页界面,Vscode 插件负责把同一个推理端点接进代码编辑器。三者共用同一个http://localhost:11434端点,模型只加载一份,显存不重复占用。
适合谁看:手上有 16G 内存以上、有一块 8G 显存左右显卡的个人开发者;已经装过 Ollama 但只会在终端里用的人;想给团队内部做一个不联网的代码助手原型的人。如果你还没装 Ollama,下面第二节会从零给命令。
先明确一个概念,避免后面混淆。Ollama 本身是一个模型运行时,它启动后会在本地监听一个 HTTP 服务,默认端口 11434。这个服务提供两类接口:一类是 Ollama 自己的/api/chat、/api/generate,另一类是兼容 OpenAI 格式的/v1/chat/completions。web-ui 和 Vscode 插件本质上都是这个端点的客户端。理解这一点,后面所有配置就都是在填“Base URL + 模型名”这两个字段。
我试过把 web-ui 和编辑器插件分别指向不同的模型实例,结果 8G 显存直接爆掉,两个进程互相抢显存,最后都卡死。所以本文的核心原则是:一个 Ollama 服务,多个客户端共用。
2. 用 Ollama 拉起 deepseek-r1 并确认推理端点可用
这一节的目标是让你得到一个稳定运行的本地推理服务,并且能用 curl 验证它真的在流式输出。如果你已经跑通了,可以快速扫一眼启动参数部分,重点看OLLAMA_HOST和OLLAMA_KEEP_ALIVE这两个环境变量,它们决定了后面 web-ui 和 Vscode 能不能连上。
2.1 安装与拉取模型
Windows 和 macOS 直接去 Ollama 官网下载安装包,Linux 用一行脚本:
curl -fsSL https://ollama.com/install.sh | sh安装完成后验证版本:
ollama --version拉取 deepseek-r1。这里要按显存选型号,别盲目上 14b:
| 模型型号 | 参数量 | 量化后体积 | 建议显存 | 适用场景 |
|---|---|---|---|---|
| deepseek-r1:1.5b | 1.5B | 约 1.1GB | 2GB+ | 轻量补全、低配笔记本 |
| deepseek-r1:7b | 7B | 约 4.7GB | 6GB+ | 日常代码问答,推荐起点 |
| deepseek-r1:8b | 8B | 约 5.2GB | 7GB+ | 比 7b 略强,显存够就选 |
| deepseek-r1:14b | 14B | 约 9GB | 12GB+ | 复杂推理,8G 卡会溢出到内存 |
8G 显存的卡,我建议从deepseek-r1:7b或8b起步。14b 在 8G 卡上会部分卸载到 CPU,token 速度会掉到个位数,体验很差。
ollama pull deepseek-r1:7b拉取完成后确认模型在列表里:
ollama list2.2 带参数启动服务
默认ollama serve只监听127.0.0.1:11434。如果你后面要用 Docker 跑 web-ui,容器内的localhost指向的是容器自己,连不到宿主机,所以要么用host.docker.internal,要么让 Ollama 监听0.0.0.0。我选择后者,配置更省心。
Linux/macOS 下用环境变量启动:
export OLLAMA_HOST=0.0.0.0:11434 export OLLAMA_KEEP_ALIVE=24h export OLLAMA_NUM_PARALLEL=2 ollama serveWindows PowerShell:
$env:OLLAMA_HOST="0.0.0.0:11434" $env:OLLAMA_KEEP_ALIVE="24h" $env:OLLAMA_NUM_PARALLEL="2" ollama serve三个参数的作用:OLLAMA_HOST让服务对外可访问,Docker 和局域网设备都能连;OLLAMA_KEEP_ALIVE=24h让模型在最后一次请求后 24 小时内常驻显存,避免每次提问都重新加载,冷启动那十几秒真的很劝退;OLLAMA_NUM_PARALLEL=2允许两个并发请求,web-ui 和编辑器同时用不会互相阻塞。
注意:
OLLAMA_HOST设为0.0.0.0后,同局域网的其他机器也能访问你的模型。如果只在个人电脑上用,可以改回127.0.0.1,然后 Docker 那边用host.docker.internal连接。
2.3 用 curl 验证流式输出
服务起来后,先别急着装 web-ui,用 curl 确认端点正常。这一步能帮你排除掉后面 80% 的“连不上”问题。
curl http://localhost:11434/api/chat -d '{ "model": "deepseek-r1:7b", "messages": [ {"role": "user", "content": "用一句话解释什么是递归"} ], "stream": true }'如果返回的是一行行 JSON,每行带一个message.content字段,说明流式输出正常。你会看到类似这样的分块:
{"model":"deepseek-r1:7b","message":{"role":"assistant","content":"递归"},"done":false} {"model":"deepseek-r1:7b","message":{"role":"assistant","content":"就是"},"done":false} {"model":"deepseek-r1:7b","message":{"role":"assistant","content":"函数"},"done":false}再验证一下 OpenAI 兼容接口,因为 Vscode 的 Continue 和 Cline 默认走这个格式:
curl http://localhost:11434/v1/chat/completions -d '{ "model": "deepseek-r1:7b", "messages": [{"role": "user", "content": "hello"}], "stream": false }'两个接口都通,说明 Ollama 这一层已经稳了。接下来所有客户端都只需要填http://localhost:11434和deepseek-r1:7b。
3. 搭建 web-ui 对话界面并配置环境变量
web-ui 我选 Open WebUI,原因是它对 Ollama 的原生支持最好,装完基本不用改配置就能识别本地模型,而且对话历史、多会话管理、Markdown 渲染都齐全。这一节给出 Docker 启动命令和关键环境变量,重点解决“容器连不上宿主机 Ollama”这个高频坑。
3.1 Docker 启动命令
先确认 Docker 已安装并运行:
docker --version docker ps然后拉取并启动 Open WebUI:
docker run -d -p 3000:8080 \ --add-host=host.docker.internal:host-gateway \ -e OLLAMA_BASE_URL=http://host.docker.internal:11434 \ -e WEBUI_AUTH=true \ -v open-webui:/app/backend/data \ --name open-webui \ --restart always \ ghcr.io/open-webui/open-webui:main逐项说明:-p 3000:8080把容器内 8080 映射到宿主机 3000,浏览器访问http://localhost:3000;--add-host=host.docker.internal:host-gateway让容器内能用host.docker.internal解析到宿主机,这是 Linux 上必须加的,Windows/macOS 的 Docker Desktop 自带;OLLAMA_BASE_URL指向宿主机的 Ollama 服务;WEBUI_AUTH=true开启登录,本地单人用也可以设false免登录;-v open-webui:/app/backend/data把对话数据持久化到命名卷,容器重建不丢历史。
如果你在第二节把OLLAMA_HOST设成了0.0.0.0,也可以直接用宿主机 IP:
-e OLLAMA_BASE_URL=http://192.168.1.100:11434把 IP 换成你机器的实际地址。两种方式都行,host.docker.internal更通用。
3.2 环境变量配置文件
如果你不想每次都用一长串docker run,可以写一个docker-compose.yml,把配置固化下来。这也是我推荐的方式,改参数不用重敲命令:
version: "3.8" services: open-webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui ports: - "3000:8080" extra_hosts: - "host.docker.internal:host-gateway" environment: - OLLAMA_BASE_URL=http://host.docker.internal:11434 - WEBUI_AUTH=true - WEBUI_NAME=Local DeepSeek - DEFAULT_MODELS=deepseek-r1:7b volumes: - open-webui:/app/backend/data restart: always volumes: open-webui:DEFAULT_MODELS让新会话默认选中 deepseek-r1:7b,省得每次手动切。WEBUI_NAME只是改页面标题,无所谓。
启动:
docker compose up -d查看日志确认没有报错:
docker logs -f open-webui看到Uvicorn running on http://0.0.0.0:8080就说明起来了。
3.3 首次登录与模型选择
浏览器打开http://localhost:3000,第一次会让你注册一个管理员账号,这个账号只存在本地数据库里,随便填。登录后进入设置,确认模型列表里出现了deepseek-r1:7b。如果没有,去设置 -> 连接里检查 Ollama 地址是否填对,点一下刷新按钮。
选中模型后发一条消息测试。正常的话你会看到文字逐字出现,这就是流式输出在工作。如果转圈很久才一次性出结果,说明流式没生效,回去检查OLLAMA_BASE_URL是否指向了正确的端点。
提示:Open WebUI 的对话历史存在
open-webui这个 Docker 卷里。想备份就docker run --rm -v open-webui:/data -v $(pwd):/backup alpine tar czf /backup/webui-backup.tar.gz -C /data .,恢复同理。
到这里,网页对话界面就通了。同一个 Ollama 服务现在同时服务浏览器和终端,显存里只有一份模型。
4. 把 Vscode 接到同一推理端点做代码补全
这一节是整篇的重点。web-ui 解决的是“聊天”,编辑器插件解决的是“在写代码的地方直接问”。两者连的是同一个http://localhost:11434,所以不需要额外加载模型。我给出 Continue 和 Cline 两套配置,你可以都装,按场景切换。
4.1 Continue 配置 config.json
在 Vscode 扩展市场搜 Continue 安装。装完后左侧会出现 Continue 图标,点开,再点设置齿轮,选择打开config.json。这个文件的位置在~/.continue/config.json(Windows 是C:\Users\你的用户名\.continue\config.json)。
把 models 数组改成下面这样:
{ "models": [ { "title": "deepseek-r1:7b", "provider": "ollama", "model": "deepseek-r1:7b", "apiBase": "http://localhost:11434", "systemMessage": "You are an expert software developer. Answer in Chinese, be concise and give runnable code." }, { "title": "deepseek-r1:8b", "provider": "ollama", "model": "deepseek-r1:8b", "apiBase": "http://localhost:11434", "systemMessage": "You are an expert software developer. Answer in Chinese, be concise and give runnable code." } ], "tabAutocompleteModel": { "title": "deepseek-r1:1.5b", "provider": "ollama", "model": "deepseek-r1:1.5b", "apiBase": "http://localhost:11434" } }三个字段必须对齐:provider填ollama,model填ollama list里显示的完整名字,apiBase填 Ollama 地址。名字写错一个字符就会报model not found。
tabAutocompleteModel是行内补全用的模型,建议单独用 1.5b,因为补全触发频繁,7b 会拖慢输入。1.5b 虽然能力弱,但补全这种短任务够用。
保存后回到 Continue 面板,模型下拉框里应该能看到两个选项。选中deepseek-r1:7b,在编辑器里选中一段代码,按Ctrl+L把选中内容发到对话框,问它“这段代码有什么问题”。如果它能基于你选中的代码回答,说明编辑器接入成功。
4.2 Cline 配置与三件套
Cline 是另一个 Vscode 插件,特点是能自主读写文件、执行命令,适合让它帮你改多个文件。安装后在设置里选 API Provider 为Ollama,然后填三件套:
| 配置项 | 填写值 |
|---|---|
| Base URL | http://localhost:11434 |
| API Key | 随便填,如ollama,本地不校验 |
| Model ID | deepseek-r1:7b |
Cline 走的是 OpenAI 兼容接口,所以 Base URL 后面不用加/v1,插件会自己拼。如果它报 404,试着改成http://localhost:11434/v1,不同版本行为略有差异。
填完点保存,在对话框里输入“用中文回答:写一个 Python 函数计算斐波那契数列”。如果它开始输出并给出代码块,说明通了。Cline 的自主模式会请求文件写入权限,第一次用会弹确认框,本地自己用可以允许。
4.3 验证流式输出与代码补全
两个插件都配好后,做三个验证:
第一,流式输出。在 Continue 里问一个需要长回答的问题,观察文字是否逐字出现。如果卡住几秒后整段蹦出来,说明流式被缓冲了,检查 Ollama 是否用了stream: true,以及插件版本是否过旧。
第二,代码补全。在.py文件里输入def quick_sort(arr):然后换行,等一两秒看是否出现灰色补全建议。没有的话检查tabAutocompleteModel是否配了 1.5b 模型,以及该模型是否已ollama pull。
第三,上下文引用。在 Continue 里用@引用一个文件,问它这个文件的作用。能正确回答说明文件索引正常。
三个都通过,你的本地代码编辑器就算接上了 deepseek-r1。整个过程模型只加载了一份,web-ui 和 Vscode 共享同一个推理端点。
5. 常见报错排查:401、local proxy failed 与 reading choices
这一节按真实报错来。下面这些是我和身边人踩过的,按出现频率排序。
报错一:401 Unauthorized
Continue 或 Cline 报 401,通常不是 Ollama 的问题,而是插件把请求发到了需要鉴权的云端。检查apiBase或 Base URL 是否被自动填成了https://api.openai.com。本地 Ollama 不校验 Key,但插件如果 provider 选错,会带上错误的鉴权头。解决:确认 provider 是ollama,Base URL 是http://localhost:11434,API Key 留空或填任意字符串。
报错二:local proxy failed或connect ECONNREFUSED 127.0.0.1:11434
这个报错说明客户端连不上 Ollama。三种可能:Ollama 没启动,端口不是 11434,或者 Docker 容器里的localhost指向了自己。排查顺序:先在宿主机curl http://localhost:11434/api/tags,能返回模型列表说明服务正常;如果 web-ui 在 Docker 里报这个错,把OLLAMA_BASE_URL改成http://host.docker.internal:11434;如果 Vscode 插件报这个错,确认apiBase没写成0.0.0.0,客户端要用localhost或127.0.0.1。
报错三:Error reading choices或choices field missing
这个报错一般出现在 Cline 这类走 OpenAI 格式的插件上。原因是 Ollama 的/v1/chat/completions返回结构和插件预期不完全一致,或者模型名写错导致返回了错误对象。先确认ollama list里的名字和插件里填的 Model ID 完全一致,包括冒号和后面的 tag。如果名字对,试着把 Base URL 从http://localhost:11434改成http://localhost:11434/v1,或者反过来。不同插件版本对路径拼接处理不同。
报错四:model requires more system memory
这是显存/内存不足。8G 卡跑 14b 会触发。解决:换 7b 或 8b,或者设置OLLAMA_NUM_GPU限制卸载层数。也可以关掉 web-ui 和编辑器插件中的一个,减少并发。
报错五:OAuth 或登录循环
Open WebUI 如果开了WEBUI_AUTH=true但数据库卷权限有问题,会出现登录后跳回登录页。检查docker logs open-webui有没有数据库写入错误。解决:删掉容器和卷重建,docker rm -f open-webui && docker volume rm open-webui,然后重新docker compose up -d。数据会丢,但首次搭建阶段无所谓。
报错六:流式输出变成一次性返回
检查 Ollama 版本,老版本对/v1/chat/completions的流式支持不完整。升级到最新版:curl -fsSL https://ollama.com/install.sh | sh。另外确认插件里没有开启“等待完整响应”之类的选项。
排查通用思路:先在终端用 curl 确认 Ollama 端点本身正常,再确认客户端填的地址和模型名,最后看插件日志。90% 的问题出在地址和模型名这两个字段上。
6. 把本地推理端点固定下来,后续按需扩展
走到这里,你手上应该有三个能用的入口:终端 curl、浏览器 web-ui、Vscode 里的 Continue 和 Cline。它们背后是同一个 Ollama 服务、同一份 deepseek-r1 权重。这个结构的好处是扩展成本低——以后想加一个新客户端,只要它能填 Base URL 和模型名,就能直接接进来,不用重新部署模型。
如果你后面想让这套东西更稳定,有两个方向可以继续。一是把 Ollama 做成系统服务,开机自启,省得每次手动ollama serve。Linux 用 systemd,Windows 用任务计划程序,macOS 用 launchd。二是如果你需要在多台机器之间共享这个推理端点,或者想用更大的模型但本地显卡扛不住,可以考虑把请求转发到统一的 API 网关。我目前个人项目里用的是 TaoToken 的接入方式,它的 API 地址是https://taotoken.net/api,兼容 OpenAI 格式,把 Continue 的apiBase从本地地址换成它、再填上对应的 Key 和模型 ID 就能切换,本地和远端两套配置可以并存,按场景选。
具体操作上,如果你要试远端接入,去控制台建一个 Key,然后在 Continue 的config.json里加一个 provider 为openai的模型条目,apiBase填https://taotoken.net/api,apiKey填你建的 Key,model填平台上对应的模型 ID。这样本地 deepseek-r1 和远端模型就在同一个下拉框里,写代码时按需切换。模型对话入口在https://taotoken.net/models,接入文档在https://taotoken.net/doc,API Key 管理在https://taotoken.net/api-keys。如果你主要做长期编码和 Agent 任务,可以看下 Coding Plan:https://taotoken.net/coding-plan。
回到本地这套。最后给你一个实用技巧:把 Ollama 的OLLAMA_KEEP_ALIVE设长一点,比如24h,然后每天第一次用之前先发一条短消息“hi”把模型预热到显存,后面所有请求都是秒回。这个习惯能省掉大量等待时间。另外,web-ui 里的对话历史定期导出,别只依赖 Docker 卷,卷删了就没了。
整套链路的核心就一句话:Ollama 提供端点,其他都是客户端。把端点地址和模型名这两个字段填对,剩下的就是顺手用起来。