返回博客

AI 入门指南

什么是提示缓存?重复的提示如何被复用

提示缓存让 API 复用你请求中未变化的部分。了解它在 usage 字段中是什么样子,以及如何估算账单。

作者:CheapTokens Team发布于 更新于 6 分钟阅读

封面:什么是提示缓存,配有一个聊天界面在问为什么重复的提示又被计费了
本页内容
  1. 那个反复重读同一页面的客服机器人
  2. 什么算“相同”:前缀规则
  3. 如何查看:usage 中的缓存字段
  4. 它对账单的影响
  5. 五分钟自己试一下

提示缓存意味着 API 会记住你请求的开头部分,并在你下次发送相同开头时复用它。你每次调用仍然发送完整文本,但提供商可以跳过重新读取重复部分的工作,部分提供商还会对这部分按更低费率计费。它只对请求的开头生效,而且仅当该开头完全相同时才有效。

那个反复重读同一页面的客服机器人#

假设你运营一个每天处理 2,000 张工单的客服机器人。每个请求都以相同的 3,000 个 token 开头:语气风格、退款规则、配送政策。之后是一行客户消息,比如“我的订单在哪?”(如果对 token 还没有概念,请先看什么是 token。)

没有缓存时,提供商要为第 1 张工单、第 2 张工单和第 2,000 张工单重新读取全部 3,000 个 token 的规则。同一页,读了 2,000 遍。有了缓存,第一个请求支付读取它的全价,之后以相同文本开头的请求可以复用这项工作。

两个请求开头相同、最后一行不同
请求 2 重复了请求 1 的开头;只有最后一行不同。

DeepSeek 的 API 指南(2026 年 10 月 24 日查阅)描述的正是这一点:上下文缓存默认开启,无需修改代码,后续请求只要前缀有重叠就算作“缓存命中”。只有输入会被缓存。答案每次都会重新生成。

什么算“相同”:前缀规则#

缓存从第一个字符开始匹配。你的请求一旦与缓存内容不同,该点之后的所有内容都算新的。这就是为什么请求的顺序比长度更重要。

下面这个错误会悄悄让缓存失效。开发者想让机器人知道时间,于是把它放在最前面:

text
Current time: 14:03:22
You are a support assistant for a shop...
(3,000 tokens of rules)

时间每秒都在变,所以每次请求的第一行都不同,它之后的内容都无法匹配。解决办法是把会变化的内容移到末尾:

text
You are a support assistant for a shop...
(3,000 tokens of rules)
Current time: 14:03:22
Customer: Where is my order?

现在 3,000 个 token 的规则排在最前并保持不变。同样的逻辑也适用于另外两种常见情况:长对话在每一轮都会重发完整历史,因此旧消息就是一个现成的重复开头(更多内容见为什么长对话更贵);而智能体在每一步都会重复其工具定义和指令。

缓存也是尽力而为的。DeepSeek 表示,缓存需要几秒钟构建,命中需要与现有缓存前缀单元完全匹配,不保证命中率,未使用的缓存会被清除,通常在数小时到数天内。因此,在第一个请求后半秒发出的第二个请求可能还不会命中,而且命中覆盖的范围可能小于你的整个前缀。

如何查看:usage 中的缓存字段#

你不必猜测它是否生效。每个提供商都会在响应的 usage 部分用自己的字段名报告。

DeepSeek 使用两个字段:

  • prompt_cache_hit_tokens — 在缓存中找到的输入 token
  • prompt_cache_miss_tokens — 未在缓存中找到的输入 token

假设你的第一张客服工单返回 prompt_cache_hit_tokens: 0 和 prompt_cache_miss_tokens: 3200,一分钟后的一张工单显示 prompt_cache_hit_tokens: 3000 和 prompt_cache_miss_tokens: 200。那 3,000 个 token 的规则被复用了;只有新的客户消息和少量 token 是从头读取的。如果每次调用的命中数都保持为零,请检查请求的开头:那里有内容在变化。

Anthropic 的工作方式不同,因为你需要标记要缓存的内容。你在请求或内容块中添加 cache_control,类型为 ephemeral:

json
{
  "model": "your-model-id",
  "max_tokens": 300,
  "system": [
    {
      "type": "text",
      "text": "You are a support assistant... (long rules)",
      "cache_control": {"type": "ephemeral"}
    }
  ],
  "messages": [{"role": "user", "content": "Where is my order?"}]
}

根据 Anthropic 的提示缓存文档(2026 年 10 月 24 日查阅),响应会报告三个数字:cache_creation_input_tokens(本次写入缓存)、cache_read_input_tokens(从缓存读取)和 input_tokens(最后一个缓存断点之后的内容)。假设第一次调用显示 cache_creation_input_tokens: 10000、cache_read_input_tokens: 0;第二次显示 0 和 10000。这就是先写缓存、后读缓存。

屏幕上有一个陷阱。短于模型最小长度(取决于模型,为 512、1,024 或 4,096 个 token)的提示会在不缓存的情况下处理,也不会报错。你会在两个缓存字段中都看到零,且没有任何警告。默认生命周期为 5 分钟,每次使用时免费刷新;可选的 ttl 设为 1h 可以延长保留时间。

它对账单的影响#

缓存会改变重复部分的价格,所以值得算一次。Anthropic 在基础输入价格上列出了倍数:5 分钟生命周期的缓存写入费用为 1.25×,读取费用为 0.1×(Opus 5.5 和 Sonnet 5.5 为 0.05×)。假设一个 10,000 token 的前缀在 5 分钟窗口内被 20 个请求复用,使用标准的 0.1× 读取:

10,000 × 20 = 200,000 个 token,按无缓存的基础价格计算

10,000 × 1.25 = 12,500,用于写入缓存的第一个请求

19 × 10,000 × 0.1 = 19,000,用于读取缓存的 19 个请求

12,500 + 19,000 = 31,500 个 token 等价值,使用缓存时

因此,重复部分的成本远低于未缓存金额的五分之一。但要注意:如果请求之间超过 5 分钟,下一个请求会再次以 1.25× 写入缓存,而一个很少使用的前缀最终可能比完全不用缓存还贵。

现在回到开头的机器人,作为全价基线。每天 2,000 个请求,每个请求 3,000 个输入 token 和约 300 个输出 token:

2,000 × 3,000 = 每天 6,000,000 个输入 token

2,000 × 300 = 每天 600,000 个输出 token

下表将这一天的工作负载按每个可用的 CheapTokens 模型定价,并与 OpenRouter 对比:

模型 每次请求 2,000 次请求 OpenRouter,2,000 次请求
GLM-5.3-Flash $0.000072 $0.144 $0.293
DeepSeek-V4-Flash $0.000075 $0.15 $0.379
MiniMax-M2.7 $0.0002 $0.39 $2.52

每次请求 3,000 个输入 token 和 300 个输出 token。每 100 万 token 的价格为当前价格,会随我们的资费一同变动;OpenRouter 列显示相同工作负载的参考价格。

DeepSeek-V4-Flash 在输入和输出合计的总价上比 OpenRouter 便宜,而且工作负载轻松适配:380K 上下文,每个答案最多 32,768 个输出 token。这是工作负载的全价成本:输入 token 数 × 每 token 价格。长而稳定的前缀正是输入占比最大的地方。

五分钟自己试一下#

计划:用两个不同的问题发送两次相同的长系统提示,然后查看 usage。把你自己的规则文本放进 support_rules.txt(一两页文本就够了)。端点是 OpenAI 兼容的 CheapTokens API,你可以从账户中获取密钥。

python
from openai import OpenAI

client = OpenAI(base_url='https://api.cheaptokens.dev/v1', api_key='YOUR_API_KEY')

SYSTEM = open('support_rules.txt').read()  # long, never changes

for question in ['Where is my order?', 'Can I change the address?']:
    r = client.chat.completions.create(
        model='deepseek-ai/DeepSeek-V4-Flash-0731',
        messages=[
            {'role': 'system', 'content': SYSTEM},
            {'role': 'user', 'content': question},
        ],
        max_tokens=300,
    )
    print(r.usage)

打印输出中要检查什么:prompt_tokens 告诉你请求有多大。两个请求携带相同的 SYSTEM 文本,所以这个数字的大部分会在请求之间重复——大致就是你的规则文件的大小。这个重复的开头正是像上面提到的 DeepSeek API 或 Anthropic 这样支持缓存的提供商可以复用的部分。现在做一个关于顺序的练习:在 SYSTEM 顶部添加一行当前时间(datetime.now()),然后再次运行。两个请求不再共享开头,因为它们从第一行起就不同。把同一行放到提示末尾,共享的开头就回来了。

给你自己的提示的一份简短清单:

  1. 稳定文本在前:指令、规则、工具定义、示例。
  2. 变化文本在后:日期、用户名、最新消息。
  3. 保持前缀逐字节相同——多一个空格也算不同。
  4. 在疑惑为什么没有缓存之前,先检查提供商的最小长度。
  5. 改动后查看 usage 字段,而不是改动前。

要为你自己的工作负载定价,请打开定价页面并填入你的输入和输出大小,或者从 DeepSeek 页面开始。第一个请求跑通后,对任何你写的提示做同样的估算只需一分钟。关于请求两侧的成本,请参阅输入 token 与输出 token。