analysis_claude_code/articles/上下文缓存经济学.md
CrazyBoyM 85f44c358a Complete rewrite: original educational content only
- Remove all reverse-engineered Claude Code source code
- Replace with 100% original educational content from mini-claude-code
- Add clear disclaimer: independent project, not affiliated with Anthropic
- 5 progressive agent implementations (v0-v4, ~1100 lines total)
- Include agent-builder skill for teaching agent construction
- Bilingual documentation (EN + ZH)

This repository now focuses purely on teaching how modern AI agents work
through original, from-scratch implementations.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-31 07:01:42 +08:00

978 lines
35 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 大模型上下文缓存经济学别让你的Agent"烧钱"
> **核心警告**: 你习以为常的"编辑消息、修改历史、DIY上下文"操作在LLM Agent中会让成本暴增7-50倍。本文帮你建立缓存意识避免成本灾难。
---
## 🚨 如果你正在做这些事,请立即停止
```python
# ❌ 危险操作1: 每次都修改system prompt
system = f"Current step: {step}, files: {files}..." # 成本爆炸!
# ❌ 危险操作2: 编辑历史消息
messages[2]["content"] = "updated content" # 缓存全失效!
# ❌ 危险操作3: 删除旧消息(滑动窗口)
messages = messages[-10:] # 每次都重新计算!
# ❌ 危险操作4: 用摘要替换历史
messages = [summary] + messages[15:] # 前缀变了,缓存失效!
# ❌ 危险操作5: 在中间插入消息
messages.insert(5, new_message) # 后面全部失效!
```
**这些操作在传统编程中很正常但在LLM API中会让你的成本增加几十倍。**
---
## 1. 思维转变:上下文不是"可编辑的变量",而是"只追加的日志"
### 1.1 传统编程思维 vs LLM Agent开发
**传统后端开发** (你习惯的方式):
```python
# 数据是可以随意修改的
user_state = {"step": 1, "data": []}
user_state["step"] = 2 # 修改状态
user_state["data"].append(new_item) # 添加数据
del user_state["history"] # 删除不需要的
```
**LLM Agent开发** (必须遵守的规则):
```python
# 上下文是"只追加日志",一旦修改前缀 = 缓存全失效
messages = [system_msg] # 永不改变
messages.append(user_msg) # ✅ 只能追加
messages.append(assistant_msg) # ✅ 只能追加
# messages[0] = xxx # ❌ 修改前缀 = 成本爆炸
# messages = messages[-10:] # ❌ 删除 = 成本爆炸
```
**关键认知**: LLM API的上下文有"前缀缓存"机制——前缀不变就能复用,前缀一变就要全部重算。
### 1.2 忽视缓存的真实代价
许多传统 AI 开发者在使用 **LangGraph、LangChain、AutoGen** 等框架开发 Agent 时,习惯性地采用传统软件开发思维:
- 编排和编辑上下文
- DIY 消息队列,插入、删除、修改历史消息
- 压缩或摘要替换长对话
- 在 system prompt 中注入动态状态
- 使用滑动窗口截断旧消息
**这些操作在传统软件中是正常的,但在大模型 API 中会导致缓存完全失效,成本和性能双重爆炸。**
### 1.2 成本差距有多大?
一个典型的 SWE (软件工程) Agent 任务可能消耗 **100K-1M tokens**。如果你的 Agent 每天处理 100 个任务,按 Claude Sonnet 4.5 的 $3/M 输入价格计算:
| 策略 | 每天成本 | 年成本 | 说明 |
|------|---------|--------|------|
| **破坏缓存** (每轮编辑上下文) | **$150** | **$54,750** | 每轮重新计算全部上下文 |
| **有缓存优化** (只追加) | **$26** | **$9,490** | 60% 缓存命中率 |
| **节省** | **$124/天** | **$45,260/年** | **83% 成本节省** |
对于一个中等规模的 Agent 应用,**理解缓存机制可以每年节省数万到数十万美元**。
### 1.3 自回归模型的本质特征
大语言模型是**自回归**的——生成每个新 token 都需要 attend 到之前所有 token。这意味着
```
上下文长度: 50K tokens
生成 1 个 token: 需要对 50K tokens 做 attention
生成 100 个 token: 需要对 50K-50.1K tokens 做 attention共 5,005,000 次 attention 操作
```
如果你**每次请求都修改上下文的前缀**
- 之前缓存的 KV 向量全部失效
- 大模型提供商需要重新计算整个前缀
- 你需要为相同内容重复付费
如果你**只追加新内容**
- 提供商复用已缓存的 KV 向量
- 只计算新增部分
- 缓存命中部分享受 **90% 折扣** (大部分提供商)
## 2. 自回归模型与 KV Cache 原理
### 2.1 为什么需要缓存?
大语言模型是**自回归**的:生成每个 token 都需要 attend 到之前所有 token。
```
输入: [A, B, C, D, E]
生成 F: Attention(F, [A,B,C,D,E]) → 计算 5 次 attention
生成 G: Attention(G, [A,B,C,D,E,F]) → 计算 6 次 attention
```
对于 200K 上下文窗口,每生成一个 token 都要与前面所有 token 做 attention 计算。**KV Cache** 通过缓存已计算的 Key-Value 向量来避免重复计算。
### 2.2 Prompt Cache 的工作原理
```
请求 1: [System, User1, Asst1, User2]
←────── 全部计算 ──────→
(首次处理,写入缓存)
请求 2: [System, User1, Asst1, User2, Asst2, User3]
←────── 缓存命中 ──────→ ←─ 新计算 ─→
(复用已缓存的 KV) (仅计算新增部分)
```
**关键条件**: 缓存命中要求**前缀完全相同**,一个字符都不能变。
## 3. 常见的缓存破坏模式与反模式
### 3.1 LangGraph / LangChain 常见反模式
许多开发者在使用这些流行框架时,会不自觉地采用破坏缓存的模式:
#### 反模式 1: 状态注入到 System Prompt
```python
def build_system_prompt(state: dict) -> str:
return f"""You are an assistant. Current state:
- Step: {state['current_step']}
- Progress: {state['progress']}%
- Context: {state['context']}
"""
response = client.chat(
system=build_system_prompt(state), # 每次都不同!
messages=messages
)
```
**问题**: 每轮 state 都变system prompt 每次都不同,**缓存 100% 失效**。
**正确做法**
```python
FIXED_SYSTEM_PROMPT = "You are an assistant." # 固定不变
messages.append({
"role": "user",
"content": f"Current state: step={state['current_step']}, progress={state['progress']}%"
})
response = client.chat(
system=FIXED_SYSTEM_PROMPT, # 永远不变,缓存有效
messages=messages # 只追加
)
```
#### 反模式 2: 消息压缩与摘要替换
```python
def compress_messages(messages: list) -> list:
if len(messages) > 20:
old_messages = messages[:15]
summary = summarize(old_messages)
# 用摘要替换旧消息
return [{"role": "system", "content": summary}] + messages[15:]
return messages
messages = compress_messages(messages) # 前缀变了,缓存失效!
```
**问题**: 替换操作改变了前缀,之前的所有缓存失效。
**成本影响** (50 轮对话,每轮 50K 上下文):
- 无压缩: 首次 $0.1875 (写入) + 后续 49 轮 × $0.015 = **$0.92**
- 压缩替换 (每 20 轮): 3 次重建缓存 × $0.1875 = **$0.56** (看似更便宜)
- **实际**: 压缩后丢失上下文,模型表现下降,需要更多轮次,**总成本反而更高**
**正确做法**: 使用子 Agent 隔离上下文,只返回摘要结果。
#### 反模式 3: 滑动窗口截断
```python
def sliding_window(messages: list, window_size: int = 10) -> list:
if len(messages) > window_size:
return messages[-window_size:] # 只保留最近 10 条
return messages
```
**问题**: 删除旧消息 = 改变前缀 = 缓存失效。
**成本对比** (Claude Sonnet 4.530 轮对话,每轮 3K 新增):
| 策略 | Token 计算 | 成本 |
|------|-----------|------|
| 只追加 | 首次 8K + 29 轮 × 3K (缓存) = 8K + 87K (缓存) | $0.030 + $0.026 = **$0.056** |
| 滑动窗口 (10 条) | 每轮重算 30K | 30 轮 × 30K × $3/M = **$2.70** |
| **成本差距** | | **48倍** |
#### 反模式 4: 消息编辑与插入
```python
def fix_message_format(messages: list) -> list:
for msg in messages:
if 'timestamp' in msg:
del msg['timestamp'] # 修改了历史消息
if msg['role'] == 'assistant' and 'tool_calls' in msg:
msg['content'] = msg['content'].strip() # 修改内容
return messages
```
**问题**: 即使是微小的修改删除字段、trim 空格),也会使缓存失效。
#### 反模式 5: LangGraph 状态管理不当
```python
from langgraph.graph import StateGraph
class AgentState(TypedDict):
messages: list[BaseMessage]
context: str
step: int
def node_a(state: AgentState) -> AgentState:
# 错误: 修改了 messages
state["messages"][0].content += f"\n[Step {state['step']}]"
return state
graph = StateGraph(AgentState)
graph.add_node("a", node_a)
```
**问题**: 在 LangGraph 节点中修改历史消息,会导致后续所有节点的缓存失效。
**正确做法**: 在 LangGraph 中,将状态信息作为**新消息追加**,而非修改现有消息。
### 3.2 缓存破坏模式总结
| 反模式 | 表现 | 缓存影响 | 成本倍数 |
|--------|------|----------|----------|
| 动态 System Prompt | 每轮注入状态 | 100% 失效 | **20-50x** |
| 消息压缩替换 | 用摘要替换历史 | 替换点后全失效 | **5-15x** |
| 滑动窗口 | 删除旧消息 | 100% 失效 | **30-50x** |
| 消息编辑 | 修改历史内容 | 修改点后全失效 | **10-30x** |
| 消息插入 | 在中间插入 | 插入点后全失效 | **10-30x** |
| 多 Agent 全连接 | 每个 Agent 看到所有消息 | 上下文膨胀 | **3-4x** (相对单Agent) |
### 3.3 为什么这些模式如此常见?
1. **传统编程习惯**: 在常规软件中,编辑、插入、删除是正常操作
2. **框架误导**: 一些 Agent 框架提供了"方便的"消息管理 API但没有警告缓存影响
3. **缺乏可见性**: 大部分 API 不显示缓存命中率,开发者看不到成本差异
4. **示例代码**: 许多教程和示例代码为了"简洁"而忽略了缓存最佳实践
### 3.4 如何检测你是否在破坏缓存?
**Claude API 响应头**:
```json
{
"usage": {
"input_tokens": 50000,
"cache_creation_input_tokens": 48000, // 首次写入缓存
"cache_read_input_tokens": 48000, // 后续命中
"output_tokens": 150
}
}
```
**如果你看到**:
- `cache_read_input_tokens` 始终为 0 → 缓存从未命中
- `cache_creation_input_tokens` 每次都很大 → 你在破坏缓存
**OpenAI / Kimi K2 / GLM (自动缓存)**:
```json
{
"usage": {
"prompt_tokens": 50000,
"prompt_tokens_details": {
"cached_tokens": 48000 // 缓存命中的 token 数
}
}
}
```
**如果你看到**:
- `cached_tokens` 为 0 或很小 → 缓存未生效
## 4. 主流模型缓存策略详解
### 4.1 Claude (Anthropic)
| 特性 | 说明 |
|------|------|
| **是否自动缓存** | **否**,必须显式使用 `cache_control` 参数 |
| **最大断点数** | 每个请求最多 4 个 cache breakpoint |
| **TTL (生存时间)** | 默认 5 分钟,可选 1 小时 (价格更高) |
| **最小 token 要求** | Opus 4.5: 1,024 tokens; Sonnet 4.5: 1,024 tokens; Haiku 4.5: 4,096 tokens |
| **缓存层级** | tools → system → messages (修改任一层级会使后续层级缓存失效) |
| **Lookback 窗口** | 每个断点向前最多检查 20 个 blocks 寻找最长可命中前缀 |
**定价 (USD/M tokens)**:
| 模型 | 输入 | 缓存写入(5min) | 缓存写入(1hr) | 缓存读取 | 输出 |
|------|------|----------------|---------------|----------|------|
| Claude Sonnet 4.5 | $3.00 | $3.75 (1.25x) | $6.00 (2x) | $0.30 (0.1x) | $15.00 |
| Claude Opus 4.5 | $5.00 | $6.25 (1.25x) | $10.00 (2x) | $0.50 (0.1x) | $25.00 |
| Claude Haiku 4.5 | $1.00 | $1.25 (1.25x) | $2.00 (2x) | $0.10 (0.1x) | $5.00 |
**使用方法**:
```json
{
"system": [
{
"type": "text",
"text": "You are a coding assistant...",
"cache_control": {"type": "ephemeral"}
}
]
}
```
**关键洞察**:
- Claude 的缓存**不是自动的**。如果你不显式设置 `cache_control`,即使前缀完全相同也不会有缓存命中
- 每次缓存命中会**自动刷新 TTL**,且不额外收费
- 修改 system prompt 会使 system 和后续 messages 缓存失效,但 tools 缓存仍保留
### 4.2 Kimi K2 (Moonshot AI)
| 特性 | 说明 |
|------|------|
| **是否自动缓存** | **是**,系统自动检测重复前缀 (无需代码修改) |
| **上下文窗口** | 256K tokens (kimi-k2-0905 版本2025年9月更新) |
| **TTL** | 自动缓存: 未公开; 显式缓存: 用户可设置 (支持刷新) |
| **型号** | `kimi-k2-0905` (Instruct 版本) |
**定价 (CNY/M tokens)**:
| 类型 | 价格 (CNY) | 价格 (USD 约) | 说明 |
|------|------------|---------------|------|
| 输入 (cache miss) | ¥4.20 | ~$0.60 | 标准输入价 |
| 输入 (cache hit) | ¥0.42 | ~$0.06 | **90% 折扣** |
| 输出 | ¥17.50 | ~$2.50 | - |
**特点**:
- Kimi K2 的自动缓存是**全自动**的,无需任何代码修改
- 系统自动检测相同前缀并复用缓存,缓存命中时享受 **90% 折扣**
- 官方称可降低长文本成本最高 90%,首 Token 延迟降低 83%
**显式缓存 API (Context Caching公测中)**:
- 缓存创建费: ¥24/M tokens (~$3.30)
- 存储费用: ¥5/M tokens/分钟 (2024年8月降价50%后)
- 每次命中调用费: ¥0.02/次
- 初期仅限 Tier5 用户,后开放公测
### 4.3 GLM-4.7 (智谱 AI)
| 特性 | 说明 |
|------|------|
| **是否自动缓存** | **是**,自动前缀匹配 (需按 Context Caching 用法组织上下文) |
| **上下文窗口** | 200K tokens (支持最高 128K 输出) |
| **TTL** | 官方未公开,描述为"有合理的时间限制,过期后重新计算" |
| **发布日期** | 2025年12月22日 (开源) |
**定价 (USD/M tokens)**:
| 类型 | 价格 | 说明 |
|------|------|------|
| 输入 (新 token) | $0.60 | 标准输入价 |
| 输入 (缓存命中) | $0.11 | **82% 折扣** |
| 输出 | $2.20 | - |
| 缓存存储 | 免费 | **限时免费**,后续可能收费 |
**特点**:
- GLM-4.7 提供 **82% 的缓存折扣**,是国产模型中折扣力度较大的
- 响应中返回 `usage.prompt_tokens_details.cached_tokens` 用于追踪缓存命中
- 智谱同时提供开源版本,本地部署可避免按 token 计费
- 在编程评测中表现接近 Claude Sonnet 4.5 和 GPT-5.2
### 4.4 MiniMax M2.1
| 特性 | 说明 |
|------|------|
| **是否自动缓存** | **否**,需要使用 `cache_control` 参数 (与 Claude 类似) |
| **上下文窗口** | 200K+ tokens |
| **TTL** | 5 分钟 (命中时自动刷新,不额外收费) |
| **发布日期** | 2025年12月22日 (开源) |
| **缓存层级** | tools → system → messages |
| **最大断点数** | 4 个 `cache_control` |
**定价 (USD/M tokens)**:
| 类型 | 价格 | 说明 |
|------|------|------|
| 输入 | $0.30 | 标准输入价 |
| 缓存写入 | $0.375 | 1.25x 输入价 |
| 缓存读取 | $0.03 | **0.1x 输入价 (90% 折扣)** |
| 输出 | $1.20 | - |
**特点**:
- MiniMax M2.1 是目前**最便宜的高性能模型之一**
- 缓存读取仅 $0.03/M是 Claude Sonnet 的 1/10
- 采用 MoE 架构 (230B 总参数10B 激活),专为代码和 Agent 场景优化
- 缓存机制与 Claude 高度相似 (cache_control, TTL, 层级)
- 提供 M2.1-lightning 高速版本,输出价 $2.4/M
### 4.5 GPT-5.2 (OpenAI)
| 特性 | 说明 |
|------|------|
| **是否自动缓存** | **是**,无需代码修改,自动针对重复前缀 |
| **上下文窗口** | 256K-400K tokens |
| **TTL** | 默认 5-10 分钟,部分模型支持扩展至 24 小时 |
| **最小 token 要求** | ≥1024 tokens 自动启用 |
**定价 (USD/M tokens)**:
| 类型 | 价格 | 说明 |
|------|------|------|
| 输入 | $1.75 | 标准输入价 |
| 缓存读取 | $0.175 | **0.1x 输入价 (90% 折扣)** |
| 输出 | $14.00 | - |
**特点**:
- OpenAI 的缓存是**全自动**的,无需任何参数配置
- 可选 `prompt_cache_key``prompt_cache_retention` 参数进行精细控制
- 官方称可降低输入成本最高 90%、延迟最高 80%
**注意**GPT-4o 等 2024 年模型缓存折扣为 50%GPT-5 系列为 90%
### 4.6 Gemini 3 (Google)
| 特性 | 说明 |
|------|------|
| **隐式缓存** | **是** (Gemini 2.5+ 默认启用),自动检测重复前缀 |
| **显式缓存** | 需要创建 `CachedContent` 对象并引用 |
| **上下文窗口** | Flash: 1M tokens; Pro: 1M-2M tokens |
| **TTL** | 显式缓存默认 1 小时,可自定义 |
| **最小 token 要求** | Gemini 3 Pro: 4096; Gemini 2.5 Flash: 1024 |
**定价 (USD/M tokens)**:
| 模型 | 输入 | 缓存读取 | 输出 | 存储费 |
|------|------|----------|------|--------|
| Gemini 3 Flash | $0.50 | $0.05 (0.1x) | $3.00 | $1.00/M·hour |
| Gemini 3 Pro | $2.00 | $0.20 (0.1x) | $12.00 | $1.00/M·hour |
**特点**:
- 隐式缓存自动生效,但不保证每次都命中 (高并发时可能溢出)
- 显式缓存需要创建缓存对象,但可确保命中
- 显式缓存有**存储费**,按 token·小时计费
- 支持超长上下文 (1M-2M),适合处理整本书或大型代码库
### 4.7 综合对比
| 模型 | 上下文 | 标准输入 | 缓存读取 | 缓存折扣 | 自动缓存 |
|------|--------|----------|----------|----------|----------|
| Claude Sonnet 4.5 | 200K | $3.00/M | $0.30/M | 90% | 否 (需 cache_control) |
| Claude Opus 4.5 | 200K | $5.00/M | $0.50/M | 90% | 否 |
| GPT-5.2 | 256K+ | $1.75/M | $0.175/M | 90% | **是** |
| Gemini 3 Flash | 1M | $0.50/M | $0.05/M | 90% | 是 (隐式) |
| Gemini 3 Pro | 1M+ | $2.00/M | $0.20/M | 90% | 是 (隐式) |
| Kimi K2 | 256K | ~$0.60/M | ~$0.06/M | 90% | **是** |
| GLM-4.7 | 200K | $0.60/M | $0.11/M | 82% | 是 |
| MiniMax M2.1 | 200K | $0.30/M | $0.03/M | 90% | 否 (需 cache_control) |
## 5. 详细成本计算50 轮 SWE 任务实例
本节通过一个典型的软件工程 Agent 任务,逐轮计算 token 消耗和成本,展示缓存优化的真实影响。
### 5.1 任务场景设定
**任务**: 修复一个涉及多文件的 bug需要读取代码、分析、修改、测试
**Agent 配置**:
- System prompt: 5,000 tokens
- 工具定义 (bash, read_file, write_file, grep, etc.): 3,000 tokens
- 基础上下文: 8,000 tokens
**每轮典型操作**:
- 用户指令: 200 tokens
- 模型推理 + 工具调用: 500 tokens
- 工具返回 (代码、测试结果等): 2,000 tokens (平均)
- 模型响应: 800 tokens
### 5.2 场景 A: 破坏缓存 (动态 System Prompt)
**错误做法**: 每轮将当前状态注入 system prompt
```python
def build_system_prompt(step: int, context: dict) -> str:
return f"""You are a coding assistant.
Current step: {step}
Files modified: {context['files']}
Tests passed: {context['tests_passed']}
...(total 5,000 tokens)"""
```
**逐轮成本计算** (Claude Sonnet 4.5, $3/M 输入):
| 轮次 | 上下文累计 | System 变化 | 缓存状态 | 计算 tokens | 成本 |
|------|-----------|------------|---------|-------------|------|
| 1 | 8K + 3.5K = 11.5K | ✗ | 无缓存 | 11.5K | $0.0345 |
| 2 | 11.5K + 3.5K = 15K | ✗ | 完全失效 | 15K | $0.0450 |
| 3 | 15K + 3.5K = 18.5K | ✗ | 完全失效 | 18.5K | $0.0555 |
| ... | ... | ... | ... | ... | ... |
| 50 | 8K + 49×3.5K = 179.5K | ✗ | 完全失效 | 179.5K | $0.5385 |
**总成本 (50 轮)**:
```
Sum(8K + n×3.5K) for n=0 to 49
= 50×8K + 3.5K×(0+1+2+...+49)
= 400K + 3.5K × 1,225
= 400K + 4,287.5K
= 4,687.5K tokens × $3/M = $14.06
```
### 5.3 场景 B: 缓存优化 (固定 System Prompt)
**正确做法**: System prompt 固定,状态作为新消息追加
```python
FIXED_SYSTEM_PROMPT = "You are a coding assistant. (5,000 tokens)"
# 每轮追加状态信息
messages.append({
"role": "user",
"content": f"Status update: step={step}, files={files}..."
})
```
**使用 Claude cache_control**:
```python
system = [{
"type": "text",
"text": FIXED_SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}
}]
```
**逐轮成本计算**:
| 轮次 | 上下文累计 | 缓存写入 | 缓存读取 | 新增计算 | 成本 |
|------|-----------|---------|---------|---------|------|
| 1 | 11.5K | 8K @ $3.75/M | 0 | 3.5K @ $3/M | $0.030 + $0.0105 = $0.0405 |
| 2 | 15K | 0 | 11.5K @ $0.30/M | 3.5K @ $3/M | $0.00345 + $0.0105 = $0.01395 |
| 3 | 18.5K | 0 | 15K @ $0.30/M | 3.5K @ $0.30/M | $0.0045 + $0.0105 = $0.0150 |
| ... | ... | ... | ... | ... | ... |
| 50 | 179.5K | 0 | 176K @ $0.30/M | 3.5K @ $3/M | $0.0528 + $0.0105 = $0.0633 |
**总成本 (50 轮)**:
```
首轮: 8K×$3.75/M + 3.5K×$3/M = $0.030 + $0.0105 = $0.0405
后续 49 轮:
- 缓存读取: (11.5K + 15K + ... + 176K) × $0.30/M
- 新增计算: 49 × 3.5K × $3/M = 171.5K × $3/M = $0.5145
缓存读取累计:
Sum(8K + n×3.5K) for n=1 to 49 = 4,287.5K × $0.30/M = $1.29
总计: $0.0405 + $1.29 + $0.5145 = $1.845
```
**节省**: ($14.06 - $1.845) / $14.06 = **86.9%**
### 5.4 场景 C: 使用国产模型 (Kimi K2 自动缓存)
**价格**: $0.60/M 输入 (标准)$0.15/M 输入 (缓存命中)
**逐轮成本计算**:
| 轮次 | 上下文累计 | 缓存命中 | 新增计算 | 成本 |
|------|-----------|---------|---------|------|
| 1 | 11.5K | 0 | 11.5K @ $0.60/M | $0.0069 |
| 2 | 15K | 11.5K @ $0.15/M | 3.5K @ $0.60/M | $0.001725 + $0.0021 = $0.003825 |
| 3 | 18.5K | 15K @ $0.15/M | 3.5K @ $0.60/M | $0.00225 + $0.0021 = $0.00435 |
| ... | ... | ... | ... | ... |
| 50 | 179.5K | 176K @ $0.15/M | 3.5K @ $0.60/M | $0.0264 + $0.0021 = $0.0285 |
**总成本 (50 轮)**:
```
首轮: 11.5K × $0.60/M = $0.0069
后续 49 轮:
- 缓存命中: 4,287.5K × $0.15/M = $0.643
- 新增计算: 49 × 3.5K × $0.60/M = $0.1029
总计: $0.0069 + $0.643 + $0.1029 = $0.753
```
**相比 Claude 无缓存**: ($14.06 - $0.753) / $14.06 = **94.6% 节省**
### 5.5 场景 D: 滑动窗口反模式
**错误做法**: 保留最近 10 轮对话,删除旧的
**每轮都需要重新计算** (因为前缀一直在变):
| 轮次 | 上下文 | 计算 tokens | 成本 (Claude) |
|------|--------|-------------|---------------|
| 1-10 | 8K + n×3.5K | 逐渐增长 | 逐渐增长 |
| 11+ | 8K + 10×3.5K = 43K | **每轮 43K** | **每轮 $0.129** |
**总成本 (50 轮)**:
```
前 10 轮: Sum(8K + n×3.5K) for n=0 to 9 = 237.5K × $3/M = $0.7125
后 40 轮: 40 × 43K × $3/M = 5,160K × $3/M = $15.48
总计: $0.7125 + $15.48 = $16.19
```
**比缓存优化版贵**: $16.19 / $1.845 = **8.8 倍**
### 5.6 多模型对比总结
**50 轮 SWE 任务总成本对比**:
| 策略 | 模型 | 总成本 | 相对成本 | 节省 |
|------|------|--------|---------|------|
| **破坏缓存** | Claude Sonnet 4.5 | **$14.06** | 7.6x | 基准 |
| **滑动窗口** | Claude Sonnet 4.5 | **$16.19** | 8.8x | -15% (更贵!) |
| **缓存优化** | Claude Sonnet 4.5 | **$1.845** | 1.0x | **87%** |
| **缓存优化** | GPT-5.2 | **$1.08** | 0.59x | **92%** |
| **自动缓存** | Kimi K2 | **$0.753** | 0.41x | **95%** |
| **自动缓存** | GLM-4.7 | **$0.84** | 0.46x | **94%** |
| **自动缓存** | MiniMax M2.1 | **$0.38** | 0.21x | **97%** |
**关键洞察**:
1. 破坏缓存比优化版贵 **7-8 倍**
2. 滑动窗口不仅破坏缓存,还因为重复计算更贵
3. 国产模型的自动缓存 + 低价格组合极具竞争力
4. MiniMax M2.1 在这个场景下成本最低
## 6. Agent 编排策略与缓存影响
不同的 Agent 编排策略对缓存有着截然不同的影响。
### 6.1 编排模式对比
| 模式 | 描述 | 缓存友好度 | Token 消耗倍数 |
|------|------|-----------|---------------|
| **单 Agent 循环** | 一个 Agent 持续调用工具直到完成 | 好 | 1x (基准) |
| **多 Agent 顺序** | 多个 Agent 顺序执行,传递结果 | 中 | 4-6x |
| **多 Agent 协作** | 多个 Agent 相互对话协商 | 差 | **15x+** |
| **层级 Agent** | 父子层级结构,子 Agent 隔离上下文 | 好 | 2-4x |
| **Graph 编排** | DAG 节点式编排 (LangGraph) | 好* | 2-4x |
| **ReAct 循环** | Thought → Action → Observation 循环 | 差 | 高 (每轮累积) |
*需要正确配置节点级缓存
**研究数据支撑**:
- Anthropic 研究 (2025年6月): 多 Agent 系统相比简单聊天消耗约**15倍** tokens性能提升90.2%
- arXiv 论文: 部分复杂任务在多 Agent 框架下消耗高达 **200 万 tokens**
- 学术研究表明,引入 Supervisor Agent 可减少约 30% 的无效 token 消耗
**重要**: 上述"15倍"是相对于简单聊天任务。多Agent相对单Agent的实际倍数约为**3-4倍**而非更高的数值。选择多Agent架构需要权衡性能提升(90%+)与成本增加(3-4x)。
### 6.2 破坏缓存的操作
| 操作 | 影响 | 结果 |
|------|------|------|
| **编辑历史消息** | 改变前缀 | 缓存完全失效 |
| **在中间插入消息** | 后续前缀变化 | 插入点之后需重新计算 |
| **修改 system prompt** | 最前面变化 | **整个对话缓存失效** |
| **消息压缩/摘要替换** | 替换原始内容 | 前缀变化,缓存失效 |
| **滑动窗口截断** | 删除旧消息 | 前缀变化,缓存失效 |
### 6.3 缓存层级与失效传播
Claude 的缓存按以下顺序处理:
```
tools 变更
↓ (使下游全部失效)
system prompt 变更
↓ (使下游全部失效)
messages 内容变更
↓ (使该点之后失效)
tool_result (作为 user message)
✓ (保持缓存有效)
```
**关键洞察**: 将动态内容放在对话末尾(作为 tool_result 或新的 user message而不是修改前面的内容。这是 Claude Code 和 Kode CLI 采用的策略。
### 6.4 多 Agent 的 Token 消耗问题
根据 Anthropic 2025年6月的研究:
| 指标 | 简单聊天 | 单 Agent | 多 Agent | 倍数关系 |
|------|---------|----------|----------|---------|
| 输入 tokens | 1x | 4x | 15x | 多Agent约为单Agent的**3.75x** |
| 性能提升 | 基准 | - | +90.2% | 相对单Agent |
| Token重要性 | - | - | - | Token使用量解释80%性能差异 |
**结论**:
- 多 Agent 系统相比简单聊天消耗约**15倍** tokens
- 多 Agent 相比单 Agent 约**3-4倍**消耗
- 性能提升90.2%,但成本显著增加
- 适合高价值任务,其收益能覆盖额外成本
**优化策略**:
- 使用**环形拓扑**或**层级结构**而非全连接,减少冗余传递
- 子 Agent 采用**隔离上下文**,只返回摘要结果给父 Agent
- 选择性共享而非广播所有消息
- 通过prompt caching复用重复的system prompt和工具定义
**数据来源**: [Anthropic: Multi-agent Research System (2025-06)](https://www.anthropic.com/engineering/multi-agent-research-system)
## 7. 典型任务的 Token 消耗
### 7.1 软件工程 (SWE) 任务
| 指标 | 范围 | 说明 |
|------|------|------|
| 单个 issue 总消耗 | 100K - 1M tokens | SWE-bench 限制 |
| 基础上下文 | ~20K tokens | 系统提示 + 工具定义 |
| 每轮交互增量 | 2K - 10K tokens | 取决于文件大小和工具输出 |
| 典型任务轮数 | 10 - 50 轮 | 复杂任务可能更多 |
**Claude Code 实际数据**:
- 平均每开发者每天: $6 (90% 用户低于 $12/天)
- Pro Plan 每 5 小时: ~44,000 tokens (10-40 次提示)
- 高级工具使用可减少 37% token 消耗
**SWE-bench 成本演变** (Claude Sonnet):
- 2024年8月 (无缓存): $5.29/任务
- 2024年9月 (有缓存): $0.91/任务
- **降幅: 83%**
### 7.2 浏览器自动化任务
| 指标 | 范围 | 说明 |
|------|------|------|
| 每次截图 | ~1,600 tokens | Claude Vision 最大图片 |
| 每个任务交互轮数 | 10 - 50 轮 | 每轮包含截图分析 |
| 单任务总消耗 | 765 - 3,225 tokens | 不含截图 |
| 完整任务 (含截图) | 20K - 100K tokens | 估算 |
**不同 Browser Agent 成本对比**:
| Agent | 成功率 | 平均 tokens/任务 | 成本/任务 |
|-------|--------|------------------|-----------|
| DroidRun | 43% | 3,225 | $0.075 |
| Mobile-Agent | 29% | 1,130 | $0.025 |
| AutoDroid | 14% | 765 | $0.017 |
**Vision Token 计算** (Claude):
```
tokens = (width × height) / 750
```
最大图片约 1,600 tokens相当于 $4.80/千张图片 (Sonnet 4.5)。
### 7.3 工具调用开销
| 指标 | 值 | 说明 |
|------|-----|------|
| 每条消息开销 | 3-6 tokens | ChatML 格式 |
| 工具定义 | 100-500 tokens/工具 | 取决于 schema 复杂度 |
| 工具返回值 | 800-1,500 tokens/次 | 平均增量,长文档可达数万 |
| 单次工具调用增量 | 1K-5K tokens | 包含调用描述和返回结果 |
**Anthropic 工程案例**:
- DevOps 助理预载几十个工具定义后,基础上下文已达 **50K+ tokens**
- 未优化时,工具定义和结果在提示中堆积可达 **134K tokens**
- 一个 Slack 查询工具返回可能有几千 tokensJira 查询可达上万 tokens
**优化案例**: Red Sift 通过 LLM-aware API 设计减少了 **84% 的 token 消耗**,且无质量损失。
### 7.4 Token 消耗估算模板
**场景: 20 轮 SWE 任务**
```
基础上下文:
- System prompt: 5,000 tokens
- 工具定义: 3,000 tokens (6 个工具 × 500)
- 基础合计: 8,000 tokens
每轮增量 (平均):
- 用户指令: 200 tokens
- 工具调用: 500 tokens
- 工具返回: 2,000 tokens (代码文件等)
- 助手响应: 800 tokens
- 每轮合计: 3,500 tokens
20 轮总消耗:
- 理论最大: 8,000 + 20 × 3,500 = 78,000 tokens
- 有缓存时实际计算: 8,000 (首次) + 20 × 3,500 × 部分 ≈ 40,000 tokens 新计算
```
## 8. 成本计算实例
### 8.1 场景 A: 无缓存意识的 Agent
**假设**:
- 每轮修改 system prompt 注入状态
- 20 轮工具调用
- 基础上下文 50K tokens
**计算**:
```
每轮都需要重新处理 50K tokens
20 轮 × 50K × $3/M = $3.00 (仅 system prompt 部分)
加上每轮增量... 总成本显著
```
### 8.2 场景 B: 缓存优化的 Agent
**假设**:
- System prompt 固定不变
- 内容只追加,不修改
- 使用 Claude 的 cache_control
**计算**:
```
首轮: 50K tokens × $3.75/M (缓存写入) = $0.1875
后续 19 轮: 50K × $0.30/M × 19 = $0.285
总计: $0.4725
节省: ($3.00 - $0.4725) / $3.00 = 84%
```
### 8.3 场景 C: 使用国产模型
**使用 GLM-4.7, 相同任务**:
```
首轮: 50K × $0.60/M = $0.03
后续 19 轮 (缓存命中): 50K × $0.11/M × 19 = $0.1045
总计: $0.1345
相比 Claude 无缓存场景节省: 95.5%
相比 Claude 有缓存场景节省: 72%
```
### 8.4 多 Agent 场景成本
**假设**: 4 个 Agent 协作,全连接消息传递
```
单 Agent 基准: 100K tokens
多 Agent (77x 系数): 7.7M tokens
Claude Sonnet 4.5:
- 单 Agent: 100K × $3/M = $0.30
- 多 Agent: 7.7M × $3/M = $23.10
使用环形拓扑优化后:
- 预估减少 60-80%: ~$5-9
```
## 9. 最佳实践
### 9.1 缓存友好的 Agent 设计
```python
# 正确: 只追加,不修改
messages.append({"role": "user", "content": results})
# 错误: 编辑历史
messages[2]["content"] = "updated" # 缓存失效!
# 错误: 修改 system prompt
system_prompt = f"Current state: {state}" # 每次都变,缓存失效!
# 正确: 状态作为新消息追加
messages.append({"role": "user", "content": f"Current state: {state}"})
```
### 9.2 Claude 缓存配置
```python
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
system=[
{
"type": "text",
"text": "Your long system prompt here...",
"cache_control": {"type": "ephemeral"} # 关键!
}
],
messages=messages,
tools=tools
)
```
### 9.3 上下文管理策略选择
| 场景 | 推荐策略 | 原因 |
|------|----------|------|
| 短对话 (<10 ) | 只追加 | 简单缓存友好 |
| 中等对话 (10-50 ) | 只追加 + Agent 隔离 | 保持主上下文干净 |
| 长对话 (>50 轮) | 分段 + 摘要 (接受缓存损失) | 避免超出上下文窗口 |
| 多 Agent | 环形拓扑 + 选择性共享 | 平衡性能和成本 |
### 9.4 模型选择建议
| 需求 | 推荐模型 | 原因 |
|------|----------|------|
| 最高质量 | Claude Opus 4.5 | 最强推理能力 |
| 性价比 (海外) | GPT-5.2 | 自动缓存,$1.75/M 输入 |
| 性价比 (国产) | GLM-4.7 / Kimi K2 | 自动缓存,~$0.60/M 输入 |
| 最低成本 | MiniMax M2.1 | $0.03/M 缓存读取 |
| 超长上下文 | Gemini 3 Pro (2M) | 最大上下文窗口 |
| 编程专精 | GLM-4.7 / MiniMax M2.1 | 开源可自部署 |
## 10. 总结
1. **缓存不是万能的,但值得理解**: 合理利用缓存可节省 50-90% 成本
2. **Claude 需要显式配置**: 使用 `cache_control` 参数,否则不会有缓存
3. **国产模型自动缓存**: Kimi K2 和 GLM-4.7 自动检测重复前缀,无需配置
4. **只追加是关键**: 把上下文当作只追加日志,不要编辑历史
5. **多 Agent 代价适中**: 相对单Agent约**3-4倍**token消耗但性能提升90%+,适合高价值任务
6. **先让它工作,再优化**: 过早优化可能得不偿失
## 11. 数据来源与免责声明
**本文数据来源**:
1. **官方文档** (A级): Anthropic、OpenAI、Google官方定价和机制文档
2. **官方研究** (A级): Anthropic Engineering Blog的多Agent研究
3. **第三方报道** (B级): 国产模型价格和特性(已标注来源)
4. **实验估算** (C级): 50轮SWE任务等场景已标注假设条件
**重要提醒**:
- 所有价格和机制以**各家官方文档为准**,本文仅供参考
- 计算示例基于特定假设如连续操作在TTL内、固定每轮增量等
- 实际成本受任务复杂度、缓存命中率、模型选择等多因素影响
- 建议在实际应用中监控`usage`字段验证缓存效果
**数据更新日期**: 2025年12月28日
本文持续更新中,欢迎指正和补充。
---
## 参考资料
**官方文档**:
- [Claude Prompt Caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)
- [Anthropic Pricing](https://www.anthropic.com/pricing)
- [OpenAI Prompt Caching](https://platform.openai.com/docs/guides/prompt-caching)
- [OpenAI Pricing](https://openai.com/api/pricing/)
- [Gemini Context Caching](https://ai.google.dev/gemini-api/docs/caching)
- [Gemini Pricing](https://ai.google.dev/gemini-api/docs/pricing)
- [Moonshot AI Pricing](https://platform.moonshot.ai/docs/pricing/chat)
- [Moonshot Context Caching](https://platform.moonshot.cn/blog/posts/context-caching)
- [智谱 AI 定价](https://open.bigmodel.cn/pricing)
- [Z.AI Context Caching](https://docs.z.ai/guides/capabilities/cache)
- [MiniMax Prompt Caching](https://platform.minimax.io/docs/api-reference/text-prompt-caching)
**研究论文**:
- [SWE-agent: Agent-Computer Interfaces (NeurIPS 2024)](https://proceedings.neurips.cc/paper_files/paper/2024/file/5a7c947568c1b1328ccc5230172e1e7c-Paper-Conference.pdf)
- [CodeAgents: Token-Efficient Framework](https://arxiv.org/html/2507.03254v1)
- [Rethinking Multi-Agent Through Small-World Networks](https://arxiv.org/html/2512.18094v1)
- [Stop Wasting Your Tokens: Towards Efficient Runtime Multi-Agent Systems](https://arxiv.org/html/2510.26585v1)
**工程实践**:
- [Anthropic: Effective Context Engineering for AI Agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents)
- [Anthropic: Advanced Tool Use](https://www.anthropic.com/engineering/advanced-tool-use)
- [Building Agents with Claude Agent SDK](https://www.anthropic.com/engineering/building-agents-with-the-claude-agent-sdk)
- [AWS: Claude Code + Bedrock Prompt Caching](https://aws.amazon.com/blogs/machine-learning/supercharge-your-development-with-claude-code-and-amazon-bedrock-prompt-caching/)
- [Microsoft Azure SRE Agent Context Engineering](https://techcommunity.microsoft.com/blog/appsonazureblog/context-engineering-lessons-from-building-azure-sre-agent/4481200/)
- [Google: Architecting Efficient Context-Aware Multi-Agent Framework](https://developers.googleblog.com/architecting-efficient-context-aware-multi-agent-framework-for-production/)
**数据来源说明**: 本文价格和机制数据来自多个 AI 的网络调研结果交叉验证,部分数据可能随时间变化,请以各家官方文档为准。