你的LLM缓存让你付出双倍成本省钱(并且有道理)

几周前我写了一篇文章,解释了为什么你发给Claude的99%数据已经在缓存里。KV张量、VRAM、本地SSD——所有的内部机制。但我遗漏了最痛的部分:账单。 因为prompt缓存是那种看起来像超值优惠的东西,但一旦仔细看看数字,你就会发现为了节省成本,你竟然被要求付更多的钱。 成本悖论 让我们用一些数字来说明。在Claude Sonnet的定价中: 项目 每百万tokens价格 常规输入 $3.00 缓存写入 $3.75 (1.25倍) 缓存读取 $0.30 (0.10倍) 注意一件事:写入缓存的成本比直接处理输入高25%。你为了让下一次使用更便宜而需要额外付费。 这就像加入Costco那样。年费有点心疼。但如果买得足够多,就会值回票价。 问题是,“足够多”取决于你能在缓存过期前读取它的次数。 什么时候你会亏钱? 假设你用cache_control发了一个100K tokens的prompt。第一次请求: 100,000 tokens × $3.75/M = $0.375 (缓存写入) 如果你没有用缓存发送它: 100,000 tokens × $3.00/M = $0.300 (常规输入) 你额外多付了$0.075,比常规价格高出25%。你亏钱了。 现在第二次请求,同样有100K tokens的前缀: 100,000 tokens × $0.30/M = $0.030 (缓存读取) 对比来看: 100,000 tokens × $3.00/M = $0.300 (常规未缓存输入) 你节省了$0.27。两次请求的总成本不仅回本了之前多支付的$0.075,现在还实现了盈亏平衡。 盈亏平衡点是1.4次读取。 用更直白的话说:如果你计划在接下来的5分钟内至少重复使用该前缀两次,缓存就是值得的。 为什么对Claude Code来说使用缓存是明智选择 在Claude Code的一次会话中,每条消息都会包含system prompt、工具定义以及整个对话历史。每条消息都在重复发送相同的上下文。如果没有缓存,每次发送“把这个按钮换个颜色”,你都需要为相同的150K tokens上下文支付$3.00/M。 没人能负担得起这个。 而有了prompt缓存,你只需为写入缓存支付一次费用,之后每次读取只需要$0.30/M。在包含150K上下文的50条消息会话中,差距很明显: 无缓存: 50 × 150,000 × $3.00/M = $22.50 有缓存: 1 × 150,000 × $3.75/M + 49 × 150,000 × $0.30/M = $2.77 从$22.50降到$2.77。节省了88%。这就是为什么Anthropic默认在Claude Code中启用缓存。如果不这样做,从经济角度看是不可行的。 ...

2026年3月10日 · Fernando

RustyClaw:我要用 Rust 重写一个AI代理(因为梗在召唤我)

“你知道 Rust 最棒的一点是什么吗?它不会允许你编译粗制滥造的代码。你知道最糟糕的一点是什么吗?起初你写的所有代码都是粗制滥造的。” —— 蟹老板,大概是这样说的 比一个 AI 代理更好的是什么?是一个用 Rust 重写 的 AI 代理。 如果你上网超过五分钟,就会知道这个梗。不管是什么项目:文本编辑器、DNS 服务器、BMI 计算器,总会有人跳出来评论“你应该用 Rust 重写它”。这就是 Rewrite It In Rust —— 简称 RIIR,和地心引力一样不可避免的存在。 好吧,那我就来做一次真的。我将把一个有 8,300 行代码的 Python AI 代理移植到 Rust。但不是因为这个梗在召唤我(嗯…有一点是因为它)。我这么做,是因为我需要一个实验对象。 论点 最近几周,我一直在写关于静默失败、五种防止幻觉的方法、以及"一个 LLM 如何生成看似正确但实际上错误的代码"的文章。我甚至还给它起了个名字:对抗性开发。永远不要相信,总要验证。 很多理论,是时候实践了。 于是,我需要一个项目,满足三个特点:范围适中(而不是一个需求会不断变化的新应用)、明确的真相来源(现有可用的 Python 代码)、以及足够的复杂度,让 LLM 的幻觉能“藏起来”。一个纯粹的移植可以完全满足这三点。输入和期望输出已然存在。如果 Rust 版本的行为和 Python 的不完全一样,那肯定有问题。就是这么简单。 既然要做移植,那为什么不顺便真正学学 Rust 呢?借用检查器 (borrow checker)、所有权 (ownership)、生命周期 (lifetimes)… 我读了好几年资料,却几乎没有亲自实践过。如果是写一个真实项目而不是第 N 次看教程,一切或许会大不相同。 目标对象 它的名字叫 nanobot。这是一个基于 OpenClaw 开发的个人 AI 代理。它能将各种 LLM(如 Claude、GPT、DeepSeek)接入聊天渠道——Telegram、Discord、Slack、电子邮件——并赋予它们更多功能。比如读取和编辑文件、执行命令、网络搜索、通过 cron 编排任务,甚至在对话之间保存记忆。 它可以正常工作。而且已经运行了几个月。在 Python 上。 问题呢?它是单线程的。一次只能处理一条消息。如果你连续发送三条信息,它会像周六中午的超市购物队伍一样排队等待。它的内存消耗约为 50MB,而它实际上只是在不同的 API 之间传递 JSON。此外,它的错误处理方式令人羞愧:到处都是return f"Error: {str(e)}"。 ...

2026年2月24日 · Fernando

为什么你发送给Claude的99%内容都已经被缓存了

我正在构建一个应用来监控我在Claude Code中的token消费。几天前,查看原始数据时,我遇到了这样的情况: cacheReadInputTokens: 4.241.579.174 inputTokens: 1.293.019 从缓存中读取的四十二亿个tokens。一百三十万个"新鲜"tokens。这是**99.97%**的缓存命中率。 我的第一反应是认为出了什么问题。没人能达到99%的缓存率。Redis不行。Cloudflare不行。你妈妈说她已经知道你要吃什么的时候也不行。 但事实证明它没有坏。就是这样工作的。而原因既优雅又反直觉。 缓存的不是文本 这里是大多数解释都不够深入的地方。当你看到"提示词缓存"时,你会想到类似Redis的东西:保存问题,保存答案,如果有人问同样的问题就返回同样的答案。 完全不是这样。 缓存的是KV张量——transformer在预填充阶段计算的Key和Value矩阵。用通俗的话说:当LLM收到你的提示词时,它首先要做的是将所有这些文本转换为内部数字表示(embeddings),然后与权重矩阵相乘,得到注意力机制生成响应所需的"键"(K)和"值"(V)。 这种计算是极其昂贵的。在一个200,000个tokens的提示词中(在Claude Code中很常见,对话历史会累积),我们谈论的是数十亿次矩阵乘法运算。这是最消耗GPU的部分,最耗时的部分,成本最高的部分。 这就是巧妙之处:在你的一条消息和下一条消息之间,99%的提示词不会改变。系统提示词是相同的。之前的对话历史是相同的。它读取的文件是相同的。唯一新的是你的最后一条消息。 为什么要重新计算你30秒前已经计算过的东西呢? 匹配机制的工作原理 仅仅缓存是不够的。你必须知道缓存什么时候有用。这里Anthropic使用了一个优雅的技巧:按前缀的累积哈希。 提示词的每个块(system、tools、消息)生成一个哈希。但不是单独的哈希:是累积哈希。第3块的哈希包括第1、2、3块的内容。如果前面任何块中的任何东西发生变化,后面所有块的哈希也会改变。 当新请求到达时,系统从标记有cache_control的点开始向后搜索,逐块比较哈希,直到找到匹配的最长前缀。所有匹配的→从缓存读取。只有新的→重新计算。 这就像一部你已经看了40遍的电影。你不需要看完整部电影就知道会发生什么。你只需要从与你记忆中不同的点开始看。 注意这个数据:系统只向后检查最多20个块。超过这个范围,它就停止搜索。这是一个实用的决定,避免花在搜索缓存上的时间超过直接计算张量的时间。 为什么Claude Code有99%的缓存命中率 现在你知道匹配是如何工作的了,99%就不再神秘了。看看Claude Code中典型会话发生的情况: 消息1(会话中的第一条): 系统提示词 (8K tokens) + 工具 (2K tokens) + 你的消息 (500 tokens) = 10,500 tokens → 全部计算,全部写入缓存 消息2: 系统提示词 (8K) + 工具 (2K) + 消息1 (500) + 响应1 (3K) + 你的消息2 (500) = 14,000 tokens → 前面的10,500个 → 缓存命中(我们之前已经计算过) → 新的3,500个 → 计算并添加到缓存 缓存命中率:75% 消息10: 系统提示词 + 工具 + 9条消息 + 9个响应 + 你的消息10 = ~150,000 tokens → 前面的~149,500个 → 缓存命中 → 新的~500个 → 计算 缓存命中率:99.7% 看到了吗?对话历史只是增长。每条新消息都是累积总数的微小部分。缓存比率以自然对数的确定性收敛到99%。 ...

2026年2月19日 · Fernando