是如何工作的?)
提示缓存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 EncodingBPE。于是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 从缓存读取就说明缓存生效了。