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

35 KiB
Raw Permalink Blame History

大模型上下文缓存经济学别让你的Agent"烧钱"

核心警告: 你习以为常的"编辑消息、修改历史、DIY上下文"操作在LLM Agent中会让成本暴增7-50倍。本文帮你建立缓存意识避免成本灾难。


🚨 如果你正在做这些事,请立即停止

# ❌ 危险操作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开发

传统后端开发 (你习惯的方式):

# 数据是可以随意修改的
user_state = {"step": 1, "data": []}
user_state["step"] = 2  # 修改状态
user_state["data"].append(new_item)  # 添加数据
del user_state["history"]  # 删除不需要的

LLM Agent开发 (必须遵守的规则):

# 上下文是"只追加日志",一旦修改前缀 = 缓存全失效
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

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% 失效

正确做法

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: 消息压缩与摘要替换

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: 滑动窗口截断

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: 消息编辑与插入

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 状态管理不当

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 响应头:

{
  "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 (自动缓存):

{
  "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

使用方法:

{
  "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_keyprompt_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

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 固定,状态作为新消息追加

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:

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)

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 设计

# 正确: 只追加,不修改
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 缓存配置

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日

本文持续更新中,欢迎指正和补充。


参考资料

官方文档:

研究论文:

工程实践:

数据来源说明: 本文价格和机制数据来自多个 AI 的网络调研结果交叉验证,部分数据可能随时间变化,请以各家官方文档为准。