news 2026/7/8 4:49:43

模型token缓存命中 vs 缓存未命中?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
模型token缓存命中 vs 缓存未命中?

一、先说清楚:缓存命中 vs 缓存未命中

1.1 一句话说清楚

大模型处理你的请求时,主要成本在计算而不是“读取”。如果这次请求的前缀内容和之前某次请求一模一样,平台就不用从头再算一遍,而是复用之前保存下来的中间结果。

  • 缓存命中(Cache Hit):你的请求前缀已经被处理过并缓存了 → 直接复用 →便宜 + 快

  • 缓存未命中(Cache Miss):你的请求前缀没被处理过 → 从头计算 →贵 + 慢

1.2 价格差距有多大?用真实数据说话

DeepSeek V4 Flash为例(平时价格):

类型百万Token价格备注
输入(缓存命中)0.02元便宜到几乎可以忽略
输入(缓存未命中)1元是命中价格的50倍
输出2元输出无法缓存

再看DeepSeek V4 Pro

类型百万Token价格
输入(缓存命中)0.025元
输入(缓存未命中)3元
输出6元

差距有多大?同样是100万Token的输入,命中缓存只要2分钱,没命中要3块钱——差了120倍

缓存命中的价格通常是未命中的十分之一到百分之一,具体取决于模型和厂商。

1.3 缓存命中 vs 未命中:一张图看懂

二、模型是怎么判断缓存是否命中的?——命中逻辑架构

2.1 核心原则:精确前缀匹配(Exact Prefix Match)

所有主流模型的缓存判断逻辑,都遵循同一个核心原则:

缓存命中要求两次请求的“前缀”在字节级别完全一致。

“完全一致”的意思是——哪怕多一个空格、改一个标点,缓存都可能失效

2.2 三步判断流程

整个缓存判断过程可以分为三步:

2.3 不同厂商的缓存实现差异

OpenAI:内存缓存 + 扩展缓存

OpenAI的缓存机制:

  • 自动开启:所有API请求自动启用,无需改代码

  • 触发条件:提示词至少1024个Token才会触发缓存

  • 命中单位:以128个Token为增量进行缓存命中

  • 缓存时长

    • 内存缓存:5-10分钟不活跃即失效,最长1小时

    • 扩展缓存:最长24小时

  • 路由机制:基于前缀哈希值路由到特定机器

DeepSeek:硬盘缓存(全球首创)

DeepSeek采用硬盘缓存技术,是全球第一家在大范围API服务中采用硬盘缓存的大模型厂商:

  • 默认开启:所有用户默认享受,无需修改代码

  • 缓存落盘时机有三种:

    1. 请求边界落盘:每次请求结束位置产生缓存单元

    2. 公共前缀检测落盘:多次请求检测到公共前缀时独立落盘

    3. 固定Token间隔落盘:长输入按固定间隔截取缓存

  • 匹配规则:后续请求必须完整匹配缓存前缀单元才能命中

  • 查看命中:返回的usage字段包含prompt_cache_hit_tokensprompt_cache_miss_tokens

阿里云:显式缓存 vs 隐式缓存

阿里云提供两种模式:

模式特点命中价格
隐式缓存(自动)系统自动识别公共前缀,无需配置输入单价的20%
显式缓存(手动)主动创建缓存块,确定性高输入单价的10%

显式缓存需要主动添加cache_control标记:

{ "role": "system", "content": [ {"type": "text", "text": "这里放长文本...", "cache_control": {"type": "ephemeral"}} ] }

2.4 为什么说“缓存命中的判断是精确匹配”?

来看DeepSeek官方文档的两个例子:

例1:能命中

第一次请求:A + B
第二次请求:A + B + C → 完整匹配 A+B → ✅ 命中

例2:第一次不能命中,但后续可以

第一次请求:A + B
第二次请求:A + C → 不能完整匹配 A+B → ❌ 未命中
→ 但系统检测到公共前缀 A,把它缓存了
第三次请求:A + D → 完整匹配 A → ✅ 命中

关键洞察:缓存是动态学习的。即使某次没命中,系统也会从失败中提取公共前缀,为后续请求创造命中机会。

三、怎么判断你的请求是否命中了缓存?

3.1 查看API返回的usage字段

大多数模型API会在返回中告诉你缓存命中情况。

DeepSeek API返回示例

{ "usage": { "prompt_tokens": 1500, "prompt_cache_hit_tokens": 1200, // ← 命中了1200个Token "prompt_cache_miss_tokens": 300, // ← 没命中300个Token "completion_tokens": 200, "total_tokens": 1700 } }

计费公式

费用 = 命中Token数 × 命中单价 + 未命中Token数 × 未命中单价 + 输出Token数 × 输出单价

3.2 VSCode代码:解析缓存命中情况

import requests import json def call_with_cache_check(prompt, api_key, model="deepseek-chat"): """ 调用API并检查缓存命中情况 """ url = "https://api.deepseek.com/v1/chat/completions" headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } data = { "model": model, "messages": [ {"role": "system", "content": "你是一个乐于助人的助手"}, {"role": "user", "content": prompt} ] } response = requests.post(url, headers=headers, json=data) result = response.json() # 提取缓存命中信息 usage = result.get("usage", {}) hit_tokens = usage.get("prompt_cache_hit_tokens", 0) miss_tokens = usage.get("prompt_cache_miss_tokens", 0) total_prompt = usage.get("prompt_tokens", 0) # 计算命中率 if total_prompt > 0: hit_rate = (hit_tokens / total_prompt) * 100 else: hit_rate = 0 print(f"📊 缓存命中统计:") print(f" - 命中Token: {hit_tokens}") print(f" - 未命中Token: {miss_tokens}") print(f" - 总输入Token: {total_prompt}") print(f" - 命中率: {hit_rate:.1f}%") # 估算费用(以DeepSeek V4 Flash为例) hit_price = 0.02 / 1_000_000 # 0.02元/百万Token miss_price = 1.0 / 1_000_000 # 1元/百万Token cost = hit_tokens * hit_price + miss_tokens * miss_price print(f" - 预估费用: {cost:.6f}元") return result # 使用示例 # 第一次调用:构建缓存 result1 = call_with_cache_check("中国的首都是哪里?", "your-api-key") # 第二次调用:相同前缀,应该命中缓存 result2 = call_with_cache_check("中国的首都是哪里?请详细介绍一下", "your-api-key")

代码解析

  • prompt_cache_hit_tokens:命中的Token数,按低价计费

  • prompt_cache_miss_tokens:未命中的Token数,按高价计费

  • 命中率 = 命中Token ÷ 总输入Token

四、怎么提高缓存命中率?——实战技巧

4.1 黄金法则:稳定的放前面,变化的放后面

这是最核心、最有效的一条原则:

❌ 错误做法(动态内容在前):
[当前时间: 2026-07-07 10:30] + [系统提示词] + [用户问题]
→ 时间每分每秒都在变 → 缓存永远失效

✅ 正确做法(稳定内容在前):
[系统提示词] + [工具定义] + [项目规则] + [用户问题]
→ 前三项长期不变 → 缓存持续命中

对于Coding Agent来说,请求结构通常是这样:

[tools] 工具定义 ← 长期稳定
[system prompt] 系统提示 ← 长期稳定
[project rules] 项目规则 ← 长期稳定
[conversation history] ← 相对稳定(追加内容)
[tool results] 工具结果 ← 每轮不同
[new user message] "继续" ← 真正新增的只有这几个字

越稳定越靠前,缓存越管用;越动态越靠前,缓存越容易废

4.2 避免动态内容破坏缓存

以下内容只要出现在请求前缀位置,就会破坏缓存命中

动态内容为什么破坏缓存
当前时间戳每分每秒都在变
随机Request ID每次请求都不同
重排过的工具列表顺序一变,前缀就变了
动态拼接的System Prompt每次可能多一句话

解决方案:把这些动态内容放到请求的最后面,不要放在开头。

4.3 使用缓存Key(OpenAI)

OpenAI提供了prompt_cache_key参数,可以手动控制路由:

# 相同cache_key的请求会被路由到同一台机器 response = client.chat.completions.create( model="gpt-4o", messages=messages, prompt_cache_key="my-app-v1" # ← 手动指定缓存Key )

这样即使前缀略有不同,只要prompt_cache_key相同,请求也会被路由到同一台机器,提高命中概率。

4.4 多轮对话中保持上下文连贯

在多轮对话中,把历史对话放在前面,新问题放在最后

# ✅ 好的做法:历史在前,新问题在后 messages = [ {"role": "system", "content": system_prompt}, # 稳定 {"role": "user", "content": "第一轮问题"}, # 已固化 {"role": "assistant", "content": "第一轮回答"}, # 已固化 {"role": "user", "content": "第二轮问题"}, # 已固化 {"role": "assistant", "content": "第二轮回答"}, # 已固化 {"role": "user", "content": "新问题"} # ← 只有这个是新增的 ]

前面的内容因为已经处理过并被缓存,新增的只有最后一小段,大部分Token都能命中缓存

五、总结:一张表看懂全部

维度缓存命中缓存未命中
发生了什么复用之前计算好的中间结果从头开始计算
价格极低(通常为未命中的10%-20%)正常价格
速度快(首Token延迟降低80%)
DeepSeek V4 Flash0.02元/百万Token1元/百万Token
DeepSeek V4 Pro0.025元/百万Token3元/百万Token
判断方式请求前缀精确匹配缓存请求前缀没有匹配项
命中条件稳定内容在前 + 动态内容在后动态内容破坏了前缀匹配

小编建议

  1. 检查API返回的usage字段:看prompt_cache_hit_tokensprompt_cache_miss_tokens,知道自己到底命中率多少

  2. 重排你的Prompt结构:稳定内容放前面,动态内容放后面

  3. 避免在请求前缀插入时间戳、随机ID:这些会让缓存完全失效

  4. 多轮对话中保持历史上下文顺序:新问题追加在最后

  5. 善用缓存Key(如有):把相同类型的请求路由到同一台机器

小编团队自主研发 大型文件翻译、润色文本链接

https://blog.csdn.net/weixin_54524403/article/details/162078447?spm=1011.2415.3001.10575&sharefrom=mp_manage_linkhttps://blog.csdn.net/weixin_54524403/article/details/162078447?spm=1011.2415.3001.10575&sharefrom=mp_manage_link

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 4:49:13

影刀RPA API调用的重试退避与超时策略

影刀RPA API调用的重试退避与超时策略 作者:林焱 什么情况用这个 调用外部API时,有三种情况一定会遇到:超时、限流、服务暂时不可用。如果每种情况都让流程直接报错中断,那你每天有三分之一的时间在手动重启流程。 API调用的稳定…

作者头像 李华
网站建设 2026/7/8 4:48:36

【LeetCode704】二分查找

目录 题目 解法一、二分查找(闭区间) 解法二、二分查找(半开半闭区间) 题目 解法一、二分查找(闭区间) int search(int *nums, int numsSize, int target) {int left 0;int right numsSize - 1;int …

作者头像 李华
网站建设 2026/7/8 4:47:33

基于STM32设计的PPG脉搏波采集装置_370

文章目录 一、前言 1.1 项目介绍 【1】项目开发背景 【2】设计实现的功能 【3】项目硬件模块组成 【4】设计意义 【5】国内外研究现状 【6】摘要 1.2 设计思路 1.3 系统功能总结 1.4 开发工具的选择 【1】设备端开发 【2】上位机开发 1.5 参考文献 1.6 系统框架图 1.7 系统原理…

作者头像 李华
网站建设 2026/7/8 4:47:13

信创内网IM替代,为什么决不是“换一个聊天软件”那么简单

信创内网IM替代,为什么决不是“换一个聊天软件”那么简单 当某海外协作工具突然宣布停止在华服务时,一家大型制造企业的CIO在深夜召开了紧急会议。问题不止是“换个软件”,而是所有研发群组的历史记录、几十个自动化运维机器人的指令通道、以…

作者头像 李华
网站建设 2026/7/8 4:45:46

PRD写作的工程化方法:从模糊需求到可验证规格的完整路径

PRD写作的工程化方法:从模糊需求到可验证规格的完整路径 一、PRD为什么是一个工程问题? PRD(Product Requirement Document)的传统写法是叙事性的。"用户想要X功能,所以我们做Y"。这种方式在需求简单时够用&…

作者头像 李华