LLM Prompt Caching 全解析:让 API 成本直降 90% 的工程实战
你的应用每秒钟都在把同一份系统提示词、同一批工具定义、同一段知识库文档重复发给大模型 API,并为此反复付费。Prompt Caching(提示词缓存)是 2026 年投入产出比最高的一项 LLM 成本优化——不改模型、不改架构,只改 Prompt 结构与几行配置,就能把输入成本砍掉 50%~90%。本文从 KV Cache 底层原理讲起,覆盖 Anthropic、OpenAI、Gemini、DeepSeek 四家最新接入方式与定价,附 7 个可运行代码与真实踩坑案例。
开篇:从一个真实业务场景说起
假设你负责一个企业级客服 RAG 机器人,架构非常简单:每次用户提问,应用把 系统提示词(约 500 tokens)+ 知识库检索结果(约 3000 tokens)+ 对话历史(约 2000 tokens)+ 用户问题(约 50 tokens) 拼成一条 5550 tokens 的请求发给 Claude。逻辑上毫无问题,账单却让你心惊肉跳。
按 Claude Sonnet 4.6 标准输入价 $3/百万 tokens 计算:日请求 1 万次、月输入约 1.67B tokens,月成本高达 $5,010——而其中 90% 的 token 是每天重复发送的同一批内容。更残酷的是,在 Agent 场景中问题会被放大十倍:一个会连续调用 30~50 次工具的 Agent,每一轮都把 System Prompt 和工具 Schema 重新发一遍。有开发者实测,一个几分钟的 Agent 任务烧掉近 50 美元,后台缓存命中率却是 0。
这就是 Prompt Caching 要解决的问题:让服务端记住你发过的前缀,下一次直接复用计算结果。Anthropic 官方宣称它能把长 Prompt 的延迟最高降低 85%,而缓存命中的输入 token 价格仅为正常的 1/10。2026 年,主流厂商已全部支持,且实现成本从"零代码改动"(OpenAI、DeepSeek)到"请求体里加一个字段"(Anthropic)不等。本文的目标很直接:让你彻底搞懂它的原理、学会四家厂商的接入方式,并避开那些让命中率归零、甚至引发数据泄露的坑。
技术背景与核心概念扫盲
要理解 Prompt Caching,得先厘清几个层层递进的概念。它们之间有严格的包含关系,很多文章混为一谈,这里一次讲清。
Tokenizer(分词器) 把文本切成 token(词元)并映射为整数 ID。相同的文本永远产生相同的 token 序列——这是缓存能工作的前提。
Embedding(嵌入) 把每个 token ID 变成高维向量。Transformer 的每一层都对这些向量做变换,其中最关键的运算是 Attention(注意力机制):每个 token 生成 Query(查询)、Key(键)、Value(值)三个向量,用 Query 与所有 Key 做点积、经 Softmax 归一化得到权重,再加权求和 Value。注意力的数学形式是:
$$\text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V$$
KV Cache(键值缓存) 是推理引擎内部的优化。LLM 逐 token 自回归生成,每生成一个新 token,理论上都要重新计算前面所有 token 的 Key/Value。KV Cache 把这些 Key/Value 向量缓存下来,后续只需计算新 token 的三个向量,复杂度从 O(n²) 降到 O(n)。这是所有生产级推理框架的标配。
Prompt Caching(提示词缓存) 是 KV Cache 的"跨请求"延伸:既然同一个前缀在多次请求中重复出现,那不如把该前缀的 KV 计算结果存在服务端,下次请求若前缀一致,直接复用——省掉的是 prefill(预填充)阶段最耗时的重复计算。它缓存的是注意力计算结果(二进制 KV 张量),不是对话文本,所以缓存命中不影响输出质量,连续发送十几次相同 Prompt 每次回复仍各不相同。
TTL(Time-to-Live,生存时间) 指缓存条目的存活时长,过期即失效。
TTFT(Time-to-First-Token,首 token 延迟) 指从发出请求到收到第一个输出 token 的耗时。prefill 是 TTFT 的主要来源,因此缓存命中能显著压低 TTFT。
一句话总结:KV Cache 是"一次请求内部"的复用,Prompt Caching 是"多次请求之间"的复用。前者是推理框架的事,后者是你要主动设计的事。
底层原理深度拆解
一次推理请求的完整旅程
大模型推理分两个阶段:prefill(预填充) 和 decode(解码)。prefill 阶段一次性处理整个输入 Prompt,计算所有 token 的 Key/Value 张量,产生第一个输出 token;decode 阶段逐 token 生成后续内容,每步只算新 token 的 Query/Key/Value。生成 100 个 token,就要 decode 100 次。
flowchart TD
A[用户 Prompt] --> B[Tokenizer 分词]
B --> C[Embedding 向量化]
C --> D["prefill 阶段<br/>一次性计算全部 token 的 K/V"]
D --> E["KV Cache 存储<br/>K/V 张量驻留显存"]
E --> F["decode 阶段<br/>每步仅计算新 token 的 Q/K/V"]
F --> G[输出新 token]
G -->|追加到上下文| E
G -->|达到终止条件| H[生成结束]
D -.->|"跨请求复用<br/>(Prompt Caching)"| I[服务端 KV 缓存池]
I -.->|"前缀哈希命中则直接加载"| E
图 1:一次 LLM 推理请求的两阶段流程,以及 KV Cache(请求内复用)与 Prompt Caching(请求间复用)的关系。
没有 KV Cache 时,生成第 10 个 token 要把前 9 个 token 的注意力全部重算;有了 KV Cache,只需做一次向量-矩阵乘法。而 Prompt Caching 更进一步:如果两个请求共享前缀,第二个请求甚至不用重新执行 prefill——直接从缓存池中把这段前缀的 KV 张量拼接进新的 KV Cache 即可。
服务端是怎么判断"命中"的
各家实现细节不同,但核心机制一致:对输入前缀做哈希,哈希一致即命中。以 Anthropic 为例,你在某个内容块上打上 cache_control 断点(cache breakpoint),服务端对该断点之前的所有 token 计算哈希作为缓存 Key。下一次请求如果前缀逐 token 完全一致(连一个空格都不能差),哈希匹配,命中缓存。
flowchart TD
A[新请求到达] --> B{前缀长度 ≥ 最小阈值?<br/>Anthropic/OpenAI 1024 tokens<br/>Gemini 4096 tokens}
B -->|否| C[不进入缓存路径<br/>全量计费]
B -->|是| D{断点前前缀哈希<br/>与缓存条目匹配?}
D -->|是| E[缓存命中<br/>跳过 prefill 计算<br/>按缓存读取价计费 10%]
D -->|否| F[缓存未命中<br/>正常 prefill 计算<br/>按缓存写入/全量价计费]
E --> G[只计算断点后的新增部分]
F --> H[计算结果写入缓存池<br/>更新 TTL 计时]
G --> I[输出]
H --> I
图 2:Prompt Caching 的命中判定流程——前缀哈希逐 token 精确匹配,任何字节差异都会导致未命中。
为什么缓存能便宜 90%:成本结构拆解
对服务商而言,prefill 是计算密集(compute-bound)阶段,吃 GPU 算力;decode 是访存密集(memory-bound)阶段。Prompt Caching 让高频重复的 prefill 只算一次,服务商省下算力,自然愿意给缓存读取大幅折扣。Anthropic 的定价逻辑最具代表性:
- 缓存写入(cache creation):正常价的 1.25 倍($3.00/M → $3.75/M,Sonnet 4.6)——首次计算要付出溢价
- 缓存读取(cache read):正常价的 0.1 倍($3.00/M → $0.30/M)——之后每次命中只付 1 折
- 盈亏平衡点:同一个前缀被读取 2 次以上 即回本,此后每一次命中都是纯赚
这个 1.25x 写入溢价极其关键,它意味着:低频、一次性请求用缓存反而更贵。缓存的经济性必须建立在"前缀稳定 + 高频重复"的前提上。DeepSeek 则凭借 MLA(Multi-head Latent Attention,多头潜在注意力)架构把 KV Cache 压缩到极小,敢把缓存直接落到硬盘阵列,缓存命中价压到常规的约 1/10,且对用户完全透明、默认开启。
手把手实战落地
下面按厂商逐一实战。所有代码基于 2026 年 8 月各 SDK 最新稳定版本,环境要求 Python ≥ 3.10,安装对应官方 SDK:
# Anthropic / OpenAI / Gemini 官方 SDK
pip install -U anthropic openai google-genai
实战 1:Anthropic 显式缓存(cache_control)
Anthropic 的缓存是手动开启的,你把哪个内容块标记为可缓存,服务端就缓存哪个块。最典型的场景是 RAG:把 5000 tokens 的产品知识库放进 system 并打上 cache_control,用户问题保持动态。
import anthropic
client = anthropic.Anthropic(api_key="YOUR_API_KEY")
# 静态知识库:所有用户共享、长期不变,是最高价值的缓存目标
KNOWLEDGE_BASE = """[此处放入 5000+ tokens 的产品文档/知识库内容]"""
def ask_question(user_question: str, conversation_history: list) -> str:
"""RAG 客服问答:知识库静态缓存,用户问题动态传入"""
response = client.messages.create(
model="claude-sonnet-4-6", # 2026 年最新稳定模型
max_tokens=1024,
system=[
{
"type": "text",
"text": "你是一个专业的售后客服助手,只能依据知识库回答。",
},
{
"type": "text",
"text": KNOWLEDGE_BASE,
# 关键:标记该内容块可缓存(cache breakpoint)
"cache_control": {"type": "ephemeral"},
},
],
messages=[*conversation_history, {"role": "user", "content": user_question}],
)
# 通过 usage 字段验证缓存命中情况
usage = response.usage
print(f"缓存写入 tokens: {usage.cache_creation_input_tokens}")
print(f"缓存读取 tokens: {usage.cache_read_input_tokens}")
return response.content[0].text
# 第一次调用:cache_creation_input_tokens > 0(建立缓存)
result1 = ask_question("如何申请退款?", [])
# TTL 内的后续调用:cache_read_input_tokens > 0(命中缓存,按 1 折计费)
result2 = ask_question("退款多久到账?", [{"role": "assistant", "content": result1}])
代码 1:Anthropic 显式缓存接入。首次调用 cache_creation_input_tokens 非零,后续 TTL 内 cache_read_input_tokens 非零且输入成本降到 1/10。
实战 2:Anthropic 多断点分层缓存
真实 Prompt 包含多种变化频率的内容,Anthropic 支持最多 4 个缓存断点,正好用于分层。原则:完全静态的放最前,次静态的随后,动态的放最后不缓存。
def multi_breakpoint_call(system_prompt: str, tenant_config: str,
user_message: str) -> str:
"""三层缓存:系统规则 + 租户配置缓存,用户消息不缓存"""
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[
# 断点 1:全局系统规则(所有人共享,缓存价值最高)
{"type": "text", "text": system_prompt,
"cache_control": {"type": "ephemeral"}},
# 断点 2:租户级配置(同租户共享、跨租户不同,天然隔离)
{"type": "text", "text": tenant_config,
"cache_control": {"type": "ephemeral"}},
],
messages=[{"role": "user", "content": user_message}],
)
return response.content[0].text
代码 2:多断点分层。注意租户配置块放在独立断点后——两个租户的字节不同,前缀哈希自然不同,不会互相命中,安全性由字节级匹配天然保证。
实战 3:OpenAI 自动缓存
OpenAI 的缓存是全自动的,无需任何标记。你只需要保证:① 前缀足够稳定;② 前缀长度超过 1024 tokens。它在服务端自动做前缀匹配并计价折扣。
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY")
LONG_SYSTEM_PROMPT = """你是企业的智能客服...(此处展开,务必超过 1024 tokens 才会触发缓存)"""
def auto_cached_chat(user_message: str) -> str:
"""OpenAI 自动缓存:零配置,但必须保证 system 前缀逐字节稳定"""
response = client.chat.completions.create(
model="gpt-5.4", # 2026 年主推旗舰,缓存读 90% off
messages=[
{"role": "system", "content": LONG_SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
# 关键:通过 usage.prompt_tokens_details.cached_tokens 统计命中率
details = response.usage.prompt_tokens_details
cached = details.cached_tokens if details else 0
total = response.usage.prompt_tokens
print(f"缓存命中率: {cached / total:.1%}({cached}/{total} tokens)")
return response.choices[0].message.content
代码 3:OpenAI 自动缓存。cached_tokens 字段持续为 0 时,说明动态内容泄漏进了 system 前缀,需要回头检查 Prompt 结构。
实战 4:Gemini 显式 Context Caching
Gemini 走的是另一条路:显式创建一个命名缓存对象,按小时付存储费,请求时用 cached_content 引用它。适合"一份大文档要被反复分析"的场景,比如代码审查流水线把整个代码库缓存一次,跑多轮分析。
import datetime
from google import genai
from google.genai import types
client = genai.Client(api_key="YOUR_API_KEY")
LARGE_DOCUMENT = """[100k tokens 的代码库/长文档]"""
# 创建缓存:一次性计算并存储,之后按存储时长计费
cache = client.caches.create(
model="models/gemini-3-flash-preview", # 2026 年最新模型
config=types.CreateCachedContentConfig(
display_name="codebase_cache",
system_instruction="你是一个资深的代码审查助手。",
contents=[types.Content(role="user",
parts=[types.Part(text=LARGE_DOCUMENT)])],
ttl=datetime.timedelta(hours=1), # TTL 即"真相衰减预算",按需设置
),
)
def review_code(code_snippet: str) -> str:
"""复用已创建的缓存做多轮分析,只对新增 snippet 计费"""
response = client.models.generate_content(
model="models/gemini-3-flash-preview",
contents=code_snippet,
config=types.GenerateContentConfig(cached_content=cache.name),
)
return response.text
# 用完后删除缓存,停止存储计费(Gemini 独有的收费项,务必清理)
client.caches.delete(name=cache.name)
代码 4:Gemini 显式 Context Caching。存储费是按 token 数 × 小时计算的,低频任务用显式缓存前必须先算账。
实战 5:DeepSeek 硬盘缓存(零改动)
DeepSeek 的 Context Caching on Disk 对所有用户默认开启,无需任何代码改动。它把 KV Cache 存到分布式硬盘阵列(得益于 MLA 架构,缓存体积极小),只要后续请求与之前请求存在前缀重复即自动命中。你唯一要做的是读取 usage 字段验证并统计收益:
from openai import OpenAI # DeepSeek 兼容 OpenAI SDK 协议
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.deepseek.com",
)
def deepseek_chat(user_message: str, history: list) -> str:
response = client.chat.completions.create(
model="deepseek-chat",
messages=[*history, {"role": "user", "content": user_message}],
)
# 命中缓存的输入 token 会出现在 cached_tokens 中
details = response.usage.prompt_tokens_details
print(f"本次缓存命中 tokens: {details.cached_tokens if details else 0}")
return response.choices[0].message.content
代码 5:DeepSeek 零配置缓存。官方定价中缓存命中的输入价格约为常规的 1/10,高峰/低谷时段价格不同,命中判定同样是前缀匹配。
实战 6:缓存命中率监控与成本核算
没有观测就没有优化。生产环境必须把每次响应的 usage 汇总成可追踪的指标,用真实数据驱动决策——而不是靠"感觉便宜了"。
from dataclasses import dataclass, field
from collections import deque
@dataclass
class CacheMetrics:
"""缓存命中率与成本节省追踪器(以 Claude Sonnet 4.6 为例)"""
total_requests: int = 0
cache_hits: int = 0 # 有缓存读取的请求数
total_input_tokens: int = 0
cached_tokens: int = 0
recent_hit_rates: deque = field(default_factory=lambda: deque(maxlen=100))
BASE_PRICE = 3.00 # 标准输入 $/M tokens
READ_PRICE = 0.30 # 缓存读取 $/M tokens(1 折)
@property
def request_hit_rate(self) -> float:
"""请求级命中率:有多少请求吃到了缓存"""
return self.cache_hits / self.total_requests if self.total_requests else 0.0
@property
def token_cache_rate(self) -> float:
"""Token 级命中率:输入 token 中有多少走了缓存"""
return self.cached_tokens / self.total_input_tokens if self.total_input_tokens else 0.0
@property
def saved_usd(self) -> float:
"""相比无缓存省下的钱:命中 token × (标准价 - 缓存价)"""
return self.cached_tokens * (self.BASE_PRICE - self.READ_PRICE) / 1_000_000
metrics = CacheMetrics()
def tracked_call(system_prompt: str, user_message: str) -> str:
"""带缓存追踪的 LLM 调用(Anthropic 版)"""
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[{"type": "text", "text": system_prompt,
"cache_control": {"type": "ephemeral"}}],
messages=[{"role": "user", "content": user_message}],
)
usage = response.usage
cache_read = getattr(usage, "cache_read_input_tokens", 0) or 0
metrics.total_requests += 1
metrics.total_input_tokens += usage.input_tokens
metrics.cached_tokens += cache_read
if cache_read > 0:
metrics.cache_hits += 1
# 每 10 次请求输出一次关键指标,接入 Prometheus 后改为上报
if metrics.total_requests % 10 == 0:
print(f"请求命中率: {metrics.request_hit_rate:.1%} | "
f"Token 缓存率: {metrics.token_cache_rate:.1%} | "
f"累计节省: ${metrics.saved_usd:.2f}")
return response.content[0].text
代码 6:缓存监控类。两个命中率指标含义不同——请求命中率低说明"前缀不稳定",Token 缓存率高说明"静态内容占比大",要分开看。
实战 7:缓存友好 Prompt 构建器
最后把全部经验固化成"缓存友好 Prompt 构建器",作为团队统一的 Prompt 组装入口,从源头杜绝动态内容泄漏。
import json
class CacheOptimizedPromptBuilder:
"""缓存友好的三层 Prompt 构建器:
第 1 层静态(跨会话不变)→ 第 2 层会话级(会话内稳定)→ 第 3 层动态(每次变化)
"""
def __init__(self):
self.static_context = "" # 公司信息、产品手册、工具定义等永远不变的内容
self.session_context = "" # 用户画像、偏好等会话内稳定的内容
self.dynamic_content = "" # 每次请求都不同的内容
def set_static(self, text: str):
self.static_context = text
def set_session(self, user_profile: dict, preferences: dict):
"""会话级上下文:对字段排序,确保相同内容生成字节级一致的字符串
这是缓存命中的前提——dict 的键顺序不稳定会直接打碎前缀"""
self.session_context = (
"用户信息:" + json.dumps(user_profile, ensure_ascii=False, sort_keys=True)
+ "\n偏好设置:" + json.dumps(preferences, ensure_ascii=False, sort_keys=True)
)
def build(self, user_message: str) -> dict:
"""动态内容永远追加在最后,绝不插入静态前缀中间"""
return {
"system": [
{"type": "text", "text": self.static_context,
"cache_control": {"type": "ephemeral"}},
{"type": "text", "text": self.session_context,
"cache_control": {"type": "ephemeral"}},
],
"messages": [
{"role": "user",
"content": f"[{self.dynamic_content}]\n{user_message}"},
],
}
代码 7:缓存友好构建器。sort_keys=True 与动态内容后置,是让缓存命中率从 0 拉到 80%+ 的两个关键细节。
关键细节与踩坑指南
这一节是真实生产经验的核心。下面是 5 个高频坑,每一个都对应真实的账单事故。
坑 1:系统提示里混入动态内容,命中率直接归零
最常见的错误:把时间戳、请求 ID、用户问候语塞进 System Prompt。
# ❌ 错误:时间戳在 System Prompt 里,每秒都不同 → 缓存永远不命中
system = f"当前时间是 {datetime.now().isoformat()}。你是客服助手..."
# ✅ 正确:时间戳挪到 user 消息里,System Prompt 保持完全静态
system = "你是客服助手。..."
user_msg = f"[{datetime.now().isoformat()}] 用户问:{question}"
同样的坑还有:在 system 里动态拼接用户实时状态、把 AGENTS.md / MEMORY.md 每轮实时刷新后塞进 system。凡是要变的,全部放到断点之后。
坑 2:知识库检索结果排序不稳定
RAG 场景里,相同的查询可能因为向量检索排序微变、或命中文档顺序不同,产生字节不同的上下文,缓存随之失效。解决:按文档 ID 稳定排序后再拼接。
# ❌ 错误:检索结果顺序不稳定 → 相同查询不同前缀
context = "\n".join(doc.content for doc in retrieved_docs)
# ✅ 正确:按文档 ID 排序,保证相同查询永远得到相同字节的前缀
context = "\n".join(
doc.content for doc in sorted(retrieved_docs, key=lambda d: d.id)
)
坑 3:Agent 的 Plan/Act 模式切换改了 System Prompt 和工具列表
Agent 场景命中率为 0 的头号元凶:进入 Plan 模式时换了一套 System Prompt、增减了工具列表,导致前缀彻底变化。排查实录显示,某 Agent 一个任务几分钟烧掉近 50 美元,后台命中率 0,原因正是"模式切换改前缀"。正确做法:System Prompt 与工具 Schema 全局恒定,模式限制交给 Policy 层在应用侧兜底,而不是每轮改 Prompt。
坑 4:MCP 工具动态刷新打碎 Tools Schema
工具列表里的 JSON Schema 一旦有字段增减、描述微调,前缀哈希就变。工具定义是 Agent 最大的静态缓存块(常占 2000~5000 tokens),务必让它在会话生命周期内保持不变;低频变更内容做快照,不要每轮实时刷新。
坑 5:缓存 Key 是正确性边界,不是计费旋钮
这是最隐蔽、最危险的坑。缓存断点之上的内容,等于你向服务商宣告"这些事实可以在请求之间互换"。如果你为了凑够前缀长度、提高命中率,把用户级权限、租户配置、个性化偏好放到了断点之上,那么当两个用户的字节前缀一致时,一个用户会读到另一个用户的上下文——这不是缓存泄露,是你把边界划错了地方。
业界已有实证:NDSS 2025 发表的 PROMPTPEEK 研究表明,多租户共享 KV 缓存存在侧信道攻击,攻击者能通过计时"哪些前缀已被预热"来重建其他用户的 Prompt。同时,缓存的 TTL 就是缓存内容的"真相衰减预算":5 分钟 TTL 意味着你愿意在事实变化后 5 分钟内继续提供旧事实。用户改了权限却立刻看到旧行为,用户会认为这是 Bug。
修复原则:
- 跨租户泄露 → 把主体身份纳入缓存 Key(租户块放在独立断点,字节不同自然隔离)
- 过期个性化 → 加失效逻辑:事实变化时更新块内的版本号/内容哈希,强制前缀哈希改变导致未命中
- 命中率必须与"正确性探针"并列监控:构造跨租户、跨新鲜度的评估请求,断言响应不携带他人事实
生产环境最佳实践
Prompt 结构黄金法则:不变在前,变化在后
flowchart TB
subgraph 缓存层1["断点 1:完全静态(缓存价值最高)"]
A1[System Prompt 系统规则]
A2[Tool Definitions 工具 Schema]
A3[Few-shot 示例]
end
subgraph 缓存层2["断点 2:租户级 / 半静态"]
B1[租户策略与品牌配置]
B2[知识库检索结果(按 ID 稳定排序)]
end
subgraph 不缓存["断点之后:动态(每次全价)"]
C1[对话历史]
C2[用户最新消息 / 时间戳]
end
A1 --> A2 --> A3 --> B1 --> B2 --> C1 --> C2
图 4:缓存友好的 Prompt 分层结构——静态内容按变化频率分层缓存,动态内容全部后置。
可直接复用的生产配置模板
- System Prompt 完全静态化:版本号管理,变更走发布流程,不热插拔
- 知识库块按 ID 稳定排序 + 内容哈希版本化(知识更新时改版本号,强制重写缓存)
- Agent 场景:工具列表会话内恒定;模式切换不碰 Prompt,交给应用层 Policy
- TTL 按层级选择:静态共享内容用长 TTL;用户级可变内容用短 TTL 或不缓存
- 监控:请求命中率 + Token 缓存率 + 节省金额三指标接入 Prometheus/Grafana;配套跨租户正确性探针
- 清理:Gemini 显式缓存用完即删,避免存储费累积;DeepSeek 无需管理
与 Batch API 叠加
Anthropic 的 Batch API 给所有 token 打 5 折,与缓存读取的 1 折叠加后,重复部分总节省可达 95%。批量数据提取、离线分析等任务强烈建议组合使用。
横向对比与选型建议
截至 2026 年 8 月,四家主流厂商的缓存能力对比如下(定价为官方公开价,可能随版本调整):
| 维度 | Anthropic Claude | OpenAI GPT-5.x | Google Gemini | DeepSeek |
|---|---|---|---|---|
| 接入方式 | 显式 cache_control 断点 |
全自动,零代码 | 显式命名缓存 + 隐式缓存 | 全自动,默认开启 |
| 缓存读折扣 | 90%($3.00→$0.30/M,Sonnet 4.6) | 90%($2.50→$0.25/M,gpt-5.4) | 90%(显式缓存读 $0.0075/M,Flash) | ~90%(缓存命中约 $0.007/M 非高峰) |
| 缓存写成本 | 1.25x 溢价 | 无额外费用 | 无写入费,但按小时收存储费 | 无额外费用 |
| 最小缓存长度 | 1024 tokens | 1024 tokens | 4096 tokens(显式) | 无公开门槛 |
| TTL | 5 分钟(默认,命中刷新) | 约 24 小时 | 1 分钟 ~ 24 小时可配 | 较宽松 |
| 断点数量 | 最多 4 个 | 自动前缀 | 1 个缓存对象 | 自动前缀 |
| 与 Batch 叠加 | 支持(最高 95% 节省) | 不支持 | 不支持 | — |
选型决策路径
- 已经在用 OpenAI:先修 System Prompt 顺序,迁移到 gpt-5.4 享受 90% 缓存折扣,零代码改动,收益立现。
- 在 Anthropic 且 system 长 / RAG 文档大:加
cache_control,盯cache_read_input_tokens。高频场景(命中率 >80%)Claude 总成本最低,但要接受首次写入 1.25x 溢价。 - 一份大文档被反复分析(代码审查、文档问答):Gemini 显式 Context Caching 最合适——缓存一次、多轮复用,但务必算清存储费、用完即删。
- 国内链路 / 预算极敏感:DeepSeek 硬盘缓存零配置、零管理成本,MLA 架构让缓存命中价格压到极低,是性价比之选。
性能实测与效果验证
权威评测:PwC 三家厂商 500 会话实测
2026 年 1 月,普华永道团队在 DeepResearch Bench 上对 OpenAI、Anthropic、Google 三家旗舰模型做了系统性评测(arXiv:2601.06007),每个 agent 会话携带 10000-token system prompt,累计 500+ 会话:
- API 成本降低 41%~80%,四款模型全部达到统计显著
- TTFT 提升 13%~31%(缓存命中的前缀越长,收益越明显)
- 关键发现:策略性缓存边界控制(只缓存 system prompt / 排除动态工具结果)比"朴素全量缓存"收益更一致——朴素全量缓存可能因动态内容反复触发缓存写入而反而增加延迟

图 3:PwC 2026 年评测结果——Prompt Caching 在各旗舰模型上带来 41%~80% 的成本降低与 13%~31% 的 TTFT 提升(来源:arXiv:2601.06007)。
成本核算模型(可复算)
以客服 RAG 场景,Claude Sonnet 4.6 为例(日 1 万次、月 30 天、输入 5550 tokens/次,其中静态 5000 + 动态 550):
| 场景 | 计算过程 | 月输入成本 |
|---|---|---|
| 无缓存 | 5550 × 30 万 × $3/M | $4,995 |
| 有缓存(高命中) | 动态 550×$3/M + 缓存读 5000×$0.30/M | $945 |
| 节省比例 | (4995 − 945) / 4995 | 81% |
再叠加 Anthropic Batch API 的 5 折,总节省可达 95%。注意:若前缀不稳定导致频繁"写入",写入 1.25x 溢价会吃掉收益——这正是把缓存监控指标接入生产的原因。
延迟收益
Anthropic 官方声称长 Prompt 延迟最高降低 85%;实测中,当全部输入 token 命中缓存时,TTFT 下降明显,而逐 token 生成速度(TTST)保持不变——因为缓存只跳过了 prefill。这意味着缓存命中的请求既便宜又快,是少见的"省钱又提速"的优化。
总结与未来展望
Prompt Caching 是 2026 年 LLM 成本优化中投入产出比最高的一项技术:不改模型、不改架构,只需把静态内容前置、动态内容后置,再按厂商规则接入,即可获得 50%~90% 的输入成本下降和 13%~31% 的首 token 延迟改善。它的本质是 KV 计算结果的跨请求复用,缓存的是注意力张量而非文本,因此不影响输出质量。但请记住:缓存断点是正确性边界,不是计费旋钮——静态共享内容进缓存,用户级可变内容必须留在断点之下,命中率要配合正确性探针一起监控。未来,随着 DeepSeek MLA 类架构与 LMCache 类 KV 卸载层(NVMe/远端存储)的成熟,缓存将走向跨引擎、跨节点的"AI 原生知识"复用,Prompt Caching 会从"可选项"彻底变成所有 LLM 应用的默认底座。