Skip to content

部署与服务化

本页速览 从显存估算公式(权重+KV cache+激活)、量化(GPTQ/AWQ/GGUF)、continuous batching 到 TTFT/TPOT 指标、GPU 选型与 vLLM 部署示例,讲透"把模型从笔记本搬到生产"的完整链路与决策方法。

部署与服务化

部署的目标不是"把模型跑起来",而是用可接受的成本,把模型以可预测的延迟和吞吐稳定地提供给用户——它是一场关于显存、算力、并发与成本的工程权衡。

模型在笔记本上跑通只是开始。生产环境要回答的问题完全不同:显存够吗?并发 100 时延迟多少?租什么 GPU 最划算?量化会不会掉分? 本文给出完整的部署链路:先定指标,再算显存,然后选量化与批处理策略,最后落到 vLLM 的可运行示例。底层机制(自回归循环、KV cache、采样)见推理基础

一、先定指标:部署语言是数字

部署团队必须用同一套指标说话:

指标全称/含义衡量什么典型量级(参考)
TTFTTime To First Token,首 token 延迟用户"等多久开始有反应"数百 ms~秒级
TPOTTime Per Output Token,每输出 token 时间生成速度数十 ms~百 ms/token
吞吐tokens/s,单位时间输出量服务整体产能单卡数百~数千 token/s
并发同时服务的请求数容量与显存/批处理强相关
text
用户体验的换算:TTFT < 1s 属"可接受",TPOT 越快"打字感"越强。
吞吐 × 单请求 token 数 ÷ 并发 = 你需要的 GPU 数量(粗略)。

延迟 vs 吞吐的取舍

延迟优先(交互式对话)与吞吐优先(离线批量)是两种完全不同的调优方向:前者减小 batch 保速度,后者加大 batch 拉满吞吐。先明确业务属于哪一种,再调参数。

指标的量级参考与目标设定

指标没有绝对的"标准值",但可以按业务形态给出参考区间(具体以实测和产品要求为准):

业务形态TTFT 目标TPOT 目标主要约束
实时对话(Chat)< 1s越快越好(打字感)延迟优先
客服/工单辅助< 2s< 100ms/token延迟 + 质量
代码补全< 500ms< 50ms/token延迟极度敏感
离线批处理(摘要/抽取)不敏感不敏感吞吐 + 成本优先

目标设定的原则:先测出当前基线(P50 与 P95),再定"可接受的 P95"而非"平均"——P95 才是用户体验的真实感受,平均值会被少数超快请求拉低。

二、显存估算:权重 + KV cache + 激活

推理显存由三部分组成,先学会手算,再信任何监控工具

总显存 ≈ 权重显存 + KV cache 显存 + 激活/临时显存

1. 权重显存

权重显存 = 参数量 × 每参数字节数
fp16/bf16: 2 字节/参数     INT8: 1 字节/参数     INT4: 0.5 字节/参数
模型参数量FP16INT8INT4
7B/8B约 8B约 16GB约 8GB约 4GB
13B约 13B约 26GB约 13GB约 6.5GB
70B约 70B约 140GB约 70GB约 35GB

2. KV cache 显存

KV cache 存放每个序列在每层产生的 Key/Value(机制见 Transformer 架构详解),随并发请求数 × 上下文长度线性增长:

每 token KV 显存 = 2 × 层数 × KV 头数 × 头维度 × 字节数
KV cache 总量 = 每 token 显存 × 上下文长度 × 并发数

以 Llama-2 70B(80 层、8 个 KV 头、头维度 128、fp16)为例:

每 token = 2 × 80 × 8 × 128 × 2 字节 = 327,680 字节 ≈ 0.31 MB/token
4096 上下文 × 32 并发 ≈ 0.31MB × 4096 × 32 ≈ 40GB !

这组数字揭示了部署的第一定律:KV cache 的增速远超权重,长上下文 + 高并发时它才是显存大头(这也是 MoE 稀疏专家模型 与量化都缓解不了的部分)。KV cache 的工程优化见第四节。

3. 激活显存

预填充阶段每一层的中间激活也占显存,与 batch 大小、序列长度成正比,通常用 FlashAttention 等算子大幅压缩。估算时把"权重 + KV cache"的结果乘以 1.1~1.3 留出激活余量即可。

推理显存与训练显存的区别

训练显存还要加上梯度与优化器状态(全参训练约 12~16 字节/参数),是推理的 4~8 倍。"70B 模型 140GB 显存"是推理口径,训练另算。 训练侧估算见微调实战的 QLoRA 表。

三、量化:用精度换显存与速度

量化把权重从 fp16 压到低比特,是"小卡跑大模型"与"降本"的主要手段。

方法精度特点典型工具
动态量化(INT8)8-bit通用、简单、几乎不掉分vLLM 内置、bitsandbytes
GPTQ4-bit训练后量化,激活时反量化;省显存显著auto-gptq、vLLM 支持
AWQ4-bit按激活分布感知的量化,精度损失更小vLLM 支持、autoawq
GGUF(K-quant)1~8-bitllama.cpp 生态,CPU/边缘可跑llama.cpp、Ollama
FP88-bit新一代 GPU(H 系列)原生支持TensorRT-LLM、vLLM
bash
# 用 vLLM 直接加载量化模型(AWQ 与 GPTQ 均支持)
pip install vllm

# 加载 4-bit AWQ 版 Qwen2.5-7B
python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen2.5-7B-Instruct-AWQ \
  --quantization awq \
  --gpu-memory-utilization 0.9 \
  --max-model-len 8192

量化不是免费的

4-bit 量化通常带来 1~3% 的基准分下降(数值随任务与模型而变),但推理速度与显存收益巨大。决策顺序:先跑 fp16 基准,再跑 INT8/AWQ 对比,用评估实战的方法确认掉分可接受后再上线。

四、批处理与 KV cache 优化

1. Continuous batching:吞吐的最大杠杆

传统批处理是"静态批量"(一批全部完成后才开始下一批),导致短请求等长请求。Continuous batching(连续批处理)让序列在token 级进出 batch——完成一个就立即腾出位置给新请求,GPU 利用率显著提升。

2. PagedAttention:KV cache 的显存管理

vLLM 的核心创新 PagedAttention 把 KV cache 切成"页"管理(类似操作系统的虚拟内存),消除碎片、按需分配,在相同显存下吞吐可提升 2~4 倍(官方基准,具体数值随负载而变,见参考资料)。

3. 其他优化项速览

优化作用
FlashAttention融合算子,省显存 + 提速
前缀缓存(prefix caching)相同 system prompt 复用 KV cache
推测解码(speculative decoding)小模型草稿 + 大模型验证,降低 TPOT
结构化输出约束解码生成 JSON 时跳过非法 token,省时稳格式

4. 多卡部署:张量并行

单个模型放不下一张卡时,用**张量并行(Tensor Parallelism)**把一层拆到多卡,卡间通过高速互联(NVLink/InfiniBand)同步。要点:

并行方式拆分对象何时用
张量并行单层内的矩阵/注意力头拆到多卡单卡放不下权重;对卡间带宽敏感
流水线并行按层分组到不同卡层数很多;吞吐略降
数据并行每卡一份模型、分数据吞吐扩展(配合 TP 使用)

vLLM 用 --tensor-parallel-size 2 一行启用 TP;注意 TP 需要卡间高速互联,否则通信会拖垮性能。70B fp16 用 2×80GB 或 4×40GB 是常见组合。

五、GPU 选型

GPU显存参考定位(以 2024-2025 主流市场为基准,价格随时波动)
RTX 409024GB消费级:7B 全精度 / 13B INT4 单卡
L40S48GB单卡跑 13B fp16 / 70B INT4
A100 40/80GB40/80GB数据中心通用主力:70B INT4(80GB)
H100 80GB80GB大模型训练/推理旗舰,FP8 原生
H20 / 国产卡各异受限环境的选择,注意生态兼容

选型决策表(怎么选 GPU):

你的模型 + 精度最低单卡要求备注
7B INT48~16GB 即可边缘/低预算
7B fp1624GBRTX 4090 级别
13B fp16 / 70B INT440~48GBL40S / A100
70B fp1680GB × 2(张量并行)H100/A100
并发很大显存按"KV cache 公式"再放大别只看权重

显存够不够的快速判据

权重显存 + KV cache(按你的并发与上下文)≤ 单卡显存 × gpu-memory-utilization。超了就先量化,再不够就上多卡张量并行或降并发。永远把 KV cache 算进去——只算权重是部署事故的头号来源。

六、vLLM 部署示例:端到端

vLLM 提供 OpenAI 兼容的 API,前端代码一行不用改。

bash
# ① 启动服务(以 7B 模型为例)
python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen2.5-7B-Instruct \
  --served-model-name my-llm \
  --gpu-memory-utilization 0.9 \
  --max-model-len 8192 \
  --enforce-eager          # 兼容性差的环境可关 CUDA graph

# ② 用 OpenAI SDK 调用(客户端无感)
python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")

resp = client.chat.completions.create(
    model="my-llm",
    messages=[{"role": "user", "content": "什么是 KV cache?"}],
    temperature=0.7,
    max_tokens=512,
    stream=True,                       # 流式输出
)
for chunk in resp:
    print(chunk.choices[0].delta.content or "", end="")
bash
# ③ 监控与压测
curl http://localhost:8000/v1/models                     # 查看模型列表
# 压测工具:使用 openai-benchmark / h2o-llmstudio 或自写并发脚本
# 关键监控指标:TTFT 分位数、TPOT 分位数、GPU 利用率、显存使用率、队列积压

OpenAI 兼容 API:协议细节

vLLM 提供的 /v1/chat/completions 兼容 OpenAI 协议,四个容易踩的细节:

细节说明
流式(stream)stream=true 返回 data: 分片(SSE),以 data: [DONE] 结束
工具调用tools 参数与 tool_calls 返回字段需客户端支持
结构化输出JSON mode / response_format 的支持因引擎与模型而异,需先验证
鉴权与暴露自建服务的鉴权(API key)要自己加,别裸奔公网
python
# 流式响应的 SSE 处理(客户端侧)
import requests

resp = requests.post(
    "http://localhost:8000/v1/chat/completions",
    json={"model": "my-llm",
          "messages": [{"role": "user", "content": "你好"}],
          "stream": True},
    headers={"Authorization": "Bearer EMPTY"},
    stream=True,
)
for line in resp.iter_lines():
    if line and line.startswith(b"data: "):
        payload = line[6:]
        if payload == b"[DONE]":
            break
        # 解析 JSON,取 choices[0].delta.content 逐片打印

兼容 ≠ 功能全等

"OpenAI 兼容"是协议兼容,不代表功能等价:不同引擎对 toolsresponse_formatlogprobs 等扩展字段的支持程度不同。上线前把你要用的每个字段都实测一遍,而不是默认可用。

部署清单(上线前逐项核对)

检查
显存预算权重 + KV cache(峰值并发 × 峰值上下文)≤ 显存
量化验证INT4 相对 fp16 的基准差已评估
指标达标TTFT/TPOT 满足产品要求(含 P95)
兼容性OpenAI 兼容 API 已联调(流式/工具调用/JSON mode)
监控延迟、吞吐、显存、错误率、队列积压全接入告警
回滚模型/配置版本化,可一键回滚

七、灰度与监控

上线不是终点,是新一轮工程的开始:

手段做法
灰度新模型只服务 5% 流量,观察指标与用户反馈再放量
影子模式新老模型并行跑,新模型结果只记录不展示,离线对比
监控TTFT/TPOT 的 P50/P95、错误率、队列长度、GPU 利用率
评估联动线上抽检结果回流到 golden set,形成闭环(见评估实战

部署事故高发区

显存 OOM(只算了权重没算 KV cache)、无限重试导致的雪崩(设置超时与退避)、流式中断无重连、模型版本回滚困难。把"如何优雅失败"写进设计,而不是等它发生。

监控指标体系:上线后盯什么

类别指标告警线(示例)
延迟TTFT / TPOT 的 P50、P95P95 TTFT 超 2s
容量并发数、队列积压队列持续积压
算力GPU 利用率、显存使用率显存使用率 > 95%
质量错误率、重试率、超时率错误率 > 1%
业务完成率、用户负面反馈率负面反馈率上升

监控数据的价值在趋势:显存使用率从 60% 缓慢爬到 90%,说明有流量增长或内存泄漏,比"今天崩了"更值得先处理。

八、云 vs 本地 vs API:三个选项的决策

维度自建 GPU(云/本地)托管 API(OpenAI/Anthropic 等)自托管开源模型
成本曲线固定成本高、边际成本低按量付费、无沉没成本同左,但需运维
数据安全数据出网可控数据出网(需评估合规)数据完全在内
能力上限开源模型为准闭源旗舰能力最强开源模型为准
运维负担高(K8s、GPU、弹性)中高
定制完全可控有限(微调需平台支持)完全可控

决策顺序建议:

数据能出网、要最强能力、不想运维 → 托管 API
数据敏感/合规限制/深度定制 → 自托管开源模型(vLLM)
量很大且稳定 → 自建 GPU(或混合:API 兜底 + 自建主路)

成本算账:一个简化示例

选型前先算一笔账(数字仅为教学示例,价格随时变化,以官方报价为准):

场景:7B 模型,日均 10 万次请求,平均输入 1000 token、输出 300 token
每日 token 数 ≈ 10万 × (1000 + 300) ≈ 1.3 亿 token

方案 A:托管 API(假设 0.3 元/百万输入 token、1.2 元/百万输出 token)
  成本 ≈ 10万×(1000×0.3 + 300×1.2) / 100万 ≈ 6.6 元/天 ≈ 2400 元/年
方案 B:自建 1×RTX 4090(约 24GB,可跑 7B INT4)
  一次性硬件约 1.5 万元;电费/运维另计;容量上限约几万~几十万 token/分钟

结论模式:量小用 API(零运维),量大且稳定自建(摊薄固定成本),中间地带用混合。同时别忘了把开发/运维人力成本算进去——那往往是最贵的部分。

延伸阅读

参考资料