Prompt 缓存 API 完全指南:用 Anthropic 和 OpenAI 缓存机制把重复调用成本压到最低

Prompt 缓存 API 完全指南:用 Anthropic 和 OpenAI 缓存机制把重复调用成本压到最低

为什么 prompt 缓存 API 值得你认真研究

调用大模型的成本里,有一块被严重低估:重复传输的 system prompt 和上下文。一个典型的 RAG 应用,每次请求都要把几千 token 的文档上下文塞进 prompt;一个代码审查 bot,每次都要附带几百行的规范说明。这些内容在单次对话里几乎一字不差,但每次都按全量 token 计费。

Anthropic 和 OpenAI 都提供了 prompt 缓存 API 机制来解决这个问题。两家的实现思路不同,命中条件也不同,用错了照样按原价跑。本文把两家的缓存逻辑拆开来看,并给出一套可以直接落地的结构设计方法。

---

两家缓存机制的核心差异

Anthropic:显式标记,精确控制

Claude Opus 4.8 / Sonnet 4.6 / Haiku 4.5 使用的是显式缓存机制,开发者需要在请求体里用 cache_control 字段手动标记需要缓存的 block:

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "你是一个代码审查助手,以下是完整的编码规范文档...",
            "cache_control": {"type": "ephemeral"}
        }
    ],
    messages=[{"role": "user", "content": user_question}]
)

关键参数和规则:

返回的 usage 对象里会包含 cache_creation_input_tokens 和 cache_read_input_tokens,可以直接监控命中情况。

OpenAI:自动缓存,无需标记

GPT-5.5 / GPT-5.4 / GPT-5.4-mini 使用的是隐式缓存机制,不需要任何额外字段,系统自动对 ≥ 1024 tokens 的 prompt 前缀进行缓存:

response = client.chat.completions.create(
    model="gpt-5.4",
    messages=[
        {"role": "system", "content": long_system_prompt},
        {"role": "user", "content": user_question}
    ]
)

# 命中情况在 usage 里查看
print(response.usage.prompt_tokens_details.cached_tokens)

OpenAI 缓存规则:

对比一览

| 维度 | Anthropic | OpenAI | |---|---|---| | 缓存方式 | 显式 cache_control | 自动前缀匹配 | | 最低门槛 | 1024 / 2048 tokens | 1024 tokens | | 命中折扣 | 标准价 × 0.1(节省 90%) | 标准价 × 0.5(节省 50%) | | TTL | 5 分钟 | 5~10 分钟 | | 最大断点数 | 4 个 | 不限(自动) | | 监控字段 | cache_read_input_tokens | cached_tokens |

---

最大化缓存命中率的结构设计方法

两家机制不同,但有一条共同的核心原则:把不变的内容放前面,把变化的内容放后面。

原则一:严格的内容稳定性分层

把 prompt 的内容按变动频率分成三层,从上到下排列:

1. 静态层(完全不变):角色定义、任务描述、输出格式要求、few-shot 示例、大段知识文档 2. 半静态层(按会话变化):当前对话的历史记录 3. 动态层(每次请求都变):用户当前输入

对于 Anthropic,在静态层末尾打上 cache_control 标记;对于 OpenAI,确保 system message 和 few-shot 示例放在 messages 数组最前面,且内容逐字节不变。

原则二:few-shot 示例的位置很关键

很多人把 few-shot 示例放在 user message 里,这在 OpenAI 的自动缓存下会导致每次前缀长度不固定,缓存无法命中。正确做法是把示例统一挪到 system message,或在 messages 数组里作为固定的前置对话轮次出现(role: user + role: assistant 交替),并保证它们在动态内容之前。

messages = [
    # 这两轮是固定 few-shot,始终在最前面
    {"role": "user", "content": "示例输入 A"},
    {"role": "assistant", "content": "示例输出 A"},
    {"role": "user", "content": "示例输入 B"},
    {"role": "assistant", "content": "示例输出 B"},
    # 动态内容从这里开始
    *conversation_history,
    {"role": "user", "content": current_user_input}
]

原则三:控制请求频率以维持 TTL

Anthropic 的 5 分钟 TTL 意味着,如果你的应用请求间隔超过 5 分钟,缓存就会失效,下一次又是 cache write 价格。对于低频场景,有两种应对方式:

原则四:用 Anthropic 的多断点做分段缓存

4 个 cache_control 断点可以应对"部分内容变、部分不变"的场景。比如一个法律助手,有一段固定的通用法规(2000 tokens),还有一段每个用户不同的合同文本(1500 tokens):

system=[
    {
        "type": "text",
        "text": FIXED_LEGAL_RULES,  # 所有用户共享,永远缓存
        "cache_control": {"type": "ephemeral"}
    },
    {
        "type": "text",
        "text": user_specific_contract,  # 同一用户的多轮对话里缓存
        "cache_control": {"type": "ephemeral"}
    }
]

这样通用法规对所有用户共享缓存,用户合同对单个用户的多轮对话内缓存,两层各自独立命中。

---

实际降本效果估算

以一个典型的文档问答应用为例:system prompt 4000 tokens,每次用户问题 50 tokens,模型回答 300 tokens,每天 10000 次调用。

使用 Claude Sonnet 4.6:

命中率能做到 80% 以上,前提是你的请求间隔稳定在 5 分钟以内,且 prompt 结构严格遵循"静态在前"原则。

---

如果你在做这类精细化的 API 成本控制,顺带推荐一下我用的接入方案:XycAi 词元平台(https://www.xyc.ai)。它是 OpenAI 兼容协议,一个 API key 能接 200+ 模型,Claude Code、Codex、Gemini CLI 都支持一键配置。GPT-5 和 Claude Opus 4.8 这类旗舰模型有时候低至官方价 1.4 折,加上全球 CN2 直连节点,延迟比直连官方 API 还低——对于需要频繁刷新缓存心跳的场景,这个延迟优势还挺实在的。企业用的话也有大模型算法备案号和全球发票支持。