更新于

Claude Prompt Caching ROI 分析:什么场景值得开启缓存


Anthropic 在 Claude API 中引入了 Prompt Caching 功能,理论上可以将重复内容的输入 token 成本降低 90%。这个数字非常吸引人,但在实际项目里,「开了缓存就能省 90%」的情况并不普遍——能省多少,取决于你的使用模式。

本文用量化的方式拆解 Prompt Caching 的成本机制,帮你判断在你的场景里,启用缓存的实际 ROI 是多少,值不值得改造代码去支持它

一、Prompt Caching 的工作原理

Claude 的 Prompt Caching 允许你把一段前缀内容(通常是系统提示词、工具定义、或大段固定上下文)标记为可缓存。首次请求时,Anthropic 会在服务端缓存这段内容;后续请求如果包含同样的前缀,就可以读取缓存,而不必重新处理这段内容。

定价结构(以 Claude 3.7 Sonnet 为例,价格随 Anthropic 更新而变动,以官网为准):

Token 类型相对价格
普通输入 token基准价(1x)
缓存写入(首次)约 1.25x(贵 25%)
缓存读取(后续)约 0.1x(省 90%)
输出 token不受缓存影响

关键点:第一次请求反而更贵,因为要支付缓存写入费用。节省是从第二次请求开始累积的。

二、ROI 计算框架

盈亏平衡点公式

设可缓存前缀长度为 P tokens,普通输入价格为 r,则:

  • 不缓存时,每次请求前缀成本 = P × r
  • 启用缓存时:
    • 第 1 次:写入成本 = P × 1.25r
    • 第 2–N 次:读取成本 = P × 0.1r

N 次请求后的总节省额

节省 = (N-1) × P × r - (P × 1.25r - P × r) + (N-1) × P × r × 0.9
     = (N-1) × 0.9 × P × r - 0.25 × P × r
     = P × r × [(N-1) × 0.9 - 0.25]

盈亏平衡点(节省 > 0):

(N-1) × 0.9 > 0.25
N > 1 + 0.28 ≈ 1.28

理论上只要同一缓存被使用超过 2 次,就开始净节省。但这是最理想情况——前提是缓存命中率 100%,且缓存没有失效(Anthropic 的缓存 TTL 目前约为 5 分钟)。

实际 ROI 的关键变量

实际节省率 = 缓存命中率 × 0.9 - (1 - 缓存命中率) × 0 - 写入溢价 / 总请求数

影响实际 ROI 的因素:

  1. 缓存命中率:5 分钟内没有重复请求,这段缓存就失效了
  2. 前缀占总输入的比例:前缀占比越高,节省幅度越大
  3. 并发量:高并发场景下,相同前缀被多个并发请求命中,ROI 更高
  4. 请求间隔:间隔超过 5 分钟就需要重新写入缓存

三、适合 Prompt Caching 的场景

场景 1:带大型系统提示词的对话机器人

典型参数:

  • 系统提示词:2,000 tokens(品牌语调、回答规则、FAQ 背景)
  • 用户消息:平均 50 tokens
  • 高峰期 QPS:50 个并发会话

计算:

不缓存时,每次输入 = 2,050 tokens
缓存后,每次输入 ≈ 50(用户消息) + 200(缓存读取等效成本)tokens
等效节省 ≈ 1,800 tokens/次 ≈ 每次节省 88%

在高 QPS 场景下,缓存 TTL 内会有大量请求命中,这是 Prompt Caching 收益最高的场景

场景 2:文档分析工具(RAG 替代方案)

有些场景不适合做向量检索,而是需要让 LLM「读完整文档」后回答多个问题:

  • 一份 50,000 token 的合同文本
  • 同一个会话里,用户提出 10 个不同问题

不缓存:10 次 × 50,000 tokens = 500,000 tokens 输入成本
启用缓存:50,000(写入)+ 9 × 5,000(缓存读取等效)= 约 95,000 tokens 等效成本

节省约 81%,这类场景非常适合缓存。

场景 3:代码辅助工具(固定代码上下文)

把整个项目的关键文件(2–5 万 tokens)作为前缀,然后针对这个上下文反复提问/修改。每次写代码时,同一个前缀在 5 分钟内被多次使用,缓存命中率高,ROI 显著。

四、不适合 Prompt Caching 的场景

场景 1:低频 / 批处理任务

如果每次请求的前缀都不同(比如每个用户的个性化系统提示),或者请求间隔超过 5 分钟(夜间批处理),缓存命中率接近 0,写入溢价反而让成本更高。

结论:对于 Anthropic Batch API 类的批处理任务,Prompt Caching 没有收益,换用 Batch API 折扣(50% off)更实际。 详情见如何用 Anthropic Batch API 节省 50% 成本

场景 2:前缀很短的场景

如果系统提示词只有 100–200 tokens,即使 100% 命中缓存,绝对节省额也很小。在这种情况下,工程上引入缓存标记的改造成本可能比节省下来的钱更高。

建议:只有当可缓存前缀超过 1,000 tokens 时,引入缓存才有实质意义。

场景 3:前缀频繁变化

Prompt Caching 是基于前缀内容的精确匹配(或近似匹配)。如果你的系统提示词每次请求都动态注入用户信息,导致前缀内容不固定,缓存命中率会大幅下降。

修复方案:把固定部分和动态部分分离:

# 不好的做法:动态内容混入系统提示词
system_prompt = f"""
你是一个客服助手。
当前用户:{user_name},会员等级:{user_level}
[后面是 2000 字的固定规则...]
"""

# 好的做法:固定部分标记为可缓存,动态部分放用户消息
messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": "[2000 字固定规则...]",
                "cache_control": {"type": "ephemeral"}  # 标记为可缓存
            },
            {
                "type": "text",
                "text": f"当前用户:{user_name},会员等级:{user_level}\n用户问题:{user_question}"
            }
        ]
    }
]

五、代码实现:正确标记缓存断点

import anthropic

client = anthropic.Anthropic()

# 固定的大型系统上下文(可缓存部分)
SYSTEM_CONTEXT = """
你是一个专业的法律文件分析助手。
[在这里放入 5000+ tokens 的固定指令和背景知识...]
"""

def analyze_document(document_text: str, question: str) -> str:
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        system=[
            {
                "type": "text",
                "text": SYSTEM_CONTEXT,
                "cache_control": {"type": "ephemeral"}
            }
        ],
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": document_text,
                        "cache_control": {"type": "ephemeral"}  # 文档也可缓存
                    },
                    {
                        "type": "text",
                        "text": f"问题:{question}"
                    }
                ]
            }
        ]
    )
    
    # 检查缓存使用情况
    usage = response.usage
    print(f"输入 tokens: {usage.input_tokens}")
    print(f"缓存命中 tokens: {getattr(usage, 'cache_read_input_tokens', 0)}")
    print(f"缓存写入 tokens: {getattr(usage, 'cache_creation_input_tokens', 0)}")
    
    return response.content[0].text

# 第一次调用(写入缓存)
answer1 = analyze_document(contract_text, "甲方的主要义务有哪些?")
# 5 分钟内第二次调用(命中缓存)
answer2 = analyze_document(contract_text, "违约金条款在第几条?")

六、监控缓存效率

启用缓存后,建议监控以下指标来判断实际 ROI:

class CachingMetrics:
    def __init__(self):
        self.total_input_tokens = 0
        self.cache_hits = 0
        self.cache_misses = 0
        self.cache_creation_tokens = 0
        self.cache_read_tokens = 0
    
    def record(self, usage):
        self.total_input_tokens += usage.input_tokens
        cache_hit = getattr(usage, 'cache_read_input_tokens', 0)
        cache_create = getattr(usage, 'cache_creation_input_tokens', 0)
        
        if cache_hit > 0:
            self.cache_hits += 1
            self.cache_read_tokens += cache_hit
        elif cache_create > 0:
            self.cache_misses += 1
            self.cache_creation_tokens += cache_create
    
    def hit_rate(self) -> float:
        total = self.cache_hits + self.cache_misses
        return self.cache_hits / total if total > 0 else 0
    
    def estimated_savings(self, base_price_per_token: float) -> float:
        saved = self.cache_read_tokens * base_price_per_token * 0.9
        extra = self.cache_creation_tokens * base_price_per_token * 0.25
        return saved - extra

健康的缓存效率指标

  • 缓存命中率 > 70% → 效果显著
  • 缓存命中率 40–70% → 效果中等,可接受
  • 缓存命中率 < 40% → 考虑是否值得维护缓存逻辑

七、与其他成本优化手段的组合

Prompt Caching 不是万能的,它应该和其他成本优化手段结合使用:

优化手段适合场景节省幅度
Prompt Caching高频重复前缀可达 90%(命中部分)
Batch API低实时性批量任务固定 50%
模型降级(Haiku/mini)简单任务95%+
Token 裁剪历史消息过长20–50%
结构化输出减少解析复杂 JSON 输出10–20%

对于大多数生产项目,Prompt Caching + 模型降级的组合是性价比最高的方案:对高频请求用缓存减少输入成本,对简单任务换用小模型减少输出成本。

更多 Token 优化技巧可参考LLM Prompt Token 精简实践LLM 成本优化检查清单

八、相关阅读

如果你正在寻找成本合理的 Claude API 接入方案,YoTradeApi 提供国内直连的 Claude API 中转服务,支持 Prompt Caching,按量计费,适合各规模的生产应用。