生成式推荐(GR)大模型KV Cache优化:用户粒度+内存池化,显著降低延迟与成本,小白程序员必备收藏!
生成式推荐(GR)因请求高密、前缀稳定,导致KV Cache重复计算与显存瓶颈。本文介绍了用户粒度KV Cache和池化管理方案,通过将KV Cache从单卡显存扩展到集群级池化存储,提升前缀命中率和缓存容量,从而降低首token延迟和单位请求成本。文章深入解析了vLLM-Ascend的落地设计,包括Prefix Cache和PD分离、用户粒度管理、Mooncake内存池等技术细节,为优化GR大模型推理性能提供了实用参考。
1 生成式推荐
生成式推荐(generative recommendation,GR)是一类以生成模型为核心的推荐范式:把用户的历史交互(浏览、点击、会话)与候选序列拼进提示词,由GR模型一次性生成候选打分,把推荐建模为条件生成问题。推理时,候选通常与用户上下文拼进同一个提示词批量打分,因此候选部分随请求轮换、无法被前缀缓存覆盖,可复用的部分集中在用户前缀。这类负载有两个直接影响缓存设计的特征。
- 其一是前缀稳定。同一用户的上下文在大量请求之间几乎不变,变化的主要是候选序列:候选不断轮换,用户前缀保持不变,KV 复用集中在用户前缀部分;候选部分虽然每次都在变,但计算量通常远小于前缀,复用收益依然显著。
- 其二是请求高密。推荐请求都是以用户的粒度发送的,上下文又长,属于典型的“少用户、多请求、长上下文”负载。
与LLM相比,GR 的前缀有更高的“确定性”:对话中每个用户的话题随时变化,相同前缀的复用机会有限;推荐场景中用户上下文(历史序列)长期稳定,前缀复用是常态而非巧合。
2 Prefix Cache 和 PD 分离
- 1 Prefix-cache
Prefix-cache 是一种针对 LLM 推理场景中常见冗余现象的优化技术。

- 冗余来源: 在高并发场景下,许多请求往往包含相同的 Prompt 前缀
- 原理: Prefix-cache 机制识别出这些共享的前缀,并将其对应的 KV Cache 块预先计算并持久化存储 在一个可共享的区域。
- 工作流程:当新的请求到来时,系统首先在缓存中查找是否有匹配的前缀。
请求只需计算并生成 Prompt 差异部分和后续生成 Token 的 KV Cache。
- 优势:显著减少了计算资源浪费和端到端延迟,特别是在 Prompt 较长、用户请求模式相似的场景下。
- 劣势:常规的Prefix-cache是将KV Cache 块预先计算并持久化存储在HBM上,但是HBM资源有限,存储的KV Cache有限,且卡间机间不共享,导致命中率低,收益不及预期。
- 2 Prefill 和 Decode
一次 LLM 推理请求在引擎里经历两个阶段:prefill(预填充)阶段并行处理整段输入,一次性产出 KV Cache;decode(解码)阶段逐 token 生成,反复读取并追加 KV Cache。KV Cache 是衔接两个阶段的关键产物,也是显存占用的大头。PD 分离(prefill-decode disaggregation)把两个阶段部署到不同节点,让计算密集的 prefill 与延迟敏感的 decode 各自独立扩缩容;代价是 KV Cache 必须跨节点传输。两个阶段的差异是后续设计的前提:
| 维度 | prefill(预填充) | decode(解码) |
| 处理方式 | 并行处理整段输入 | 逐 token 串行生成 |
| 主要工作 | 一次前向计算,生成完整 KV Cache | 每步读取并追加 KV Cache,输出一个 token |
| 计算特征 | 计算密集、并行度高 | 延迟敏感、单步依赖前序输出 |
| KV Cache 角色 | 生产方:一次性写入 | 消费方:反复读取、持续追加 |
| 资源瓶颈 | 算力吞吐 | 显存带宽与访存延迟 |
3 为什么生成式推荐要按用户粒度管理?
“缓存粒度”在工程语境里常被混为一谈,它横跨三个相互独立的问题:物理上按什么单位分页存储、复用时按什么单位判定命中、生命周期按什么语义组织。
物理存储层面(块)
vLLM 采用分页式 KV Cache,KV 按固定大小的块(block)分配,块是缓存、传输、驱逐的最小单元。vLLM 默认块大小为 16 token(CacheConfig.DEFAULT_BLOCK_SIZE);vLLM-Ascend 在开启 prefix caching 或 chunked prefill 时会把块大小设为 128 token。
缓存复用层面(token 前缀块)
vLLM 的 automatic prefix caching(APC)以“完整块”为复用单位:块哈希由父块哈希、块内 token 以及 LoRA ID、多模态 hash、cache salt 等因子共同构成,只有完整块才会被缓存和命中。命中判定只看 token 前缀是否相同,与用户身份、会话 ID 无关;vLLM 社区明确,多轮对话需要把完整聊天历史拼进每次请求,APC 才能跨轮复用。因此,vLLM 引擎层面的原生复用粒度是“块对齐的 token 前缀”。
在复用判定这一层,业界主流实现各有侧重:
| 框架 | 复用机制 | 复用粒度 | 特点 |
| vLLM | 自动前缀缓存(APC) | 完整块(默认 16 token/块) | 只按 token 前缀匹配,不感知用户/会话 |
| vLLM-Ascend | 片上 prefix cache + KV 池 | 块(开启 prefix caching/chunked prefill 时默认 128) | 池按块 put/get,命中后只拉缺失块 |
| SGLang | RadixAttention(前缀树) | 任意长度 token 前缀 | 同一父前缀可分叉,适合多轮对话与分支请求 |
| NVIDIA Dynamo | KVBM / Flash Indexer(radix tree + 全局索引) | 块 + 前缀深度 | 跨 worker 全局索引,按最深前缀匹配路由 |
生命周期/应用语义层面(请求、会话、用户)
用户/会话粒度属于应用层,由请求构造方式决定:把用户上下文稳定地放在每个请求的最前面,引擎的块级前缀缓存就会自动跨请求复用这段前缀,vLLM 官方文档推荐的多轮对话模式正是这个机制。
生成式推荐请求的输入序列是用户的历史行为序列和候选集,对于生成式推荐而言,请求天然是用户粒度的,而KVCache本质是根据请求计算得到的,所以GR模型要用户粒度管理kvcache。
因此本文所说的“用户粒度管理”,准确含义是“按用户组织缓存的复用与生命周期”。
4 为什么生成式推荐需要KV Cache内存池?
为解决HBM资源有限,Prefix-cache命中率低的问题,引入了KV Cache内存池,该系统定义是 一个跨越异构存储介质(HBM、DDR、SSD/网络存储)的集中式 KV Cache 存储与调度系统,突破单卡的 HBM 限制,将 KV Cache 扩展到更大容量的存储空间,并实现集群范围内的共享,实现多集群共享的Prefix-cache。

前缀缓存的收益高度依赖命中率,如果 KV Cache 只放在片上内存里,容量非常有限、跨节点不可见,命中率自然受限。于是“多级缓存”成为必然:把 KV Cache 从片上内存延伸到 DRAM、SSD 等更便宜的层级,让常用前缀保持“热”,低频数据溢出到低成本存储。
具体怎么放,取决于存储介质的物理特性:HBM 快但容量小,DRAM 容量大但带宽低,SSD 便宜但延迟高;热数据留在最快层级,冷数据下沉到低成本介质。
- 跨节点传输的性价比由网络决定:RDMA 零拷贝直传可以接近网卡线速,而 TCP 通常只有它的 1/2–1/4。这就是 PD 分离下要做专用 P2P 连接器、而不是走通用存储协议的原因:Mooncake 官方基准中,RDMA P2P 直传带宽可达 TCP 的约 2.4–4.6 倍。
5 为什么是 Mooncake?
- 1 KV Cache 池化方案
多级缓存需要一个“池化”方案,把散落在各层级的 KV 块统一管理起来。目前vLLM社区主流选择有两个:LMCache 与 Mooncake(MooncakeStore)。
| 维度 | LMCache | Mooncake(MooncakeStore) |
| 定位 | 通用 KV 缓存库 | 分布式 KV 缓存池 + KVCache-centric 架构 |
| 存储层级 | 本地 GPU/CPU/磁盘,可挂远程后端 | CPU/DRAM/SSD 统一资源池,跨节点共享 |
| 接入 vLLM V1 | 经 LMCacheConnectorV1 | 经 MooncakeStoreConnectorV1(借鉴 LMCacheConnectorV1) |
| 对昇腾 NPU | MooncakeStore 只能作远程后端,多一层 LocalBuffer 拷贝 | 原生直连:移除 LocalBuffer、KVTransferThread 异步 put/get |
两者都是“池”,差异在调度能力与传输路径:LMCache 胜在通用生态,Mooncake 胜在 KVCache-centric 调度与昇腾上的传输效率。对 vLLM-Ascend 而言,直接集成 Mooncake 而非“LMCache + 远程 MooncakeStore”,省掉的正是中间那层冗余拷贝。
- 2 Mooncake:以 KVCache 为中心的分离式架构
Mooncake 是 Moonshot AI 打造的 serving platform,开源。它的核心是把 KV Cache 当作系统里可调度的资源:prefill 与 decode 集群分离,CPU、DRAM、SSD 等被闲置的资源纳入统一存储体系,再由 KVCache-centric 调度器在满足服务等级目标(SLO)的前提下最大化吞吐。这套思路与多级缓存天然契合:KV Cache 不再只是显存里的临时数据,而是可以分级存放、跨节点共享的资源。

vLLM-Ascend 与 Mooncake 的集成分两步落地:先接入 Transfer Engine,解决 PD 分离下的 KV 注册与跨节点传输;再把 Mooncake Store 作为分布式 KV 池后端。对昇腾而言,直连 Mooncake 意味着传输路径可以针对 NPU 硬件优化,而不是套用通用 GPU 路径。
6 接入实现:vLLM-Ascend 的 Connector
为了解决跨介质集群池化问题,vLLM-Ascend 基于vLLM KV Connector 抽象层的 KV Cache 传输机制,实现了AscendStoreConnector,这是一套支持多后端、对接推理与存储系统的集群池化方案。 AscendStoreConnector在架构上层负责操作的编排与协调,底层通过调用具体的存储引擎完成数据传输

- 1 vLLM V1 的 KV Connector
引擎如何调用、多级存储如何接进来
vLLM V1 通过“KV 缓存池”(KV Cache Pool)落地多级缓存:各存储层级经由统一的连接器(Connector)接口接入,按访问频率与硬件带宽存取和搬运 KV 块。

vLLM-Ascend 目前支持 MooncakeStore 作为 KV 池后端。相关连接器有:
- MooncakeStoreConnector(Ascend 侧称 MooncakeStoreConnectorV1 / AscendStoreConnector):将 MooncakeStore 作为分布式 KV 缓存池,负责键查找与异步 put/get;V1 版本大量借鉴 LMCacheConnectorV1,并针对 NPU 做了传输优化(移除 LocalBuffer 消除冗余拷贝,用 KVTransferThread 多线程异步传输)。上游 vLLM 已把同源实现注册为 MooncakeStoreConnector。
- MooncakeConnector:PD 分离场景下,decode 节点经 P2P 从 prefill 节点直接拉取 KV Cache。
- MooncakeLayerwiseConnector:PD 分离下,prefill 节点逐层把 KV 推送给 decode 节点,让计算与传输重叠。
- Multi Connector:按指定顺序组合多个连接器,同时获得 P2P 传输与 KV 池两种能力。
连接器存在的必要性在于解耦:如果没有这层抽象,vLLM 引擎就得为每个存储后端各写一套调度与传输逻辑,LMCache、MooncakeStore 乃至未来新后端都无法即插即用。

上图呈现了三层结构:引擎(调度器与工作节点)在最上层,通过连接器访问存储层;MooncakeStoreConnector 面向 KV 池,MooncakeConnector 面向 P2P 传输;存储层按速度与成本分层,SSD/远端层正在从“设计方向”变为可部署能力(Mooncake master 的 SSD offload)。连接器夹在中间,隔离了引擎与存储的实现细节,任何一层的替换都不需要改动其他层。
- 2 vLLM V1 引擎调用 KV Connector 的完整生命周期
连接器不是被“某一行代码”调用的,而是由 V1 引擎的三个角色(Scheduler、Worker/ModelRunner、Engine)在每步推理中协同调用。按一次请求的推进顺序:
-
启动阶段:KVConnectorFactory.create_connector 分别创建 scheduler 侧与 worker 侧实例;模型 KV tensor 分配完成后,ModelRunner 调用 register_kv_caches(kv_caches)(或 register_cross_layers_kv_cache)注册显存地址,并 set_host_xfer_buffer_ops 注册主机侧搬运函数。
-
调度阶段(Scheduler):
- 先查本地 prefix cache 得到 num_new_local_computed_tokens;
- 再调 connector.get_num_new_matched_tokens(request, block_aligned_local):返回 (外部可加载 token 数, 是否异步加载);返回 None 表示连接器还需要时间查询,本步先把请求放回队列;
- 分配 KV 块后调 connector.update_state_after_alloc(request, blocks, num_external_tokens),连接器据此登记需要加载的块;
- 步骤末尾调 connector.build_connector_meta(scheduler_output),把本步要搬的块元数据挂到 scheduler output 上。
- 执行阶段(Worker/ModelRunner):
- bind_connector_metadata(metadata) 绑定元数据;
- 若发生抢占,先 handle_preemptions(metadata);
- start_load_kv(forward_context) 启动异步加载(MooncakeStoreConnector 这里是 no-op,真正的加载在 get_finished 中发起以最大化与计算重叠);
- 前向计算过程中,逐层连接器(Layerwise/LMCache 等)会在每层调用 wait_for_layer_load(layer_name) 与 save_kv_layer(…),把“等整批 KV 到达”变成“边算边等边传”;
- 前向结束后 wait_for_save() 等待写回完成,然后 get_finished(finished_req_ids) 返回 (done_sending, done_recving),并收集 invalid_block_ids、统计、KV 事件与 worker 元数据。
- 收尾阶段(Scheduler/Engine):
- connector.update_connector_output(kv_connector_output):finished_recving 的请求本步可调度,finished_sending 的请求释放块;
- 请求结束时 connector.request_finished(request, block_ids) 返回 (delay_free, kv_transfer_params);若为 True,块由连接器异步发送后经 get_finished 释放;
- take_events() 收集跨 worker 聚合的 KV 事件;has_pending_push_work() 让引擎在 push 模式下继续空转,直到推送完成;
- 关停时 shutdown() 释放 Mooncake 句柄与 RDMA 注册。
关键点:MooncakeStoreConnector 的 start_load_kv / wait_for_save 都是 no-op,加载与写回全部在 get_finished() 里批量发起,由 KVTransferThread(发送线程)与多个 KVCacheStoreRecvingThread(接收线程池)异步执行;调度器只在下一次 update_connector_output 时看到完成状态。这正是“传输时间被藏进计算”的实现细节。

-
3 用户粒度 KV 池:MooncakeUserStore
-
1 的 Connector 抽象与 6.2 的调用生命周期是通用框架;用户粒度方案在此基础上落地为两层:vLLM 侧的 KVCacheCoordinatorForGR 负责按用户管理 HBM 块与淘汰,昇腾侧的 MooncakeUserStoreConnector / MooncakeEngine / MooncakeUserStore 负责把 KV 按用户写入分布式存储池,两侧通过 ZMQ RPC 与 MooncakeStore 的键查询衔接。
-
3.1 用户级键与双数据形态
池中每个对象由 MooncakeUserKey 标识,字段为 uid、model_name、world_size、worker_id 与 value_type,序列化为 {uid}@{model_name}@{world_size}@{worker_id}@{value_type}。value_type 区分两类数据:
| value_type | 内容 | 用途 |
| token_id | 用户历史 token 序列 | 跨实例查询“该用户已缓存多少 token”,只用于命中判定 |
| kv_cache | 用户前缀对应的 KV 块 | 实际的加载与保存对象 |
逐层模式下,MooncakeUserKey.split_layers() 把 kv_cache 键进一步拆成 LayerMooncakeUserKey(追加 layer_id),每层独立 put/get,加载可与逐层前向计算重叠。跨实例命中查询只需要 token 计数而不需要内容,因此 get_history_token_ids 在 ZMQ 回退路径上用等长占位零补齐,仅用于对齐块分配。
- 3.2 vLLM 侧协调器:KVCacheCoordinatorForGR
设置环境变量 KV_MANAGER_FOR_GR 后,get_kv_cache_coordinator 返回 KVCacheCoordinatorForGR,替代通用 prefix-cache 协调器,缓存组织单位从“token 前缀”变为“用户”:
- HBM 用户块表:user_to_blocks 保存用户历史 KV 块(跨请求保留),user_to_new_blocks 记录本次请求 decode 阶段新增的块(请求结束即释放),user_to_last_page_index 记录末块实际 token 数,用于精确计算命中 token 数。
- 三级命中判定:find_user_cache_hit 先查 HBM,命中返回 (blocks, tokens);HBM 未命中时经 check_user_kv_in_dram 用 MooncakeLookupClient.lookup(uid) 查询 DRAM 池,存在则返回 -1 标记“需要换入”;完全未命中返回 0。
- 用户级 LRU:UserKVLRUManager 按访问顺序维护用户队列(VLLM_ENABLE_USER_KV_LRU 默认开启,VLLM_USER_KV_LRU_MAX_USERS 默认 100);HBM 块不足时 _evict_lru_users 按 LRU 淘汰冷用户(跳过有运行中请求的用户),只释放 HBM 块,KV 仍留在 DRAM 池中可换回;VLLM_USER_KV_LRU_MIN_FREE_BLOCKS 控制保留的最少空闲块。
- 统计:lru_evictions、dram_hits、dram_misses、swapin_attempts、swapin_successes 用于观察淘汰与命中情况。

7 收益与限制
对生成式推荐这类高前缀复用负载,收益首先体现在命中率上:重复 prefill 显著减少,显存压力向低成本层级转移,长上下文与高并发场景下吞吐更稳。这些收益最终传导到业务指标:首 token 延迟(TTFT)因跳过重复 prefill 而降低,单卡吞吐因显存让位给更多并发而上升,单位请求成本随算力利用率改善而下降。对大规模在线服务,单位请求成本的小幅下降都会转化为可观的运营收益,这也是 KV 复用技术这两年成为推理优化主线的商业原因。
8 小结
vLLM-Ascend + Mooncake 的组合,本质是把 KV Cache 从“显存里的临时缓冲”升级为“用户粒度、多层级、可跨节点共享的缓存资源”,为生成式推荐这类高前缀复用场景提供了清晰的工程路径。这套收益的适用边界是前缀高度复用的负载:用户上下文越稳定、请求越密集,效果越明显;对话等前缀随意变化的场景,收益会相应缩水。
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】


为什么要学习大模型?
我国在A大模型领域面临人才短缺,数量与质量均落后于发达国家。2023年,人才缺口已超百万,凸显培养不足。随着AI技术飞速发展,预计到2025年,这一缺口将急剧扩大至400万,严重制约我国AI产业的创新步伐。加强人才培养,优化教育体系,国际合作并进是破解困局、推动AI发展的关键。


大模型入门到实战全套学习大礼包
1、大模型系统化学习路线
作为学习AI大模型技术的新手,方向至关重要。 正确的学习路线可以为你节省时间,少走弯路;方向不对,努力白费。这里我给大家准备了一份最科学最系统的学习成长路线图和学习规划,带你从零基础入门到精通!

2、大模型学习书籍&文档
学习AI大模型离不开书籍文档,我精选了一系列大模型技术的书籍和学习文档(电子版),它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。

3、AI大模型最新行业报告
2025最新行业报告,针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。

4、大模型项目实战&配套源码
学以致用,在项目实战中检验和巩固你所学到的知识,同时为你找工作就业和职业发展打下坚实的基础。

5、大模型大厂面试真题
面试不仅是技术的较量,更需要充分的准备。在你已经掌握了大模型技术之后,就需要开始准备面试,我精心整理了一份大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

适用人群

第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐
所有评论(0)