【无标题】

Claude Code 缓存机制与请求架构

核心问题

大语言模型的 API 是**无状态**的------服务端不会记住你之前说了什么。每次请求都必须把完整上下文(系统提示 + 工具定义 + 全部历史消息)重新发送。

这意味着在多轮对话中,**大量相同的内容被反复发送、反复计算**:

  • 第 1 轮:计算 1 万 token 的 KV

  • 第 2 轮:重新计算同样的 1 万 + 新增的 1 千 token 的 KV

  • 第 3 轮:重新计算同样的 1.1 万 + 新增的 1 千 token 的 KV

  • ...

对话越长,重复计算越多,**GPU 算力和用户费用双重浪费**。

**Prompt Cache 解决的就是这个问题**:把已经计算过的 KV Cache 持久化存储,后续请求直接复用,跳过重复的计算。结果是服务端 GPU 计算量减少、响应延迟降低、用户费用降到 1/10。


一、整体请求架构

```

┌─────────────────────────────────────────────────┐

│ 本地电脑 │

│ │

│ Claude Code (CLI) │

│ ├─ 组装请求:system prompt + tools + 历史消息 │

│ ├─ 标记 cache_control │

│ └─ 发送 HTTPS 请求 → Anthropic API │

└──────────────────────┬──────────────────────────┘

│ HTTPS (streaming SSE)

┌─────────────────────────────────────────────────┐

│ Anthropic API Gateway │

│ ├─ 认证 (API Key) │

│ ├─ 限流 / 计费 │

│ └─ 路由到对应模型集群 │

└──────────────────────┬──────────────────────────┘

┌─────────────────────────────────────────────────┐

│ 模型推理集群 (GPU Servers) │

│ │

│ 1. 检查 Prompt Cache │

│ ├─ 命中 → 直接加载已有 KV Cache │

│ └─ 未命中 → 从 token 计算 KV,写入缓存 │

│ │

│ 2. Prefill 阶段 │

│ └─ 处理新增 token,计算它们的 KV │

│ │

│ 3. Decode 阶段(逐 token 生成) │

│ ├─ Q × K → 注意力分数 │

│ ├─ 加权 V → 输出 token │

│ ├─ 新 token 的 KV 追加到缓存 │

│ └─ 每生成一个 token 就流式返回 │

└──────────────────────┬──────────────────────────┘

│ streaming tokens

┌─────────────────────────────────────────────────┐

│ Claude Code (CLI) │

│ ├─ 流式接收 token,实时显示 │

│ ├─ 如果返回 tool_use → 本地执行工具 │

│ │ (Read/Edit/Bash/Grep 等都在本地电脑上跑) │

│ ├─ 把工具结果拼入消息,发起下一轮请求 │

│ └─ 循环直到模型不再调用工具 │

└─────────────────────────────────────────────────┘

```

**关键点**:

  • 模型计算全在服务端,本地电脑只负责发请求和执行工具

  • Read、Bash、Grep 等工具都是 Claude Code 在本地执行的

  • 一个问题可能触发多轮请求(模型调用工具 → 本地执行 → 结果发回 → 模型继续)

服务端组成

服务端不只是大语言模型,而是一整套基础设施:

| 组件 | 职责 |

|------|------|

| API Gateway | 认证、限流、计费、路由(不涉及模型计算) |

| 推理引擎 | 管理 KV Cache、调度请求、批处理优化 |

| 大语言模型 | 跑在 GPU 上的 Transformer 权重,负责实际 token 生成 |


二、Transformer 中的 KV 计算

注意力机制(Attention)

Attention 要解决的问题:模型在生成每个 token 时,需要"回顾"之前所有 token,决定该关注哪些内容。

每个 token 被变换成三个向量:

| 向量 | 角色 | 类比 |

|------|------|------|

| **Q** (Query) | "我在找什么" | 当前的问题 |

| **K** (Key) | "我是什么" | 每段历史内容的标签 |

| **V** (Value) | "我的内容" | 每段历史内容的实际信息 |

计算过程:

  1. 用当前 token 的 **Q** 和所有历史 token 的 **K** 做点积 → 得到注意力分数(该关注谁)

  2. 用注意力分数对所有 **V** 加权求和 → 得到当前 token 的输出

为什么 KV 可以缓存

模型逐个生成 token 时,**之前 token 的 K 和 V 不会变**。不缓存的话,生成第 N 个 token 要重新计算前面 N-1 个 token 的 KV,浪费大量算力。

核心原则:**历史不变,算一次就够了。**


三、KV Cache 与 Prompt Cache 的关系

两者是同一个东西的不同作用范围:

| | KV Cache | Prompt Cache |

|--|----------|-------------|

| **是什么** | 注意力层算出的 K、V 向量 | 同样是 K、V 向量 |

| **范围** | 单次请求内复用 | 跨请求复用 |

| **谁管的** | 推理引擎自动做 | Anthropic 额外做的持久化 |

| **生命周期** | 请求结束就释放 | 保留 5 分钟,命中续期 |

**Prompt Cache 的底层实现就是 KV Cache 的持久化存储**------"算好的 KV 别扔,留着下次用"。

跨请求流程示例

  1. **第 1 次请求** --- 算出所有 token 的 KV → 生成回复 → KV 不丢弃,存下来(Prompt Cache 写入)

  2. **第 2 次请求** --- 前缀相同的部分直接加载之前存的 KV(Prompt Cache 命中)→ 只算新增 token 的 KV → 生成回复


四、Prompt Cache 机制详解

什么内容会被缓存

按 API 处理顺序,以下内容构成缓存前缀:

  1. **工具定义(tools)** --- Claude Code 的内置工具 + MCP 工具

  2. **系统提示(system prompt)** --- 核心指令、CLAUDE.md、Memory 等

  3. **消息历史(messages)** --- 所有之前的 user/assistant 轮次

缓存遵循严格的层级关系:`tools → system → messages`。某一层变化,该层及之后的缓存全部失效。

触发方式

全自动,无需配置。Claude Code 在 API 请求中设置 `cache_control: {"type": "ephemeral"}`,服务端自动处理。

费用对比(以 Opus 模型为例)

| 操作 | 价格 | 与基础价格的倍率 |

|------|------|-----------------|

| 普通输入 token | $15/MTok | 1x(基准) |

| 缓存写入 | $18.75/MTok | 1.25x |

| **缓存命中** | **$1.50/MTok** | **0.1x** |

**缓存命中时,输入 token 费用降到原来的 1/10。** 10 轮对话大约节省 ~78% 的输入 token 费用。

缓存失效场景

| 场景 | 影响 |

|------|------|

| `/compact` 压缩对话 | 消息历史改变,缓存重建 |

| 切换模型 | 工具/系统提示可能变化,全部失效 |

| MCP 工具动态加载 | tools 数组变化,全部失效 |

| 超过 5 分钟没交互 | 缓存自然过期 |

相关推荐
꧁细听勿语情꧂2 小时前
合并两个有序表、判断链表的回文结构、相交链表、环的链表一和二
c语言·开发语言·数据结构·算法
Rust语言中文社区2 小时前
【Rust日报】2026-04-24 Vizia 0.4 发布——纯 Rust 声明式响应式 GUI 框架
开发语言·后端·rust
weisian1512 小时前
Java并发编程--45-分布式一致性协议入门:Raft、Paxos与ZAB的核心思想
java·分布式·raft·paxos·zab
木井巳2 小时前
【递归算法】解数独
java·算法·leetcode·决策树·深度优先·剪枝
普通网友2 小时前
JavaScript:ESLint+Prettier 规范代码格式
开发语言·javascript·ecmascript
t***5442 小时前
如何在 Dev-C++ 中切换编译器
java·开发语言·c++
Lisonseekpan2 小时前
Git:如何将一个分支的特定提交合并到另一个分支?
java·大数据·git·后端·elasticsearch
Boop_wu2 小时前
[Java EE 进阶]Mybatis进阶(动态SQL)
java·数据库·maven·mybatis
Elastic 中国社区官方博客2 小时前
使用 EDOT Browser 和 Kibana 进行 OpenTelemetry 浏览器端埋点
大数据·服务器·数据库·elasticsearch·搜索引擎·单元测试·可用性测试