Lovely Router文档
获取密钥
模型 API

提示缓存

重复的提示词前缀只需支付输入价格的一小部分。使用各厂商自己的缓存机制,并由网关让每个对话始终留在持有其缓存的渠道上。

提示缓存让模型可以复用它最近处理过的提示词前缀。缓存输入的价格只有普通输入价格的一小部分:在 claude-sonnet-5.5 上,缓存读取每百万 token $0.10,而未缓存输入为 $2.00。对于智能体和长对话,每一轮都会重新发送全部历史,因此大部分输入 token 都可以从缓存中读取。

通过 Lovely Router 使用提示缓存,依靠两点:

  1. 厂商缓存。 你完全按照各厂商的文档使用其缓存机制。cache_control、prompt_cache_key 等请求字段原样透传。
  2. 对话亲和。 缓存存在于写入它的渠道上。网关会识别同一对话的各轮请求,并把它们送回同一个渠道,这样下一轮到来时缓存仍然在那里。

Anthropic#

Claude 只缓存你标记的内容。把 cache_control 放在稳定前缀(工具、系统提示词、之前的轮次)的最后一个块上。你最多可以设置四个断点,或者在请求的顶层放一个 cache_control,缓存截至最后一个块的所有内容。

response = client.messages.create(
    model="claude-sonnet-5.5",
    max_tokens=1024,
    system=[{
        "type": "text",
        "text": SYSTEM_PROMPT_AND_REFERENCE_DOCS,
        "cache_control": {"type": "ephemeral"},
    }],
    messages=history,
)
print(response.usage)

响应会报告 cache_creation_input_tokens(写入,按缓存写入价格计费)和 cache_read_input_tokens(读取,按缓存读取价格计费)。短于模型最低长度的前缀不会被缓存。断点的放置位置以及哪些情况会使缓存失效,请参阅 Anthropic 的缓存指南。

OpenAI#

GPT 模型会自动缓存较长的提示词前缀,无需任何标记。把提示词中稳定的部分放在前面,变化的部分放在最后。为每个对话或每个用户把 prompt_cache_key 设为一个固定值可以提高命中率,网关也会用它把该对话保持在同一个渠道上。

response = client.chat.completions.create(
    model="gpt-6.1-sol",
    messages=history,
    prompt_cache_key="conv_8f2a91",
)
print(response.usage.prompt_tokens_details.cached_tokens)

usage.prompt_tokens_details.cached_tokens 按缓存读取价格计费,prompt_tokens 的其余部分按输入价格计费。GPT 模型没有单独的缓存写入费用。请参阅 OpenAI 的缓存指南。

Gemini#

Gemini 模型会自行缓存重复的前缀(隐式缓存)。缓存的 token 显示在 usageMetadata.cachedContentTokenCount 中,按缓存读取价格计费,没有缓存写入费用。不支持通过 cachedContents API 进行显式上下文缓存。

如何识别对话#

网关会为每个对话生成一个指纹,取以下列表中的第一个匹配项:

来源API 格式
x-session-id 请求头全部
x-lovely-session 请求头全部
x-claude-code-session-id 请求头(由 Claude Code 发送)全部
请求体中的 metadata.user_idAnthropic
请求体中的 prompt_cache_keyOpenAI
请求体中的 userOpenAI
系统提示词加上第一条用户消息全部

最后一条规则不需要你做任何事。对话的后续轮次只会追加消息,系统提示词和第一条用户消息保持不变,因此每一轮都会得到相同的指纹。两者都只比较前 4,000 个字符。

指纹的作用范围限定在你的 API 密钥、模型和渠道分组之内。同一个对话如果用不同的密钥发送,或发往不同的模型,会开始一次新的锁定。

对话会锁定多久#

对话的第一次成功调用会把它锁定到服务该调用的渠道上。之后的轮次会优先发往该渠道。

  • 时长。 锁定最长持续一小时,对话活跃期间会持续续期。30 到 60 分钟内没有请求时,锁定过期,下一轮会像新对话一样重新分配渠道。
  • 缓存已过期。 使用 Anthropic Messages 格式时,如果对话空闲的时间超过了提示词缓存的有效期(5 分钟;cache_control 断点设置 ttl: "1h" 时为 1 小时),锁定也会结束。此时它保护的缓存已经失效,下一轮会像新对话一样分配渠道,而不是继续使用上次服务的渠道。
  • 渠道繁忙。 如果锁定的渠道容量已满,这一轮会短暂等待它(短提示词约一秒,长提示词最多十秒),而不是换到别的渠道并为新的缓存写入付费。如果等待后仍然已满,这一轮会转到另一个渠道。
  • 渠道故障。 如果锁定的渠道正在出错,这一轮会转到一个健康的渠道,锁定也随之转移。这一轮会写入新的缓存;之后的轮次会再次从中读取。

发送显式会话 ID#

当第一条用户消息在不同轮次之间发生变化时,自动指纹就会失效,例如你的应用会改写或摘要旧的历史记录。这种情况下,请为每个对话发送一个固定的 ID。请求头在所有 API 格式中都可用:

curl https://lovelyrouter.com/v1/messages \
  -H "x-api-key: $LOVELY_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "x-session-id: conv_8f2a91" \
  -H "content-type: application/json" \
  -d '{"model": "claude-sonnet-5.5", "max_tokens": 1024,
       "messages": [{"role": "user", "content": "Continue the report."}]}'

请求体字段同样可用:Anthropic 格式用 metadata.user_id,OpenAI 格式用 prompt_cache_key。每个对话使用一个 ID;如果在许多互不相关的对话中复用同一个 ID,它们会全部落到同一个渠道上。

在日志和账单中查看缓存使用情况#

日志为每次调用显示:

字段含义
输入未缓存输入加上缓存写入。
已缓存从缓存读取的输入 token。
缓存写入(详情)写入缓存的输入 token。
缓存命中(详情)缓存 token 占全部输入 token 的比例。
会话亲和(详情)explicit:你发送了会话 ID。sticky:对话已被锁定,并回到了它的渠道。new:对话的第一次调用,或者它的锁定已过期、渠道不可用。none:无法生成指纹。

控制台概览页显示你所有调用的缓存命中率。每类 token 按各自的价格计费;请参阅每次调用如何计费。

排查命中率偏低

如果一个对话在每一轮都显示 new,说明它的系统提示词或第一条用户消息在不同轮次之间发生了变化。最常见的原因是系统提示词中带有时间戳,这同样会破坏厂商的缓存:把时间戳移到最新的用户消息中,或发送显式会话 ID。如果各轮显示 sticky,但 已缓存 一直为空,请检查前缀是否达到模型的最低长度,以及(对 Claude 而言)是否带有 cache_control。