Claude API 成本直降90%:Prompt Caching 提示词缓存 Python 实战

同一个 1 万 token 的系统提示,不带缓存每次调用要 0.03,带上缓存后第 4 次起每次只要 0.003。到第 100 次调用,账单是 0.33 而不是 3.00。这个差价,就是 cache_control 一个参数带来的。

文章目录

一、先说结论:重复调用的钱,你一直在白交

我在香港做 FinTech,日常会用 Claude API 批量处理一堆东西------解析合同条款、提取财务报告字段、生成周报。最开始图省事,每次调用都把完整的 system prompt(包含一堆行业规则和示例)原样发过去。

结果月底看账单傻眼了:几千次调用,大部分 token 消耗全花在了那段一模一样、每次都重发的系统提示上。

直到我把那段静态内容加上 cache_control 标记,成本直接砍掉一大块。原因很简单------Anthropic 提供了一个叫 Prompt Caching(提示词缓存) 的机制:标记为可缓存的内容,第一次请求时写入缓存(略贵),之后相同前缀的请求直接从缓存读取(便宜 90%)。

这篇文章我把原理、定价、代码、踩坑一次性讲清楚。核心结论先放这:只要你重复调用同一个 Claude 且带长 system prompt / 参考文档 / few-shot 示例,Prompt Caching 就能帮你省掉大部分重复的输入成本。

收藏提示①:文末的缓存封装函数可以直接复用,套到你自己的调用链里就能看到 usage 里的缓存命中数。

二、环境信息

版本
Python 3.13.12
anthropic SDK 最新版
模型 claude-sonnet-4-6(示例用,实际以官方为准)
数据/价格 Anthropic 官方文档(价格会变,发布前请以官方定价页为准)

三、为什么能省 90%:三种 token 定价

Prompt Caching 把输入的 token 拆成了三种价格(以 Sonnet 4.6 为例,$3/M 基础输入):

token 类型 含义 价格 相对基础价
缓存写入 第一次发可缓存内容,写进服务端缓存 $3.75/M(5min) 1.25 倍
缓存读取 后续相同前缀,直接从缓存读 $0.30/M 0.1 倍
普通输入 不可缓存、每次重算的部分 $3/M 1 倍

关键点在于那个 0.1 倍 ------缓存读取只有基础输入的十分之一,也就是省 90%。而写入虽然贵 25%,但这是"一次性投入":只要同一个缓存块被命中两次以上,就开始回本。

算笔账(1 万 token 系统提示,$3/M 基础价):

复制代码
无缓存:每次 $0.03
有缓存:第 1 次写入 $0.0375,之后每次读取 $0.003

第 1 次调用:有缓存反而多花 $0.0075(写入溢价)
第 4 次调用:开始省钱
第 100 次调用:$0.33 vs $3.00 ------ 省了 89%

调用越频繁、静态内容越长,省得越狠。这就是为什么它最适合"多轮对话 + 长上下文 + 批量处理"的场景。

上图:调用次数从 1 到 100,无缓存成本线性增长,有缓存成本几乎走平------剪刀差就是省下来的钱。

四、两种用法:自动缓存 vs 显式断点

先记住缓存的一个核心规则:缓存按 tools → system → messages 的顺序层级累积,断点之前的静态内容才会被缓存。

4.1 自动缓存(最简单)

在请求顶层 加一个 cache_control 字段即可,系统会自动把断点放到最后一个可缓存的块上,随对话增长自动前移:

python 复制代码
import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    cache_control={"type": "ephemeral"},   # 一行开启自动缓存
    system="You are a helpful assistant that remembers our conversation.",
    messages=[
        {"role": "user", "content": "My name is Alex. I work on machine learning."},
        {"role": "assistant", "content": "Nice to meet you, Alex!"},
        {"role": "user", "content": "What did I say I work on?"},
    ],
)

# 打印 usage,能看到缓存相关的三个字段
print(response.usage.model_dump_json())

自动缓存最适合多轮对话------它不用你手动维护断点位置,对话每长一轮,断点就自动前移,之前的内容自动走缓存读取。

4.2 显式断点(精细控制)

cache_control 放在具体的 content block 上,精确指定哪些内容缓存:

python 复制代码
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "你是一个合同分析助手,提取关键条款、义务和风险点,输出结构化 JSON。",
            "cache_control": {"type": "ephemeral"}   # 缓存这段系统指令
        },
        {
            "type": "text",
            "text": LONG_INDUSTRY_RULES,             # 一堆行业规则,也缓存
            "cache_control": {"type": "ephemeral"}
        },
    ],
    messages=[{"role": "user", "content": contract_text}],  # 每次变化的合同文本,不缓存
)

显式断点适合静态内容 + 变化内容混着的场景------把不变的系统指令、规则、few-shot 示例缓存起来,每次变的正文单独传。

收藏提示②:cache_control={"type": "ephemeral"} 这个字段就是全部关键。自动缓存加在顶层,显式断点加在单个块上。记住这一个参数,就能上手。

五、完整实战:长文档批量分析

下面是我实际用的封装函数,把缓存逻辑包起来,批量分析同一批文档时能明显看到成本下降:

python 复制代码
import anthropic

client = anthropic.Anthropic()

# 缓存的静态部分:系统角色 + 一份固定的"分析规范"
def build_system() -> list:
    return [
        {
            "type": "text",
            "text": "你是香港金融数据分析助手。提取字段:金额、日期、交易对手、风险评级。输出 JSON。",
            "cache_control": {"type": "ephemeral"}
        },
        {
            "type": "text",
            "text": REFERENCE_GUIDE,   # 一份很长的行业分析规范,几千 token
            "cache_control": {"type": "ephemeral"}
        },
    ]

def analyze_document(doc_text: str):
    resp = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        system=build_system(),
        messages=[{"role": "user", "content": doc_text}],  # 每次变化的文档
    )
    # 看缓存命中情况
    usage = resp.usage
    print(
        f"缓存写入: {usage.cache_creation_input_tokens}, "
        f"缓存读取: {usage.cache_read_input_tokens}, "
        f"普通输入: {usage.input_tokens}"
    )
    return resp.content

# 批量处理 50 份文档
for doc in documents[:50]:
    analyze_document(doc)

跑起来后你会看到:第一份文档的 cache_creation_input_tokens 很大(写入缓存),从第二份开始 cache_read_input_tokens 稳定出现(命中缓存),input_tokens 只剩每份文档本身的量。

六、踩坑记录:这四个坑,我全踩过

  1. 最小 token 阈值 :缓存内容不够长,缓存根本不生效。Sonnet 4.6 要 2048 token 以上,Opus 4.6 要 4096 token 以上。如果系统提示只有几百 token,标记了也白标记------系统会静默跳过缓存。
  2. 断点别放在会变化的内容上 :如果你把 cache_control 放在一个包含时间戳或动态 ID 的块上,那每次哈希都不同,缓存永远命中不了,反而每次都在付"写入"的溢价。静态内容放断点,动态内容放断点之后。
  3. TTL 默认只有 5 分钟 :缓存从最后一次命中起算,5 分钟不用就失效。批量处理时如果中间隔太久,缓存会凉掉,下一次又是全价写入。有需要可以显式指定 "ttl": "1h"(1小时缓存,写入价是 2 倍,但适合长时间批处理)。
  4. 回溯窗口只有 20 块:缓存命中会向后查找最长匹配前缀,但最多回溯 20 个块。如果对话长得离谱,前一次的缓存条目可能掉出窗口,导致命中失败------长对话记得手动加多个断点。

七、什么时候该用、什么时候别用

值得用(能省大钱)

  • 长 system prompt(行业规则、角色设定、详细指令)
  • 固定参考文档(合同模板、代码库、规范文件)
  • few-shot 示例(几十个示例,每次重发很贵)
  • 多轮对话(对话历史自动缓存)

别用(反而亏)

  • 每次请求内容完全不同、没有重复前缀
  • 静态内容很短(低于最小 token 阈值)
  • 调用频率极低(缓存 5 分钟就失效,写入溢价赚不回来)

一句话:缓存省的是"重复"的钱,没有重复就没有节省。

八、写在最后

Prompt Caching 不是什么高深技巧,就是 Anthropic 给"重复发送相同前缀"这件事打了个折。但据我观察,身边不少用 Claude API 的人根本不知道这个参数,每个月都在为同一段系统提示重复付费。

把它加到你的调用链里,去看一眼 response.usage 里的 cache_read_input_tokens------如果这个数是 0,说明你的缓存根本没生效,要么内容太短,要么断点位置错了。把它调对,账单上省下来的数字会非常直观。

需要说明的是,价格和最小阈值是版本敏感信息,会随 Anthropic 调整而变化,本文数据以写作时的官方文档为准,动手前建议先查一下最新的定价页。

收藏提示③:如果这篇帮你省了钱,收藏 + 点赞,下次调整调用链时直接回来查。。

相关推荐
郝学胜-神的一滴1 小时前
并查集深度入门:从玄学抽象到 QuickFind & QuickUnion 源码实战
数据结构·c++·python·程序人生·算法·软件开发
tachibana21 小时前
怎么让大模型同时给意图节点打分
大数据·人工智能·ai·大模型·llm·prompt
她说可以呀1 小时前
Spring AI 常用 Advisor
人工智能·python·spring
小玮看世界1 小时前
[Python] str() 和 join() 的区别与实战避坑指南
前端·javascript·python
卷无止境2 小时前
FastAPI 的 WebSocket 装了些什么
后端·python·fastapi
码云骑士2 小时前
108-vLLM推理引擎-PagedAttention-连续批处理-吞吐提升10倍
python·vllm
DeepVisionary2 小时前
从微软砍掉Copilot的AI播客、Deep Research看AI产品“做减法“:个人版与企业版合并,超级应用呼之欲出
python·自动化
IT·侯老师2 小时前
qq-auto-reply
python
迷迭香yy2 小时前
大宗交易折溢价因子怎么挖掘本地化Python全流程实战
开发语言·人工智能·python