Prompt 缓存是什么原理?怎么设计 prompt 才能「缓存友好」?

Q1-14prompt 缓存常见新增prompt缓存前缀TTL缓存断点成本优化

谁在问:工程向二面;平台组 / 网关组必问

口语化问法

  • prompt 缓存是怎么工作的?它到底缓存了什么?
  • 你们的缓存命中率是多少?断点打在哪儿?
  • 哪些操作会让缓存失效?说几个不太明显的。

考察意图

这是一道典型的「省钱题」,但它真正测的是细节掌控力。缓存这个功能的特点是:配错了不报错,只是悄悄不生效。所以问它,等于问你有没有真的去看过返回字段、算过账。

面试官在看:机制理解(为什么必须是前缀)、断点位置的判断、以及最重要的——没生效时你怎么查

参考答案

图 2 · 60 分与 90 分差在哪:代价、演进、怎么验证

60

60 分答案(及格线)

Prompt 缓存是把请求前缀的中间计算结果在服务端留存一段时间,下次发来同样的前缀就直接复用,省掉重新计算。效果是首 token 延迟下降、这部分输入的费用大幅降低(命中价大约是原价的十分之一)。

用法上是在稳定内容的末尾标记一个缓存断点,把系统提示词、工具定义、长参考资料这类不变的内容放前面,变化的用户输入放后面。

90

90 分答案(有生产经验的回答)

补三层:

第一,为什么必须是前缀。 因为缓存的本质是复用前文的中间计算结果,而这些结果依赖它之前的全部内容。所以缓存键是一个累积到断点为止的哈希——断点及之前任何一个字节变了,哈希就变了,整段作废。层级是 tools → system → messages,改上层废下层。

第二,几个容易踩的机制细节:写入只发生在断点处,读取时向前回溯,而回溯窗口是 20 个 block——长会话里一轮加太多 block,会把上一次的写入推出窗口,内容明明没变也命中不了,这时候要加第二个断点。另外有最小可缓存长度门槛,按模型不同从 512 到 4096 token 不等,不到门槛不缓存且不报错。计费上 5 分钟写入约 1.25 倍原价、1 小时写入约 2 倍、命中约 0.1 倍,命中会免费续期。

第三,一条常被忽略的期望校准。 缓存只作用于输入侧被缓存的那一段。如果你的成本大头在输出 token 或思考 token 上,上缓存本来就救不了多少——这时候正确的动作是去看 effort 和输出长度,而不是继续调缓存。

我们的设计原则就一句:稳定的在前,变化的在后;断点打在跨请求完全一致的最后一个 block 上;系统提示词末尾单独一个断点,让它能在压缩发生时幸存下来。

追问链

图 1 · 五层追问树:面试官会往哪儿挖
一道省钱题,真正测的是「没生效你怎么发现」

  1. 它缓存的到底是什么?为什么必须是前缀?

    期望缓存的是前缀的中间计算结果(KV),本质与推理时的 KV Cache 同源;每个位置的结果都依赖它之前的全部内容,所以只有从头开始完全一致的那一段才能复用 —— 中间改一个字,后面全废
    信号能把它和 KV Cache 联系起来 → 到了机制层;只说「缓存了 prompt」→ 当成普通字符串缓存
  2. 断点该打在哪里?打错了会怎样?

    期望打在跨请求完全一致的最后一个 block 上。典型错误是打在带时间戳、会话 ID 或本轮用户输入的 block 上,每次哈希都不同 —— 每次付写入费、永远读不到,比不开缓存还贵。回溯只找「之前请求真写过的位置」,不会替你把断点前的稳定内容缓存起来
    信号说得出「每次付写入费、永远读不到」这个具体后果 → 真踩过或真算过账
  3. 哪些操作会让缓存失效?说几个不明显的。

    期望明显的:改系统提示词、改工具定义(后者废掉整个缓存,层级 tools → system → messages,改上层废下层)。不明显的:JSON 序列化时键顺序不稳定、工具定义排列顺序变了、prompt 里图片增删、思考或 effort 配置变动、tool_choice 变化
    信号说得出「键顺序不稳定」或「改 effort 会失效」→ 一定亲自排查过命中率问题
  4. 5 分钟和 1 小时的 TTL 怎么选?

    期望判据是请求密度:同一前缀用得比 5 分钟更勤,5 分钟档就够 —— 命中会免费续期;1 小时档给「间隔常超 5 分钟但在一小时内」和首 token 延迟敏感的场景,写入溢价 1.25 倍 → 2 倍,要摊到足够多次读取才划算。寿命从请求开始时刻算起,一次久的流式生成自己就吃掉一截
    信号知道「命中会免费续期」→ 才判断得了该不该升 1 小时档;不知道的容易一上来就选 1 小时
  5. 上了缓存账单只降 8%,团队怀疑没生效,你怎么查?

    期望① 先看数据别猜:写入 / 读取 / 未缓存三类 token 构成 → ② 对症:只写不读 = 前缀不稳定,查时间戳、会话 ID、JSON 键顺序、工具顺序、efforttool_choice;两字段全 0 = 没够最小长度门槛,静默失败 → 命中率忽高忽低 = TTL 到期或断点挤出 20 block 回溯窗口 → ③ 查网关是否吃字段 → ④ 校准预期
    信号敢说「8% 可能是对的,问题不在缓存」→ 会校准预期;一路调断点调 TTL、从不质疑省钱的地方找错没 → 差档
一句「命中会免费续期」就把「开过缓存」和「算过账」切开了。前四层考机制细节,第 5 层考你敢不敢说「8% 就是这条路的天花板」。

评分要点

  1. 说清缓存的是前缀的中间计算结果,与 KV Cache 同源
  2. 解释为什么必须是前缀(累积哈希,改一处后面全废)
  3. 知道层级 tools → system → messages,改上层废下层
  4. 断点打在跨请求完全一致的最后一个 block 上
  5. 知道存在最小长度门槛,且未达标是静默失败
  6. 说得出至少两个不明显的失效项
  7. 知道命中会免费续期,据此判断 TTL 档位
  8. 排查时先看字段构成,最后会校准预期

常见错误

把它理解成「把回答缓存起来,同样的问题直接返回」。
认为开了缓存就自动省钱,从没看过命中相关的返回字段。
把断点打在包含用户输入或时间戳的位置。
不知道缓存未生效时不会报错。
排查思路只有「换 TTL 试试」,不做构成分析。
认为缓存能降低上下文窗口占用(它只改计费,不改占用)。
含糊标志词:「SDK 会自动处理」「开了肯定比不开省」「命中率大概挺高的吧」。

关联学习