大模型推理前缀缓存(prefix caching)复用与首字延迟优化落地

日期:2026-08-18

一、项目背景

我们推理服务接的都是长 system prompt 加长上下文,每来一个请求都从第一个 token 重算 KV,GPU 算得满头汗,首字延迟(TTFT)高得离谱,并发一上来排队排到天边,业务方吐槽等得花儿都谢了。我们一开始以为是算力不够,加卡加到钱包疼,延迟还是下不来,才回头看请求本身,发现大半算力花在重复算同一段前缀上。更离谱的是,很多租户用的几乎是同一套系统提示词,几百分之一模一样的前缀被算了几十遍,纯属浪费,加卡根本治不了这个病。

二、落地场景

现在把 system prompt 和 few-shot 示例钉成缓存块,请求进来先算前缀哈希,命中就直接复用已算好的 KV,跳过前面那一截。多租户共用同一套提示词的,缓存一堆人抢着用,一个块喂饱所有相似请求。缓存块带版本号,提示词一改版本号变,旧块失效重算,不会拿错版本。跨请求共享让高峰时段新请求省掉最贵的前缀计算,排队长度肉眼可见地短了,业务方终于不催了。

三、关键技术挑战与解决思路

缓存命中率是第一道关,哈希算得粗就命中不了,我们对前缀做精确分块,system prompt 整段作为一个块,few-shot 单独成块,块边界对齐 token 而不是字符。KV 复用正确性不能马虎,前缀一样但后面上下文不同,复用后必须接得上线,我们在调度层保证缓存块只覆盖前缀位置,后面的自算。缓存淘汰是显存和命中率的拉锯,全留显存放不下,乱删命中率掉,我们按访问频率和最近使用做分级淘汰,热块留冷块走。长前缀内存占用也得管,一个超长 system prompt 的缓存块本身就大,我们设了单块上限,超限就退化成部分缓存,至少省一半。还有哈希冲突要防,我们用前缀内容加块类型双因子,避免不同提示词算成同一块。

案例片段(已脱敏): 前缀缓存启用与淘汰配置片段(字段示意):prefix_cache:  enabled: true  block_by: token  blocks: [system_prompt, few_shot]  versioned: true  evict:    policy: lru_freq    max_block_mb: 512  fallback: partial一次效果:某长提示词场景,缓存命中后 TTFT 从约 2.4 秒降到约 0.6 秒,单卡并发从 8 提到约 20,GPU 利用率从常满降到平稳,原来排到几十的队基本消失。

缓存块大小的选择我们纠结过,太大浪费显存、太小命中率低,最终按提示词长度分布取了中位数附近,配合单块上限兜底。多租户抢同一块缓存时谁先算谁填,我们用了一个轻量分布式锁,避免两个人同时算同一前缀重复占显存,这锁加得及时,否则高峰会瞬间打满。版本回滚也要考虑,提示词改坏命中率跳水时,我们保留上一版块一段时间,能快速切回去,这兜底让我们敢放心迭代提示词。还有一层是冷启动,服务刚起缓存是空的,前几分钟命中率很低,我们做了预热,把高频提示词块提前算好灌进去,业务方基本无感。

四、效果数据

首字延迟在长前缀场景下降最猛,命中缓存的请求 TTFT 砍掉一大半。GPU 算力因为我们不再重复算前缀,同样卡数能扛的并发翻倍往上。缓存命中率稳在九成附近,前提是我们把提示词版本管住了,乱改提示词命中率就跳水。并发吞吐提升后,原来排队的长尾请求基本消失,高峰时段不再有请求等到超时。文中数据为项目复盘口径,已做脱敏。

五、可复用经验总结

长前缀别每次重算,这是烧钱又慢的典型。我们加卡加到心疼才想到缓存,回头看早该做,那笔加卡的钱够做半年优化。缓存块按 token 对齐、版本管住提示词,这俩细节决定命中率,当初对齐字符踩过坑,哈希对不上白缓存。淘汰策略别拍脑袋,全留显存爆、乱删命中掉,lru_freq 是我们调出来的平衡点。前缀缓存和显存是死对头,单块上限必须设,不然一个超长提示词就能把缓存吃光。哈希冲突不能忽略,双因子才稳,我们差点因为冲突拿到错版本。

前缀缓存这事,收益大头在长提示词场景,短提示词本来算得快,缓存意义不大,我们后来按前缀长度决定是否启用,省了显存给真正需要的请求。该不该缓存得看请求画像,一刀切反而亏。

结语

推理服务最容易被冤枉的就是算力,我们加卡加到财务来问,延迟还是高,才去扒请求。长 system prompt 每来一次重算一遍 KV,纯属浪费,前缀缓存一上,TTFT 直接腰斩。token 对齐这细节我们栽过,最早按字符分块,哈希对不上,缓存形同虚设,改成 token 边界才活。版本号管提示词很重要,有人随手改了句提示词没更版本,命中率当场跳水,排查半天才发现。淘汰策略是艺术,全留显存先爆,乱删命中掉,lru_freq 调了两轮才稳。单块上限当时嫌麻烦没设,结果一个超长提示词把缓存吃光,其他请求全 miss,那次告警把我们叫醒。哈希冲突那次更隐蔽,两个提示词算出同一块,答出来的内容串了味,加了块类型双因子才消停。并发翻倍后业务方不再吐槽排队,但我们清楚,缓存命中率才是这块的成本命门,提示词一乱全完。