什么时候该本地部署模型?答案很明确:数据不能出内网、调用量大到 API 成本扛不住、或者需要极低延迟。这篇讲部署的选型、量化、服务化的完整路径,以及真实的成本对照。
一、先算账:本地部署真的更便宜吗
| 方案 | 月成本(估) | 适合 |
|---|---|---|
| 云 API(按 token) | 按量:1M token 约 ¥1-15(看模型) | 调用量小、快速验证 |
| 本地 8B 模型(自有 GPU) | 一次性 ¥1-2 万 + 电费 | 长期高频、数据敏感 |
| 本地 8B(租 GPU) | 约 ¥2000-4000/月 | 中等量、不想买硬件 |
| 本地 70B(租 A100) | 约 ¥1.5-3 万/月 | 需要接近大模型质量 |
粗略的盈亏平衡点:如果每月 API 花费超过「租 GPU 的成本」,本地部署就划算。以 8B 模型为例,月租 2500 元大约对应 200-400 万次小请求的 API 开销。低于这个量,用 API 更省事。
二、模型选型:先看显存,再看质量
| 模型规模 | 量化后显存 | 典型质量 | 适用 |
|---|---|---|---|
| Qwen3-1.7B | 约 1-2 GB | 简单分类、抽取 | CPU 也能跑 |
| Qwen3-8B | 约 5-6 GB(Q4) | 通用问答、RAG 生成 | 性价比最高 |
| Qwen3-14B | 约 9-11 GB | 接近小模型上限 | 单卡 16G 可跑 |
| Qwen3-32B | 约 20-24 GB | 明显更好 | 需 24G 显存 |
| 70B+ | 40 GB+ | 接近闭源大模型 | 多卡或 A100 |
经验值:显存 ≈ 参数量 × 量化位宽 / 8 + 缓存。Q4 量化下 8B 模型约 5GB + 2-3GB KV cache,8G 显存单卡刚好。
三、量化:质量与显存的取舍
| 量化 | 显存占比 | 质量损失 | 建议 |
|---|---|---|---|
| FP16 | 100% | 无 | 显存充足时用 |
| Q8 | 约 50% | 几乎无损 | 质量敏感场景 |
| Q4_K_M | 约 28% | 轻微可感知 | 默认选它 |
| Q3 | 约 22% | 明显下降 | 仅显存极紧张 |
| Q2 | 约 15% | 严重下降 | 不建议 |
# 用 llama.cpp 量化(GGUF 格式,CPU/GPU 都能跑)
1. 1. 转格式
python convert_hf_to_gguf.py Qwen3-8B --outtype f16 --outfile qwen3-8b-f16.gguf
1. 2. 量化到 Q4_K_M
./llama-quantize qwen3-8b-f16.gguf qwen3-8b-q4km.gguf Q4_K_M
1. 3. 跑起来
./llama-server -m qwen3-8b-q4km.gguf \
--host 0.0.0.0 --port 8080 \
-ngl 99 \ # 全部层放 GPU,没有 GPU 就去掉
-c 4096 \ # 上下文长度
--parallel 4 # 并发槽位数-ngl 99是把所有层都放到 GPU:纯 CPU 转载会极慢(8B 在 4 核 CPU 上约 1-2 token/s)-c是上下文长度,直接决定 KV cache 显存:4096 比 32768 省得多- Q4_K_M 是公认的甜点:质量接近 Q8,显存只有一半
四、服务化:OpenAI 兼容接口最省事
无论用 vLLM、llama.cpp 还是 Ollama,都提供 OpenAI 兼容的 /v1/chat/completions。这样应用代码不用改,只换 base_url:
from openai import AsyncOpenAI
1. 本地模型
client = AsyncOpenAI(
base_url="http://localhost:8080/v1",
api_key="not-needed", # 本地不需要,但 SDK 要求非空
)
resp = await client.chat.completions.create(
model="qwen3-8b", # llama.cpp 会忽略这个名字
messages=[{"role": "user", "content": "你好"}],
temperature=0.3,
max_tokens=512,
)| 服务 | 吞吐 | 易用性 | 适合 |
|---|---|---|---|
| llama.cpp (llama-server) | 中 | 最高(单文件) | 中小规模、CPU 也能跑 |
| vLLM | 高(PagedAttention + 连续批处理) | 中 | 生产高并发首选 |
| Ollama | 中低 | 很高(一条命令) | 本地开发、快速试 |
| TGI | 高 | 中 | HuggingFace 生态 |
生产环境选 vLLM:连续批处理让并发吞吐比 llama.cpp 高数倍,代价是需要 GPU 且配置稍复杂。
# vLLM 部署
pip install vllm
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen3-8B \
--quantization awq \ # 或 gptq
--max-model-len 8192 \
--gpu-memory-utilization 0.9 \
--port 8000五、并发与显存:KV cache 是隐形杀手
# KV cache 显存估算(8B 模型,Q4 权重)
1. 每 token 的 KV cache ≈ 2 × 层数 × hidden_size × 2 字节
1. 8B 模型约 128 KB/token(粗略)
1. 上下文 4096 + 并发 8 → 128KB × 4096 × 8 ≈ 4 GB 额外显存
1. 所以:显存 = 权重 + KV cache + 激活
1. 8B Q4(5GB)+ KV(4GB)+ 余量 = 约 10GB → 12G 卡勉强,16G 舒适| 现象 | 原因 | 调整 |
|---|---|---|
| OOM 但显存看起来够 | KV cache 超了 | 降 -c 或 --max-model-len |
| 并发上不去 | 单请求占满序列槽 | 加 --parallel,代价是每槽上下文变短 |
| 首 token 很慢 | prompt 太长或没做前缀缓存 | 开 prefix caching |
| 吞吐波动大 | 批处理不均衡 | vLLM 的连续批处理能缓解 |
六、真实体验:本地模型的短板
- 工具调用能力弱:8B 级模型在 function calling 上明显不如闭源大模型,Agent 场景要慎重
- 长上下文易失焦:32K 上下文里塞 20K 资料,模型容易忽略中间部分(「lost in the middle」)
- 中文质量看模型:Qwen 系列中文好,Llama 系英文好但中文偏弱
- 推理速度受限:单卡 8B 约 30-60 token/s,并发高时会分摊
- 需要自己维护:模型更新、显存监控、OOM 重启都要自己做
务实定位:本地 8B 模型适合做「RAG 的生成端」(资料已给定,只需组织语言)和「简单分类抽取」。不适合做复杂 Agent 规划——那需要更强的推理能力,还是得上闭源大模型。
七、混合架构:本地 + 云端的务实组合
async def smart_route(task: str, payload: dict):
"""按任务复杂度路由到本地或云端。"""
if task in ("classify", "extract", "summarize"):
return await local_client.chat(...) # 简单任务本地
if task in ("plan", "agent_step", "code_review"):
return await cloud_client.chat(...) # 复杂推理走云端
1. 兜底:先本地试,失败或置信度低时升级
r = await local_client.chat(...)
if r.confidence < 0.6:
return await cloud_client.chat(...)
return r这个模式能显著降低成本:80% 的简单请求走本地几乎免费,20% 的复杂请求走云端。
八、部署检查清单
| 项 | 检查内容 |
|---|---|
| 显存 | 权重 + KV cache + 余量,留 15% 缓冲 |
| 并发 | 压测确认 QPS 与首 token 延迟 |
| 上下文 | 按实际需求设 max-model-len,不要盲目设大 |
| 监控 | 显存占用、请求队列长度、OOM 次数 |
| 降级 | 模型不可用时回退到云端 API |
| 版本 | 模型文件要存档,避免上游更新导致行为变化 |
九、总结
- 先算盈亏平衡点:月 API 花费低于租 GPU 成本时,用 API 更省事
- Q4_K_M 是甜点:质量接近 Q8,显存只要一半
- KV cache 决定并发上限:不是权重占了显存,是上下文与并发
- OpenAI 兼容接口让应用无感切换:base_url 一改就换成本地
- 本地 8B 适合生成端,不适合 Agent 规划——认清能力边界比堆硬件重要
- 混合架构最务实:简单任务本地,复杂任务云端