缓存省的是哪一段
多轮对话和长系统提示里,大部分 token 每次都一模一样。缓存把这些前缀存在服务端,下次命中就按更低的价格计费,省下的钱与前缀长度成正比,与调用次数成正比。请求结构几乎不用改,变的是前缀的稳定程度。
粗略估算一句话就够:省下的钱 ≈ 前缀 token 数 ×(输入原价 − 命中价)× 命中次数。前缀两万 token、每天命中两百次,按 claude-sonnet-5 的价格算,一天省 9 美元左右,一个月接近 270 美元。
Anthropic:显式标记,写入更贵
Anthropic 的 prompt caching 要在请求里标出缓存点,给系统提示或文档块加 cache_control: {"type": "ephemeral"}。缓存写入按输入价的 1.25 倍计费,命中读取按 0.1 倍计费,缓存有存活时间,具体倍数与时长以官方文档为准。
claude-sonnet-5 在 Claude Max 分组输入 2.55 美元每百万 token,对应缓存写 3.19 美元、缓存读 0.255 美元。2 万 token 的前缀用 10 次:不缓存是 0.51 美元;缓存后首次写入 0.064 美元,后 9 次读取合计 0.046 美元,总共约 0.11 美元,省掉近八成。
前缀用两次就能回本。写入溢价只有 25%,每次读取省下 90%,多读一次就把多付的钱赚回来。
OpenAI:自动命中,前缀必须一致
OpenAI 的缓存不用改请求,服务端按前缀自动匹配,命中量在 usage.prompt_tokens_details.cached_tokens 里能看到。折扣力度因模型而异,最小前缀长度和保留时间也不一样,具体以官方文档为准,命中部分通常只有原价的几分之一。
它对前缀的要求更严格:从第一条消息开始逐 token 相同才算命中。在 system 里拼一个当前时间,或者在历史前面插一条"今天是几号",整段前缀就失效,cached_tokens 会直接归零。
提示词怎么排
把变化的部分往后放。系统提示、工具定义、参考文档、few-shot 示例放前面,用户输入和时间戳放后面。
- 工具定义的顺序固定,别按字典序每次重排。
- 文档拼接用固定的分隔符和标题。
- 多轮对话不在前面插入新消息,需要补上下文就写进末尾那条 user 消息。
- 模型名或版本号变了,缓存自然失效,这属于正常情况。
如果一次请求的前缀只有几百 token,缓存基本没意义,省下的钱还不够一次调用的零头。
一段可复用的请求
import requests
BASE = "https://ai.idcidiot.com/v1"
KEY = "sk-..."
# 前缀一个字都不要改,改了就重新计费
PREFIX = """你是财务对账助手,严格按下面的制度回答:
1. 出差住宿一线城市每晚不超过 600 元,其他城市 400 元。
2. 市内交通凭票报销,单次不超过 100 元。
...(把你的制度全文贴在这里,几万字也可以)"""
def ask(question: str) -> str:
r = requests.post(
f"{BASE}/chat/completions",
headers={"Authorization": f"Bearer {KEY}"},
json={
"model": "claude-sonnet-5",
"messages": [
{"role": "system", "content": PREFIX},
{"role": "user", "content": question},
],
"max_tokens": 800,
},
timeout=120,
)
r.raise_for_status()
data = r.json()
cached = data["usage"].get("prompt_tokens_details", {}).get("cached_tokens", 0)
print(f"prompt={data['usage']['prompt_tokens']} cached={cached}")
return data["choices"][0]["message"]["content"]
print(ask("出差住宿的标准是多少?"))
print(ask("打车费怎么报?"))如果渠道按 Anthropic Messages 协议转发,缓存点加在 system 的文本块上:{"type": "text", "text": PREFIX, "cache_control": {"type": "ephemeral"}}。这条路径是否开放,看模型页的说明。
什么时候不该开
一次性长文档、前缀每次都要变的任务、总量不到一两千 token 的短请求,都不值得缓存。缓存还会让排查变复杂:改了提示词忘了前缀已经变了,命中率掉下来,账单会先告诉你。
还有一类隐性成本:前缀缓存住以后,改动提示词要整段重发一次。版本迭代频繁的阶段,命中率会一直上不去,这时候先把提示词定稿,再考虑缓存。
判断模型和分组的价格差别,去 定价页 对一下;claude-sonnet-5 的参数在 模型页,OpenAI 系模型可以从 模型总览 里找 gpt-6-astra 这类长上下文型号。
先在日志里加上 cached_tokens,跑两天再决定要不要重排提示词。