缓存命中和缓存未命中

成本与用量

讲清缓存命中与未命中在概念和计费口径上的差别,给开发者一套判断哪些请求能命中、命中不了该怎么改的实操方法。

你可能已经发现,同一段系统提示词、同一份长文档反复发,账单却时高时低。问题多半出在缓存命中与未命中的差异上:命中的部分和未命中的部分,走的不是同一个计价口径。这篇不背数字,只讲清两者到底差在哪、DeepSeek 这类按缓存分层计价的服务里怎么判断自己命中了没有,以及代码和调用结构上要改哪几处。具体单价去站内官方价格页看当时的数字。

同一段系统提示词、同一份长文档反复发,账单却时高时低,这种落差多数不是单价变了,而是每次请求里命中缓存的部分和没命中的部分占比不一样。这两块走的不是同一个计价口径,一块按相对便宜的档位算,另一块按标准输入算,比例一浮动,总价自然跟着飘。

这篇不背任何数字,只讲清两者差在哪、DeepSeek 这类按缓存分层计费的服务里怎么判断自己到底命中了没有,以及提示词排版和调用结构上要改哪几处。想对当前口径,去站内官方价格页看当时的数字;想对表现,去用量相关页面看命中与未命中的占比。

缓存命中与未命中,差的到底是什么

命中指的是这次请求里有一段前缀,和之前某次请求完全一致,服务端直接把当时算好的中间状态复用过来,不用重算。未命中就是没找到可复用的前缀,这段内容从零开始算一遍。注意这是前缀匹配,不是整段文本的相似度匹配,差一个字符、多一个空格,整段前缀就可能作废。

对比项缓存命中缓存未命中
计费口径按命中档位算,通常明显更低按标准输入档位算
响应延迟省掉重复计算,通常更快要重新算一遍,相对慢
复用条件从第一个字起前缀完全一致没有可复用前缀,或前缀已失效
常见诱因系统提示、长文档、固定示例重复用开头塞了时间戳、随机数、用户 ID
  • 命中看的是前缀复用,不是语义相近,措辞改了就不算同一段
  • 命中和未命中的差别落在两处:延迟和计价口径,账单波动主要来自后者
  • 请求本身很短、几乎没有可复用前缀时,讨论命中率没有意义,优化收益接近于零
  • 缓存有存活窗口,超过窗口没被再次引用就失效,下次又按未命中算

为什么同一段提示词,账单还是忽高忽低

提示词没变、账单在变,通常有三个原因。一是缓存窗口到期,两次调用间隔太久,之前的中间状态已经没了;二是前缀被动态内容污染,比如把当前时间、用户 ID、随机数放在提示词最前面,每次开头都不一样,后面再长也白搭;三是并发和请求顺序,同一时刻多个请求一起打进来,先到的负责算,后到的未必来得及复用。

  • 缓存过期:两次请求间隔超过存活窗口,下一次重新算
  • 前缀污染:开头放了每次都变的内容,整段前缀失效
  • 并发冲撞:同一批请求同时发出,缓存还没写完就被下一条用到
  • 顺序打乱:多轮对话里把历史消息重新排序,前缀被切断

碰到账单波动,别先盯着单价看,先去站内用量页把命中与未命中的 token 占比拉出来。如果命中占比一直很低,说明你的请求结构本身就不具备复用条件;如果占比忽高忽低,多半是缓存过期或请求节奏的问题。

怎么判断自己这次到底命中了没有

最直接的办法是看接口返回的用量字段。这类服务一般会把命中部分和未命中部分拆成两个数字返回,两者相加才是本次的总输入量。只记总量、不拆字段,永远查不出问题到底出在结构还是节奏上。

  1. 拆开记账把返回里的命中 token 和未命中 token 分别写进日志,别只存一个合计值
  2. 补上标识每条记录带上请求 ID 和时间戳,出问题时能顺着时间轴还原是哪些调用出了偏差
  3. 按天算占比用命中 token 除以命中加未命中,得到当日命中率,这个比值比总花费更能说明问题
  4. 对照结构命中率掉下来的那几天,回头查提示词开头有没有被塞进动态内容,或请求间隔是否被拉长
# 日志里至少留这几列,便于后续复盘;具体字段名以当期接口文档为准
# ts | request_id | prompt_tokens_hit | prompt_tokens_miss | total_input

把提示词排版改一改,命中率就上来了

核心原则只有一句:稳定不变的内容往前放,每次都在变的内容往后放。系统提示、角色设定、固定示例、长文档正文这些跨请求重复的部分放最前面,用户问题、当前时间、会话 ID、临时参数一律甩到最后。这样前缀才立得住,服务端才有东西可以复用。

位置放什么理由
最前面系统提示、角色设定、固定示例跨请求重复,最容易命中
中间长文档、知识库正文同一份内容被多个请求共用时复用价值高
最后用户问题、时间戳、会话 ID、临时参数每次都变,放在后面不破坏已有前缀
避免开头塞随机数或用户标识会让整段前缀每次都不同,直接毁掉命中
  • 同一份长文档被多个请求共用时,先发一次把前缀建起来,再让后续请求复用
  • 多轮对话不要每轮重排历史消息顺序,顺序一变前缀就断
  • 拼接提示词用固定模板,避免引入不可控的空行和空格差异
  • 前缀太长容易顶到窗口上限,太短又没复用价值,按任务实际上下文来定

代码层面要动的几处

提示词排版解决的是「能不能命中」,代码结构解决的是「命中了能不能被稳定复用」。这两件事要一起做,只改文案不改调用方式,命中率还是会飘。

  • 用固定模板拼提示词,别用会引入不确定空白的字符串拼接
  • 同一批任务尽量串行或小并发发,给缓存留出写入时间
  • 把命中与未命中 token 落到日志表,方便后面做预算和复盘
  • 给长前缀单独抽成可复用的片段,改动时只动变化的那一小段
  • 上线前做一次对照:改结构前后各跑一批相同请求,比较命中率变化

这些参数和接口细节不同时期可能调整,动手前到站内相关页面核对当期说明,别照抄旧代码。

在 DeepSeek 这类服务上怎么落地

这类服务一般会把输入分成命中档和未命中档两套口径,具体单价去站内官方价格页核对当期数字,不要记死。判断要不要为命中率做优化,标准只有一条:调用频次高、前缀重复度高,收益就明显;一次性任务基本没意义。

场景是否值得优化原因
客服知识库问答值得同一份知识库反复作为前缀
长文档摘要与改写值得文档正文可长期复用
固定角色批量生成值得系统提示与示例高度重复
单次文案或脚本生成不值得没有可复用前缀
实时个性化问答谨慎每次内容都新,优化空间有限
  • 核对计价口径时,确认缓存窗口和计费单位是不是同一套说法,别把不同页面的数字混着算
  • 并发数不要开得过大,避免缓存还没写完就被下一批请求覆盖
  • 把命中率当成一个持续观察的指标,不是一次性调完就完事

做一个能持续看的小闭环

不用搞得很复杂,固定一个观察周期就够了,比如每周拉一次命中与未命中 token 的汇总,算出命中占比,和上一期比。占比下降时按固定顺序排查,比漫无目的地翻代码高效得多。

  1. 第一查开头看提示词最前面有没有被塞进时间戳、用户 ID 这类每次都变的内容
  2. 第二查间隔看两次复用之间的时间是不是被拉长了,导致缓存已经失效
  3. 第三查顺序看多轮对话或批量任务的历史消息有没有被重新排序
  4. 第四查并发看同一时刻发出的请求数量有没有明显变大,导致缓存来不及写入
  5. 记录对比把改动前后的命中占比并排放,比只看总花费更能定位到具体改动

这几种情况下别折腾缓存

缓存优化不是万能动作,有些场景投入产出比很低,硬做反而增加代码复杂度。判断标准很简单:你的请求里有没有一段高频重复的长前缀,没有就别花这个时间。

  • 每次请求内容完全不重复的一次性任务,比如单次文案生成、单张图片脚本
  • 上下文本身就很短,前缀复用的空间不大
  • 对延迟极度敏感、又必须每次拿最新内容的实时问答,缓存带来的稳定性风险可能大于收益
  • 调用频次很低、几周才跑一次的任务,缓存窗口基本等不到下一次复用

如果你的场景在「不值得」这一档,把精力放回提示词质量和输出稳定性上更划算;确实想确认某个服务有没有缓存能力、按什么口径算,到站内对应的评测和价格相关页面看当期结论再决定。

下一步先把你最近一周的请求按命中与未命中拉一份占比出来,再对照站内价格页核对当期口径,然后按排查顺序改提示词开头,改动一次对比一次。

常见问题

缓存命中和缓存未命中,是不是就是快和慢的区别?

不只是。速度差别确实明显,但真正影响账单的是计价口径:命中的那部分 token 通常按另一档单价算,未命中的按标准输入价。所以同一段提示词,命中和没命中的花费可能差出一截。具体倍数去站内官方价格页看当期数字。

我怎么知道自己有没有命中缓存?

看接口返回的用量字段。多数服务会把命中部分和未命中部分分开给出,两个数字相加才是这次的总输入量。只记总量是查不出问题的,建议把这两个数字连同请求时间一起写进自己的日志。

把提示词改一改就能命中吗?

关键在顺序。稳定不变的部分放最前面,每次都在变的内容放最后,前缀从第一个字开始保持一致才可能命中。把时间戳、用户 ID 这类动态内容放在开头,基本等于主动放弃命中。

缓存一直不命中,一般是什么原因?

先查三个地方:提示词开头有没有混进动态内容;两次请求之间隔了多久、有没有超过缓存存活窗口;同批请求是不是并发太高,前一个还没写完缓存后一个就来了。这三条覆盖了大部分常见原因。

所有场景都值得为缓存命中做优化吗?

不是。调用频次高、前缀重复度高的场景收益最明显,比如知识库问答、固定系统提示的批处理。每次内容都不同的一次性任务,或者上下文本身很短的请求,花时间调提示词结构意义不大。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。