1024 token 缓存触发条件

缓存不生效的常见原因

Anthropic Prompt Caching Docs(访问于 2026-05-19),触发缓存有两条硬规则:

  1. 最小块:被 cache_control 标记的累积 token ≥ 1024(Sonnet / Opus / Haiku 4.5 起统一)
  2. 字节级一致:同一段 block 文本一字、一空格、一换行符不变

Solopreneur 常见踩坑(实测见过的真实案例):

踩坑模式现象
system 含「今天是 2026-05-19」每天换文本,cache 每天失效
system 含用户名 / 租户名每个用户独立 cache 块,无法共享
用 f-string 拼 system,变量在中间每次插值不同,字节哈希变
system 只有 600 token不到 1024 条件,cache_control 被忽略
多 block 但 cache_control 只放在第一个后续 block 不缓存

工程化方案:三段分层

┌─────────────────────────────────────┐
│ 第 1 层:tools 定义(2-5K token)    │  ← cache_control
├─────────────────────────────────────┤
│ 第 2 层:品牌 system prompt(2-4K)  │  ← cache_control
├─────────────────────────────────────┤
│ 第 3 层:用户上下文 / 文档(可变)   │  ← 不加 cache_control
└─────────────────────────────────────┘

   messages: [{role: user, content: 今日问题}]

Anthropic Cookbook(访问于 2026-05-19)推荐写法,cache_control 一次请求最多 4 个,通常用 2-3 个分层。

代码示例:三层缓存

import anthropic

client = anthropic.Anthropic()

TOOLS = [...]  # tool 定义,3-5K token

BRAND_SYSTEM = """你是 [品牌名] 的 AI 助手,回复语气友好专业。

产品功能 1:...
产品功能 2:...
常见问答:Q1...A1...
常用术语:...
回复格式:...
"""  # 2-4K token,绝对不变

# 调用
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1500,
    tools=TOOLS,  # 自动可缓存(SDK 内部支持)
    system=[
        {
            "type": "text",
            "text": BRAND_SYSTEM,
            "cache_control": {"type": "ephemeral"},
        }
    ],
    messages=[
        {
            "role": "user",
            "content": f"当前用户:{username}\n租户:{tenant}\n时间:{now}\n\n问题:{q}",
        }
    ],
)

注意:把 username / tenant / now 全部塞 user 消息,绝不混进 system

1024 token 怎么数

文本类型1024 token 大致字数
中文长文(全汉字)1500-1800 字
中英文混合(技术文档)1200-1500 字
代码 + 注释800-1200 字符
JSON 结构600-1000 字符

Anthropic Token Counting API(访问于 2026-05-19),可以预先 POST 文本到 /v1/messages/count_tokens 拿精确 token 数。Solopreneur 部署前在 CI 里跑一次校验,避免改 system 后跌破 1024 条件而不自知。

版本指纹:防止悄无声息失效

PROMPT_VERSION = "brand-v3-2026-04-08"

# 在 system 末尾加版本注释(不影响语义)
BRAND_SYSTEM = f"""你是 [品牌名] 的 AI 助手...

<!-- prompt-version: {PROMPT_VERSION} -->
"""

部署管线里加一个测试:

  1. staging 启动后发一条测试请求
  2. 看响应 usage.cache_creation_input_tokens 是否非零
  3. 再发第二条相同 system 的请求
  4. 看响应 usage.cache_read_input_tokens 是否非零
  5. 都符合预期才推 production

按 2026 年 Anthropic Pricing(访问于 2026-05-19),Sonnet 4.6 cache_write 单价 $3.75/MTok、cache_read $0.30/MTok,如果 cache 失效一天,5K prompt × 10K 请求多花 $112.5。版本指纹这一步省下的钱比花的时间多 100 倍。

命中率监控与周度复盘

每条请求记日志:

log = {
    "timestamp": ...,
    "prompt_version": PROMPT_VERSION,
    "input_tokens": usage.input_tokens,
    "cache_creation_tokens": usage.cache_creation_input_tokens,
    "cache_read_tokens": usage.cache_read_input_tokens,
    "user_id": ...,
    "path": "/chat",
}

周度 SQL:

SELECT
  prompt_version,
  path,
  SUM(cache_read_tokens) * 1.0 /
    (SUM(cache_read_tokens) + SUM(input_tokens)) AS hit_rate
FROM api_log
WHERE created_at > now() - interval '7 days'
GROUP BY 1, 2;

健康参考线:

场景健康命中率
客服 SaaS(共享 brand prompt)80-95%
文档对话(每用户独立文档)30-50%
多轮 Agent(同一 session)90%+
RAG 检索类(每次 chunk 不同)看 system 是否稳定,40-70%

一字不改的部署纪律

Anthropic Cookbook(访问于 2026-05-19)和社区实测,稳定 cache 的关键是部署纪律:

  • system prompt 写死成常量,不要拼接动态值
  • 不要 trim() 不要二次格式化(空格变了 cache 也变)
  • 不要在 system 里 print 调试信息
  • 改 prompt 走 PR,升版本号
  • staging 跑命中率测试再 merge

很多团队踩的坑是「我只改了一个错别字」——错别字也是 cache miss。

tool definitions 也要 cache

跑 Agent 场景的 Solopreneur 特别注意:tools 数组通常 2-5K token,每次多轮调用全部重发。

# tool 定义 cache
response = client.messages.create(
    model="claude-sonnet-4-6",
    tools=[
        {"name": "search_db", "description": "...", "input_schema": {...}},
        # 10-30 个 tool
    ],
    system=BRAND_SYSTEM,
    messages=conversation_history,
)

按 Anthropic 文档,tools 是 cacheable block。Agent 在一个 session 内来回调 10-20 次,tool 定义全部 cache_read 单价(0.1x base),省钱效果显著。

中转方透传性测试

签约中转方前,跑这个脚本:

# 同一 system 发 2 次,看第二次的 cache_read
resp1 = client.messages.create(..., system=[{"text": LONG_PROMPT, "cache_control": {"type": "ephemeral"}}])
print(resp1.usage.cache_creation_input_tokens)  # 应非零
print(resp1.usage.cache_read_input_tokens)  # 应零(首次)

time.sleep(2)
resp2 = client.messages.create(..., system=[{"text": LONG_PROMPT, "cache_control": {"type": "ephemeral"}}])
print(resp2.usage.cache_creation_input_tokens)  # 应零
print(resp2.usage.cache_read_input_tokens)  # 应非零(命中)

如果中转方第二次响应里 cache_read 还是零,要么协议没透传,要么内部走了不同 endpoint。这种中转方一律不签。Solopreneur 用一条独立开发者用得起的 Claude 4.7 / GPT-5.5 中转跑日常,签约前用上面 6 行代码验证,半小时就能判清。

关联文章