🎁 新人 免费注册,送 10 次调用,最高 $1,免绑卡。
Python 实战:用代码实现 LLM 提示词缓存

Python 实战:用代码实现 LLM 提示词缓存

目录
  1. 0. 环境准备
  2. 1. 感知缓存的调用方式(所有供应商相同)
  3. 2. Anthropic Claude — 显式 cache_control 标记
  4. 3. OpenAI GPT-5.x — 自动缓存
  5. 4. Google Gemini — 隐式缓存
  6. 5. DeepSeek-v4-flash — 磁盘型自动缓存
  7. 6. Alibaba Qwen — 已报告命中,但折扣不稳定
  8. 7. 跨供应商基准测试(实测于 2026-05-25)
  9. 8. 上线前检查清单
  10. 9. 感知 TTL 的设计模式
  11. 8.1 会话型工作负载(聊天、IDE 助手)
  12. 8.2 Batch / Cron 的心跳保活
  13. 8.3 冷存储文档
  14. 10. 网关实际提供了什么
  15. 常见问题

TL;DR — 一套 OpenAI SDK、一个 base_url,即可调用所有主流 LLM。本文数据于 2026-05-25 通过在线 Synthorai 网关实测,使用约 7,300 token 的稳定 system prompt。这里使用网关的理由很简单:统一 endpoint、统一认证 header,并直接返回 usage.cost,无需自行维护各供应商的价格矩阵。缓存背后的 Transformer 原理见第 1 篇:缓存原理;各供应商的设计差异见第 2 篇:供应商对比

系列文章:第 3 篇,共 5 篇 · 前文:第 1 篇 — 缓存原理 · 第 2 篇 — 供应商对比与评估 · 后续:第 4 篇 — 按场景选择最佳 LLM · 第 5 篇 — LangChain 集成


0. 环境准备

pip install openai
# common.py — reused across every example
import os, time
from openai import OpenAI

oai = OpenAI(
    api_key=os.environ["SYNTHORAI_KEY"],
    base_url="https://synthorai.io/v1",
)

网关对所有接入的模型(GPT、Claude、Gemini、DeepSeek、Qwen)都使用 OpenAI wire format。切换模型只需修改 model 字段,不必更换 SDK。认证方式为 Authorization: Bearer <key>

公共网关上支持缓存的 model ID(2026-05 快照)包括:claude-haiku-4-5claude-sonnet-4-5 / 4-6claude-opus-4-5 / 4-6 / 4-7gpt-5.4-minigpt-5.4-nanogpt-5.2gpt-5.5-progemini-2.5-flashgemini-2.5-progemini-3.1-pro-previewdeepseek-v4-flashqwen3-maxqwen3.5-flash。可通过 GET /v1/models 获取完整的实时列表。


1. 感知缓存的调用方式(所有供应商相同)

不需要手动启用。只要上游模型支持提示词缓存,网关就会透传响应元数据。通过两个字段即可确认缓存情况:

resp = oai.chat.completions.create(
    model="gpt-5.4-mini",
    max_tokens=128,
    messages=[
        {"role": "system", "content": LONG_STABLE_PROMPT},   # ~7K tokens
        {"role": "user",   "content": "First question"},
    ],
)
print(resp.usage.prompt_tokens_details.cached_tokens)   # cache hit count
print(resp.usage.cost)                                  # USD, gateway-computed

cached_tokens 表示命中上游前缀缓存的输入 token 数。usage.cost 是网关计算出的单次调用美元成本,无需在本地维护各供应商的费率表。

由缓存架构决定的两条规则,对所有供应商都适用:

  1. 稳定内容放前面,动态内容放后面。 前缀从第 0 个 token 开始匹配;开头只要变化一个 byte,整个前缀都会失效。
  2. 不要把动态数据放进 system prompt。 当前时间戳、session ID 和 request UUID 都会导致缓存失效。

下面只是针对不同供应商演示同一种模式。


2. Anthropic Claude — 显式 cache_control 标记

Claude 属于显式标记类型,Anthropic API 不会自动缓存。要命中缓存,需要在 systemmessages 数组中添加 cache_control breakpoint,最多可设置四个。读取缓存的成本约为正常输入价格的 10%;写入缓存按 125% 计费,即溢价 25%。

通过网关使用 cache_control 的最佳方式,是将官方 anthropic SDK 指向网关的 Anthropic 原生 endpoint。目前,兼容 OpenAI 的 /chat/completions 路径不会传递 cache_control 标记;Claude 缓存需要使用 /v1/messages

import os
from anthropic import Anthropic

anth = Anthropic(
    api_key=os.environ["SYNTHORAI_KEY"],
    base_url="https://synthorai.io/",   # SDK appends /v1/messages
)

msg = anth.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=512,
    system=[
        {"type": "text", "text": SYSTEM_INSTRUCTIONS,
         "cache_control": {"type": "ephemeral"}},       # BP 1: never changes
        {"type": "text", "text": TOOL_DESCRIPTIONS,
         "cache_control": {"type": "ephemeral"}},       # BP 2: rarely changes
        {"type": "text", "text": RETRIEVED_DOCUMENTS},  # changes per call — not cached
    ],
    messages=[{"role": "user", "content": question}],
)

print(msg.usage)
# Usage(input_tokens=18, output_tokens=64,
#       cache_creation_input_tokens=0, cache_read_input_tokens=8123,
#       cost=...)

TTL 选项。 {"type": "ephemeral"} 默认采用 5 分钟的滑动 TTL,每次命中都会延后过期时间。如果工作负载的空闲间隔超过 5 分钟,可以在同一标记上指定 1 小时 TTL:

"cache_control": {"type": "ephemeral", "ttl": "1h"}

分层 breakpoint。 最多四个标记可分别缓存“永不变化”“很少变化”和“按任务变化”的内容。这种机制最适合 agent 和 RAG,因为各段提示词的更新频率不同。即使末尾一层(例如检索到的文档)每次调用都会变化,前面的各层仍然可以命中缓存。

模型选择。 截至 2026-05,网关提供的 Claude model ID 包括 claude-haiku-4-5claude-sonnet-4-5 / 4-6claude-opus-4-5 / 4-6 / 4-7。低成本聊天选 Haiku;通用场景及需要更强 agent 缓存模式的场景选 Sonnet;难度最高的推理任务选 Opus。

实测缓存命中、写入及无缓存基准(2026-05-25,约 7,976-token system prompt,max_tokens=64):

模型缓存写入缓存读取无缓存基准读取折扣命中 TTFT(stream)
claude-haiku-4-5$0.00916$0.00086$0.00725−88%1.31 s
claude-sonnet-4-5$0.02713$0.00247$0.02175−89%1.76 s
claude-sonnet-4-6$0.02736$0.00253$0.02198−88%1.81 s
claude-opus-4-5$0.04522$0.00409$0.03624−89%2.08 s
claude-opus-4-6$0.04522$0.00411$0.03625−89%2.55 s
claude-opus-4-7$0.06545$0.00609$0.05259−88%2.30 s

整个 Claude 系列的折扣基本一致。写入成本比无缓存调用高约 25%,与 Anthropic 公布的费率相符;命中一次即可回本。


3. OpenAI GPT-5.x — 自动缓存

当前缀足够长时,OpenAI 会自动缓存。无需修改代码,也不需要添加标记。

def ask_gpt(question: str):
    t0 = time.perf_counter()
    resp = oai.chat.completions.create(
        model="gpt-5.4-mini",
        max_tokens=64,
        messages=[
            {"role": "system", "content": LONG_STABLE_PROMPT},
            {"role": "user",   "content": question},
        ],
    )
    return resp, time.perf_counter() - t0

r1, t1 = ask_gpt("Which export formats are supported?")
r2, t2 = ask_gpt("How long is the refund window for annual plans?")

print(t1, r1.usage.prompt_tokens_details.cached_tokens, r1.usage.cost)
# 3.63   0       0.00267
print(t2, r2.usage.prompt_tokens_details.cached_tokens, r2.usage.cost)
# 1.23   6400    0.00257

同一个 6,887-token prompt 连续调用两次。第二次调用中,93% 的 system prompt 命中缓存,总延迟从 3.6 s 降到 1.2 s。这里的成本变化很小,因为第一次调用生成的 completion 更长,抵消了缓存折扣。§7 提供了更清晰的跨供应商数据。

gpt-5.4-nano 的折扣更明显,命中后成本降低 44%。如果聊天 UI 只关注首 token 延迟,应查看 streaming 数据:

def ttft(model, question):
    t0 = time.perf_counter()
    stream = oai.chat.completions.create(
        model=model, max_tokens=64,
        messages=[
            {"role": "system", "content": LONG_STABLE_PROMPT},
            {"role": "user",   "content": question},
        ],
        stream=True, stream_options={"include_usage": True},
    )
    for ev in stream:
        if ev.choices and ev.choices[0].delta and ev.choices[0].delta.content:
            return time.perf_counter() - t0     # first content token

缓存命中后的实测 TTFT:gpt-5.4-mini0.73 sgpt-5.4-nano1.00 s


4. Google Gemini — 隐式缓存

通过网关调用时,Gemini 也会自动缓存,无需执行 cachedContent 创建步骤。

r = oai.chat.completions.create(
    model="gemini-2.5-flash",
    max_tokens=128,
    messages=[
        {"role": "system", "content": LONG_STABLE_PROMPT},
        {"role": "user",   "content": "Summarize section 6 in two bullets."},
    ],
)
print(r.usage.prompt_tokens_details.cached_tokens, r.usage.cost)

使用约 7,300-token system prompt 测试 gemini-2.5-flash 时,7,140 个 token 命中缓存(97%),成本从 $0.00198 降至 $0.00024,本次调用节省 88%

需要注意两个问题

  • Gemini 的 *-pro 变体是 reasoning model。max_tokens 较小时,预算可能全部消耗在隐藏的思考过程中,因此经常会看到 completion_tokens=0。面向用户的任务应将 max_tokens 提高到 ≥256。
  • 隐式缓存的 TTL 很短,官方也没有公布具体值。测试中,间隔 5 s 的两次调用可以命中;约 10 s 后的第三次调用有时会 miss。不要让业务逻辑依赖缓存必定命中。应检查 cached_tokens,并为 miss 做好降级处理。

5. DeepSeek-v4-flash — 磁盘型自动缓存

DeepSeek 的自动缓存比其他供应商常见的 GPU 内存缓存保留得更久。调用方式相同:

r1 = oai.chat.completions.create(
    model="deepseek-v4-flash", max_tokens=128,
    messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
              {"role": "user",   "content": "Q1"}],
)
# r1.usage.cost = $0.00091, cached_tokens = 0

r2 = oai.chat.completions.create(
    model="deepseek-v4-flash", max_tokens=128,
    messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
              {"role": "user",   "content": "Q2"}],
)
# r2.usage.cost = $0.00023, cached_tokens = 6784  →  74% saved

命中缓存后的 streaming TTFT 为 2.93 s。在这组模型中,DeepSeek 并不是延迟最低的选择。它的优势在于成本,以及即使请求间隔达到小时级,缓存仍可保持 warm。


6. Alibaba Qwen — 已报告命中,但折扣不稳定

r = oai.chat.completions.create(
    model="qwen3-max", max_tokens=128,
    messages=[{"role": "system", "content": LONG_STABLE_PROMPT},
              {"role": "user",   "content": "Q1"}],
)
print(r.usage.prompt_tokens_details.cached_tokens, r.usage.cost)
# 7040    0.00549

本轮测试中有一个限制:cached_tokens 显示缓存命中(7,040 / 7,234 = 97%),但命中后的 usage.cost 并未下降,仍约为 $0.0055。这说明上游确实命中了缓存,因为 TTFT 从冷启动时的 3.03 s 降至 1.53 s,但截至测试日期,网关返回的该供应商成本字段尚未体现缓存费率折扣。如果对 Qwen 的成本敏感,应同时监控 cached_tokens,在这一问题恢复正常前,以其上游价格页面为准。


7. 跨供应商基准测试(实测于 2026-05-25)

单次顺序测试。稳定 system prompt 长 7,284 个字符,不同 tokenizer 下约为 6,900–7,300 个 token。max_tokens=64。先调用一次产生 miss,随后立即调用一次产生 hit。

以下供应商支持自动缓存,无需添加标记:

模型Miss 成本Hit 成本成本 ΔMiss 总耗时Hit 总耗时Hit TTFT(stream)缓存命中率
gpt-5.4-nano$0.00131$0.00074−44%2.18 s1.48 s1.00 s5,888 / 6,887 (85%)
gpt-5.4-mini$0.00267$0.00257−4%*3.63 s1.23 s0.73 s6,400 / 6,887 (93%)
gemini-2.5-flash$0.00198$0.00024†−88%2.49 s1.37 sn/a‡7,140 / 7,322 (97%)
gemini-2.5-pro$0.00824$0.00205†−75%2.99 s1.76 sn/a‡6,120 / 7,328 (84%)
deepseek-v4-flash$0.00091$0.00023−74%4.02 s3.71 s2.93 s6,784 / 7,101 (96%)
qwen3-max$0.00553$0.00549−1%§4.80 s2.37 s1.53 s7,040 / 7,234 (97%)

* gpt-5.4-mini 的 miss 调用生成了 44 个 token,而 hit 调用只生成了 19 个,因此成本差异同时受到缓存折扣和 completion 长度变化的影响。延迟从 3.63 s 降至 1.23 s,更能直接体现缓存效果。 † 这是 streaming 调用的成本,当时返回了 cached_tokens。Gemini 的非 streaming 调用偶尔会返回 cached_tokens=null,此时成本也不会下降。网关目前返回的 Gemini 元数据并不稳定;存在 cached_tokens 时,以该字段为准。 ‡ Gemini 的 *-pro / *-flash reasoning model 在 max_tokens 较小时经常不会生成任何内容 token,因此这个预算下的 TTFT 没有意义。在生产环境测量时,应提高 max_tokens。 § 参见 §6。上游缓存已命中,延迟也随之下降,但截至测试日期,网关的 usage.cost 字段尚未体现 qwen3-max 的折扣。

Anthropic Claude 依赖显式标记。由于必须通过 cache_control 主动启用折扣,数据单独列出,具体模式见 §2。使用相同 prompt,分别测量缓存写入和缓存读取:

模型写入成本读取成本读取折扣Hit TTFT(stream)
claude-haiku-4-5$0.00916$0.00086−88%1.31 s
claude-sonnet-4-5$0.02713$0.00247−89%1.76 s
claude-sonnet-4-6$0.02736$0.00253−88%1.81 s
claude-opus-4-5$0.04522$0.00409−89%2.08 s
claude-opus-4-6$0.04522$0.00411−89%2.55 s
claude-opus-4-7$0.06545$0.00609−88%2.30 s

实际结果会受到区域、时段以及其他租户是否已预热相同前缀等因素影响。这些数据只来自单次、单日测试,不应当作权威基准引用。


8. 上线前检查清单

上线感知缓存的提示词前,逐项检查:

  1. 稳定内容放前面 — system prompt、知识库和 tool schema 放在 messages 顶部。
  2. 动态内容放后面 — 用户输入、检索文档和时间戳放在底部。
  3. system 中不要出现动态变量 — 当前时间、user ID 和随机种子都会破坏前缀缓存。
  4. 记录每次调用的 cached_tokens 如果生产环境命中率低于 50%,说明前缀并不稳定。应检查发生 miss 的 prompt。
  5. 不要根据一次命中做判断。 TTL 很短;设计时应按 hit_rate ∈ [0, 1) 处理,而不是假设“始终命中”。

9. 感知 TTL 的设计模式

生产环境最常见的问题并不是“忘记启用缓存”,而是“请求并没有在 TTL 窗口内到达,导致命中率只有 12%”。

8.1 会话型工作负载(聊天、IDE 助手)

这类请求的自然间隔通常远低于 TTL。只要 prompt 结构合理,缓存会自行保持 warm,不需要增加其他机制。

8.2 Batch / Cron 的心跳保活

假设每天 09:00 运行报表任务,在 3 分钟内调用模型 50 次。由于缓存经过一夜已经变冷,09:00 的第一次缓存写入无法复用之前的结果。可以从 08:55 开始,每隔 TTL/2 发送一次带缓存前缀的 1-token “ping”,让缓存保持 warm:

def keepalive():
    oai.chat.completions.create(
        model="gpt-5.4-mini",
        max_tokens=1,
        messages=[
            {"role": "system", "content": LONG_STABLE_PROMPT},
            {"role": "user",   "content": "."},
        ],
    )

每次 ping 的成本是输入 token 数 × 缓存费率。对于本文在 gpt-5.4-mini 上使用的 7K-token 前缀,约为 $0.0026,远低于让 batch job 的前 50 次真实调用都支付完整 prefill 成本。

8.3 冷存储文档

对于查询频率较低的文档,例如每天以每小时一次的频率查询,内存缓存大多数时候都会处于 cold 状态。截至本文发布时,网关尚未提供托管式显式缓存创建 endpoint。需要长 TTL 时,可使用 deepseek-v4-flash,其磁盘型缓存实测可跨越小时级间隔;也可以绕过网关,直接调用 Google 原生的 cachedContent API。


10. 网关实际提供了什么

声称网关“替你完成缓存”并不准确。缓存发生在模型层,网关只是将相关能力暴露出来。与直接使用各供应商的原生 SDK 相比,网关提供三项能力:

  1. 一个 base_url、一套认证 header、所有模型。 只需替换 model 字段,调用结构保持不变。messages 数组和 usage 字段结构也完全一致,不必为五个供应商维护五套 SDK。
  2. 每次调用都返回美元计价的 usage.cost 网关根据当前上游费率计算成本并写入响应。无需在代码中维护价格矩阵,也不必订阅各供应商的价格调整通知。
  3. 统一的 cached_tokens 字段。 Anthropic 通过 cache_read_input_tokens 报告缓存命中,OpenAI 使用 prompt_tokens_details.cached_tokens,DeepSeek 使用 prompt_cache_hit_tokens。网关将这些字段统一为 OpenAI 格式,监控代码无需按供应商分支处理。

网关的价值就是这三点。至于何时缓存、如何组织 prompt、选择哪个模型,将在下一篇文章中讨论。


下一篇第 4 篇 — 如何按使用场景选择最佳 LLM:聊天、API 与 AI Agent — 通过决策矩阵将工作负载类型与最佳模型及缓存策略对应起来,并给出成本计算。


常见问题

为什么用 OpenAI SDK 调用非 OpenAI 模型? 网关对接入的每个供应商都使用 OpenAI wire format。官方 openai SDK 提供类型化响应、自动重试和 streaming 辅助工具,没有必要自行实现五套 HTTP client。

缓存是否适用于 streaming 响应? 适用。传入 stream_options={"include_usage": True} 后,最后一个 chunk 中的 usage 对象会报告缓存命中数。缓存带来的延迟改善在 streaming 场景最明显,因为用户直接感知的是 TTFT。

对于我的工作负载,哪家供应商的缓存折扣最高? 按照 2026-05 的价格,在命中率达到 70% 以上时,§7 表格中的 gemini-2.5-flashdeepseek-v4-flash 成本最低。gpt-5.4-mini 的 TTFT 最优。Claude 官方标明缓存折扣为 90%,但需要添加最多四个 cache_control breakpoint,详见 §2。最可靠的方式是用自己的 prompt 运行相同测试。这只需要一天,不必进行持续数周的迁移。

什么时候需要 cache_control 标记? 只有调用 Anthropic Claude 时需要,详见 §2。OpenAI、Gemini、DeepSeek 和 Qwen 会在上游自动缓存足够长的前缀,因此不需要标记;向这些供应商传入该字段时会被静默忽略。

这些数据有多新? 数据于 2026-05-25 在公共网关上实测。它们只代表单个数据点;价格和延迟会随每个发布周期变化。

Anthropic Claude 怎么处理? 网关支持通过显式 cache_control 标记使用 Claude。请使用 anthropic SDK,并设置 base_url="https://synthorai.io/",SDK 会自动追加 /v1/messages。目前兼容 OpenAI 的 /chat/completions 路径不会传递这些标记;Claude 缓存必须使用 §2 所示的 Anthropic 原生路径。


来源与验证:所有数据均于 2026-05-25 使用 openai SDK 2.38.0,通过 https://synthorai.io/v1 实测。供应商价格页面:Anthropic 提示词缓存 · OpenAI 提示词缓存 · Google Gemini 上下文缓存 · DeepSeek KV Cache 指南 · Alibaba Bailian 上下文缓存

← 返回博客