无GPU服务器也能跑大模型:CPU推理部署Qwen实战
2026/9/12 17:27:25 网站建设 项目流程

1. 一张没有 NVIDIA 的服务器,怎么接住同事的需求

1.1 需求是怎么来的

起因是一个很普通的午后。运营同事在群里吐槽:"ChatGPT 是挺好,可客户数据不能在网页上乱贴啊。"紧接着技术总监就转到我这边:"咱们能不能在公司内网搞一个大模型?不用多聪明,能帮忙写周报、改文案、翻译文档、总结会议纪要就行,大概二十来个人用。"

我当时的第一个反应和大多数人一样:本地部署大模型,不是得先有块 NVIDIA 显卡吗?网上搜一下本地部署 AI 大模型,十个教程里有九个在讲 CUDA 怎么配、nvidia 驱动怎么装、显存要多大。可眼下公司机房只有一台退役不久的旧服务器,不但没有 NVIDIA GPU,连块像样的独显都没有。要在这种条件下把本地大模型端给同事用,听起来有点像拿集成显卡打 3A 大作。

但这次我没有按惯性去申请预算。原因很简单:二十个人用,不等于二十个人同时高强度的算,大家主要是写写改改、偶尔问几个问题。这种场景的计算量,并没有想象中那么夸张。我决定先把需求拆清楚,再看他手上有什么牌。

1.2 为什么不能直接上云端写

可能有人会问:既然要的是"能帮忙写文案的大模型",为什么不直接买云 API?每天几十块钱也不贵,省时省力。但实际去问一圈业务部门,你会发现几个绕不开的点:

  • 数据边界:运营和销售手里的有些信息属于客户资料,不能出内网。哪怕云端服务商承诺数据不留存,业务负责人也未必敢担这个责任。
  • 账号和权限:二十多个人,不能让他们每人注册一个云账号,也不希望有人把公司的 API Key 带回家。集中内网部署一套,账号权限都在自己手里,注销、禁用、审计都方便。
  • 网络稳定性:我们公司出口带宽不算宽裕,视频会议一开会就把上行占满,云 API 的响应速度也跟着抖。放在内网,至少链路是自己能控制的。

需求定下来以后,我对它的定义是:一个跑在内网、能接纯文本任务、并发不高、对延迟容忍度尚可的"办公辅助工具"。不是给甲方演示的对话机器人,也不是半夜跑批量任务的训练集群。

1.3 我的判断:先别急着买卡,看看手里的机器

最开始我也在 N卡、A卡、苹果 M 系列之间纠结。但盯着预算表看了两天以后,我做了个违背"常识"的决定:先不买任何硬件,把手头那台没人要的老服务器利用起来,用纯 CPU 推理先跑通,再根据实际情况决定要不要升级。

这个决定有两个支撑:

一是很多同事的需求是"轻度文字生成",不是"高并发低延迟业务接口"。文字生成任务对延迟的容忍度远高于识别类任务,多等一两秒没人会在意,但只要能在一体化界面里顺畅操作,大家就觉得"能用"。

二是大模型推理在 CPU 上虽然慢,但没有慢到完全不可用的程度。尤其是 7B、14B 这种中小规模模型,用 Q4 量化后模型体积只有 5~9GB,靠内存带宽硬算,单 token 生成速度做到每秒 3~6 个字符是可能的。这个速度拿来写一段两百字的周报,等个一两分钟,完全可以接受。

所以我的结论是:没有 NVIDIA 并不是死路,关键看你愿不愿意把"体验预期"从 30 秒响应调到 1 分钟响应,以及愿不愿意在参数调整上多花点功夫。下面就把我这套从零到一的过程完整记录下来。

2. 不买新显卡,CPU 推理到底能跑到什么程度

2.1 硬盘里到底有什么

先看一眼这台服务器到底是什么配置。机房里那台机器是几年前采购的 2U 机架式服务器,型号是戴尔 PowerEdge R730,配置如下:

部件具体规格
CPU双路 Intel Xeon E5-2698 v4,共 40 核 80 线程,基准频率 2.2GHz
内存192GB DDR4-2400,四通道
系统盘480GB SSD
数据盘4× 2TB HDD
显卡无独显,主板集显
系统Ubuntu 22.04 LTS

这台机器最大的优势是内存足够大。对于 CPU 推理来说,内存的大小和带宽,比 CPU 的核心数量还要关键

为什么?因为大模型推理的时候,模型参数是放在内存里的。每次生成一个 token,都要把模型的所有参数从头到尾读一遍。也就是说,模型文件多大,每次生成 token 就要读多少数据。比如一个 7B Q4 量化模型大约是 4.7GB,那么生成一个 token,内存就要输出约 4.7GB 的数据。

懂一点计算机组成原理的应该明白了:这个场景的瓶颈不是 CPU 的计算速度,而是内存的吞吐能力。E5-2698 v4 是四通道 DDR4,理论内存带宽大约 76GB/s,但实际能跑到一半多就算不错。70 多个 GB/s 除以 4.7GB,理论上每秒能读 15 遍模型,也就是每秒最多生成 15 个 token。再扣掉内存实际访问的效率损失、KV cache 的读写、CPU 内部调度的开销,实际能到 5~8 个 token/s 就算很健康了。所以,这决定了 CPU 部署 7B 模型是可以的,14B 模型就比较吃力。

2.2 决定生成速度的不是算力,是内存带宽

很多人以为没有 NVIDIA 显卡就跑不动大模型,其实是把"训练"和"推理"混在一起了。

训练大模型需要巨大的算力去算梯度、做反向传播,那个确实离不开大规模 GPU 集群。但推理不一样,推理只是把模型里已经存好的参数拿出来,按照输入的条件做一次前向传播,计算量虽大,却远没有训练那么恐怖。而且 CPU 推理有一套完整的加速方案,llama.cpp 项目就是专门干这件事的,它把大模型计算做了大量优化,让普通 CPU 也能跑得动。

但要认清一个现实:CPU 推理的瓶颈在内存带宽,这个瓶颈比 GPU 显存带宽低太多。NVIDIA 的 A100 显存带宽是 2TB/s 级别,普通消费级 RTX 4090 也有 1TB/s 左右,而服务器 DDR4 内存带宽只有几十 GB/s,差了差不多一个数量级。所以同样是跑 7B 模型,显卡能做到每秒几十个 token,CPU 只能做到每秒几个。

但是,"每秒几个 token"在办公场景里不代表不能用。只要模型能产生流畅的文字,同时多个用户共享一台机器,排队响应,体验上完全可以接受。我在部署前就给同事打了预防针:"不要指望秒回,泡杯茶的工夫刚好。"实际上他们接受了这种节奏,也并没有人抱怨。

2.3 模型选型:7B 和 14B 之间的一笔账

确认 CPU 推理可行之后,接下来就是选模型。考虑到同事都是中文办公场景,第一梯队自然是阿里的 Qwen 系列,也就是热搜里经常看到的千问大模型本地部署。当前比较合适的是 Qwen2.5-7B-Instruct 和 Qwen2.5-14B-Instruct。我拿这两个做了对比:

模型默认 Q4_K_M 大小预估生成速度(本项目 CPU)中文能力适合任务
Qwen2.5-7B-Instruct约 4.7GB5~8 token/s够用文案润色、周报、问答
Qwen2.5-14B-Instruct约 9.0GB2~4 token/s更强,逻辑更稳长文档总结、复杂推理
Qwen2.5-32B-Instruct约 19GB1~2 token/s最强基本放弃实时交互

内存容量本身不是问题,192GB 内存哪怕跑 32B 都装得下,问题是带宽决定了速度。模型越大,每次生成 token 需要读取的数据就越多,速度呈反比下降。同样一块内存,跑 7B 需要读 4.7GB,跑 14B 要读 9GB,速度几乎减半。再考虑到二十几个人共用一台机器,不能只照顾单用户的最强效果,必须选一个"综合等待时间可接受"的档位。

最终我选择了 7B 作为主力模型,理由有三个:一是生成速度快,多人并发时每个人排队的时间短;二是办公场景要求的不是"模型多聪明",而是"输出是否通顺、够不够符合语境",7B 在中文日常文本上已经表现不错;三是这台机器还要承担轻量的数据库任务,不能把内存和 CPU 全占满。

我还提前下载了 14B 模型备用,白天跑在低优先级,晚上或午休时切换给同事用。后面发现,这个"双模型轮换"的策略真的管用。

2.4 方案对比:Ollama 为什么是首选

选推理框架时,我认真对比过几个方案:

  • llama.cpp 直接编译:功能很强,但需要自己处理模型转换、参数调优、API 封装,适合喜欢折腾底层的人。对我们需要快速交付、还要伺候二十几个同事的场景来说,有点重。
  • Text-generation-webui:功能丰富,自带 Web UI,但依赖的包很多,部署稍微复杂,更新也频繁。
  • LM Studio:桌面端工具,图形化界面友好,但更适合个人电脑使用,放在服务器上做多用户服务不是它的主场。
  • Ollama:一条命令安装,一条命令启动服务,自带 OpenAI 兼容接口,还能通过 Docker 部署。它底层就是 llama.cpp 的优化引擎,CPU 推理支持得非常好。而且社区里已经有很多现成的模型,拉下来就能用,不需要自己转换格式。

从"给团队交付一个可用服务"的角度,Ollama 完胜。它有系统化的并发管理、模型管理、环境变量调优,还天然支持局域网服务暴露,即使后续买了 NVIDIA 显卡,也可以通过切换环境变量无缝用上 GPU 加速。也就是说,今天用 CPU 顶上的这套方案,以后不会白做。

3. 从装系统到同事打开浏览器的完整过程

3.1 基础环境:Ubuntu 22.04 与 Docker

第一步并不是直接装 Ollama,而是先把系统环境整理好。这台机器原本装的是 CentOS 7,很多软件源都老了,我索性重装成 Ubuntu 22.04 LTS。选它的原因很简单:社区支持最好,Docker、Ollama 的官方安装脚本都优先支持,遇到问题搜解决方案也最容易。

装好系统后先做几件基础事:

  1. 更新系统包:sudo apt update && sudo apt upgrade -y
  2. 安装 Docker Engine,并配置镜像加速
  3. 设置防火墙,只开放 22、80、11434、8080 这几个端口到内网
  4. 开启 swap 空间,避免内存峰值时直接 OOM

这里特别说一下 swap。虽然 192GB 内存装 7B 模型绰绰有余,但多个会话同时跑的时候,内存会出现短暂的峰值波动,特别是长上下文生成时,KV cache 会占掉不少内存。服务器上又没有显卡,全部依赖内存,内存长时间打满会导致服务直接崩溃。所以我划了 32GB 的 SSD swap 作为兜底,宁可速度慢一点,也不能让服务死掉。注意 swap 设置在 SSD 上,不能用 HDD,否则切换的时候卡到没法用。

3.2 用容器把 Ollama 跑起来

Ollama 官方推荐的最简单方式是二进制安装,一行脚本就搞定。但考虑到后续要迁移、备份、回滚,我用 Docker 容器部署。这样即使系统出问题,把容器重新拉起来就能恢复。

实际的部署命令很简单:

docker run -d \ --name ollama \ --restart=always \ -v /data/ollama:/root/.ollama \ -p 11434:11434 \ ollama/ollama:latest

这里有个细节一定要注意:-v /data/ollama:/root/.ollama必须挂载外部目录。如果不挂载,模型文件会写在容器内部,每次容器升级、重建,模型全部要重新下载。7B 模型下载一次几 GB,虽然网络快,但没必要。把模型放在宿主机独立目录里,升级容器版本时模型还在,这才是正经的运维姿势。

启动之后,用curl http://localhost:11434验证服务是否响应。如果看到Ollama is running,说明服务已经起来了。

接下来拉取模型:

docker exec -it ollama ollama pull qwen2.5:7b docker exec -it ollama ollama pull qwen2.5:14b

Ollama 的模型标签体系里,qwen2.5:7b默认就是 Q4_K_M 量化版本,不需要手动指定量化级别,这也是它比 llama.cpp 省心的地方。首次 pull 需要点时间,7B 大约 4.7GB,14B 大约 9GB,放在内网环境,几分钟能搞定。

3.3 通过 Open WebUI 提供可视化界面

Ollama 本身只提供 API 接口,同事不可能都对着命令行敲 curl,需要一个网页聊天界面。我选了 Open WebUI,这个项目可以说是目前最流行的 Ollama 可视化前端之一,功能非常完整,支持多用户登录、会话管理、模型切换、Markdown 渲染、文档上传解析等。

部署命令:

docker run -d \ --name open-webui \ --restart=always \ -e OLLAMA_BASE_URL=http://ollama:11434 \ -e WEBUI_AUTH=email_verified \ -v /data/open-webui:/app/backend/data \ --network bridge \ -p 8080:8080 \ ghcr.io/open-webui/open-webui:main

注意这里的OLLAMA_BASE_URL,如果 Open WebUI 容器和 Ollama 容器在同一宿主机,可以用http://host.docker.internal:11434,也可以直接用宿主机 IP。因为两个容器默认跑在同一个 bridge 网络里,但容器名不能直接互相解析,我用了宿主机 IP 的方式,简单可靠。

部署完以后,打开http://服务器IP:8080,注册第一个账号,它默认就是管理员账号。然后进入管理后台,把 Ollama 连接地址填好,界面上就能看到已经拉取的两个模型了。

WebUI 配好之后,我又做了一件事:开启用户注册审核。毕竟是公司内网,二十多个同事可以注册,但管理员必须审核通过才能访问。这能防止无关人员混进来,也方便以后统计活跃用户。

3.4 指定模型并做首次预热

模型拉取完成、WebUI 运行正常之后,我并没有直接让同事开始用,而是先在命令行做了一次"预热"测试:

curl http://localhost:11434/api/chat \ -d '{"model":"qwen2.5:7b","messages":[{"role":"user","content":"你好,请用一句话介绍你自己"}]}'

这一步很重要的原因是:Ollama 首次加载模型需要把几 GB 的参数从硬盘读到内存里,这个过程非常慢,可能十几秒,如果有人在 WebUI 上点了"发送"却没有心理准备,他会以为服务挂了。我先通过 API 触发一次,让模型常驻内存,后面的请求响应就快了。另外,这一步也能确认模型文件没有损坏、tokenizer 正常工作、CPU 推理没有报错。

实测下来,7B 模型首次加载约 12 秒,之后每次请求的内存读取开销就是纯生成时间了。也就是说,只要模型常驻内存,响应速度就能稳定下来。如果要让模型一直驻留,可以在 Ollama 的环境变量里设置OLLAMA_KEEP_ALIVE=24h,默认好像是 5 分钟,不设置的话模型会在空闲一段时间后从内存卸载,遇到午休后第一个请求就会卡一下。这个参数后面调优会专门说。

4. 二十个人访问之后的真问题:并发、内存和排队

4.1 并发处理逻辑与显存无关时会发生什么

等到第二天同事开始体验,真正的坑才一个个浮出来。

第一个问题很简单:群里一喊"可以用了",运营部五个同事同时点开网页,每个人都在发消息,结果每个人都看到"在生成中……"且迟迟不出字。这是因为 Ollama 默认情况下,同一个模型同时只处理一个请求,其余请求全部排队。如果在 WebUI 上开了多会话,甚至连当前用户自己开两个页面都会互相排队。

这在 GPU 机器上问题不大,因为 GPU 推理快,一个请求几秒就结束,排到后面的请求等一会儿也就出来了。但 CPU 推理一个请求可能要几十秒甚至一两分钟,排队效应就会被放大,大家直观感受就是"卡死了"。

解决办法是调并发数。Ollama 通过环境变量OLLAMA_NUM_PARALLEL控制同一个模型同时处理的请求数量。我一开始直接设成 4,结果问题更严重:4 个请求同时跑,每个请求都在抢 CPU 和内存带宽,单个请求的速度直接降到 1 token/s 以下,四个人全都觉得体验崩溃了。这说明 CPU 推理不能盲目设置并发,要根据硬件实际能力精确计算。

4.2 OLLAMA_NUM_PARALLEL 和上下文长度的取舍

CPU 推理的并发可不是简单地"越多越好"。因为模型参数是共享的,但每个请求还要分配自己的 KV cache 空间,而且内存带宽是固定值。4 个并发请求同时生成,意味着每生成一个 token,内存要付出 4 倍的数据读取量,每个请求的生成速度自然变成原来的四分之一。GPU 因为带宽充裕,并发几个请求可能问题不大;CPU 本就带宽紧张,并发设置过高反而是灾难。

我后来做了个小型压测,用脚本模拟不同并发数量下每个请求的平均速度,结果如下:

并发数每个请求平均速度(7B Q4)体验
15~7 token/s顺畅,但其他人排队久
23~4 token/s比较均衡,可以接受
41~2 token/s明显卡顿
80.5~1 token/s几乎不可用

最终我把OLLAMA_NUM_PARALLEL设成 2,配合OLLAMA_MAX_LOADED_MODELS=1,让机器在多数情况下同时只处理两个请求,排队的第三个请求等待时间也不会太长,体验均衡很多。

还有另一个重要参数是上下文长度。Ollama 默认的上下文长度是 2048 token,但这个值直接影响 KV cache 的内存占用。上下文越长,KV cache 占用越高,每次生成时的内存访问量也越大。办公场景有相当一部分请求是"复制一篇文章进来,让它总结摘要",这种情况下 2048 的默认值不太够用。我在模型设置里把上下文调到了 4096,日常够用,内存也扛得住。如果再往上调,速度又会掉一大截,所以没有盲目追求长上下文。

对了,Open WebUI 端也能配置模型参数,比如温度、top_p,我在后台给 Qwen 设了温度 0.7,这是文案生成和翻译任务比较稳妥的中间值。太低了缺乏创造力,太高了容易跑偏。

4.3 性能实测数据与同事体验

调优之后的真实表现,我用一组数据来说明:

  • 单用户访问 Qwen2.5-7B,写一段 200 字的周报,大约等待 35~45 秒;
  • 两个用户并发访问,各自请求平均等待增加到 60 秒左右;
  • 模型首 token 延迟(TTFT)在模型热启动后约 2~4 秒,这个用户感知不明显;
  • 生成速度稳定在 3~5 token/s,文字是一行一行蹦出来的,有"打字机"的感觉;
  • 内存占用:模型常驻约 5GB,加上 KV cache 和 WebUI 本身,整机内存占用约 15GB,非常轻松;
  • CPU 占用率:一个请求大约占用 30 个线程,八十线程的机器还剩一半多给其他任务。

同事的实际反馈大多数是正面的:"虽然有点慢,但不用往外面传数据了""写的文案比我预算快多了""你不是说不能联网吗?我贴了一整段合同进去,它居然能总结出甲方乙方赔付条款,太靠谱了"。

当然也有人问:"为什么不能像手机输入法一样自动补全下一句?"这种需求就属于对延迟要求极其敏感的实时场景了,别说 CPU,没有很好的 GPU 也做不到流畅。给同事解释清楚原理之后,大家都能理解,他们对"本地部署"的期望值也从一开始就放得比较低。

4.4 那些没有单独处理的细节:日志、模型切换、磁盘空间

服务上线后,我顺手把几个运维细节也处理了,它们看着不显眼,实际影响很大。

日志:Docker 容器默认的日志驱动是 json-file,在 WebUI 上访问较多的情况下,日志文件会膨胀。我在daemon.json里加了log-driverlog-opts的限制,单个日志文件超过 50MB 就轮转,避免日志撑爆系统盘。

模型切换:7B 模型确实有不够聪明的时候,比如让同事做复杂推理,或者分析一篇带图表的 PDF,它的逻辑会明显变弱。我在 WebUI 的管理后台设定了管理员可以切换默认模型。白天主力 7B,如果某个同事临时有更复杂的任务,我可以手动切到 14B 让他跑完再切回来。因为 14B 模型体积大,不能常驻内存,切换时会有一段时间加载,约 20 秒,但同事都能接受。

磁盘空间:模型文件放在/data/ollama/models,7B 和 14B 加一起占掉 15GB 左右。看起来不多,但如果同事在 WebUI 上传文档,或者后续又试其他模型,磁盘会悄悄被占满。我加了一个简单的 cron 定时任务,每天检查磁盘使用率,超过 80% 时告警,避免最后一个模型把磁盘塞满导致容器异常退出。

5. 复盘后的几条经验,以及下一步怎么走

5.1 没有 NVIDIA 也能做的事

这次落地最大的收获,是验证了一个结论:在没有 NVIDIA 显卡的条件下,中小规模大模型完全可以在内网完成办公辅助级别的部署。7B 模型、CPU 推理、Docker 容器、Open WebUI,这套组合已经稳稳跑了两个多月,同事们从每天只有几个人试用,变成了运营、销售、人事三个部门轮流用的固定工具。

这让我重新思考了部署和硬件投入之间的关系。很多团队的实际情况是:大模型应用还在探索期,需求不明确、业务场景没跑通、预算也紧张。这时贸然买几万块钱的 GPU,或者租大量云端资源,其实风险不小。不如先用手头的 CPU 服务器跑起来,让大家真实用几个月,把真正的需求和体验边界摸清楚,再决定后续要投多少钱在硬件上。

实际上,这次投入的成本只有一块 2TB 的 SSD 和一个 VGA 转接头,加起来不到一千块。如果当时去申请一张显卡,要过层层审批,可能到现在还在等。

5.2 CPU 推理的适用边界

必须说清楚,CPU 推理有自己的边界,别被"能跑"误导成"无所不能"。

这次方案适合的是:并发要求不高、文本生成类任务为主、单次请求的上下文不长的场景。如果业务需求变成"二十个人同时要求秒回"、"要处理很长的合同全文并准确提取条款"、"要做语音实时转写",那 CPU 推理就不够用了,老实上 GPU 才是正路。

还有一点,CPU 推理不适合跑太大的模型,14B 已经很勉强,32B 在这个硬件上基本放弃实时交互。团队如果对模型智商的要求很高,还是得考虑用 GPU 跑 70B 甚至更大的模型。另外,虽然这是"没有 NVIDIA"的方案,但引入 AMD 显卡或者 Apple Silicon 也是一个分支,不过我这次没有走这条路线,因为服务器的适配性不好,不做过多展开。

5.3 以后如果要升级,从哪里开始

如果后续真的需要升级,我会优先考虑加一块 NVIDIA GPU,因为现在整个 Ollama 和 Open WebUI 的架构已经准备好了,插上 GPU、设置环境变量,服务会自动利用显卡推理,不需要重装任何东西。这也是当初选 Ollama 作为底层框架的另一个原因——它屏蔽了硬件差异,把"从 CPU 到 GPU 的迁移成本"降到了最低。

但在那之前,我更愿意花时间做一些低成本的优化:给同事建一个常用提示词模板库,把"写周报""改合同条款""翻译邮件"这些反复使用的场景做成按钮,让不懂 Prompt 的同事也能直接用;再往后,可以接一个简单的 RAG 流程,把团队内部的一些常见文档放进向量库里,让模型基于公司自己的知识库回答,这才是比单纯堆显卡更有价值的方向。

如果这条经验能给你带去一点启发,我建议你也找一台旧服务器,装上 Ollama,拉个 7B 模型,先用两周再说。亲自体验过 CPU 推理的真实速度之后,你对"本地大模型到底需要什么硬件"的判断,会比看一百篇评测都准确。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询