大模型API缓存的底层原理:从显存到网关
一、一个直觉引发的思考最近和一位朋友聊到API的缓存他提出了一个很敏锐的问题“其实tokens缓存都是假的吧LLM本身就是无状态的。这种缓存只是一种计费规则。实际上跟上下文显存空间有关你来用他那边就会给你开一个显存池就是为了反复压缩切换。不可能你现在来一次等下不来了他还把你这份留着来压缩显存开销太大了。”这个直觉基本完全正确但只猜中了故事的一半。LLM确实是无状态的。每一次推理都必须把全部上下文系统提示词全部历史消息新问题重新输入计算。那么所谓的“缓存”到底缓存在哪里为什么API厂商的定价里都有“缓存命中”这个折扣项答案在于市面上的“缓存”其实是三种完全不同的机制。我们一层层来看。二、第一层推理引擎的KV Cache这是最底层、也是朋友直觉最准的那部分。模型生成文本时为了避免每个新token都把之前所有token的计算重跑一遍推理框架会把已经算好的Key-Value状态矩阵暂存在GPU显存VRAM里。这就是KV Cache。核心特征目的加速单次对话的生成过程不是为了跨请求复用。存放位置显存极其昂贵且容量有限。生命周期对话结束或超时几秒到几分钟后立刻释放。和计费的关系不直接体现为“缓存命中折扣”。但多轮对话本质上是持续占用这个显存池所以连续对话的单价通常较高。朋友提到的“反复压缩切换显存”正是现代推理框架管理KV Cache的核心技术。比如vLLM的PagedAttention把显存切成小块像操作系统管理虚拟内存一样分配和回收。这种KV Cache对用户是透明的。你没法单独为它付费也没法要求服务商“把我这份KV Cache留到明天”。它只是一个瞬时的、服务于当前连续对话的工程优化。三、第二层网关的响应缓存这才是我们在API平台后台看到的“开启缓存”开关主要控制的那一层。原理很简单——它就是一个巨大的、以请求为key、以回复为value的分布式字典通常用Redis实现。流程如下请求到达网关时系统提取能唯一代表这次请求的部分完整请求体、模型名称等计算出一个SHA-256哈希。拿这个哈希去内存数据库里查。命中了直接把上次存好的回复返回后端模型完全不参与。没命中转发给模型拿到回复后存入缓存设置过期时间TTL。关键特征判定条件很严格必须一字不差。多一个空格、标点半角全角不同都是两个不同的哈希无法命中。存放位置内存速度快、能跨请求共享。生命周期可配置从几分钟到几小时。计费体现这就是“缓存命中打五折”的由来。因为它几乎没有消耗GPU算力只是做了一次内存读取。朋友直觉里“不可能你走了还把你的留着”在显存KV Cache层面是对的但在内存响应缓存层面不是。内存便宜得多服务商完全可以把你的一条回复保留24小时只要它认定这个请求的复用频率够高。四、第三层Prompt Cache这是最容易被和第二层混淆但技术上完全不同的机制。如果你的请求里有一段非常长的、完全相同的固定前缀比如一份300页的小说开头、一套复杂的Function Calling定义系统可以识别出这段前缀的哈希直接从存储器中加载它对应的KV状态跳过对这段前缀的重计算。它和KV Cache的区别KV Cache是显存里的瞬时态一旦释放就消失。Prompt Cache则是把某个前缀的KV状态序列化后持久化在了更慢但更便宜的硬盘或内存里。它和网关响应缓存的区别响应缓存要求整个请求完全一致。而Prompt Cache只要求前缀一致。你的问题可以千变万化但只要那大段前缀相同这部分计算费就省下来了。Anthropic等厂商提供的就是这种原生服务端缓存你只需标记出希望缓存的前缀部分即可。五、总结缓存类型存放位置判定方式目的KV CacheGPU显存对话序列位置加速单次对话生成网关响应缓存内存Redis等整个请求的哈希避免重复调用模型Prompt Cache内存/硬盘前缀内容的哈希跳过固定前缀的重计算回到最初的问题“API站的缓存实现原理其实就是供应商自带的吗”是的。对我们用户来说这三套机制都是服务端特性。我们能做的就是理解它们的差异然后合理设计请求结构去主动命中这些缓存从而获得更低的延迟和更好的计费折扣。