文档
提示缓存
使用 cache_control 标记一次稳定的提示前缀;或者通过 OpenAI 格式调用 Claude 模型(该格式没有此字段),Kunavo 会为你设置缓存断点。后续每次复用此前缀的调用,都会按输入价格的一小部分对该前缀计费 — 大多数聊天模型按输入价格的 10% 计费,最低可至 2.5%。Kunavo 的路由层会将对话固定到同一个上游密钥,以保持缓存处于热状态。
使用 Claude Sonnet 5 处理 30K token 的系统提示词时,缓存读取费用为 $0.14 / 1M,而不是 $1.4 / 1M。 对于每个会话中会重复发送同一上下文 50 次的智能体,缓存可节省约 90% 的输入费用。
如何启用
在任意系统块、消息或工具定义上添加一个 cache_control: { type: "ephemeral" } 断点。模型会在首次调用时缓存该断点之前的内容;后续调用只要共享相同的前缀字节,就会命中缓存。
from openai import OpenAI
client = OpenAI(
api_key="sk-kn-...",
base_url="https://api.kunavo.com/v1",
)
# Mark the large, stable prefix once with cache_control.
# Every subsequent call that sends the same prefix reads it back
# from cache at 0.10× the input rate on Claude Sonnet 5.
# Per-model rates are in the pricing table below.
SYSTEM = [
{
"type": "text",
"text": open("long_system_prompt.txt").read(),
"cache_control": {"type": "ephemeral"},
},
]
resp = client.chat.completions.create(
model="claude-sonnet-5",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "Summarize the doc above in 3 bullets."},
],
)
u = resp.usage
# OpenAI-compat fields populated by Kunavo:
# - prompt_tokens_details.cached_tokens — read from cache
# - cache_creation_input_tokens — written to cache this call
print(u.prompt_tokens_details.cached_tokens,
getattr(u, "cache_creation_input_tokens", 0))在原生 Messages API 上使用完全相同的线路格式 — cache_control 会原样传递给 Claude,不做翻译:
# Native Anthropic Messages API — cache_control passes through untranslated.
curl https://api.kunavo.com/v1/messages \
-H "Authorization: Bearer $KUNAVO_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"system": [
{
"type": "text",
"text": "<your large stable system prompt>",
"cache_control": { "type": "ephemeral" }
}
],
"messages": [
{ "role": "user", "content": "Summarize the doc above in 3 bullets." }
],
"max_tokens": 1024
}'在 OpenAI 格式端点上自动插入断点
OpenAI Chat Completions 和 Responses 格式都没有 cache_control 字段 — OpenAI 会在自己的服务器上隐式缓存。Claude 则不会:它只缓存由断点标记的内容。因此,使用 OpenAI 协议的客户端无法请求缓存;如果只是直接翻译请求,发给 Claude 的内容就不会带有任何断点 — 长对话的每一轮都会按完整输入费率对全部历史记录重新计费。
因此,当您通过 /v1/chat/completions 或 /v1/responses 调用 Claude 模型时,Kunavo 会设置协议无法传递的断点。您无需开启任何设置。此功能仅适用于 Claude 模型 — 其他所有模型系列均通过其供应商会隐式缓存的协议提供服务,无需设置断点。
# Plain OpenAI Chat Completions — no cache_control anywhere in the body.
# The format has no field for one; Kunavo inserts the breakpoints instead.
resp = client.chat.completions.create(
model="claude-sonnet-5",
messages=[
{"role": "system", "content": LONG_SYSTEM_PROMPT},
{"role": "user", "content": "first question"},
{"role": "assistant", "content": "...previous answer..."},
{"role": "user", "content": "follow-up"},
],
)
u = resp.usage
# Turn that writes the cache:
# u.cache_creation_input_tokens -> 18,000
# u.prompt_tokens_details.cached_tokens -> 0
# Next turn, same prefix, inside the 5-minute window:
# u.cache_creation_input_tokens -> 240 (only the new turn)
# u.prompt_tokens_details.cached_tokens -> 18,000
#
# Both stuck at 0 on a conversation well over the threshold? The prefix is
# changing between calls — a timestamp or request id inside the cached span.断点的位置及预算的使用顺序如下:
- 在最后一条消息上设置滚动断点 — 放在最后一条消息的最后一个内容块上,以便缓存之前的所有内容;如果请求以一条留在对话中的 system 消息结尾(见下文),则改放在该消息前面紧挨着的那个内容块上。只有在
messages已有一轮 assistant 对话后才会添加:写入缓存会按1.25×输入计费,因此标记一个不会被再次发送的提示会多花四分之一的费用,却没有任何收益。之前已有 assistant 对话,表明这个完全相同的前缀即将再次出现。 - 在
system和tools上各设置一个断点 — 用于标记提示中稳定不变的开头。即使是单次调用,也值得标记,因为调用方只要发送一次系统提示,几乎总会在下一次调用中发送相同的提示。 - 在留在对话中的 system 消息前面 — 滚动断点和
system、tools上的断点用剩的预算,会放在最后一条后面还有内容的此类消息前面紧挨着的内容块上,然后是再前面的一条。它排在最后填充,因为只有在不同轮次之间移动此类消息的客户端才需要它;没有此类消息的对话(几乎所有对话都是这样)就没有这个位置。
该功能受两项限制。提示内容(包括消息、system 和工具架构)少于 8,192 个字符时,不会插入任何断点:Anthropic 会静默忽略其可缓存长度下限以下的前缀上的断点(1,024 个令牌,Haiku 为 2,048 个),也不会收取缓存写入或读取费用,因此在此处添加断点没有任何收益。此外,Anthropic 每个请求最多接受 4 个断点 — 第 5 个断点会导致硬性 400 错误,而非静默忽略。
模型首次回答之后发送的 system 或 developer 消息会留在对话中、留在它被发送时所在的那一轮,而不会被提升到 system 中:那样做会在加入它的那一轮改变提示的开头,并把整段历史重新写入缓存。在上游接受的情况下,Claude 会以 system 消息的形式收到它;否则,它会作为该用户轮次中的文本,放在 <system-reminder> 标签之间。在模型首次回答之前发送的 system 消息,或其自身断点要求一小时缓存的消息,仍会放入 system。
/v1/messages 端点上不会插入任何内容:您的请求体会按原样传递,其中的每个断点都由您设置。报告方式不会改变:无论断点是由您还是网关添加,响应字段部分所述的同一组 cached_tokens 和 cache_creation_input_tokens 字段都会得到填充,因此您可以通过 usage 对象确认插入的断点是否确实带来了缓存命中。
定价
缓存费率根据每个模型的输入价格,按照供应商规定的比例计算 — 以下表格为准,表中每项费率均根据该模型的输入价格计算得出,而非手动填写。在 Anthropic 和 OpenAI 上,缓存读取均按输入价格的 0.10× 计费,有2项例外:0.025× on Claude Fable 5.1, 0.05× on Claude Opus 5.5。每个 Claude 模型的缓存写入均按输入价格的 1.25× 计费 ,GPT-6 Astra、GPT-6 Sol、GPT-6 Luna、GPT-5.6 Sol和GPT-5.6 Terra 也适用同一费率。Kunavo 对 Claude 的 1 小时 TTL 写入也按相同的 1.25× 计费,低于 Anthropic 的 2×。其他所有模型均没有单独的写入价格:其写入按普通输入费率计费。无论哪种情况,前缀只要复用一次,缓存后的费用就会低于重新发送。每种缓存类型都采用模型自身的折扣,因此缓存价格相对于供应商标价的折扣幅度,与其输入和输出价格的折扣幅度相同。
Anthropic
| Model | Input | Cache read | Cache write |
|---|---|---|---|
| Claude Fable 5.1 | $7 | $0.175 0.025× | $8.75 1.25× |
| Claude Fable 5 | $7 | $0.7 0.10× | $8.75 1.25× |
| Claude Opus 5.5 | $2.8 | $0.14 0.050× | $3.5 1.25× |
| Claude Opus 5 | $3.5 | $0.35 0.10× | $4.375 1.25× |
| Claude Opus 4.8 | $3.5 | $0.35 0.10× | $4.375 1.25× |
| Claude Opus 4.7 | $3.5 | $0.35 0.10× | $4.375 1.25× |
| Claude Opus 4.6 | $3.5 | $0.35 0.10× | $4.375 1.25× |
| Claude Sonnet 5 | $1.4 | $0.14 0.10× | $1.75 1.25× |
| Claude Sonnet 4.6 | $2.1 | $0.21 0.10× | $2.625 1.25× |
| Claude Haiku 4.5 | $0.7 | $0.07 0.10× | $0.875 1.25× |
OpenAI
| Model | Input | Cache read | Cache write |
|---|---|---|---|
| GPT-6 Astra | $4 | $0.4 0.10× | $5 1.25× |
| GPT-6 Sol | $0.8 | $0.08 0.10× | $1 1.25× |
| GPT-6 Luna | $0.04 | $0.004 0.10× | $0.05 1.25× |
| GPT-5.6 Sol | $2 | $0.2 0.10× | $2.5 1.25× |
| GPT-5.6 Terra | $0.7 | $0.07 0.10× | $0.875 1.25× |
| GPT-5.5 | $2 | $0.2 0.10× | $2 1× |
max(catalog_cost, upstream × markup) 计费 — 该最低价根据缓存输入费率而非未缓存输入费率计算,因此节省的费用会由您享有,而不会被抵消。亲和性路由让缓存保持热状态
上游提示缓存按 API 密钥隔离。如果每个请求都随机分配到不同的上游密钥,缓存命中率约为 1/N。Kunavo 会根据您的系统提示和第一条用户消息生成稳定哈希,并将具有相同前缀的所有调用路由到同一个上游密钥 — 使用加权 rendezvous 哈希,因此池发生变化时,只有约 1/N 的密钥会被重新映射。
您无需进行任何配置。亲和性路由会自动应用于所有聊天调用。(图像 / 视频 / TTS 使用随机路由 — 这些模态没有按密钥隔离的缓存。)
仪表盘指标
开始命中缓存后,/app/usage 会针对所选时间范围显示两项汇总指标:
- 命中率 — 缓存输入令牌数 ÷ 输入令牌总数。根据每次调用的令牌数精确计算。
- 节省金额 — 此时间范围内节省的美元金额,按模型使用其实际缓存读取费率计算(不采用简单平均值近似)。此金额按目录费率估算 — 实际账单以目录价格为最低价,而缓存调用的费用可能低于该最低价,因此此数值是实际节省金额的严格上限。对于典型的聊天工作负载,两者相差不到几个百分点。
每次调用的详情页面(/app/usage/<id>)会显示非零的缓存及缓存写入令牌数,以及实际计费金额。
响应字段
Kunavo 会在两种响应格式中显示缓存令牌。在 OpenAI 兼容的 /v1/chat/completions 端点上:
| 字段 | 含义 |
|---|---|
usage. | 输入令牌总数(包括缓存令牌和写入缓存的令牌)。 |
usage. | 输入令牌中由缓存提供的部分。 |
usage. | 此次调用写入缓存的令牌(按上表所列模型的缓存写入费率计费)。 |
在 /v1/messages 的原生 Messages API 上,会原样传递 Anthropic 的原始字段:
| 字段 | 含义 |
|---|---|
input_tokens | 新输入(未缓存)。 |
cache_ | 从缓存提供,按 0.10× 输入价格计费(在Claude Fable 5.1上的比例为0.025×,在Claude Opus 5.5上的比例为0.05×)。 |
cache_ | 此次调用写入缓存的内容(按输入价格的 1.25 倍计费 — 1 小时 TTL 写入也是如此,低于 Anthropic 的 2 倍)。 |
接下来
- Messages API 参考 — 原生 Anthropic 格式,包含缓存示例。
- Claude 提示缓存 — 如何根据 usage 对象中的数值诊断缓存,以及通过网关路由导致命中率下降的三种方式。
- 计费与账本 — 缓存感知的 max() 最低价如何与上游成本交互。
- 完整定价表 — 所有聊天模型的未缓存输入 / 输出价格,底部附有缓存子表。