最近在一台 CentOS 8 服务器上部署 Ollama,本来目标很简单:
把 qwen3.5:9b 拉下来,跑在 NVIDIA RTX 3060 上。
结果实际情况是:
nvidia-smi正常- 显卡驱动正常
- Ollama 服务也启动了
- 模型也成功拉下来了
- 但
ollama ps显示的却是:
PROCESSOR 100% CPU
也就是说,模型根本没有跑在 GPU 上,而是完全跑在 CPU 上。
这类问题很容易把人带偏。很多人一看到“没跑 GPU”,第一反应就是:
- 是不是显卡不支持?
- 是不是 CUDA 没装?
- 是不是模型太大?
- 是不是 Ollama 有 bug?
但真正把这个问题解决下来后,我发现这类排障最关键的并不是“会不会几条命令”,而是有没有正确的排查路径。
这篇文章就把这次完整过程整理出来。 我会尽量不用“只给答案”的方式,而是把背后的判断思路讲出来。 这正是我理解的 Polanyi 默会知识(Tacit Knowledge):很多时候,真正决定排障成败的,不是某一条标准命令,而是长期实践中形成的“先看哪里、哪些现象最关键、如何缩小范围”的经验判断。
一、问题现象:模型能跑,但跑在 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:说明模型完整跑在 GPU 上100% CPU:说明完全跑在 CPU 上xx% CPU / xx% GPU:说明部分层卸载到了 GPU
所以第一条经验是:
不要凭感觉判断 Ollama 是否使用了 GPU,先看
ollama ps。
二、第一层排查:先分清“显卡不可用”还是“Ollama 没用上显卡”
这个问题最容易一上来就陷入“重装 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
+-----------------------------------------------------------------------------+
这一步说明的不是“Ollama 一定能用 GPU”,而是先确认:
- Linux 内核已经识别显卡
- NVIDIA 驱动已经正常安装
- 用户态基本可以看到 GPU
这只能说明“显卡没坏、驱动没坏”,不能说明“Ollama 一定能调用 GPU”。
这就是排障里一个很重要的 tacit knowledge:
系统看到 GPU,不等于应用一定能用 GPU。
三、第二层排查:看 Ollama 服务是否真的启动正常
当时我先确认了 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 服务真正稳定运行
- 排除“只是命令行临时启动,服务环境和交互环境不一致”的问题
- 为后续看日志做准备
这也是一个排障经验:
GPU 问题不要只盯着模型命令本身,要把服务启动方式也纳入排查。
因为很多时候,命令行前台运行和 systemd 后台运行,环境变量、权限、库路径都可能不同。
四、第三层排查:用日志判断 Ollama 处于哪个阶段失败
当模型仍然跑在 CPU 上时,我没有继续反复 run,而是开始看日志:
journalctl -u ollama -n 200 --no-pager | egrep -i 'cuda|gpu|runner|library|offload|vram'
日志里出现了非常关键的几类信息:
1. 看到了 GPU 发现阶段日志
discovering available 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 不够用”和“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 调用失败都是权限问题。
很多时候一看到 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
这一下就把整件事解释通了。
这是这次排障里最核心的结论:
GPU 运行失败,不一定是显卡、驱动、CUDA 的问题,也可能是 Ollama 自己的运行库没有装完整。
随后我又查了另一个目录:
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. 不要先重装,先定性
先回答一个问题:
到底是“GPU 根本没识别”,还是“GPU 识别了但没被用上”?
方法很简单:
- 看
nvidia-smi - 看
ollama ps - 看日志里的
library=cpu还是 CUDA 相关信息
2. ollama ps 是第一现场
不要只看模型会不会回答。 会回答不代表用了 GPU。
真正要看的是:
ollama ps
这一步能最快避免“自以为跑在 GPU 上”的误判。
3. 日志里最关键的不是“有 GPU”,而是“用了哪个 library”
像这种日志:
discovering available 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 排障给我最大的感受是:
很多时候,真正决定能不能解决问题的,不是会不会查一条命令,而是有没有形成一套稳定的判断路径。
这正是我理解的 Polanyi 默会知识:
- 书上不会告诉我先怀疑库路径还是先怀疑驱动
- 官方文档也不会完整复现我遇到的这个场景
- 但通过一次次排障,会慢慢形成一种“看到什么现象,就该往哪个方向继续缩小范围”的能力
所以这次我真正收获的,不只是“怎么让 Ollama 跑到 GPU 上”,而是形成了这样一个习惯:
先定性,再缩圈;先排路径,再动系统;先找证据,再下结论。
如果正在本地部署 Ollama,而且也遇到了“模型明明能跑,但就是跑在 CPU 上”的问题,希望这篇文章能帮少走一些弯路。
文末引流
如果也在做:
- Ollama 本地大模型部署
- Dify + 本地模型接入
- GPU 推理环境排障
- 制造业/运维场景下的大模型落地
欢迎持续关注。 后面我会继续把本地大模型、Dify、NetBox、自动化运维这些真实落地过程中的问题和经验,整理成一套可复现、可实操的系列文章。