深夜十一点,街角面馆的后厨灯还亮着。老板发现一个秘密:每天最耗时的不是煮面,而是熬汤——葱姜爆香、猪骨焯水、文火慢炖,两小时起跳。于是他想了一个办法:每天清晨先熬好一大锅高汤,等客人点单时,后厨只需舀汤、下面、加上客人自己想要的配菜,几十秒就能上桌。汤底的钱,被“批量摊薄”了;等餐的时间,也大大缩短了。 大模型 API 的 Prompt(提示词)就像这碗面:你发送的一大段文字里,系统提示词、历史对话、背景资料这些“汤底”往往占了绝大部分,而且每次都一模一样;真正变化的,只有末尾那个“新问题”。Prompt Caching(提示缓存)就是 API 服务商的“高汤策略”——把你常用的那段前缀提前算好、暂存在后厨。下次请求只要前缀一致,就不再重复“熬汤”,只收你“加料”的钱,还省去了漫长的等待。 这篇文章,我们就沿着这家面馆的运作方式,把提示缓存的原理、厂商支持、成本账和最佳实践一笔一笔算清楚。学会它,你的 API 账单可能直接打七折甚至更低。
对 AI 应用开发者而言,掌握提示缓存意味着用最低的成本获得最低的延迟——这是从“能跑通”迈向“规模化盈利”的必修课,也是应对高并发推理账单的底气所在。
可视化演示
通过二维投影展示词向量的语义聚类关系,选中单词可查看与其语义最近的邻居词及余弦相似度。
本节配有交互动效(进入视口后自动加载,约 3KB)。
词向量语义空间 语义相近的词在向量空间中距离更近,形成自然聚类 余弦相似度衡量词向量方向一致性,值越接近1越相似 sim(a,b)=cos(θ)=(a·b)/(|a||b|) 选中单词后高亮显示其最近邻居及连接强度。
缓存工作原理
夜晚十一点,面馆后厨的灯还亮着。老板发现,每天最耗时的不是煮面,而是熬汤——葱姜爆香、猪骨焯水、文火慢炖,两小时起跳。于是他改成清晨统一熬一大锅高汤,客人点单时,后厨只需要舀汤、下面、加料。Prompt Caching 就是大模型 API 的“高汤策略”:既然你每次都发送同样的系统提示词和历史对话,为什么每次都要从头“熬”一遍?
大模型读到一段 Prompt,并不是“看一遍”就完事——它要把每个 Token 都编码成一堆中间状态(业内称为 KV Cache,你可以把它想象成“熬好的汤底”),然后才能开始生成回答。Prompt 越长,这锅“汤”熬得越久、越贵。提示缓存的原理,正是把这锅“汤底”暂存在服务端:下一次请求到来时,API 先检查开头部分是否与缓存前缀逐 Token 完全一致,且是否还在保鲜期(TTL)内。两个条件都满足,就直接复用“汤底”,只对新出现的尾巴做计算——首 Token 延迟(TTFT,即从发出请求到收到第一个字的耗时)大幅下降,费用也按缓存价结算。
反过来,只要前缀里多了一个空格、改了一个字,或者间隔太久,那锅汤就得倒掉重熬——这就是“缓存未命中”,一切按原价、原延迟计算。所以,面馆最爱“老顾客点老配方”;API 缓存也最爱“同一前缀反复请求”。
- 命中判定符$\iff$ 表示“当且仅当”,左边“缓存命中”成立,必须同时满足右边的两个条件
- 前缀长度$N$ 为本次请求中与前缀匹配的 Token 个数,通常要求 $N \ge 1024$ 才够资格进入缓存
- 完全一致逐 Token 比对,任何位置多一个空格、改一个符号都会导致不匹配
- 有效期限制$\Delta t$ 为距离上次请求的时间差,$TTL$ 是缓存保鲜期(OpenAI 约 5-10 分钟,Anthropic 可设 5 分钟或 1 小时)
成本节省模型
打烊后,老板算了一笔账:如果每碗面都从零熬汤,光汤底成本就要 3 元;清晨批量熬好,复用一次汤底只要 1.5 元。省下的 1.5 元,就是“不重复劳动”的奖励。API 账单里同样有这行奖励:命中的输入 Token 只按折扣价计费,未命中的部分仍是原价。
以 OpenAI 为例(GPT-4o 系列):标准输入约 $2.5/百万 Token,命中后的缓存输入 $1.25/百万 Token,相当于五折;Anthropic 则把价格拆成“写缓存”(原价 1.25 倍)和“读缓存”(原价 0.1 倍)两笔——头一次写入稍贵,之后每次读取只要一折。要量化到底能省多少钱,可以把复杂的价格规则抽象成两个数字:命中比例和折扣力度。
设 $h$ 为本批请求中命中缓存的 Token 占比,$d$ 为命中价折扣(命中价 ÷ 原价),那么实际输入费用是:
举个例子:某请求输入 8000 Token,其中 6000 是稳定前缀($h=75\%$),缓存五折,调用 1000 次、输入单价 $3/百万 Token$。无缓存总费用是 $24 美元;启用缓存后只需 $15 美元,整整省下 37.5%。换句话说,你的“面钱”越来越接近“只买配料”的价钱。
- 全价基准 $C_{\text{全价}}$假设所有输入 Token 都不命中时应付的费用,这是比较的基准线
- 命中比例 $h$稳定前缀 Token 数 ÷ 总输入 Token 数,代表“高汤”在整碗面中的分量
- 命中折扣 $d$命中一个 Token 只需付原价的 $d$ 倍,如五折则 $d = 0.5$
- 节省因子 $1 - h(1-d)$括号内 $h(1-d)$ 是被省掉的比例,命中越多、折扣越大,实际费用越接近全价的零头
主流厂商支持
同样是“高汤策略”,各家面馆的规矩完全不同:有的老板内向,默默在后厨备好汤,客人不用打招呼(OpenAI);有的老板要求你提前“订锅”,才给你留汤(Anthropic);还有的老板只在汤量足够大时才批量熬(Gemini)。
OpenAI 提供自动缓存:无需改任何代码,只要 Prompt 总长 ≥ 1024 Token,且前缀在约 5-10 分钟的滑动窗口内重复出现,命中部分就自动按折扣价计费。Anthropic 提供显式缓存:必须在系统提示词或消息中通过 cache_control 断点“预订汤底”,写缓存按原价 1.25 倍、读缓存按 0.1 倍计费,TTL 可选 5 分钟或 1 小时。Gemini 则是隐式缓存:当前缀足够长(数万 Token 级别)时自动生效,开发者几乎无感知。
各家定价可以统一写成如下分段函数:
选哪家面馆,取决于你的点单习惯:整天点一样的招牌面,显式“订锅”反而更省钱;点单天马行空,自动备汤更省心。理解各家计费差异,是把缓存红利吃到嘴里的第一步。
- 原价 $P_{\text{原价}}$未命中时每个输入 Token 的标准单价,是各家账单的底价
- 折扣系数 $d$命中后只需付原价的 $d$ 倍;$d$ 越小,缓存越“香”
- 分段判断第一个 case 对应命中(复用已熬好的高汤),第二个 case 对应未命中或首次写入(重新熬汤或订锅)
- Anthropic 特殊性首次写入实际乘以 1.25,属于“订锅费”,之后才享受 $d = 0.1$ 的读取价
最佳实践方法
想让“高汤”次次都能被复用,最笨也最有效的办法是:别换汤底配方。把稳定的东西(系统提示词、示例、背景资料)放在 Prompt 最前面,把每次都变的东西(新问题、动态参数)放到最后——后厨才能精准地“只加料,不换汤”。
具体做法有四条:第一,系统提示词、few-shot 示例、知识库背景统一放在 Prompt 头部,逐字保持不变;第二,别在系统提示词里塞“当前时间”“随机 ID”这类动态内容,它们会让整锅汤失效;第三,多轮对话中,把历史消息按固定顺序拼在前部,最新的用户问题放在尾部;第四,批量任务用同一个模板加不同的末尾参数,模板天然成为可复用的前缀。
要判断你的 Prompt 能否吃上缓存,只需核对下面三个条件是否同时成立:
面馆的招牌之所以畅销,是因为老板十年不换配方;你的 Prompt 结构稳定,缓存命中率自然水涨船高。这套“稳定置前、变化置后”的布局,就是提示缓存时代的 Prompt 排版美学。
- 长度门槛 $L_{\text{前缀}} \ge 1024$前缀 Token 数至少 1024,不到门槛,API 认为“不值得开锅”
- 时间窗口 $\Delta t \le TTL$两次请求间隔不能超过保鲜期,否则高汤馊了,只能倒掉重熬
- 逐字不变前缀任意位置的字符都必须与缓存一致,多一个空格、改一个标点都不行
缓存监控调优
老板每天打烊都要翻账本:今天多少碗面复用了汤底?复用率低了,是配方换了,还是客人间隔太久?API 的返回结构里,也藏着同样的“账本”,只看你愿不愿意翻开。
OpenAI 在 usage.prompt_tokens_details 中返回 cached_tokens(命中缓存的 Token 数);Anthropic 在 usage 中返回 cache_read_input_tokens 和 cache_creation_input_tokens(读取与写入的 Token 数)。把这些字段接入日志系统,就能逐日统计缓存命中率、节省金额,形成一张成本看板。
命中率的定义非常朴素——复用“汤底”的 Token 占总输入的比例:
账本不会说谎。命中率就是“后厨高汤复用率”,盯住它,你的成本优化就有了仪表盘;一旦发现它走低,立刻回到上一节检查 Prompt 结构。
- $T_{\text{命中}}$一段时间内所有请求中命中缓存的 Token 总数,直接来自 usage 字段
- $T_{\text{未命中}}$未命中、按原价计费的 Token 总数
- 比值 $h$命中率越高,平均单价越低;配合第二节的公式即可换算节省率
适用场景展望
不是所有菜都适合提前熬汤——凉拌菜不用汤,一天只卖两碗的面也不值得备一大锅。缓存也一样,只在“底味稳定、出菜量大”的场景才划算。
高价值场景有三类:一是多轮对话机器人,历史消息是天然稳定前缀,用户每追问一轮都能命中;二是批量文档审核或翻译,同一套“审核标准”模板加每篇不同的文档,模板就是高汤;三是长文档与代码库问答,超大上下文被反复提问,命中的前缀极长,节省最明显。反过来,一次性随机问答、前缀经常变化、两次请求间隔超过 TTL 的场景,缓存帮不上忙。
对 Anthropic 式“写缓存要加价”的计费,可以算一笔回本账。设同一前缀被请求 $N$ 次:第一次写入付 1.25 倍原价,之后每次读取付 0.1 倍;而不用缓存的话,每次都是全价:
聪明的面馆只给招牌菜备汤底,聪明的工程师只为高复用前缀开缓存。先算清复用次数,再决定要不要“开锅”——这是提示缓存时代的成本铁律。
- 写缓存开销 1.25第一次“订锅”要付原价 1.25 倍的汤底费,这是一次性的
- 读缓存开销 $0.1(N-1)$之后 $N-1$ 次复用,每次只付一折的汤底费
- 不等号左边是使用缓存的总成本,右边是不使用缓存的全价总成本,左边小于右边才划算
- 结论 $N > 1.28$约等于 $N \ge 2$,即同一前缀复用到 2 次就回本,此后每次都是净赚
AI 应用场景
智能客服机器人多轮对话
阶段:应用部署 / 推理成本优化
解决的问题:每轮对话都要重复发送“客服守则 + 商品目录 + 历史消息”(常达 4000-8000 Token),传统方式逐 Token 全价计算,且上下文越长首 Token 延迟越慢。
具体案例:某电商客服系统把系统提示词和商品知识固定在 Prompt 头部,用户每次新提问只动尾部。启用 OpenAI 自动缓存后:输入费用打五折,首 Token 延迟从 1.8 秒降到 0.7 秒,月 API 账单下降约 40%。
批量简历初筛
阶段:批处理 Pipeline
解决的问题:500 份简历用同一套“岗位 JD + 评分标准 + 提示模板”逐个打分,传统方式每份简历都从零完整计算一遍模板,浪费惊人。
具体案例:数据团队把 JD 和评分标准放在 Prompt 前缀、简历正文放在尾部。命中缓存后,单份处理成本从 $0.03 降到 $0.019,整批 500 份的耗时缩短近三分之一。
代码仓库问答机器人
阶段:推理服务 / 知识增强
解决的问题:把整个代码库说明(数万 Token)作为固定上下文反复询问,每次全价计算非常昂贵,团队协作时浪费成倍放大。
具体案例:研发团队使用 Anthropic 显式缓存,对“代码库说明”设置 cache_control 断点并选 1 小时 TTL。团队 20 人围绕同一代码库提问,读缓存一折价格让周均推理成本下降 60% 以上。
Python 演示
# -*- coding: utf-8 -*-"""模拟提示缓存(Prompt Caching)的成本节省: 对比有/无缓存的输入费用""" class TokenCache: """模拟大模型API的前缀缓存, 统计命中率与费用""" def __init__(self, price=3.0, cached_price=1.5): self.price = price # 普通输入价: $3 / 百万 Token self.cached_price = cached_price # 命中输入价: $1.5 / 百万 Token self.cached_prefix = None # 当前缓存的前缀内容 self.hit_count = 0 # 命中次数 self.miss_count = 0 # 未命中次数 def request(self, total_tokens, prefix_tokens): """发起一次请求: total_tokens 为输入总数, prefix_tokens 为稳定前缀""" prefix = "P" * prefix_tokens if self.cached_prefix == prefix: self.hit_count += 1 hit = prefix_tokens # 命中的 Token 数 else: self.miss_count += 1 self.cached_prefix = prefix hit = 0 # 首次写入, 全部按原价 miss = total_tokens - hit return (miss * self.price + hit * self.cached_price) / 1e6 def main(): cache = TokenCache() # (总输入Token, 稳定前缀Token) 第二项为0表示前缀彻底变化 tasks = [(5000, 4000), (5400, 4000), (5100, 4000), (5300, 4000), (6000, 0), (5200, 4000)] total = 0.0 for total_tokens, prefix_tokens in tasks: total += cache.request(total_tokens, prefix_tokens) calls = cache.hit_count + cache.miss_count hit_rate = cache.hit_count * 1.0 / calls no_cache = sum(t * cache.price / 1e6 for t, _ in tasks) print("请求次数: %d, 缓存命中率: %.1f%%" % (calls, hit_rate * 100)) print("无缓存费用: $%.4f" % no_cache) print("使用缓存费用: $%.4f" % total) print("节省金额: $%.4f (%.1f%%)" % (no_cache - total, (1 - total / no_cache) * 100)) if __name__ == "__main__": main()
class TokenCache:定义一个模拟缓存器的类,等价于“面馆后厨的汤底管理台账”if self.cached_prefix == prefix:判断新请求前缀与缓存前缀是否逐字一致(命中判定)self.hit_count += 1命中后记录一次“复用汤底”的账,后面用来算命中率hit = 0 # 首次写入, 全部按原价没命中就重新熬汤,本次前缀按原价计费return (miss * self.price + hit * self.cached_price) / 1e6按“未命中原价 + 命中折扣价”折算成美元返回单次费用tasks = [(5000, 4000), (5400, 4000), (5100, 4000),模拟 6 次真实请求:总输入在变,但前缀稳定在 4000 Token;第 5 次前缀为 0,模拟一次“换汤底”no_cache = sum(t * cache.price / 1e6 for t, _ in tasks)计算不使用缓存时的全价账单,作为对比的基准线print("节省金额: $%.4f (%.1f%%)" % (no_cache - total,输出最终省下的“面钱”和节省率
常见误区
误区我以为缓存是按语义匹配的,只要问题意思差不多,就能命中缓存,省下钱来。反正 AI 不是能“理解”吗?
正解提示缓存是逐 Token 的精确匹配,相当于顾客必须一字不差地点同一款招牌面,“差不多”的汤底不会复用。任何前缀差异——多一个空格、改一个标点、插入一个动态时间——都会导致整段前缀未命中,按全价计算。缓存是纯工程机制,不讲意思,只讲字节。
为何常见:人们习惯把 AI 想象成“理解语义”的智能体,容易把缓存也想象成模糊匹配;实际上它是哈希表式的精确比对,语义理解在这里完全不起作用。
误区Prompt 越短越好,短 Prompt 本身 Token 就少,费用自然低,没必要费劲研究什么缓存。
正解短 Prompt(低于 1024 Token)根本达不到缓存门槛,反而享受不到折扣。更好的策略是:把系统提示词、few-shot 示例这些稳定内容写足、放前,让前缀长度跨过门槛,之后每次请求的头部都能打折。汤底越大,复用的折扣绝对值越大。
为何常见:省钱直觉是“少发内容”,但缓存经济学的核心是“稳定的长前缀”——同样是打五折,打在 6000 Token 上远比打在 200 Token 上实惠。
误区Anthropic 写缓存要加收 25% 的钱,这不是明摆着坑人吗?我还是用 OpenAI 的自动缓存算了。
正解写缓存只发生一次,读取缓存却只有原价的一折。按公式 $1.25 + 0.1(N-1) < N$,同一前缀被用到第 2 次就回本;对于批量任务或团队共享的大上下文,$N$ 往往高达几十次,总成本能降到原来的两三成。只看首笔费用是“捡了芝麻丢了西瓜”。
为何常见:人们只看到明面上多收 25% 的“订锅费”,没有把“之后每次一折”的长期收益算进来,被首笔支出吓退了。
误区只要配置好了缓存,它就永远在那儿,我随时调用都能省钱,不用再管它。
正解缓存有保鲜期:OpenAI 约 5-10 分钟滑动窗口,Anthropic 需显式选择 TTL(如 5 分钟或 1 小时),Gemini 也有类似限制。间隔超过 TTL,缓存就失效,下次请求重新全价计算。对有峰谷的业务,要评估请求密度能否撑起 TTL,必要时用 Anthropic 的 1 小时 TTL 覆盖低频场景。
为何常见:“缓存”这个词容易让人联想到本地文件或 CDN 的长期存储,忽略了 LLM 缓存本质上是短时效的临时计算状态,省电但易碎。
面试题
Q1. Prompt Caching 的核心机制是什么?
- A.按语义相似复用前缀结果
- B.复用前缀计算好的中间状态← 正确答案
- C.缓存模型的最终输出答案
- D.压缩提示词来减少 Token
答案:B。提示缓存复用的是“熬好的汤底”——前缀的 KV 中间状态,而不是最终答案;语义相似不命中,必须逐字一致;压缩提示词属于另一类优化手段,与缓存无关。
Q2. 提示缓存命中必须满足下列哪一条件?
- A.前缀逐 Token 完全一致← 正确答案
- B.问题主题大致相同
- C.输入输出长度相同
- D.模型版本完全一致
答案:A。缓存命中是纯工程比对,要求前缀逐 Token 完全一致,多一个空格都不行;“主题大致相同”只对人类理解有意义,对缓存毫无作用,这正是初学者最容易踩的坑。
Q3. OpenAI 提示缓存的最大特点是?
- A.需要在代码中声明启用
- B.自动生效且命中按折扣价← 正确答案
- C.只对输出 Token 打折
- D.缓存永久有效不失效
答案:B。OpenAI 采用自动缓存,无需任何代码改动,命中部分自动按折扣价计费;它不对输出 Token 打折,缓存也有 TTL 时效,并非永久有效。Anthropic 才需要显式声明。
Q4. 输入 8000 Token、其中 6000 命中缓存,缓存价五折,节省率是多少?
- A.总费用节省约 25%
- B.总费用节省约 37.5%← 正确答案
- C.总费用节省约 50%
- D.总费用节省约 75%
答案:B。命中比例 $h = 6000/8000 = 75\%$,折扣 $d = 0.5$,节省率 $= h(1-d) = 0.75 \times 0.5 = 37.5\%$。千万别把“命中比例”和“节省率”混为一谈——汤底占了四分之三,五折只省了其中一半,整体省 37.5%。
Q5. Anthropic 缓存价格中“写缓存”与“读缓存”分别是原价的多少?
- A.写入 0.5 倍、读取 0.5 倍
- B.写入 1.25 倍、读取 0.1 倍← 正确答案
- C.写入 1 倍、读取 0.5 倍
- D.写入 2 倍、读取 0.5 倍
答案:B。Anthropic 的显式缓存把价格拆成两笔:首次写入按原价 1.25 倍(“订锅费”),之后读取只要 0.1 倍(一折)。0.5 倍是 OpenAI 自动缓存的典型折扣,不能张冠李戴。
Q6. 超过保鲜期 TTL 后再次请求同一前缀,会发生什么?
- A.缓存自动续期并保持折扣
- B.缓存永久保留等待复用
- C.缓存失效需按全价重新计算← 正确答案
- D.缓存费用会自动退还
答案:C。TTL 是“高汤的保质期”。超过保鲜期,那锅汤就要倒掉重熬:前缀需要重新全量计算,按原价计费。缓存不会自动续期,也不会退还费用,这是监控请求密度的重要原因。
Q7. 把当前时间等动态内容写进系统提示词,会导致什么后果?
- A.模型输出的质量更好
- B.前缀变化从而使缓存失效← 正确答案
- C.输入费用自动降低一半
- D.缓存命中率自动提升
答案:B。系统提示词位于 Prompt 最前部,一旦塞入“当前时间”这类每次变化的动态内容,整个前缀就逐字不匹配,缓存必然失效。正确做法是把动态信息放到 Prompt 末尾的“加料区”。
Q8. 以下哪些场景适合启用提示缓存?
- A.多轮客服对话机器人← 正确答案
- B.批量模板化的审核任务← 正确答案
- C.前缀每次随机的问答
- D.超长文档反复提问← 正确答案
答案:ABD。多轮对话有稳定历史前缀,批量任务共享同一模板,长文档被反复提问时前缀极长——三者都是“高汤复用”的理想场景。前缀每次随机变化等于每次换汤底,缓存无从生效。
Q9. Anthropic 显式缓存中(写 1.25 倍、读 0.1 倍),同一前缀至少复用几次才开始省钱?
- A.只需复用 1 次
- B.复用 2 次即可← 正确答案
- C.复用 5 次即可
- D.复用 10 次即可
答案:B。由 $1.25 + 0.1(N-1) < N$ 解得 $N > 1.28$,约等于 $N \ge 2$。复用 1 次时写缓存成本 1.25 倍高于全价,不划算;从第 2 次起就开始净赚,复用次数越多省得越多。
Q10. 关于 Anthropic 显式缓存,下列说法正确的是?
- A.需用 cache_control 标注断点← 正确答案
- B.写缓存加收原价 25%← 正确答案
- C.读缓存只要原价一成← 正确答案
- D.无需任何代码配置
答案:ABC。Anthropic 必须通过 cache_control 断点显式“预订汤底”,写缓存 1.25 倍(加收 25%),读缓存 0.1 倍(原价一成)。“无需代码配置”是 OpenAI 自动缓存的特征,与 Anthropic 恰好相反,不能混淆。