审计 Claude 中转缓存,识别虚报与失效
文章分析第三方 API 中转可能因轮换上游账号、移除缓存参数或伪造返回字段,导致缓存失效或账单失真。内容包含缓存成本计算与审计脚本,强调检查会话路由和实际缓存行为。
AI 深度解读
Claude Code、Cline 用得越勤,长上下文的缓存账单越值得核对。作者审计了十多家第三方 API 中转,发现有些平台虽然宣称支持 Claude Prompt Caching,却因为路由不稳定、修改请求,甚至伪造用量数据,让用户付出了额外费用。
这篇最有用的提醒是:界面显示缓存命中,不足以证明你拿到了缓存折扣。 要把请求内容、缓存计数和实际扣费放在一起看。不过,作者也在推广自己的网关,文中的审计结论需要与产品宣传分开判断。
缓存为什么可能越用越贵
按原文给出的价格,写入缓存检查点收取基础输入价格的 1.25 倍,读取缓存收取 0.1 倍。所谓最高节省 90%,指的是命中部分的读取价格,首次写入反而贵 25%。
作者指出,Anthropic 的缓存按上游账户隔离,文中讨论的有效期是 5 分钟。如果中转把几十个 Key 放进池里轮询,第一次请求落到账户 A,第二次落到账户 B,后者就无法复用前者的缓存。
这里要区分 Key 和账户:多个 Key 是否属于同一账户,会影响这个推论。原文没有交代受审平台的具体账户结构。
另一个问题是前缀被修改。作者称,缓存要求前缀逐字节一致;网关如果在 system prompt 前面插入变化的时间戳、追踪标签或提示词,就可能破坏匹配。动态内容具体插在哪里很关键,不能据此推断请求中任何位置变化都会让全部缓存失效。
作者还给出了收支平衡公式。设命中率为 H,平均成本为:
1.25 × (1 - H) + 0.10 × H
令结果等于不缓存时的 1.0,可得 H 约为 21.7%。按这个模型,命中率低于约 22%,开缓存反而更贵。
前提是每次处理的缓存部分规模相同,未命中都产生写入费用。它不是整张账单的通用公式,输出费用、未缓存内容和中转自己的定价都没有算进去。
哪些中转行为会让缓存失真
作者列出的另外两种做法,直接涉及请求和账单的可信度。
一种是删除 cache_control。有些转售商宣称价格便宜 50%、完全兼容,却在转发前剥掉缓存配置,把请求交给不支持缓存的渠道。作者称,部分平台还会收取没有实际发生的缓存创建加价。
另一种是伪造 usage。代理能够控制返回的 JSON,可以通过内存中的前缀哈希识别重复内容,再往 cache_read_input_tokens 填入数字。CLI 因而显示命中,但实际扣费仍按普通输入价格计算。
这些都是作者报告的现象。原文没有公布平台名单、请求样本、账单截图或各类问题的出现比例,因此不能把它当成第三方中转行业的统计结论。
两次请求怎么检查,哪些结果还不能证明命中
作者建议准备超过 1024 tokens 的静态块,连续请求两次,间隔 2 秒:
第一次应看到 cache_creation_input_tokens > 1024;第二次应看到 cache_read_input_tokens > 1024,并且延迟下降。随后核对控制台,确认第二次缓存读取部分确实按 0.1 倍计费。
下面是原文探测脚本,用来提交相同 system 前缀、不同用户问题的两次请求。原文函数体缺少缩进,这里原样保留,直接运行会报错。
import time, requests
URL = "https://your-provider-endpoint.com/v1/messages"
KEY = "YOUR_API_KEY_HERE"
MODEL = "claude-sonnet-4-6"
prefix = "System Ref: " + ("Alpha Beta Gamma Delta " * 200)
def probe(q):
t0 = time.time()
r = requests.post(URL, headers={"x-api-key": KEY, "anthropic-version": "2023-06-01"},
json={"model": MODEL, "max_tokens": 50,
"system": [{"type": "text", "text": prefix, "cache_control": {"type": "ephemeral"}}],
"messages": [{"role": "user", "content": q}]}).json()
print(str(round(time.time() - t0, 2)) + "s | " + str(r.get("usage")))
print("--- Turn 1: Expect cache_creation ---")
probe("List 1")
time.sleep(2)
print("--- Turn 2: Expect cache_read & fast latency ---")
probe("List 2")
重点看包含 cache_control 的那一行,它显式设置了 {"type": "ephemeral"}。同时,重复 200 次文本不等于已经确认超过 1024 tokens,仍需核对实际分词结果和所用模型的缓存门槛,原文没有解释这个门槛对 claude-sonnet-4-6 是否适用。
延迟下降和缓存计数都只能提供线索,实际扣费才是省钱与否的关键。 如果用量和扣费都来自同一家代理,它们也不能独立证明上游确实发生了缓存命中。
我的判断
作者把注意力从「兼容接口」拉回到账单,这是对的。请求能成功返回,并不保证缓存语义、账户路由和计费方式都与上游一致。
但这仍是一篇带产品推广的经验分享。作者自建的 API Route 宣称兼容 OpenAI、Anthropic,支持会话粘性和细粒度日志,也提到进入官方 Docker Agent Docs 和 Dify Marketplace。原文没有提供对照测试,这些收录信息也不能替代缓存和账单验证。
直连可以减少中转改写请求、隐藏路由的环节;使用网关则需要确认它如何保持会话路由稳定。具体选哪种,不能只看标价折扣,也要看能否解释每次请求的费用。
能拿来做什么
- 给 Claude Code 或 Cline 接入新中转时,先按作者建议充值 $1 到 $5,用固定前缀完成两次请求,再核对缓存计数和扣费。
- 自建 Node 网关时,检查 system 内容和
cache_control是否完整转发,并确认同一会话是否会切换到不同上游账户。 - 排查缓存收益时,保存请求 ID、上游路由切换记录、缓存写入与读取计数;用连续多轮记录判断命中率,避免把一次成功当成长期保证。