大模型里哪些环节需要缓存
训练阶段、推理阶段、工程服务层三大块
每一处缓存都有明确收益:降低算力消耗、减少重复计算、提升吞吐、降低 latency
训练场景缓存
数据集 / 样本缓存
场景:训练时反复读取磁盘图片、文本、token 序列,IO 瓶颈严重
缓存内容:预处理后的 token ids、embedding、增强后样本、索引映射表
收益:避免重复解码、分词、图像预处理,减少磁盘 IO
梯度 / 优化器状态缓存(混合精度 / 分布式)
简介
场景:多卡训练、梯度累积、AdamW 维护 m/v 动量,显存放不下全量优化器参数
缓存内容:CPU 内存缓存优化器动量、梯度副本、FP16/FP8 中间激活
收益:缓解显存溢出,支持更大 batch / 更大模型
定义
梯度 grad:损失反向传播算出来的参数梯度张量
梯度副本:多卡分布式训练时,为了通信、梯度累积、混合精度而复制出来的梯度备份
单卡训练场景(无多卡通信)
原始梯度 grad,默认GPU 显存
前向→反向全程在 GPU 计算,梯度跟着参数存在同一张卡显存,用来更新权重
什么时候梯度会缓存到 CPU(Offloading 梯度)
超大模型、显存不够,开启梯度卸载
反向算出梯度后,异步拷贝到 CPU 主机内存进行缓存
更新参数前再从 CPU 拷回 GPU 使用
多卡分布式训练(数据并行 DP / DDP,最常见梯度副本场景)
-
DDP 梯度副本机制
每张卡独立算自己批次的局部梯度 local_grad(存本卡 GPU 显存)
框架会在每张卡显存里,额外分配一块缓冲区,存放梯度副本,用于 AllReduce 全局聚合
梯度副本:每张卡自己的 GPU 显存
每张卡算出本地梯度;复制一份到显存通信缓冲区(梯度副本);多卡对副本做 AllReduce 求和,得到全局平均梯度;用聚合后的梯度更新参数
-
梯度累积场景的梯度副本
梯度累积 = 多小批次梯度累加再更新
每一小步算出梯度,不立即更新,缓存一份梯度副本(GPU 显存)持续累加,累积 N 步后再执行参数更新
混合精度训练 FP16 梯度副本
FP16 反向梯度数值范围小易溢出,框架会维护一份 FP32 高精度梯度副本:
主权重存 FP32(GPU 显存),反向得到 FP16 梯度;拷贝转 FP32 梯度副本(仍在 GPU 显存);用 FP32 副本更新 FP32 主权重,保证精度
超大模型训练:梯度 / 副本 CPU Offloading(ZeRO 优化器)
ZeRO1 / ZeRO2 / ZeRO3 是现在大模型训练标配,彻底改变存储位置:
每张卡只持有部分参数、梯度、优化器状态;不在当前卡的梯度、梯度副本,全部缓存到 CPU 内存;需要更新时,通过 PCIe 异步预取到 GPU 显存做计算
分层总结 ZeRO 下梯度缓存位置:
当前分片梯度 / 副本:本卡 GPU 显存
其他分片梯度 / 副本:CPU 内存缓存(二级缓存)
极端显存紧张:下沉到磁盘交换区(极少用,速度很慢)
总结
普通单卡 / 多卡训练:梯度、梯度副本全都在GPU 显存
大模型 ZeRO / 显存卸载场景:大部分梯度、梯度副本缓存到CPU 主机内存,仅当前正在计算的分片留在 GPU
梯度相关缓存只存在训练流程,推理阶段完全没有梯度、梯度副本概念
激活重计算缓存(Checkpoint 缓存)
场景:大模型层数深,前向激活占大量显存;重计算需要丢弃激活再重算
缓存内容:少量关键层激活,丢弃冗余中间结果
收益:显存换算力,缓存关键节点减少重复前向计算
分布式通信缓存
场景:数据并行、张量并行、流水线并行参数同步
缓存内容:梯度分片、权重分片、通信缓冲区
收益:减少多卡频繁小块通信,批量传输提升带宽利用率
词嵌入 / 分层 embedding 缓存
场景:词汇表固定,同一 token 重复出现
缓存内容:token 对应的 embedding 向量
推理阶段核心缓存
KV Cache(注意力缓存,大模型标志性缓存)
使用场景:自回归生成(对话、续写)
大模型逐 token 生成,每一步输入 x1,x2...xt,计算所有位置的 K、V;下一轮输入 x_t+1 时,不需要重新计算 x1~xt 的 K 和 V,直接复用缓存,缓存对象是每一层 Transformer 的 K 矩阵、V 矩阵
核心收益:生成长度越长,加速比越高,大幅减少 FLOPs
缓存在什么位置?
KV Cache:必须放 GPU 显存,因为每一步注意力计算都实时依赖,频繁读写,拷贝延迟不可接受
系统 Prompt KV Cache
GPU 显存(只读共享分页),不放 CPU / 磁盘。服务运行期间常驻,重启丢失
对话生成、多轮推理,跳过 Transformer 每层的重复计算
Prompt KV Cache缓存 / 系统提示词KV Cache缓存
场景:大量用户共用相同系统提示词(客服、翻译、知识库问答)、固定前缀 Prompt
缓存内容:系统 Prompt 完整 KV Cache、Prompt embedding
收益:不用每次重复编码长系统提示,首次编码后永久复用
为什么要缓存「系统 Prompt 完整 KV Cache」?
不缓存的原始流程(无复用,性能极差):每来一个用户请求,完整流程如下:
(1)拼接:长系统提示词 + 用户问题;(2)分词,把系统提示所有 Token 送入 Transformer 每一层,逐层计算系统提示全部 Token 的 K、V;(3)再计算用户问题 Token 的 K、V;(4)开始逐字生成回答
几百上千个并发用户,每个人都重复计算一模一样的长系统提示词 KV,大量重复算力浪费,长系统词使用越久,浪费越严重。
缓存后的流程(复用系统 KV):(1)服务启动 / 第一次请求到来时,仅计算 1 次系统提示词,算出整套完整 KV,存入全局共享显存缓存;(2)后续所有用户请求直接读取缓存好的系统 KV,不用再跑一遍系统词的 Transformer 计算;(3)只单独计算当前用户问题的 KV;(4)注意力计算时,把「共享系统 KV + 用户私有 KV」拼接在一起参与运算
注意:系统提示词,必须预先算出每一层 Transformer 各自独立的 KV,每层一套,全部存在全局共享缓存里,推理时每层拿对应层的共享 KV 和用户 KV 拼接计算
为什么存的是「完整 KV Cache」?
推理阶段做注意力计算,底层必须依赖每一层每个 Token 的 K/V 向量,而不是原始文本、不是 embedding:如果只缓存文本 /embedding,每次还要完整走一遍 Transformer 多层网络才能算出 KV,等于没省算力;KV Cache 是Transformer 前向传播走完后的中间成品,可以直接喂给注意力模块,跳过系统提示词全部层的重复计算。
所有用户共用一套只读系统 KV,显存只存一份,大幅节省显存、降低延迟、提升并发吞吐
Embedding 向量缓存(检索增强 RAG、向量服务)
场景:输入文本、文档、query 重复度高,每次都走模型编码成本高
缓存内容:文本 → 稠密向量、稀疏向量(BM25 预计算特征)
分层:内存热点缓存 + 向量数据库持久缓存
缓存在哪里?
GPU L1 缓存 + CPU 内存 L2 缓存 + 磁盘向量库 L3 三级分层
L1:GPU 显存(最高优先级、热点高频 Query)
属于 GPU 侧,不是 CPU
缓存内容:高频用户提问、通用固定 Prompt 的 embedding 稠密向量
使用场景:线上推理 / RAG 同步检索,要求极低延迟
优势:向量不用 CPU↔GPU 拷贝,直接在卡上参与相似度计算
局限:显存昂贵、容量小,只存 TOP 热点文本向量
L2:CPU 主机内存(你说的 CPU 缓存层)
进程内存 / Redis 内存,完全在 CPU 侧
缓存内容:中频文本、批量文档向量
典型实现:服务进程内 LRU 哈希表、分布式 Redis
流程:命中后把向量从 CPU 拷贝到 GPU 再计算相似度
优势:容量远大于显存,成本低
L3:向量数据库(磁盘持久化,冷数据)
依然走 CPU 读写磁盘,属于冷层
缓存全量知识库文档、低频长文本向量
代表:Milvus、Chroma、FAISS 离线索引
只有 L1、L2 全部未命中,才会查询磁盘向量库
区分两种业务,缓存位置不一样
场景 A:在线 RAG 推理(和大模型推理同 GPU 服务,如 vLLM 集成 RAG)
会同时开GPU 显存 Embedding 缓存:
高频 query 向量常驻 GPU,避免反复调用 Embedding 模型编码、避免 CPU-GPU 传输开销
场景 B:独立离线向量服务(单独部署 Embedding 模型)
大多只用CPU 内存 + 向量库两级:
Embedding 模型跑在 CPU/GPU 均可,但向量缓存主体放在 Redis(CPU 内存)
系统 Prompt KV Cache 和 Prompt Embedding 缓存完全不是一个东西
Prompt Embedding 缓存
热:GPU 显存;温:CPU 内存 (Redis);冷:磁盘向量库
生命周期:大量使用 CPU Redis 做二级缓存,可配置 TTL 持久化
用途:RAG 检索、短前缀轻量化优化、显存不足时降级替代 KV 缓存
BM25 稀疏特征完全存在 CPU 侧:稀疏向量维度极大,不适合占用宝贵 GPU 显存,全部缓存在内存 / 磁盘
极简流程示例
用户 Query 输入 → 哈希 key 检索
GPU 显存 L1 缓存命中 → 直接拿向量做相似度(最快)
未命中 → 查询 CPU Redis L2 缓存
Redis 命中:CPU 拷贝向量到 GPU 计算
Redis 也未命中 → 调用 Embedding 模型编码新向量
写入 GPU L1、CPU Redis 双缓存,再执行检索
极低频文档向量只存在磁盘向量库,不进内存 / 显存缓存
权重 / 模型分片缓存
简介
场景:多模型热加载、动态切换模型、低显存机器推理
缓存内容:模型权重分片、LoRA 适配器权重
方案:GPU 显存缓存热点层权重,CPU 内存缓存冷层,按需交换
背景
KV Cache、Embedding 缓存,缓存的是「推理中间计算结果」;这里的缓存是「模型本身的参数权重」,是两套完全独立的缓存体系,解决大模型太大、多模型切换显存不够的问题。常见问题如下:
低显存小显卡推理:比如 24G 显卡跑 70B 大模型,完整权重塞不进 GPU 显存,不能一次性全加载,必须分层拆分
多模型热切换服务:一台机器同时提供翻译、客服、代码、知识库多个大模型服务,不可能把所有模型全部常驻 GPU,需要缓存 + 换入换出
多 LoRA 多租户推理:一套基座大模型,搭配几十上百个行业微调 LoRA 适配器,显存放不下全部 LoRA,冷热分层缓存按需加载
缓存分类
缓存内容分两类:基座模型分片 + LoRA 适配器
模型权重分片(基座大模型本体)
大模型由多层组成:Embedding 层、30 多层 Transformer 层、输出 LM 头,每层都有独立权重矩阵。把完整模型按层切分成一个个分片,不再是完整整块模型:
- 热分片:高频访问层(输入 Embedding、前几层注意力、最后输出头)
- 冷分片:中间少访问的 FFN、深层 Decoder 层
LoRA 适配器权重
LoRA 是基座之外的小参数矩阵(几十 MB 级别,远小于基座几十 GB),每个业务场景一套 LoRA(客服 LoRA、翻译 LoRA、代码 LoRA)
缓存 LoRA 避免每次新请求都从磁盘读取加载,大幅降低切换延迟
缓存方案
核心方案:GPU 显存存热层,CPU 内存存冷层,按需交换(分层 Offloading)
冷热分层存储规则
热层权重 → GPU 显存常驻缓存
输入层、前几层 Transformer、输出头,每一轮推理从头到尾都会访问,放 GPU 不用来回拷贝,计算最快
冷层权重 → CPU 主机内存缓存
中间深层,访问频次低,平时不占用宝贵显存,存在 CPU 内存里做二级缓存
极冷门模型 / 极少用 LoRA:下沉到 SSD 磁盘缓存,CPU 内存都不常驻
「按需交换」完整推理流程(举 32 层 Llama 举例)
假设:1~10 层热层放 GPU,11~32 冷层存在 CPU 内存
推理启动,输入先进 GPU 上 1~10 层计算;
计算完第 10 层,引擎检测下一层 11 层在 CPU 缓存;
异步预取:后台线程把 11 层权重从 CPU 拷贝到 GPU,同时 GPU 继续处理当前张量计算(计算和传输并行,掩盖延迟);
11 层加载完成,GPU 执行 11 层计算;处理完 11 层,若短时间不再复用,可把 11 层权重换出回 CPU,释放显存给其他层;
循环直到 32 层全部算完,生成 token。
LoRA 适配器缓存流程(多租户场景)
基座大模型热层永久驻留 GPU;常用 5 个 LoRA 缓存到 GPU 显存;其余几十套低频 LoRA 缓存在 CPU 内存
新请求需要冷门 LoRA:从 CPU 拷贝到 GPU,采用 LRU 淘汰很久不用的 LoRA,腾出显存;切换 LoRA 仅毫秒级,不用重新加载几十 GB 基座模型
解决的核心痛点
突破显存硬件上限
24G 显卡原本跑不动 70B 模型,冷热分层缓存后,CPU 内存分担大部分权重,小卡也能跑超大模型
多模型快速切换,消除磁盘加载慢问题
不缓存:切换模型要从硬盘读取几十 GB 权重,耗时几十秒
缓存方案:模型分片存在 CPU 内存,切换只需要 CPU↔GPU 拷贝,几百毫秒完成
多 LoRA 并发服务,节省显存
不用为每个业务完整保存一套微调模型,只存一套基座 + 按需加载小 LoRA,显存占用大幅下降
异步交换隐藏传输延迟
引擎会提前预取即将用到的冷层权重,GPU 计算和数据拷贝并行,不会明显拖慢生成速度
上述三个缓存的对比

权重缓存:存模型本体参数,解决「装不下大模型」
KV 缓存:存注意力中间结果,解决「重复计算系统提示词」
Embedding 缓存:存第一层词向量,解决「重复编码文本做检索」
输入预处理缓存
场景:高频重复 query,分词、截断、填充逻辑固定
缓存内容:文本对应的 token ids、attention mask
线上服务网关 / 业务层缓存
请求结果缓存:完全相同输入 query 的生成结果
LoRA 适配器缓存:多租户场景频繁加载不同微调 LoRA
路由 / 索引缓存:知识库文档索引、分块映射
大模型核心缓存设计
模块 1:KV Cache 底层完整设计(Transformer 推理核心)
数据结构定义
标准自回归 Transformer,每层独立维护 K、V 缓存:
维度:batch_size, head_num, seq_len, head_dim
初始状态:空;每生成一个新 token,追加新 KV 到缓存尾部
基础逻辑:
第 t 步输入 xt → 计算新 Kt, Vt
K_cache = concat(K_cache, Kt)
V_cache = concat(V_cache, Vt)
注意力计算只用缓存 + 新token,不再重算历史token
内存布局设计
显存驻留:KV Cache 全程放在 GPU 显存,避免 CPU-GPU 拷贝开销
连续内存池管理:不用每次 concat 时重新分配显存,预分配一块大连续缓冲区:预留最大上下文长度窗口;用 offset 标记当前有效长度,append 只移动指针,无内存拷贝
分页式 KV Cache(PagedAttention,工业主流)
传统连续缓存缺陷:不同请求上下文长度差异大,显存碎片严重,利用率低
PagedAttention 设计:将显存切分为固定大小「页(Page)」,每页存固定长度 KV;每个请求的 KV 由离散页链表组成,不需要连续大块显存;支持页复用、页回收、按需分配,显存利用率提升 2~4 倍;配套:页表、空闲页队列、淘汰策略(LRU)
量化压缩设计(减少 KV 显存占用)
KV Cache 占推理显存 70%+,必须压缩:
- INT8 KV Cache:浮点 KV 量化为 int8,存储减半
- FP4/INT4 KV Cache:4bit 量化,显存降至 1/4
- 混合精度:关键层 FP16,浅层 4bit,平衡精度与显存
淘汰与复用策略
滑动窗口缓存(Sliding Window)
长文本场景,只保留最近 N 个 token KV,丢弃久远历史,控制显存上限
LRU 淘汰(多并发请求)
并发多条生成请求,显存不足时淘汰最久未更新请求的 KV Page
Prompt KV 全局共享
相同系统提示词的请求共用一份 KV 缓存,多 batch 共享只读 KV,只分配用户 query 私有 KV
分布式扩展 KV Cache
张量并行:每层 KV 按头切分到多张 GPU
流水线并行:不同层缓存放在不同卡
多机推理:远端 KV 缓存池,支持跨设备 Page 交换
模块 2:Prompt / Embedding 缓存分层设计
采用多级缓存架构(冷热分离):
L1 缓存:GPU 显存缓存
热点高频 Prompt、高频 Query embedding,极低访问延迟
结构:哈希表 key = 文本 hash,value = 向量 / KV 块;淘汰 LRU
L2 缓存:CPU 内存缓存
中频数据,容量更大,访问需 CPU-GPU 拷贝
框架:Redis、进程内内存哈希池
L3 持久化缓存:向量数据库 / 磁盘
低频、海量文档 embedding,磁盘持久存储
适用 RAG 离线文档向量化缓存
缓存 key 设计:文本哈希 + 模型版本 + 量化精度,避免不同模型向量冲突
模块 3:训练侧激活 & 优化器缓存设计
CPU-GPU 双向交换缓存(Offloading)
显存放不下的优化器动量、大层激活,缓存到 CPU DRAM
预分配固定交换缓冲区,异步拷贝(计算与数据传输并行),隐藏延迟
分层激活缓存
只缓存对重计算关键的少量层激活,其余前向结果直接释放
控制缓存容量阈值,超出阈值自动丢弃做重计算
梯度缓存分片
多卡数据并行,梯度分片缓存于各卡,通信时批量聚合,减少小包通信
模块 4:权重 & LoRA 缓存设计
权重分层缓存
热层(前几层、输出层)常驻 GPU
冷层缓存 CPU,推理到时流式加载
LoRA 适配器共享缓存
多个用户使用同一个微调 LoRA,显存只存一份副本
使用引用计数,无请求时自动释放
内存映射 mmap 缓存
模型权重文件 mmap 到内存,避免完整加载,操作系统自动缓存热点权重页
模块 5:工程通用缓存基础组件设计
所有缓存通用配套机制:
统一缓存 key 规范
模型ID + 精度 + 上下文配置 + 原始文本hash,防止脏数据
过期策略 TTL
KV 临时缓存:生成结束立即回收
embedding 持久缓存:设置几小时~几天 TTL,自动刷新
并发安全
多线程 / 多并发读写锁、无锁哈希、页引用计数
监控指标
缓存命中率、显存占用、页碎片、淘汰次数、拷贝耗时
预热机制
服务启动预加载高频 Prompt、热门 LoRA、高频 query embedding,提升冷启动性能
典型线上完整缓存架构示例
用户请求 → 网关结果缓存(L0)
↓未命中
分词预处理缓存(L1 CPU)
↓未命中
├ 系统Prompt共享KV缓存(GPU全局只读)
└ 用户Query:Embedding L1(GPU) → L2(CPU Redis) → L3向量库
↓未命中,进入推理
Transformer 层:PagedAttention 分页KV显存缓存
权重:热层常驻GPU,冷层CPU交换缓存
LoRA适配器:全局共享引用计数缓存
生成结束 → 回收KV缓存页,写入各级embedding/结果缓存
总结
KV Cache 是生成式大模型最核心缓存,现代方案全部基于 PagedAttention 分页缓存 解决显存碎片
所有缓存统一遵循多级冷热分层:GPU 显存(热)→ CPU 内存(温)→ 磁盘 / 向量库(冷)
缓存设计核心权衡:显存 / 内存空间开销 vs 重复计算算力开销;长文本、高并发场景缓存收益最大
训练缓存侧重显存卸载、激活重计算
推理缓存侧重 KV 复用、向量复用、请求结果复用
附录
对话标准输入格式一般分三段
System 系统提示词:固定全局规则,所有人共用
客服场景示例:"你是电商客服,只回答订单问题,态度温和,不编造信息,超过知识范围统一回复不清楚"
翻译场景:"你是专业中英翻译,只输出译文,不加多余解释"
知识库问答:"回答必须严格参考下文知识库内容,禁止凭空回答"
特点:长度很长、所有用户一模一样、每次对话都要带上
User 用户提问:每个用户不一样
Assistant 历史回复:对话上下文
系统提示词
ChatML : Chat Markup Language,聊天标记语言
ChatML 是一套专门用于格式化对话消息的标记规范,用特殊分隔标签区分 system /user/assistant 不同角色的内容,方便大模型识别对话结构
OpenAI ChatML 标准格式示例(带独立 system)
客服场景完整消息数组
json
[
{
"role": "system",
"content": "你是电商平台智能客服,仅处理订单、物流、退款相关问题,不清楚的内容统一回复:暂时无法解答,请联系人工客服。回答简洁,语气温和。"
},
{
"role": "user",
"content": "我的快递什么时候发货?"
}
]
这里 role: system 对应的 content,就是系统 Prompt
翻译场景 system 示例
json
[
{
"role": "system",
"content": "专业中英互译助手,只输出译文,不要额外解释、不要补充说明,原文是中文就翻英文,原文英文翻中文。"
},
{
"role": "user",
"content": "今天天气很好"
}
]
底层送入模型前会拼接成带特殊标记的文本(ChatML 模板)
OpenAI / Llama 系列会把数组拼接成带分隔符的字符串,区分 system/user/assistant:
模板规则:
plaintext
<|system|>
{system内容}
<|end_of_solution|>
<|user|>
{用户问题}
<|end_of_solution|>
<|assistant|>
套用上客服例子拼接后文本:
plaintext
<|system|>
你是电商平台智能客服,仅处理订单、物流、退款相关问题,不清楚的内容统一回复:暂时无法解答,请联系人工客服。回答简洁,语气温和。
<|end_of_solution|>
<|user|>
我的快递什么时候发货?
<|end_of_solution|>
<|assistant|>
前面从 <|system|> 到 <|end_of_solution|> 这一整块,就是独立划分的 system 系统提示词
对比无独立 system 的「固定前缀 Prompt」(老式格式)
没有区分角色标签,直接把规则硬拼在文本最前面,不属于 ChatML system:
plaintext
你是电商平台智能客服,仅处理订单、物流、退款相关问题,不清楚的内容统一回复:暂时无法解答,请联系人工客服。回答简洁,语气温和。
用户问题:我的快递什么时候发货?
整段开头规则文字 = 固定前缀 Prompt,没有单独 system 角色字段
所有用户共用同一套 role:system 的文本
服务启动时,把 <|system|> + 系统内容 + 结束符 这段完整文本跑一遍模型,每层生成专属 KV 缓存
每个新用户请求,不用重复计算 system 这段的 Transformer 层,只计算用户提问部分的 KV
每层注意力计算时:该层共享system_KV + 当前用户私有question_KV 拼接计算
固定前缀 Prompt 是什么
和系统提示词本质是一类东西,只是叫法区别:
系统 Prompt:ChatML、OpenAI 格式里单独划分的 system 角色前缀
固定前缀 Prompt:没有分角色,直接拼在所有输入文本最前面的固定文本块
例子(无 system 角色的老式格式):
【你是专业翻译,只输出译文】+ 用户问题
前面中括号这段,就是固定前缀 Prompt
系统 Prompt = 标准化的固定前缀 Prompt