提示缓存(Prompt Caching)是一种技术:模型把 prompt 中重复出现的那部分已经算过的工作保存下来,下次直接复用这份保存的结果,而不必从头再算一遍。
本文我们来讲清楚提示缓存是怎么工作的。我们还会看到为什么需要它、它在大语言模型内部究竟如何运转,以及它在 AI 助手和智能体这类真实系统中用在哪些地方。
我们将覆盖以下内容:
- 什么是 prompt?
- 快速回顾:LLM 是如何读 prompt 的
- 什么是提示缓存?
- 为什么我们需要提示缓存
- 提示缓存的核心思路
- 精确前缀规则
- 缓存写入与缓存读取,以及 TTL
- 我们应该把什么放进缓存
- 提示缓存带来的好处
- 真实世界中的提示缓存
什么是 prompt?
在讲提示缓存之前,我们必须先搞明白 prompt 是什么。
prompt 就是我们发给大语言模型的那段文本。
大语言模型(large language model,简称 LLM)是 ChatGPT、Claude 这类工具背后的技术。我们给它一些文本,它还我们一些文本。
简单说,prompt 就是我们敲进去的所有内容。模型读了我们的 prompt,然后写出回复。
假设我们在做一个客服助手。发给模型的文本通常包含几个部分:
- 一组指令,告诉模型该怎么表现,比如「你是一家鞋店的礼貌客服」。
- 可能还有一份很长的文档,写着我们全部的鞋子退货政策。
- 用户真正提的问题,比如「鞋子买了 40 天还能退吗?」
这些文本合在一起,就是 prompt。
现在有一点很值得注意:指令和那份政策文档,对每个用户都是不变的。只有用户的问题在变。我们很快会回到这一点,因为它是提示缓存的核心。
快速回顾:LLM 是如何读 prompt 的
要理解提示缓存,我们必须先理解 LLM 读 prompt 时的一件事。
我们发出 prompt 时,模型并不是按整词来读的。它先把文本切成小块,这些小块叫 token。token 是一小段文本,大致是一个词或词的一部分。比如 support 这样的短词通常是一个 token,而 returning 这样的长词往往会被切成两个 token(这套切分方式叫字节对编码,Byte Pair Encoding,BPE)。
于是,prompt 变成了一串 token。
接着,模型逐个处理这些 token,为每个 token 建立起内部理解。这第一步------模型读完整段 prompt、把每个 token 都处理一遍,之后才开始写回复的第一个词------叫做预填充(prefill)步骤。
简单说,预填充就是模型把我们的整段 prompt 读进去、消化掉。
在预填充过程中,对每一个 token,模型都会算出一些内部数值并保存起来。这些被保存的数值放在所谓的 KV 缓存(KV Cache)里。
用大白话说说 KV 缓存。模型读每个 token 时,会为这个 token 生成一份小摘要------相当于一条笔记,记下这个 token 在它前面所有内容的语境里意味着什么。KV 缓存就是这一堆笔记的集合,每个 token 对应一组笔记。模型写回复需要这些笔记,并且在生成每一个新词时也会复用它们。
这里有一个关键点要记住:
为一段很长的 prompt 构建 KV 缓存是要花真功夫的。模型必须逐个 token 做大量计算。
所以,如果我们的 prompt 有 5,000 个 token,模型就要在写下任何东西之前,为这 5,000 个 token 全部做完这些工作。prompt 越长,预填充这一步花的时间和钱就越多。
这就是我们需要的铺垫。现在可以来理解问题了。
什么是提示缓存?
既然知道了模型如何读 prompt,我们来看看提示缓存。
提示缓存是一种技术:模型把 prompt 中重复出现的那部分已经算过的工作保存下来,下次直接复用这份保存的结果,而不必从头再算一遍。
简单说,提示缓存就是:难的活只干一次,然后反复复用。
「缓存(cache)」这个词的意思很简单------一个存放东西的地方,方便我们之后快速取用,而不必从零再做一遍。
把它和我们刚学的连起来看:模型干的「难活」就是在预填充阶段构建 KV 缓存。提示缓存所做的,就是把 prompt 中重复那部分的 KV 缓存保存下来。下次我们发来的 prompt 开头是同一段重复内容时,模型就载入保存好的 KV 缓存,跳过重复计算。
所以,提示缓存的核心是复用 prompt 重复开头部分的内部计算结果。
这和语义缓存(semantic caching)不同:语义缓存是在新问题和旧问题意思相同(哪怕用词不同)时,直接复用最终答案。
那么问题来了,我们到底为什么需要它?接着看。
为什么我们需要提示缓存
回到我们的鞋店客服助手。
每个用户都会发来一个问题。但别忘了,每来一个问题,我们同时还会带上同样的指令和同样那份很长的退货政策文档。用户的问题很短,指令和文档却很长。
于是,模型为每个用户、每条消息,一遍又一遍地读同样的长指令和同样的长文档。
为了便于理解,我们给点数字。假设:
- 指令和政策文档共 5,000 个 token。
- 用户的问题有 50 个 token。
用户每问一次,模型就要对 5,050 个 token 做预填充。其中 5,000 个 token 和上一次完全一样,只有 50 个是新内容。
这是浪费。模型在 5,000 个根本没变的 token 上做着大量计算。
这带来两个真实的问题:
- 慢。 把 5,000 个 token 一遍遍重新处理,会在用户看到回复之前不断增加延迟。
- 贵。 我们是按模型处理了多少 token 来付钱的。每次都重新处理同样的 5,000 个 token,等于为同一份工作一遍遍付费。
在真实应用里,这个问题会大得多。想想那些长系统指令、大文档、以及我们每次请求都要带上的大量示例。我们反复发送同一个大文本块,模型就在反复重做同样的工作。
于是,提示缓存登场救场。
提示缓存的核心思路
我们一步步理解这个核心思路。
我们已经知道,预填充期间模型会构建 KV 缓存,也就是每个 token 对应的那组内部笔记。提示缓存做了一件简单却很有力的事。
思路是:把 prompt 中固定且重复的那部分的 KV 缓存保存下来。下一次请求的开头还是同一段内容时,模型载入保存好的 KV 缓存,从那里接着往下做,跳过重算。
我们用刚才的例子走一遍。
第 1 步: 一个用户发来第一个问题。prompt 是 5,000 个 token 的指令加文档,后面跟着 50 个 token 的问题。模型对这 5,050 个 token 做预填充并构建 KV 缓存。在这个过程中,它把前 5,000 个 token 的 KV 缓存保存了下来,因为那部分被我们标记为要缓存。
第 2 步: 另一个用户发来一个不同的问题。prompt 还是同样的 5,000 个 token 指令加文档,后面跟着新的 50 个 token 问题。此时,模型不再重做前 5,000 个 token 的工作,而是直接载入它们保存好的 KV 缓存。只有那 50 个 token 的新问题需要做新计算。
就这样,模型直接跳到了缓存部分结束的位置,并从那里继续。它没有在已经理解过的 5,000 个 token 上浪费时间。
下面这张简图把这件事说清楚。
不开提示缓存时(每一次请求):
[ 5,000 个 token:指令 + 文档 ] + [ 50 个 token:问题 ]
全部重新处理一遍 只处理这部分
(慢、贵、重复计算) (真正的新工作)
开启提示缓存后(从第二次请求起):
[ 5,000 个 token:指令 + 文档 ] + [ 50 个 token:问题 ]
从缓存读取(快、便宜) 只处理这部分
跳过这部分的重计算 (真正的新工作)
问题解决了。重复那部分的难活,模型现在只干一次。
精确前缀规则
这里有一条非常重要的规则必须理解,因为大多数坑都踩在这儿。
提示缓存是基于前缀匹配的。被缓存的部分必须是 prompt 的开头,而且必须逐字符完全一致。
先说「前缀」这个词。前缀就是某个东西的开头那段。在我们的场景里,被缓存的部分是 prompt 的开头,也就是用户问题之前的那段内容。
只要新 prompt 的开头与已缓存 prompt 的开头完全一致,模型就可以复用缓存。一旦文本出现差异,从那个位置往后的缓存就失效了。
可以这样画出来:
已缓存的 prompt:你是一名礼貌的客服。退货窗口为 30 天。
新的 prompt: 你是一名礼貌的客服。退货窗口为 45 天。
|---------------- 完全一致 ----------------|
从缓存读取
^ 从这里开始不一致,这一段必须重算
这里可以看出,两段 prompt 在某个点之前是一样的,前面这段一致的部分就从缓存读取。而从第一个不一样的 token 起,前缀就不再匹配,后面所有内容模型都必须重算。
有一点我们必须格外小心:
只要 prompt 靠前的位置变了一个字符,那个位置之后的所有缓存全部失效。
举个例子说明。假设我们在指令的最顶部加了一行「今天是 2026-06-07」。这行每天都在变。因为它待在 prompt 的最开头,前缀就每天都不同。于是昨天建好的缓存今天用不了,模型只能把全部工作重做一遍。
这是非常常见的一个错误。我们不小心把会变的东西------比如当前日期、一个随机 ID、或者用户名------放在了 prompt 靠前的位置。就这一个小的变动,悄无声息地把整个缓存毁掉了。
所以要记住的规则很简单:
把稳定的部分放前面,把变化的部分放最后。
prompt 的开头不变,缓存就一直有效。开头一直在变,缓存就毫无用处。别担心,稍后我们会具体看清哪些部分该保持稳定、该放在哪里。
缓存写入与缓存读取,以及 TTL
接下来理解两个简单术语:缓存写入(cache write)和缓存读取(cache read)。
缓存写入发生在第一次。这时模型处理重复的那部分内容,并把它的 KV 缓存保存下来。我们是在第一次把结果写进缓存。
缓存读取发生在其后。这时后续请求复用保存好的 KV 缓存,而不是重新计算。我们是在从缓存里读。
把它和成本连起来看,这才是有意思的地方。
缓存写入比普通处理略贵一点,因为模型既要完成计算,又要把结果存下来。粗略地说,这部分的缓存写入成本大约是正常价格的 1.25 倍。
但缓存读取非常便宜。从缓存读取的成本只有正常价格的大约十分之一。也就是说,重复的那部分能省下差不多 90%。
所以,第一次请求多付一点写入成本,之后每一次请求都因为读缓存而便宜很多。复用次数越多,省得越多。
整个流程大致如下:
请求 1 --> 处理稳定部分 --> 保存下来(缓存写入,约 1.25 倍成本)
|
v
+-------------+
| 缓存 |
+-------------+
^ ^ ^
请求 2 ---+ | | (缓存读取,约 0.1 倍成本)
请求 3 ---------+ | (缓存读取,约 0.1 倍成本)
请求 4 ---------------+ (缓存读取,约 0.1 倍成本)
这里可以看到,只有第一个请求做了重活并把结果写进缓存。之后每一个开头相同的请求,都直接从缓存读取,所以每一次都比从头重做便宜得多。
那么下一个问题:缓存会永久保留吗?答案是不会。
缓存有 TTL,全称 time to live,即存活时间。简单说,TTL 就是缓存能活多久,过了这个时间它就过期并被清除。
常见的默认 TTL 是 5 分钟。也可以选择更长的 TTL,比如 1 小时。TTL 在实际中的含义是:
- 如果 TTL 窗口内又来了一个前缀相同的新请求,它可以读缓存。
- 如果 TTL 窗口内没有请求进来,缓存过期。下一个请求必须重新做一次缓存写入。
所以,当大量请求共享同一个开头、且时间上挨得比较近时,提示缓存的效果最好。
注意:更长的 TTL 能让缓存活得更久,在请求比较分散时有用,但长 TTL 的缓存写入成本会略高一些。所以 TTL 要根据具体场景来选。
我们应该把什么放进缓存
现在我们知道,缓存作用于 prompt 中稳定的开头部分。那么自然要问:究竟该往那里放什么?
答案很简单。把在大量请求中保持不变的部分放前面,把会变的部分放最后。
以下这些非常适合缓存,因为它们通常不变:
- 系统指令。 它们描述模型应该如何表现,比如「你是一名礼貌的客服」。这些对每个用户都一样。
- 大文档。 比如我们完整的退货政策、产品手册、或知识库中的一篇文章。它们又长又会被重复带上,缓存它们能省很多。
- 工具定义。 当我们允许模型使用工具时,需要把每个工具描述给它。这些描述通常是固定的。
- 少样本示例(few-shot examples)。 这些是我们给模型的示例问答,让它学会我们想要的风格。「few-shot」的意思就是给模型几个例子作为引导。这些示例每次都一样。
而会变、必须放在最后的那部分是:
- 用户真正的问题或消息。 它每次请求都不同,所以放在最末尾,在所有被缓存的部分之后。
用一个简图看看这个顺序。
一个设计良好的 prompt 的顺序
最前 -> 工具定义 |
系统指令 | 稳定部分:缓存它
大文档 |
少样本示例 |
最后 -> 用户的问题 变化部分:不要缓存
这个顺序就是全部的诀窍。稳定的块待在最前面并被缓存,变化的问题待在最后,不会破坏缓存。
到这儿,我们就明确知道了该缓存什么、该放在哪儿。
决定 prompt 里放什么、以什么顺序放,本身就是一门学问(即上下文工程,Context Engineering)。
提示缓存带来的好处
我们把好处快速汇总一下,因为它们才是我们用这项技术的理由。
- 更低的延迟。 延迟就是用户拿到回复之前的等待时间。既然模型跳过了重复部分的重算,它就能更快开始回复。
- 更低的成本。 缓存命中的 token 以便宜得多的价格计费,大约只有正常价格的十分之一。当我们反复发送同一个大文本块时,这笔节省会累积成很大的数目。
简单说,提示缓存在不改变答案质量的前提下,让我们的应用同时变得更快、更便宜。模型依然看到完整的 prompt,它只是避免了重做已经做过的工作。
这就是提示缓存的美妙之处。
真实世界中的提示缓存
接下来看看提示缓存用在哪些真实系统里。
主流 AI 服务商都把提示缓存做成了内置能力。比如 Claude 背后的 Anthropic、GPT 系列模型背后的 OpenAI,都支持提示缓存。我们只需把 prompt 中稳定的那部分标记为可缓存,服务商就会替我们完成保存与复用。我们还可以检查响应,看看有多少 token 被写入了缓存、有多少从缓存读取,这样随时能确认缓存确实生效了。
提示缓存在两类系统里尤其强大。
第一类是 RAG。RAG 是检索增强生成(Retrieval-Augmented Generation)的缩写。简单说,这类系统会先取回一些相关文档,再把它们连同用户的问题一起发给模型。这些取回的文档和固定指令往往很长,而且在多次请求间重复。缓存稳定的指令,以及任何我们会重复发送的文本,能同时降低成本和延迟。同样的技巧让上下文检索(Contextual Retrieval)变得负担得起------那种做法需要为文档的每个分块都把整篇文档发给模型一次,用来给该分块写一段简短的上下文注记。在同一流程更靠前的环节,文档的 embedding 也可以缓存起来,从而避免每次查询都重新计算。
第二类是智能体系统。智能体(agent)是一个 AI 程序,它一步步完成一项任务,过程中经常调用工具、来回多轮才能做完一件事。在智能体系统里,同一大块指令、工具定义和先前的文本,在每一步都会被发送。步骤可能很多,同一个开头会被复用极多次。这正是提示缓存大放异彩的场景,因为被缓存的 prefix 被一遍又一遍地读取。
在大规模场景下服务这些重复前缀,是推理引擎的职责。vLLM 在请求之间共享相同的前缀;另一个推理引擎 SGLang 用基数树(radix tree)更精确地匹配共享前缀;NVIDIA 的 TensorRT-LLM 也做同样的事,名字叫前缀复用(prefix reuse)。
所以,只要我们一直在发送同一个很大的 prompt 开头,提示缓存就能帮上大忙。
提示缓存就是这样工作的:我们把模型对 prompt 中固定且重复开头的内部计算结果保存下来,让这个开头保持完全一致并放在最前面,然后一遍又一遍地复用它,从而拿到更快、更便宜的响应。
常见问题
提示缓存和语义缓存有什么区别?
提示缓存复用模型对 prompt 重复开头的内部计算结果,也就是 KV 缓存。模型仍然要读新内容,并写出一份全新的回复。语义缓存则是在新问题与旧问题意思相同时(哪怕用词不同)直接复用最终答案。
提示缓存会改变答案质量吗?
不会。提示缓存在不改变答案质量的前提下,让应用变得更快、更便宜。模型仍然看到完整的 prompt,它只是避免重做那几个重复部分已经做过的工作。
为什么我们的提示缓存一直不命中?
最常见的原因是 prompt 顶部附近有会变的东西,比如当前日期、随机 ID 或用户名。被缓存的部分必须逐字符完全一致,所以哪怕靠前的位置只变了一处,后面所有缓存都会失效。我们应该把稳定部分放在前面,把变化部分放在最后。
提示缓存总是更便宜吗?
对第一次请求不是。缓存写入比普通处理略贵,大约是正常价格的 1.25 倍。省钱来自后续的缓存读取,大约是正常价格的十分之一。所以,当大量请求共享同一个开头、且都落在 TTL 窗口内时,缓存才是划算的。
我们怎么知道提示缓存真的生效了?
可以检查服务商返回的响应。它会显示有多少 token 被写入缓存、有多少从缓存读取。如果后续请求显示有 token 从缓存读取,就说明缓存生效了。