Ollama GPU排障指南:完整可复现的CPU误用排查方法
前段时间在 CentOS 8 上折腾 Ollama,目标明确:
拉取 qwen3.5:9b 模型,稳稳跑在 NVIDIA RTX 3060 上。
结果立刻遭遇当头一棒:
nvidia-smi输出正常- 驱动版本看着没问题
- Ollama 服务顺利启动
- 模型也成功拉取
- 但
ollama ps显示的却是:
PROCESSOR 100% CPU
模型完全没走GPU,全压在CPU上硬算。
这类问题最容易让人踩坑。很多人遇到“模型没用GPU”,第一反应是:
- 显卡太旧不支持?
- CUDA 装错了?
- 模型太大放不下?
- Ollama 本身有 bug?
但实际啃下来后,我发现排障的关键不是背几条命令,而是掌握一套结构化、可递进的排查思路。
这篇文章把这次完整过程掰开揉碎。我不只给最终答案,还会把每一步的判断逻辑也讲透。这正是我反复强调的“默会知识”:很多时候决定成败的不是某个标准语句,而是长期实战中积累的“优先看哪里、哪些线索最致命、怎样持续缩小范围”的直觉。
一、现象复现:模型能响应,但推理完全依赖 CPU
一开始,Ollama 装好,模型拉下来:
ollama run qwen3.5:9b
看起来一切如常,模型能正常对话,没有报错。
但一跑 ollama ps,看到的是:
NAME ID SIZE PROCESSOR CONTEXT UNTIL
qwen3.5:9b xxxxxxxxxxxx 8.5 GB 100% CPU 4096 4 minutes from now
这条信息是排障的第一现场。很多人忽略 ollama ps,但它在判断 Ollama 是否真正使用 GPU 上,价值无可替代。
如果这里显示:
100% GPU:模型完整占用 GPU100% CPU:完全跑在 CPU 上xx% CPU / xx% GPU:部分层卸载到 GPU
所以,第一条经验:永远先查 ollama ps,而不是凭感觉猜测。
二、第一层:区分“显卡不可用”与“Ollama 没调用 GPU”
这个问题最容易让人一上来就陷入“重装 CUDA、重装驱动、重装系统”的深坑。
我当时先做了更基础的判断:
1. 先确认显卡驱动是否正常
nvidia-smi
机器返回正常,能看到两张 RTX 3060:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 570.xxx.xx Driver Version: 570.xxx.xx CUDA Version: 12.8 |
| GPU Name ... |
| 0 NVIDIA GeForce RTX 3060 |
| 1 NVIDIA GeForce RTX 3060 |
+-----------------------------------------------------------------------------+
这一步说明 Linux 内核已识别显卡,NVIDIA 驱动也正常安装。但只能说明“显卡没坏、驱动没坏”,不能说明“Ollama 一定能调用 GPU”。
这是排障中很重要的默会知识:“我有武器”和“我会使用武器”是两码事。
三、第二层:验证 Ollama 服务是否真的稳定运行
先确认客户端:
which ollama
ollama -v
返回类似:
/usr/local/bin/ollama
client version is 0.18.2
客户端安装成功。
但随后发现:
systemctl start ollama
报错:
Unit ollama.service not found
这说明安装脚本虽然把 ollama 命令装好了,但 systemd 服务文件没正确生成。
于是手工创建了 /etc/systemd/system/ollama.service:
[Unit]
Description=Ollama Service
After=network-online.target
[Service]
ExecStart=/usr/local/bin/ollama serve
User=ollama
Group=ollama
Restart=always
RestartSec=3
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="OLLAMA_MODELS=/home/ollama/models"
[Install]
WantedBy=multi-user.target
然后启动:
systemctl daemon-reload
systemctl enable --now ollama
systemctl status ollama --no-pager
这一步的意义:确保 Ollama 服务稳定运行,排除“只是命令行临时启动,服务环境与交互环境不一致”的问题。这也是关键经验:很多情况下,命令行前台运行与 systemd 后台运行的环境变量、权限、库路径都可能不同。
四、第三层:通过日志判断 Ollama 在哪一步失败
当模型仍然跑在 CPU 上时,我没有反复 run,而是开始看日志:
journalctl -u ollama -n 200 --no-pager | egrep -i 'cuda|gpu|runner|library|offload|vram'
日志里出现了几类非常关键的信息:
1. 看到了 GPU 发现阶段日志
discovering a vailable GPUs...
这说明 Ollama 至少进入了 GPU 探测阶段。
2. 但推理后端仍然是 CPU
inference compute id=cpu library=cpu
这一句,就是“定性证据”。它说明在真正选择推理后端时,Ollama 并没有走 CUDA 路径,而是选了 CPU library。
3. 模型层没有卸载到 GPU
GPULayers:[]
offloading 0 repeating layers to GPU
offloaded 0/33 layers to GPU
runner.vram="0 B"
这几句连起来看,结论就很明确了:Ollama 尝试进入模型加载阶段,但一个层都没放到 GPU,最终 VRAM 视角下使用量为 0。
这个阶段我形成了一个重要判断:问题很可能不在“显存不够”,而在“CUDA 后端根本没被加载”。 因为如果只是“模型太大”,通常更容易看到的是“部分层上 GPU,部分层在 CPU”,而不是 0 层上 GPU。
这也是排障中一个非常重要的经验判断:现象本身,已经在告诉你下一步该去哪里找答案了。
五、第四层:环境变量是否干扰了 GPU 路径
最开始我为了让 Ollama 使用两张显卡,在服务里加过:
Environment="CUDA_VISIBLE_DEVICES=0,1"
看起来很合理,但日志里反而出现了:
user overrode visible devices
if GPUs are not correctly discovered, unset and try again
这句话让我意识到:这个变量不一定有益,在某些环境里反而可能干扰自动探测。
于是我先做了一个“减法”动作:去掉 CUDA_VISIBLE_DEVICES,让 Ollama 自己探测。
这一步的结果很有价值:
- 去掉后,日志里不再出现
CUDA_VISIBLE_DEVICES=0,1 - 但仍然显示
library=cpu - 仍然
offloaded 0/33 layers to GPU
这说明问题已经被进一步缩小:跟环境变量无关,是更底层的东西出了问题。
这就是默会知识在排障里的作用。不是每一步都能直接解决问题,但每一步都要能“缩小问题范围”。
六、第五层:权限是否构成障碍
接下来我查了服务用户和设备权限:
id ollama
ls -l /dev/nvidia*
看到:
ollama用户已经在video、render组里/dev/nvidia0、/dev/nvidia1、/dev/nvidiactl、/dev/nvidia-uvm都存在- 权限看起来也正常
这一步排除了另一个常见误区。很多时候一看到 GPU 不工作,大家就习惯性去改 chmod 777 /dev/nvidia*,甚至改一堆组权限。但这次的现象更像是:设备文件没问题,显卡驱动没问题,Ollama 也能发现“有 GPU 这回事”,只是最后没有找到自己的 GPU 运行库。
这一步再次缩小了范围。问题的靶心越来越清晰了。
七、第六层:真正的根因——不在显卡,而在 Ollama 自己的运行库目录
后面我查了两个目录:
ls -lah /usr/local/lib/ollama
find /usr/local/lib/ollama -type f
结果发现:/usr/local/lib/ollama 居然是空目录。
而日志里明明显示 Ollama 启动时使用的是:
LD_LIBRARY_PATH=/usr/local/lib/ollama
OLLAMA_LIBRARY_PATH=/usr/local/lib/ollama
也就是说:Ollama 运行时去 /usr/local/lib/ollama 找自己的运行库,但这个目录是空的。所以它根本加载不到 CUDA 后端,最后自然只能回退到 CPU。
这一下就把整件事解释通了。
这是这次排障里最核心的结论:不是你显卡不行,是你程序找不到自己的“弹药库”。
随后我又查了另一个目录:
ls -lah /usr/lib/ollama
find /usr/lib/ollama -type f | egrep -i 'cuda|ggml|runner|llama'
结果发现 /usr/lib/ollama 里其实是有内容的,里面有 CUDA 相关运行库。
也就是说,这次安装属于一种“半成功状态”:可执行文件装到了 /usr/local/bin/ollama,但运行库没有同步到 /usr/local/lib/ollama。结果程序能启动,模型也能拉,但 GPU 后端不可用。
这类问题特别容易误导人,因为它不是“装不上”,而是“能用,但用得不对”。
八、最终修复:将正确的运行库补到 Ollama 实际查找的目录
既然 /usr/lib/ollama 里有完整内容,而 /usr/local/lib/ollama 是空的,那最快的修法就是把两者接起来。
最后采用了这种方式:
systemctl stop ollama
rm -rf /usr/local/lib/ollama
ln -s /usr/lib/ollama /usr/local/lib/ollama
ldconfig
systemctl start ollama
这么做的好处显而易见:不需要重新拉模型,不需要重装驱动,不需要重装系统,只是把运行库路径纠正过来。
修复后再次执行:
ollama run qwen3.5:9b
ollama ps
结果就变成了:
PROCESSOR 100% GPU
同时 nvidia-smi 也能看到显存和 GPU 利用率的变化。问题到此彻底解决。
九、这次排障里最重要的几个“默会知识”
最后把这次的经验总结成几条,供以后快速判断。
1. 不要先重装,先定性
先回答一个问题:“显卡不可用”还是“Ollama 没用上显卡”?
方法很简单:看 nvidia-smi,看 ollama ps,看日志里的 library=cpu 还是 CUDA 相关信息。
2. ollama ps 是第一现场
不要只看模型会不会回答。会回答不代表用了 GPU。真正要看的是 ollama ps。这一步能最快避免“自以为跑在 GPU 上”的误判。
3. 日志里最关键的不是“有 GPU”,而是“用了哪个 library”
像 discovering a vailable GPUs... 这种日志,只能说明它在“找 GPU”。但真正决定胜负的是:inference compute id=cpu library=cpu。这说明最后真正用来推理的后端仍然是 CPU。
4. “0 层上 GPU”比“部分层上 GPU”更值得警惕
如果日志里看到 offloaded 0/33 layers to GPU 和 runner.vram="0 B",优先怀疑的不该是“显存不够”,而应该是:CUDA 后端没加载成功、运行库缺失、库路径不对。
5. 环境变量不是越多越好
像 CUDA_VISIBLE_DEVICES 这种变量,在某些时候有用,但也可能干扰自动探测。排障时一定要学会做减法:先去掉,看看效果。
6. 应用自己的运行库路径,往往比驱动本身更容易被忽略
这次最大的坑并不是 NVIDIA 驱动,而是 /usr/local/lib/ollama 是空目录。这类问题最难就难在它不显眼。命令能跑,模型能拉,服务能起,但 GPU 失效。如果没有顺着日志一路缩小问题范围,很容易永远怀疑错方向。
十、最终整理出来的一套 Ollama GPU 排障顺序
后面如果再遇到类似问题,会按这个顺序直接排。
第一步:确认显卡和驱动
nvidia-smi
第二步:确认 Ollama 是否真的在 GPU 上
ollama ps
第三步:看服务和日志
systemctl status ollama --no-pager
journalctl -u ollama -n 200 --no-pager | egrep -i 'cuda|gpu|runner|library|offload|vram'
第四步:判断是“GPU 没识别”还是“GPU 没被用上”
重点看:
library=cpuoffloaded 0/... layers to GPUrunner.vram="0 B"
第五步:排除环境变量干扰
检查服务文件和 override:
systemctl cat ollama
systemctl show ollama --property=Environment
第六步:排除权限问题
id ollama
ls -l /dev/nvidia*
第七步:检查 Ollama 自己的运行库目录
ls -lah /usr/local/lib/ollama
find /usr/local/lib/ollama -type f
ls -lah /usr/lib/ollama
find /usr/lib/ollama -type f | egrep -i 'cuda|ggml|runner|llama'
第八步:如果运行库在 /usr/lib/ollama,但 /usr/local/lib/ollama 是空的
直接修正:
systemctl stop ollama
rm -rf /usr/local/lib/ollama
ln -s /usr/lib/ollama /usr/local/lib/ollama
ldconfig
systemctl start ollama
第九步:重新验证
ollama run qwen3.5:9b
ollama ps
watch -n 1 nvidia-smi
十一、额外提醒:Dify 里接入 Ollama 报错,不一定是模型问题
这次 GPU 问题解决后,又遇到一个插曲:Dify 里添加 Ollama 模型失败,报的是 Connection refused。
这个问题和 GPU 无关,而是监听地址的问题。默认情况下,Ollama 只监听 127.0.0.1:11434,如果 Dify 在另一台机器上,自然就连不上。
这时候要给 Ollama 增加:
Environment="OLLAMA_HOST=0.0.0.0:11434"
然后重启服务,再检查防火墙和端口放通。
这个小插曲也提醒我:不要把“模型没跑 GPU”和“Dify 接不通”混在一起排。前者是推理后端问题,后者是网络监听问题,属于两条完全不同的链路。
十二、结语:真正能解决问题的,往往不是命令,而是判断路径
这次 Ollama 排障给我最大的感受是:很多时候,真正决定能不能解决问题的,不是会不会查一条命令,而是有没有形成一套稳定的判断路径。
这正是我一直强调的默会知识:
- 书上不会告诉我先怀疑库路径还是先怀疑驱动
- 官方文档也不会完整复现我遇到的这个场景
- 但通过一次次排障,会慢慢形成一种“看到什么现象,就该往哪个方向继续缩小范围”的能力
所以这次我真正收获的,不只是“怎么让 Ollama 跑到 GPU 上”,而是形成了这样一个习惯:每一次排障,都是在下一次为自己省下几个小时。
如果在本地部署 Ollama,也遇到了“模型明明能跑,但就是跑在 CPU 上”的问题,希望这篇文章能帮少走一些弯路。
