规模化推理 Kimi、GLM 这类前沿模型时,GPU 算力并不是唯一瓶颈。模型权重会长期占据显存,KV Cache 则随着上下文长度和并发请求持续膨胀。要让服务跑得更快、更便宜,同时避免压缩产物损坏或被替换,需要把 KV Cache 量化、权重压缩和完整性检查设计成一条完整的部署链路。
显存为什么会被 KV Cache 吃掉
自回归模型生成每个 token 时,都需要复用前文的 Key 和 Value。缓存避免了重复计算,却带来一个直接后果:上下文越长、并发越高,KV Cache 占用越大。
可以用下面的近似公式估算 KV Cache:
KV bytes = 层数 × 2 × token 数 × KV heads × head dimension × 每元素字节数 × 并发数
其中的 2 代表 Key 和 Value。假设缓存原来使用 FP16,每个元素占 2 字节;改成 INT8 后,理论数据区可缩小到约一半。不过实际节省量还会受到量化 scale、内存对齐、分页管理和推理引擎实现影响。
下面的脚本可以直接运行,用于比较不同缓存精度下的理论显存占用。请根据目标模型配置修改参数:
#!/usr/bin/env python3
def kv_cache_gib(
layers: int,
tokens: int,
kv_heads: int,
head_dim: int,
bytes_per_element: float,
concurrent_requests: int,
) -> float:
total = (
layers
* 2
* tokens
* kv_heads
* head_dim
* bytes_per_element
* concurrent_requests
)
return total / (1024 ** 3)
config = {
"layers": 64,
"tokens": 32768,
"kv_heads": 8,
"head_dim": 128,
"concurrent_requests": 16,
}
for dtype, size in {"FP16": 2, "INT8": 1, "INT4": 0.5}.items():
gib = kv_cache_gib(bytes_per_element=size, **config)
print(f"{dtype:>4}: {gib:8.2f} GiB")
运行:
python3 kv_memory.py
这个结果适合容量规划,不应被当成实际峰值。生产部署还要预留模型权重、临时张量、CUDA Graph、通信缓冲区和内存碎片所需空间。
KV Cache 和模型权重要分开压缩
两类数据的生命周期不同,因此不能只用一个“量化等级”概括整个服务。
KV Cache 量化针对运行时状态。它主要影响单实例可承载的上下文长度与并发量。压缩缓存可能提高 GPU 利用率,但也会引入量化和反量化成本,并可能影响长上下文输出质量。验证时应重点覆盖长文本摘要、代码补全、多轮对话和高并发场景。
权重压缩针对常驻模型参数。低比特权重能减少加载时间和显存占用,使模型更容易放进较少或较小的 GPU。代价可能包括额外 kernel 要求、特定硬件上的吞吐变化,以及模型质量下降。
可以这样实践:将权重格式和 KV Cache 格式设为两个独立的发布参数,而不是绑定在同一个镜像标签中。下面是一个假设推理服务支持这些参数时的 Kubernetes 配置示例;字段名需要替换为实际引擎的参数:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kimi-glm-inference
spec:
replicas: 2
selector:
matchLabels:
app: frontier-inference
template:
metadata:
labels:
app: frontier-inference
spec:
containers:
- name: server
image: registry.example.com/inference-server:1.4.0
args:
- "--model=/models/model"
- "--weight-format=int8"
- "--kv-cache-dtype=int8"
- "--max-context-length=32768"
resources:
limits:
nvidia.com/gpu: "1"
volumeMounts:
- name: model
mountPath: /models/model
readOnly: true
volumes:
- name: model
persistentVolumeClaim:
claimName: verified-model-artifacts
独立参数化后,团队可以先上线“压缩权重 + FP16 KV Cache”,确认模型质量,再单独灰度 INT8 KV Cache。出现回归时,也能快速判断是哪一层压缩造成的。
完整性检查必须进入启动路径
权重压缩会产生新的模型文件、索引和量化元数据。只校验下载是否成功还不够:节点缓存、对象存储同步、镜像构建和手工复制都可能引入截断或错配。更危险的情况是模型文件被非预期替换,但服务仍能启动。
可以为发布目录生成 SHA-256 清单:
cd /models/model
find . -type f ! -name SHA256SUMS -print0 \
| sort -z \
| xargs -0 sha256sum > SHA256SUMS
服务启动前执行验证:
cd /models/model
sha256sum --check SHA256SUMS
exec /usr/local/bin/inference-server \
--model /models/model \
--weight-format int8 \
--kv-cache-dtype int8
摘要校验能够发现文件损坏,但不能单独证明清单可信。更稳妥的发布流程还应对清单签名,将签名验证放进 init container 或启动脚本,并限制模型仓库的写权限。校验失败时必须拒绝启动,不能只记录警告后继续加载。
不要只看“每块 GPU 能放下多少请求”
压缩方案至少需要同时观察四组指标:
- 容量:峰值显存、KV Cache 使用率、可支持的最大上下文和并发数。
- 性能:首 token 延迟、逐 token 延迟、吞吐量和排队时间。
- 质量:固定评测集分数、长上下文召回、格式遵循率和任务成功率。
- 安全性:产物校验失败次数、模型版本漂移、签名验证状态和回滚耗时。
测试时应固定模型版本、提示词、采样参数和流量回放数据,再比较 FP16、INT8 等组合。否则,采样随机性或请求结构变化很容易被误判为量化收益或质量回归。
上线顺序与边界
更稳健的采用顺序是先建立未压缩基线,再压缩模型权重,随后灰度 KV Cache 量化,最后逐步提高上下文上限和并发量。每一步都保留独立版本、质量报告和回滚入口。
上线前可以检查:模型文件及量化元数据是否经过签名和摘要验证;目标 GPU 是否支持对应的低比特 kernel;长上下文与高并发是否进入压测;显存是否保留了运行时余量;校验失败是否会阻止实例接流量。
KV Cache 量化解决运行时扩张,权重压缩降低常驻成本,完整性检查保证真正加载的是经过验证的产物。三者一起落地,才能让 Kimi 和 GLM 的规模化部署不仅“放得下”,还具备可测量、可灰度和可回滚的工程边界。