1. Ollama 跑 deepseek-r1 时 GPU 先冲高再掉底,到底卡在哪
你大概率遇到过这个画面:在终端里ollama run deepseek-r1:7b聊得好好的,任务管理器里 GPU 占用能冲到 60% 以上,风扇也转起来了。接着你打开 VSCode,装上 Continue 或者 Cline,把本地 API 地址填进去,想让它在离线状态下帮你补代码。结果第一次请求发出去,GPU 占用猛地抬了一下,然后像泄了气一样掉回个位数,CPU 反而一路飙到 80% 以上,出字速度从每秒几十 token 掉到每秒两三个。
这个现象不是显卡坏了,也不是 Ollama 装错了。它本质上是模型层卸载(offload)失败,推理任务从 GPU 回退到了 CPU。Ollama 在启动模型时会根据可用显存决定把多少层放到 GPU 上,日志里会打印类似offloaded 10/37 layers to GPU这样的信息。如果只卸载了 10 层,剩下 27 层留在 CPU 侧,那 GPU 自然大部分时间在等 CPU 喂数据,占用率就上不去。
触发回退的最常见原因,是 VSCode 插件侧传过来的上下文长度参数太大。Continue 和 Cline 这类插件默认按云端 API 的规格来设contextLength,常见默认值是 32768 甚至更高。这个数值对服务器上的 A100 不算什么,但对一张 8GB 或 12GB 的消费级显卡来说,KV Cache 一开就吃掉大半显存,Ollama 一算发现放不下,就只卸载少量层,剩下的全丢给 CPU。
所以排查方向很清楚:先看 Ollama 日志里实际卸载了多少层,再回头检查插件配置里的上下文长度和模型名是否对得上。这篇就围绕config.toml和settings.json两个配置文件,给你一套能直接复制、能验证、能排错的骨架,同时把 TaoToken 统一 Key 通道的接入方式一并写清楚,方便你在本地推理和云端 API 之间做切换。
适合谁看:已经在本地用 Ollama 部署了 deepseek-r1 蒸馏版,正在用 Continue / Cline / Roo Code 这类 VSCode 插件联调,发现 GPU 占用异常、速度不达预期的人。你需要会基本的命令行操作,知道怎么打开 VSCode 的设置文件,剩下的跟着做就行。
2. TaoToken 统一 Key 通道与 Ollama 本地通道的前置准备
在动手改配置之前,先把两条通道理清楚,不然后面排查会混。
第一条是本地通道:Ollama 默认监听http://127.0.0.1:11434,提供 OpenAI 兼容的/v1/chat/completions接口。VSCode 插件直接连这个地址,走的是你本机显卡。这条通道的关键变量是模型名、上下文长度、以及 Ollama 自己的显存管理策略。
第二条是统一 Key 通道:TaoToken 提供 OpenAI 兼容接口,Base URL 是https://taotoken.net/api,用同一个 Key 就能调用多个模型。它的价值在于,当你本地显卡实在扛不住长上下文,或者需要更大参数量的模型时,可以把插件切到这条通道,不用改插件代码,只改 Base URL 和 Key。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址就是上面那个,注意 API 地址不带 UTM 参数。
前置准备分三步。
第一步,确认 Ollama 版本和模型。在终端执行:
ollama --version ollama list你应该能看到类似deepseek-r1:7b或deepseek-r1:14b的条目。如果列表为空,先ollama pull deepseek-r1:7b拉一个。7b 对 8GB 显存比较友好,14b 建议 12GB 以上。
第二步,确认 Ollama 服务在跑,并且能直接调用:
curl http://127.0.0.1:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-r1:7b", "messages": [{"role": "user", "content": "用一句话说明什么是KV Cache"}], "stream": false }'能返回 JSON 就说明本地通道通了。这一步很重要,它把「Ollama 本身有问题」和「插件配置有问题」分开。如果这条 curl 都慢,那问题在 Ollama 侧,不在插件。
第三步,准备 TaoToken 的 Key。登录后在控制台创建 API Key,地址是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。拿到形如sk-开头的字符串后,先用 curl 验证一次:
curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的Key" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-r1", "messages": [{"role": "user", "content": "回复ok"}], "stream": false }'返回正常就说明统一 Key 通道可用。这一步别跳过,后面插件报 401 的时候,你能立刻判断是 Key 问题还是插件配置问题。
两条通道都验证过之后,再进插件配置。顺序反了的话,你会在一堆变量里迷失。
3. 可复制的 config.toml 与 settings.json 骨架
这一节是核心,给你两份能直接改的配置。先讲 Continue 的config.toml,再讲 Cline / Roo Code 的settings.json,最后给一个 TaoToken 通道的对照写法。
Continue 现在用config.toml(旧版是config.json,新版迁移到了 TOML)。文件位置一般在~/.continue/config.toml,Windows 下是C:\Users\你的用户名\.continue\config.toml。打开后,模型段落这样写:
[[models]] name = "deepseek-r1-local" provider = "openai" model = "deepseek-r1:7b" apiBase = "http://127.0.0.1:11434/v1" apiKey = "ollama" contextLength = 8192 maxTokens = 2048这里每个字段都关键。apiBase必须带/v1,少了会 404。apiKey填ollama占位即可,Ollama 不校验。contextLength是这次问题的核心,默认 32768 改成 8192 甚至 4096,显存压力立刻下降。maxTokens控制单次生成上限,设小一点也能省显存。
如果你要接 TaoToken 通道,同一份文件里再加一段:
[[models]] name = "deepseek-r1-taotoken" provider = "openai" model = "deepseek-r1" apiBase = "https://taotoken.net/api/v1" apiKey = "sk-你的Key" contextLength = 32768 maxTokens = 4096注意apiBase是https://taotoken.net/api/v1,model填deepseek-r1。这样你在 Continue 的模型下拉框里能同时看到本地和云端两个选项,切换只改一个下拉,不用动代码。
Cline 和 Roo Code 用的是 VSCode 的settings.json,路径在%APPDATA%\Code\User\settings.json(Windows)或~/Library/Application Support/Code/User/settings.json(macOS)。Cline 的配置项前缀是cline.:
{ "cline.apiProvider": "openai", "cline.openAiBaseUrl": "http://127.0.0.1:11434/v1", "cline.openAiApiKey": "ollama", "cline.openAiModelId": "deepseek-r1:7b", "cline.openAiModelInfo": { "maxTokens": 2048, "contextWindow": 8192 } }contextWindow就是 Cline 侧的上下文长度,和 Continue 的contextLength是同一个东西。很多人只改了 Continue 忘了 Cline,结果换插件又复现。openAiModelId必须和ollama list里的名字完全一致,写成deepseek-r1而实际模型是deepseek-r1:7b,Ollama 会报 model not found。
切 TaoToken 通道时,把上面四个字段改成:
{ "cline.apiProvider": "openai", "cline.openAiBaseUrl": "https://taotoken.net/api/v1", "cline.openAiApiKey": "sk-你的Key", "cline.openAiModelId": "deepseek-r1", "cline.openAiModelInfo": { "maxTokens": 4096, "contextWindow": 32768 } }三件套就是 Base URL、Key、Model ID,缺一不可。Base URL 写错成https://taotoken.net/api(少了/v1)会 404,Key 写错会 401,Model ID 写错会 400。
改完配置后,重启 VSCode。Continue 和 Cline 都是启动时读配置,热重载不一定生效。重启后先在插件里发一句「你好」,观察任务管理器。
4. 验证请求与 GPU 占用回升的成功结果
配置改完,怎么确认真的生效了?给你三个验证动作,按顺序做。
第一个动作,看 Ollama 日志里的卸载层数。Ollama 在 macOS 和 Linux 上日志走journalctl或直接输出到终端;Windows 下在%LOCALAPPDATA%\Ollama\有日志文件。更简单的办法是启动时加环境变量:
OLLAMA_DEBUG=1 ollama serve然后在另一个终端发请求,日志里会打印offloaded N/M layers to GPU。改配置前可能是10/37,改完contextLength后应该变成30/37甚至37/37。这个数字是判断 GPU 是否真正接管的硬指标。
第二个动作,用nvidia-smi或任务管理器看显存和占用。Linux / Windows 有独显的用:
nvidia-smi -l 1每秒刷新一次。发请求时观察GPU-Util和Memory-Used。正常情况下,请求期间 GPU-Util 应该稳定在 40% 以上,显存占用接近你设置的模型大小。如果 GPU-Util 只在请求开头闪一下然后掉到 0,说明还是回退了。
第三个动作,测出字速度。在 Continue 里发一个稍长的任务,比如「写一个 Python 快速排序并加注释」,用秒表掐一下。7b 模型在 8GB 显卡上,改对配置后应该能到每秒 20 token 以上。如果只有每秒 2 到 3 token,基本可以确定还在 CPU 上跑。
我实测下来,把contextLength从 32768 降到 8192 之后,一张 8GB 显卡的卸载层数从 10 层涨到 32 层,出字速度从每秒 3 token 提到每秒 25 token 左右。这个提升幅度和你的显卡型号、模型量化等级有关,但方向是一致的。
如果你切到 TaoToken 通道验证,动作类似:在插件里发请求,看返回是否正常,看延迟是否稳定。云端通道不涉及本地 GPU,所以 GPU 占用不会变化,这时候你验证的是 Key 和 Base URL 是否正确。可以用模型对话页面单独测一次,地址是 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,确认模型能正常响应后再回插件里用。
三个动作做完,你手里就有了「日志层数 + GPU 占用 + 出字速度」三个证据,能明确判断问题是否解决。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
配置过程中最容易撞的几个报错,逐个拆。
401 Unauthorized。这个几乎都是 Key 问题。本地通道填ollama不会 401,因为 Ollama 不校验;如果你填了 TaoToken 的 Key 却报 401,先检查 Key 有没有复制完整,前后有没有空格。用第 2 节的 curl 命令单独测一次 Key,能过就说明 Key 没问题,问题在插件配置的字段名写错了,比如把apiKey写成了apikey。
local proxy failed / connection refused。这个报错说明插件连不上http://127.0.0.1:11434。先确认 Ollama 服务在跑:ollama serve或者看托盘图标。再确认端口没被占:netstat -ano | findstr 11434。如果 Ollama 装在 Docker 里,127.0.0.1可能不通,要换成宿主 IP。还有一种情况是插件配置里apiBase写成了http://localhost:11434,某些环境下 localhost 解析到 IPv6 而 Ollama 只监听 IPv4,改成127.0.0.1就好。
reading choices / Cannot read properties of undefined (reading 'choices')。这个报错是插件拿到了非预期格式的响应。常见原因是apiBase少了/v1,请求打到了 Ollama 的根路径而不是 OpenAI 兼容路径,返回的不是标准结构。检查apiBase是否以/v1结尾。另一个原因是模型名写错,Ollama 返回了错误 JSON,插件解析choices字段时拿到 undefined。
OAuth / 认证流程报错。如果你用的是 Claude Code 这类走 OAuth 的工具,报 OAuth 相关错误通常和本地回调端口被占、或者配置文件里的认证字段过期有关。这类工具建议直接看接入文档,地址是 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,里面有各客户端的配置样例。Claude Code 的接入可以参考 https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,里面写了 Base URL 和认证头的写法。
GPU 占用还是上不去。如果日志显示卸载层数已经很高,但 GPU-Util 依然低,检查是不是有其他进程占了显存。浏览器开着一堆标签页、或者另一个 Ollama 模型还驻留在显存里,都会导致新模型放不下。用ollama ps看当前加载的模型,用ollama stop 模型名卸载不用的。另外,contextLength别一次降太狠,4096 以下有些插件会报上下文不足,8192 是比较稳的起点。
Codex 的 auth.json。如果你在用 Codex 类工具,认证信息在~/.codex/auth.json,里面存的是 token。这个文件损坏或过期会导致认证失败。排查时先备份,再重新生成。注意这个文件不要提交到 git,里面是明文凭证。
排查的核心思路是:先用 curl 把通道单独测通,再进插件配置。通道通了,问题一定在配置字段;通道不通,问题在服务或网络。这个二分法能省掉大量瞎猜。
6. 长期编码与 Agent 场景的通道选择
本地 Ollama 适合什么场景?适合短上下文、快速补全、离线环境、以及不想把代码发出去的隐私敏感任务。7b 到 14b 的模型在消费级显卡上跑补全够用,但一旦上下文拉长、或者要做多轮 Agent 规划,本地显存就会吃紧,速度也会掉。
TaoToken 统一 Key 通道适合什么场景?适合长上下文、大参数量模型、多模型切换、以及需要稳定吞吐的 Agent 任务。同一个 Key 能调不同模型,插件配置只改三个字段,切换成本很低。如果你在做长期编码项目,或者跑 Cline 这类会连续发几十次请求的 Agent,走统一通道能避免本地显存反复加载卸载带来的抖动。
我的建议是两条通道都留着。日常补全用本地,省钱且快;遇到复杂重构、长文件分析、多步 Agent 任务,切到统一通道。配置上就是第 3 节那两段 TOML 或两组 JSON,切换时改一个下拉框。
如果你打算长期跑编码 Agent,可以看一下 Coding Plan 的说明,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,里面写了适合 Agent 场景的调用方式。需要新建或管理 Key 的时候,控制台入口在 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
最后留一个实用技巧:把 Ollama 的OLLAMA_KEEP_ALIVE设长一点,比如OLLAMA_KEEP_ALIVE=30m,这样模型在显存里驻留更久,插件连续请求时不用反复加载,GPU 占用会更稳定。这个环境变量在启动ollama serve前设置即可。改完配置记得重启 VSCode,然后按第 4 节的三个动作验证一遍,日志层数、GPU 占用、出字速度都对上了,这事就算结了。