实操 03 模型本地部署与推理优化
所属:AI 知识图谱 → 实操系列(practice/)。正文的经济账与产业格局见 07 篇 · 算力与硬件底座,本篇解决"我要自部署,用什么工具、需要什么硬件、怎么跑起来"。
速览卡
| 项 | 内容 |
|---|---|
| 一句话定位 | 从零把一个开源模型跑在自己机器上(或服务器上),并搞懂量化、显存、并发这些决定"能不能用"的硬约束 |
| 核心内容 | Ollama / vLLM / llama.cpp 选型、显存估算公式、量化实测、API 服务化、并发与 KV Cache、压测方法 |
| 前置知识 | 会用命令行;00 篇(知道什么是参数量、量化) |
| 读完能做到 | 根据手头硬件选出正确工具,把 7B~70B 级模型跑起来并对外提供 OpenAI 兼容 API;能估算"我的显存能跑多大模型" |
| 配套正文 | 自部署 vs API 的经济账见 07 篇;何时该自部署的临界点见 01 篇 |
版本约定:工具版本与模型名均标
[易变],以官方文档为准。本篇讲的是不变的判断方法与操作骨架。
一、三大工具选型:一张表定下来
| 工具 | 定位 | 一句话 | 用它当你…… |
|---|---|---|---|
| Ollama | 个人开发/体验 | 一条命令跑模型,自动管显存 | 在自己电脑上玩、做原型、离线使用 |
| vLLM | 生产服务 | 高吞吐并发服务,PagedAttention | 要给多人/多业务提供 API 服务 |
| llama.cpp | 端侧/极限压缩 | 纯 CPU 也能跑,GGUF 量化格式 | 没有像样显卡、要塞进笔记本/手机/树莓派 |
决策路径:先问"给谁用"——
自己一个人用? ──▶ Ollama
多人调用 / 要 SLA? ──▶ vLLM(GPU 服务器)
没有 GPU / 端侧设备? ──▶ llama.cpp三者不互斥:Ollama 底层就是 llama.cpp;原型用 Ollama、上线换 vLLM 是常见路径。
二、显存估算:先算账再下载(最值钱的一节)
下载 30GB 的模型才发现显存只有 24GB——用这个公式提前算:
显存需求 ≈ 参数量 × 每参数字节数(量化) × 1.2 (框架开销)
↑
FP16: 2 字节 | INT8: 1 字节 | INT4: 0.5 字节速查表(含 1.2 开销系数,单位 GB):
| 参数量 | FP16 | INT8 (Q8) | INT4 (Q4) |
|---|---|---|---|
| 1.5B | 3.6 | 1.8 | 0.9 |
| 7B | 16.8 | 8.4 | 4.2 |
| 14B | 33.6 | 16.8 | 8.4 |
| 32B | 76.8 | 38.4 | 19.2 |
| 70B | 168 | 84 | 42 |
再叠加 KV Cache(上下文越多占越多,长上下文场景不可忽略):
KV Cache ≈ 2 × 层数 × KV头数 × 头维度 × 上下文长度 × 精度字节数 × 批大小不必手算精确值,记住量级:7B 模型 FP16、8K 上下文、单并发,KV Cache 约 1~2GB;上下文翻倍它翻倍,并发数翻倍它翻倍。
例:32B 模型 INT4 ≈ 19.2GB 权重 + 2GB KV Cache ≈ 22GB → 一张 24GB 显卡(RTX 4090 级)勉强可跑。这与 07 篇端侧分析的结论一致:消费级显卡的甜点区是 7B~32B 的 INT4 量化。
三、路径 A:Ollama(个人开发首选)
# 1. 安装后(官网下载安装包),一条命令拉起模型
ollama run qwen2.5:7b # [易变] 模型名以 ollama library 为准
# 2. 就直接能聊了。退出后模型常驻本地
ollama list # 查看已下载模型
ollama ps # 查看当前加载与显存占用对外提供 OpenAI 兼容 API
Ollama 自带兼容层,你为云端 API 写的代码几乎零修改迁到本地:
from openai import OpenAI
client = OpenAI(
api_key="ollama", # 随便填,Ollama 不校验
base_url="http://localhost:11434/v1", # 关键:指向本地
)
resp = client.chat.completions.create(
model="qwen2.5:7b", # [易变]
messages=[{"role": "user", "content": "解释 KV Cache 的作用"}],
temperature=0,
)
print(resp.choices[0].message.content)常用操作:
ollama run qwen2.5:14b --verbose # 显示每秒 Token 数(TPS),性能基线就看它
ollama rm qwen2.5:7b # 删模型释放磁盘四、路径 B:vLLM(生产服务)
4.1 起服务
pip install vllm
# 单卡启动(以 Qwen 7B 为例 [易变])
vllm serve Qwen/Qwen2.5-7B-Instruct \
--max-model-len 8192 \ # 限制上下文长度,直接压住 KV Cache 上限
--gpu-memory-utilization 0.90 # 显存预算占比(留 10% 余量防 OOM)
# 显存不够装 FP16?直接加载官方 GPTQ/AWQ 量化版(模型名以 HF 为准 [易变])
vllm serve Qwen/Qwen2.5-7B-Instruct-AWQ --max-model-len 8192启动后自动提供 OpenAI 兼容 API(默认 :8000),与 Ollama 同理换 base_url 即用。
4.2 vLLM 为什么快:三个不变的机制
| 机制 | 解决什么问题 | 一句话原理 |
|---|---|---|
| PagedAttention | KV Cache 碎片浪费 | 像操作系统分页管理内存一样管理 KV Cache,碎片近乎为零 |
| Continuous Batching | 请求排队等待整批完成 | 新请求随到随插入当前批,不等下一轮 |
| Prefix Caching | 相同前缀重复计算 | 相同 system prompt / 少样本前缀只算一次 |
这就是 07 篇说的"推理优化决定自部署成本"的落地层。同样的卡,vLLM 比裸跑 HuggingFace generate() 吞吐高一个量级。
4.3 并发调参直觉
--max-num-seqs:最大并发批大小,默认 256,按业务峰值调- 显存 OOM → 先降
--max-model-len,再降--gpu-memory-utilization - 吞吐不够 → 优先确认 Prefix Caching 生效(system prompt 是否统一前缀),再考虑加卡
五、量化实测:省显存的钱,付质量的账
5.1 量化档位怎么选
| 档位 | 体积/显存 | 质量损失 | 适用 |
|---|---|---|---|
| FP16 / BF16 | 基准 | 无(训练精度) | 显存管够的生产环境 |
| INT8 (Q8) | ½ | 几乎无损 | 显存紧一档、质量敏感 |
| INT4 (Q4_K_M 等) | ¼ | 轻微(日常任务可感知度低) | 消费级显卡跑大模型的主流选择 |
| 低于 INT4 | 更小 | 明显劣化 | 仅端侧极限压缩,需评测兜底 |
5.2 量化前后必须自己测(5 分钟的对比实验)
同一批问题跑两遍,人工对比。用一个可脚本化的最小对照:
QUESTIONS = [
"解释什么是温度参数",
"把这段话翻译成英文:大模型的幻觉无法根除,只能缓解。",
"9.11 和 9.9 哪个大?", # 经典陷阱题,量化劣化容易在这暴露
"写一个二分查找的 Python 实现",
]
def compare(model_a: str, model_b: str, client):
for q in QUESTIONS:
print(f"\n=== {q} ===")
for name in (model_a, model_b):
r = client.chat.completions.create(
model=name,
messages=[{"role": "user", "content": q}],
temperature=0,
)
print(f"--- {name} ---\n{r.choices[0].message.content[:200]}")六、压测:知道你的服务的真实容量
上线前必做。用 vllm bench(vLLM 自带)或任何 HTTP 压测工具,关注三个指标:
| 指标 | 含义 | 经验参考 |
|---|---|---|
| TTFT 首 Token 延迟 | 用户按下回车到看到第一个字 | 交互式 < 1s 为佳 |
| TPS 每 Token 生成速度 | 打字机速度 | 单流 > 20 tok/s 体验尚可 |
| 吞吐 tokens/s(总) | 整机的钱花得值不值 | 并发上去后应远大于单流 TPS |
# vLLM 自带压测( shareGPT 格式数据集 [易变])
python -m vllm.entrypoints.openai.api_server ... # 先起服务
python benchmarks/benchmark_serving.py \
--backend vllm --model Qwen/Qwen2.5-7B-Instruct \
--num-prompts 100 --request-rate 5 # 100 个请求、每秒 5 个压测后回答两个问题:目标并发下 TTFT 是否达标?峰值 2 倍时是变慢还是崩?(变慢可接受,崩要加熔断——见 05 篇稳定性设计)
七、端侧与 CPU 路径(llama.cpp 速览)
没有 GPU 时的可行路径:
# llama.cpp:GGUF 格式模型,纯 CPU 推理
git clone https://github.com/ggerganov/llama.cpp && cd llama.cpp
cmake -B build && cmake --build build -j
./build/bin/llama-cli -m qwen2.5-7b-q4_k_m.gguf -p "解释 RAG" -n 256预期管理(对照 07 篇端侧分析):
- 纯 CPU 跑 7B Q4:普通笔记本约 3~8 tok/s——能用,但不流畅;3B 以下模型 + CPU 才有接近实时的体验
- Apple Silicon(M 系统一内存):GPU/CPU 共享内存,Ollama 在 Mac 上体验最佳,是个人端侧开发的主战场
- 小内存设备选 1.5B~3B 级模型,先做单一任务(如摘要、分类),别贪全能力
八、自部署决策复盘(对照正文)
跑完全流程后回看 07 篇经济账的临界点公式,你现在能填上数字了:
自部署月成本 ≈ 显卡折旧/租用 + 电费 + 运维人力
API 月成本 ≈ 实操 01 第六节算出的用量 × 单价经验判断:个人学习/原型 → API 或 Ollama 免费档足够;日均百万级请求、数据不出域、或需要深度定制(微调+私有化一体)→ 自部署开始划算。两边都搭一遍再决定,成本已经有了量级感。
九、动手任务
- [ ] 任务 1:用显存公式估算"我的设备最大能跑多大的 INT4 模型",再用 Ollama 实际拉起验证,记录
ollama ps显示的实际占用与估算的偏差 - [ ] 任务 2:跑
ollama run与--verbose记录 TPS;换一个更小的模型(7B→3B)对比速度,体会"参数量 vs 速度"的取舍 - [ ] 任务 3:把实操 02 的 RAG 问答切到本地模型(只改
base_url),对比云端模型与本地 7B 的回答质量差距,写下 3 个可感知的差异点 - [ ] 任务 4(有 GPU/服务器):vLLM 起 7B AWQ 量化版,
benchmark_serving压出 TTFT/吞吐曲线,找到 TTFT < 1s 的最大并发数 - [ ] 自检:能不看资料说出——Ollama/vLLM/llama.cpp 各自什么时候用?显存估算公式?为什么 RAG 的 Embedding 也占显存要算进去?TTFT 和吞吐为什么是两个指标?
延伸方向
- 还不会调 API(本地部署的前提是知道 API 长什么样)→ 实操 01 LLM API 实操入门
- 本地模型 + 本地知识库组合成完整系统 → 实操 02 RAG 实战
- 想自己改模型行为(微调 LoRA)→ 实操 07 微调实战(规划中)
- 芯片格局、国产替代、端云协同的产业判断 → 07 篇 · 算力与硬件底座
- 部署后的监控、扩容、稳定性设计 → 05 篇 · 工程化与 LLMOps