Skip to content
返回

DeepSeek 前缀缓存与推理模式:切换档位时缓存能否复用?

引言

DeepSeek V4 系列模型(deepseek-v4-flashdeepseek-v4-pro)支持思考模式(Thinking Mode):通过 thinking: {type: enabled|disabled} 开关思考,通过 reasoning_effort: low|high|max 控制思考强度。同时,DeepSeek API 对所有请求默认启用上下文硬盘缓存(Context Caching on Disk):相同前缀的输入只按缓存命中价计费(以 2026 年 8 月官方定价为例,V4 Flash 缓存命中输入 ¥0.02/百万 token,仅为未命中 ¥1/百万 token 的 1/50)。

一个自然的工程问题是:如果应用在同一会话中切换思考模式或思考档位(例如从 effort: none 切到 effort: high),此前建立的提示前缀缓存还能复用吗? 这个问题在官方文档中没有直接答案,市面上的博客与社区讨论也未见专门讲解。

本文通过一组受控实验回答了这个问题,并进一步揭示了缓存本身的组织方式:DeepSeek 的缓存是块级、渐进落盘的——这解释了为何切换档位会完全失效,也解释了为何单字符扰动的影响是状态依赖的。文章给出完整的实验设计、数据与可复现步骤。

背景:DeepSeek 的前缀缓存机制

根据官方文档,DeepSeek 的上下文硬盘缓存规则可以概括为三点:

  1. 前缀匹配:缓存命中要求后续请求完整匹配一个已落盘的”缓存前缀单元”(用户输入 token 序列的前缀部分)。
  2. 三种落盘时机:请求结束位置(用户输入结束与模型输出结束处)、公共前缀检测(多次请求间发现公共前缀时)、固定 token 间隔(长输入按间隔截取单元)。
  3. 尽力而为:缓存构建耗时为秒级,命中率不保证 100%,不用的缓存数小时到数天内自动清理。

缓存命中的计费结果通过 usage 字段返回:prompt_cache_hit_tokens / prompt_cache_miss_tokens(Chat Completions 通道),或 input_tokens_details.cached_tokens(Responses 通道)。

思考模式文档则说明了另一组事实:思考模式默认开启,默认档位为 higheffort 与模型实际推理强度的映射为 low → lowhigh → highxhigh → maxmax → max。文档没有说明模式切换与缓存的关系。

缓存”前缀单元”按实际发送的输入 token 序列计算,而思考模式很可能改变了实际发送的序列(例如注入指令)——这正是本文要验证的核心假设。

实验设计

研究问题

控制变量

  1. 固定 API key、固定模型(deepseek-v4-flash)、固定输入模板;思考模式下 temperature/top_p 等采样参数不生效(官方文档),天然受控。
  2. 每个实验使用全新唯一输入(内容从未发送过,并记录输入内容的 SHA-256 指纹便于审计)。这保证每个序列的首次请求必然 0% 命中(即建缓存请求),实验结果中所有”首次”行都通过该不变量校验。
  3. 关键序列(切换矩阵)完整执行两轮,验证可复现性。
  4. 请求间隔 2 秒(官方文档说明缓存落盘耗时为秒级)。
  5. 测试时间:2026 年 8 月 8 日;直接请求官方端点 https://api.deepseek.com(Responses 与 Chat Completions 两个协议),不经过任何网关或代理。

这里有一个容易被忽视的陷阱:凡报告”首次请求即高命中”的缓存实验,都应怀疑其输入在此之前是否已被发送过(例如测试前的校准请求会悄悄建立缓存)。“首次 0% 命中”是最便宜的实验卫生检查。

观测指标

每个请求记录:输入 token 数(in)、缓存命中 token 数(cached)、未命中 token 数(miss)、命中率(cached/in)、推理 token 数(r_tokens)、输入指纹。命中率为主要指标,in 的绝对值变化用于检测服务端注入的指令 token(同一输入在不同档位下 in 的差值即为注入量)。

输入模板

输入由三段独立主题文本拼接构成(神经语言模型 / 操作系统 / 公钥密码学,各约 590 token),用于探针定位;另有同质长前缀、多轮文档、短文本(117 token)等变体。每实验输入互不相同。

实验与结果

实验 A:模式切换矩阵

方法:同一输入(1476 token,指纹 373fff3b…),按 none → none → high → high → none → low → max → max → none 的顺序依次请求(Responses 通道),完整执行两轮。

结果(第一轮;第二轮完全复现模式):

步骤角色effortincached命中率推理 token
A1首次none147600.0%0
A2同档none1476140895.4%0
A3切换high1555(+79)00.0%302
A4同档high1555153698.8%857
A5切回none1476140895.4%0
A6切换low1476140895.4%611
A7切换max1568(+92)00.0%3558
A8同档max1568153698.0%11910
A9切回none1476140895.4%0

发现

  1. 首次请求命中率为 0%(建缓存),同档第二次请求恢复 95% 以上——这是”干净实验”的基本形态。
  2. nonelow 共享同一缓存(A6 命中 95.4%,in 与 none 完全相同)——low 档不注入任何额外 token。
  3. highmax 各自独立in 分别比基线多 7992 个 token,即服务端向输入中注入了固定长度的指令;切换后首次请求命中率为 0%(连此前 1408 token 的命中块都完全失配)。
  4. 同档位内部稳定复用high 第二次请求即恢复 98.8%,max 为 98.0%。
  5. 回切 none 立即恢复:none 的缓存未被切换操作驱逐,A5/A9 命中率与 A2 一致。
  6. 第二轮中,因第一轮已建立各档位缓存,high/max 切换行直接命中(98.8%/98.0%),其余行与第一轮一致——同时验证了缓存的分钟级持久性。

实验 B:注入指令的注入量

方法:用三段式输入(1770 token)在 none 档建立缓存后,依次切换 highmaxlow,观察命中率与 in 的变化。

结果

步骤角色effortincached命中率
B1首次none177000.0%
B2同档none1770166494.0%
B3切换high1849(+79)00.0%
B4切换max1862(+92)00.0%
B5切换low1770166494.0%

发现:切换 high/max 后,此前全部 1664 个命中块完全失配(cached = 0)。low 档再次确认与 none 完全共享。注入量(+79 / +92)在 117–1770 token 的多种输入长度下均为同一数值,说明它是与输入无关的固定指令模板

实验 B’:单字符改动的影响(状态依赖)

方法:在 none 档下,对同一输入(1770 token,已建立缓存)的头部中部尾部各改动一个字符,观察命中率变化。为观察缓存状态的影响,该实验在公共块落盘前与落盘后各执行一轮(落盘后含多次重复测量)。

结果(公共块落盘后,多次测量完全一致):

改动位置incached命中率
无(基线)1770166494.0%
头部一个字符1770166494.0%
中部一个字符1772166493.9%
尾部一个字符1773166493.9%

发现(重要的状态依赖行为)

  1. 公共块落盘后,单字符改动几乎不影响命中率(94%),无论改动在头部、中部还是尾部——缓存命中不需要整条前缀从头连续匹配。
  2. 但在缓存建立的早期,同样的改动曾导致命中率崩塌至 0%——原因是”公共前缀检测”落盘是渐进的:第一次遇到变体请求时,服务端只有”完整前缀”单元,改动后无法匹配;随着相似请求反复出现,重复的公共块被单独落盘,此后任意单字符变体都能命中公共块。
  3. 这一对比恰好解释了官方文档”公共前缀检测落盘”的实际效果:它是按块工作的,且需要多次请求触发。

实验 D:切换后的收敛速度

方法:新输入(698 token)在 none 档建立缓存后,连续 4 次以 high 档请求。

结果

步骤effortincached命中率
D1none(首次)69800.0%
D2-1high(切换)77700.0%
D2-2high77776898.8%
D2-3high77776898.8%
D2-4high77776898.8%

发现切换后仅需 1 次未命中请求即可重建缓存,第 2 次请求恢复满命中(98.8%)。收敛代价 = 一次未命中计费(777 token × ¥1/百万 ≈ ¥0.0008)。

实验 E:多轮对话形态

方法:采用真实 Agent 的多轮形态(system 指令 + 长文档 + user 提问,Chat Completions 通道,510 token),验证单轮结论在带系统提示的场景下是否成立。

结果

步骤角色模式incached命中率
E1首次disabled51000.0%
E2同档disabled51038475.3%
E3切换enabled/high589(+79)00.0%
E4切回disabled51038475.3%

发现:多轮形态下结论与单轮完全一致——切换全 miss、回切立即恢复;high 档注入量仍为 +79。(E2 命中率 75.3% 低于长输入实验,与输入较短、尾部未对齐块占比更高有关。)

实验 F:两个协议通道的缓存共享

方法:同一输入(594 token)先用 Responses 通道建立缓存(nonehigh 各一次),随后用 Chat Completions 通道以相同模式请求。

结果

步骤通道角色模式incached命中率
F1responses首次none59400.0%
F2responses切换high67300.0%(建缓存)
F3chat跨通道none59451286.2%
F4chat跨通道high67364095.1%

发现

  1. Responses 与 Chat Completions 共享同一前缀缓存池:chat 通道的请求命中了 responses 通道建立的缓存(F3 命中 F1、F4 命中 F2)。
  2. 两通道注入指令完全一致(均为 +79):说明模式指令注入发生在服务端协议转换的公共层,而非通道特有问题。

实验 G:最短缓存粒度

方法:用 117 token 的短输入验证缓存阈值。

结果

步骤effortincached命中率
G1none(首次)11700.0%
G2none(同档)11700.0%
G3high(切换)196(+79)00.0%

发现:117 token 的输入无法建立缓存(第二次仍 0% 命中),而另一组 185 token 的输入则可以命中 128 token。结合所有实验中 cached 值均为 128/256 的倍数,说明缓存的最小粒度约为一个 128-token 块:低于一个块的输入无法命中。注入量仍为 +79,与输入长度无关。

讨论

机制模型

综合所有实验,可以构建一个自洽的块级缓存模型:

  1. 缓存按块(约 128/256 token)组织:命中不需要整条前缀从头连续匹配;块内容一致即可命中(B’ 实验:头部单字符改动后其余块照常命中)。
  2. 块渐进落盘:首次请求只落盘”完整前缀”单元;相同或相似请求反复出现后,重复的公共块被单独落盘(官方文档的”公共前缀检测”实际按块工作)。落盘前,任何变体请求都会 miss;落盘后,仅受影响的块及其依赖失效。
  3. 模式指令注入:思考档位变化时,服务端在输入最前面注入固定长度指令(high 79、max 92、low 0;nonelow 等价)。这产生两个后果:输入从第一个 token 起就不同;且因 token 数变化,后续块的对齐边界整体错位。因此切换档位后所有块都失配——这就是实验中稳定复现的 0% 命中。
  4. 缓存池全局共享:缓存按 API key 组织,Responses 与 Chat Completions 两个协议通道共用(实验 F);none 缓存不会因切换操作被驱逐(实验 A 回切立即恢复)。

与社区观测的关系

工程启示

对使用 DeepSeek API 的工程实践(网关、Agent 框架):

  1. 固定档位:同一会话/工作负载应固定 reasoning_effort,避免在 none/high/max 之间频繁切换;每次切换的代价是一次全量未命中的输入计费(约输入长度 × ¥1/百万 token)。
  2. nonelow 可视为同一档位:两者共享缓存且 low 不注入指令,若需要”轻思考”可放心从 none 切换。
  3. 微扰动的代价低于直觉:单字符级的输入扰动(如时间戳、ID 变化)在公共块落盘后对命中率影响很小(实验 B’),不需要为”改一个字符”过度焦虑;但改变 token 数目的改动(插入/删除内容)会破坏块对齐,代价接近一次全 miss。
  4. 切换是显式成本:切换后第 2 次请求即恢复高命中(实验 D),因此”短时切换再切回”的实际成本 = 两次全量未命中。
  5. 缓存是尽力而为:官方明确不保证 100% 命中,生产设计应以”未命中可接受”为前提,把命中率当作可测量的优化指标而非承诺。

局限

结论

  1. 切换推理模式/档位会使前缀缓存完全失效(0% 命中,稳定复现于多轮、双通道、多种输入长度):服务端向输入最前面注入固定长度指令(high +79、max +92、low 0),改变后的输入在块级缓存中无法匹配任何已落盘块。
  2. nonelow 共享缓存;highmax 各自独立;同档位内稳定复用(95–99%)。
  3. 切换后第 2 次请求即恢复高命中;回切原档位立即恢复(缓存不被驱逐)。
  4. 缓存是块级、渐进落盘的:单字符扰动在公共块落盘后影响很小,但任何改变 token 数量的改动都会破坏块对齐。
  5. Responses 与 Chat Completions 两个协议通道共享同一缓存池,注入行为一致。
  6. 工程上应固定档位使用,把切换当作”一次全量未命中计费”的显式成本来管理。

附录:复现

实验脚本、测量数据与复现步骤见 github.com/JiangYingjin/deepseek-cache-experiments


DeepSeekLLMPrefix CachingAPI

Next Post
从 5.4 秒到 106 毫秒:一个 EventV2 批量写入问题的定位与修复