你的智能体在每一轮都会发送相同的系统提示词、工具定义、数据结构和策略指令。在一个 6 轮的会话中,即使唯一变化的只是用户的最新消息或智能体的最新工具结果,你也会为同一段开头内容被计费 6 次。
提示词缓存解决了这个问题。服务提供方会从缓存中读取你提示词中重复的部分,而不是每次都按全价向你收费。粘性路由则通过将会话送回持有热缓存的同一服务提供方,让这种机制在跨轮次中持续生效。
这篇文章讲的是钱的问题:缓存 token 的成本是多少,为什么缓存读取和写入的定价不同,session_id 如何从第一轮开始就让智能体的会话保持热状态,以及如何检查缓存是否真的在起作用。
太长不看版
- 缓存读取的成本是全新输入 token 的 0.1 倍到 0.5 倍,具体取决于服务提供方。在 Claude Sonnet 4.6 上,缓存读取的价格是 $0.30/M,而输入价格是 $3.00/M,正好是 0.1 倍。
- 第一个请求需要支付缓存写入费用。Anthropic 的写入成本是输入的 1.25 倍(5 分钟 TTL)或 2.0 倍(1 小时 TTL),所以一次未被复用的写入比完全不缓存还要贵。
- 热缓存只有在你的下一个请求落到同一个服务提供方端点时才有用。在 70 多个服务提供方之间,第二轮可能会命中冷端点,这时你就要付全价。
- 我们的粘性路由会把后续请求固定到持有热缓存的服务提供方上,而 session_id 则从第一个成功请求开始就强制这一点,哪怕此时还没有发生过任何缓存命中。
- 缓存未命中有 4 个原因:提示词太短、缓存过期、开头内容不断变化,或者请求被转移到了不同的服务提供方。请检查 usage 响应中的 cached_tokens 字段来确认是否命中。
提示词缓存能帮你省下多少 token 成本?
缓存读取的成本是正常输入定价的 0.1 倍到 0.5 倍,具体取决于服务提供方。正是这个区间,让缓存能够大幅降低智能体循环的成本。
重复的部分通常就是最昂贵的部分:一段很长的系统提示词、工具定义、JSON 模式、护栏、检索到的文档,或者让模型保持一致的示例。如果没有缓存,每一轮都要为所有这些内容再次支付全价。有了缓存,第一个请求会将其写入缓存,后续请求则以更低的费率读取。
以下是服务商层面的情况:
| 服务商 | 缓存读取 | 缓存写入 | 启用方式 |
|---|---|---|---|
| Anthropic Claude(5 分钟 TTL) | 输入价格的 0.1 倍 | 输入价格的 1.25 倍 | 自动或显式 |
| Anthropic Claude(1 小时 TTL) | 输入价格的 0.1 倍 | 输入价格的 2.0 倍 | 显式(ttl: "1h") |
| OpenAI(GPT-5.6 之前) | 输入价格的 0.25 倍-0.50 倍 | 免费 | 自动 |
| OpenAI(GPT-5.6 及之后) | 输入价格的 0.25 倍-0.50 倍 | 输入价格的 1.25 倍 | 自动或显式 |
| Google Gemini(隐式) | 输入价格的 0.25 倍 | 免费 | 自动 |
| Grok (xAI) | 输入价格的 0.25 倍 | 免费 | 自动 |
| Moonshot AI | 输入价格的 0.25 倍 | 免费 | 自动 |
| Groq | 输入价格的 0.5 倍 | 免费 | 自动(Kimi K2 模型) |
| DeepSeek | 输入价格的 0.1 倍 | 输入价格的 1.0 倍 | 自动 |
| 阿里云 Qwen | 输入价格的 0.1 倍 | 输入价格的 1.25 倍 | 显式(cache_control) |
| Z.AI | 约输入价格的 0.2 倍 | 免费 | 自动 |
提示词缓存文档中有完整的详细说明。具体的美元金额仍取决于模型和服务商路由;这个倍数告诉你,对于该服务商而言,缓存输入与正常输入的价格对比情况。
对于智能体构建者来说,模式很简单:第一轮可能需要付费来建立缓存,但只要后续轮次复用相同的开头部分,之后的每一轮都会便宜得多。
成本花在哪里:缓存写入还是缓存读取?
提示词缓存有两种成本:写入和读取。
当服务商存储提示词中可复用的部分时,就会发生写入。当后续请求复用该存储内容时,就会发生读取。一旦相同内容被读取足够多次以覆盖写入成本,你就开始省钱了。
在某些服务商那里,写入成本高于正常输入。Anthropic 的缓存写入,默认 5 分钟 TTL 的成本是输入价格的 1.25 倍,1 小时 TTL 的成本是输入价格的 2.0 倍。如果一次 Anthropic 缓存写入从未被复用,其成本比不缓存直接发送相同提示词还要高。
对于一次性请求,缓存可能帮不上忙。但对于多轮智能体而言,重复才是常态:智能体在整个会话期间都携带相同的指令、工具、模式(schema)和策略上下文。因此,写入缓存的成本在几轮之后就能回本。
对于下一轮很快到来的短促请求,请使用 5 分钟缓存生命周期(TTL)。当会话可能暂停较久、导致默认缓存过期,但内容仍值得保留时,请使用 1 小时缓存生命周期。
为什么热缓存并不总能对下一个请求生效?
只有当下一个请求落在持有该缓存的提供商端点上时,热缓存才会生效。
当请求可以路由到多个提供商时,第一轮可能在某个提供商上写入缓存,而第二轮却落在另一个提供商上。第二个提供商没有可读取的热缓存。请求仍然能正常工作,但你需要支付全价,且 cached_tokens 会保持很低或为零。
这就是为什么我们将粘性路由与提示词缓存搭配使用。在缓存请求之后,当某个提供商的缓存读取价格低于常规输入价格时,我们会将同一模型的后续请求路由回该提供商的同一端点。如果该粘性提供商不可用,OpenRouter 会回退到下一个可用提供商,而不是让请求失败。
默认情况下,OpenRouter 通过对会话的第一条系统消息或开发者消息以及第一条非系统消息进行哈希来识别会话。当这些开头消息保持不变时,这种方式有效。
智能体常常会打破这一点。有些智能体会在总结状态时重写首条消息、重新排列工具上下文,或添加新的运行元数据。当开头消息发生变化时,哈希值也会改变,会话就可能落到不同的提供商上。解决办法是使用显式的 session_id。
使用 session_id 从第一轮起强制启用热缓存
对于智能体循环,请设置 session_id。当你传入该参数时,OpenRouter 会直接将其用作粘性路由键,而不是从开头消息推导出键值。
使用 `session_id` 时,粘性路由会在首次请求成功之后、任何缓存命中发生之前就生效。如果不使用它,粘性只能在检测到缓存命中后才开始。对于多轮智能体来说,这决定了缓存是从第一轮起就可靠,还是只能偶尔保持温热。
你可以将 `session_id` 作为请求体的顶层字段发送,也可以通过 `x-session-id` 请求头传递。请在整个对话或智能体运行期间保持其稳定,并将其长度控制在 256 个字符以内。
curl https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4.6",
"session_id": "my-agent-session-abc123",
"messages": [{"role": "system", "content": "..."}]
}' from openrouter import OpenRouter
client = OpenRouter()
resp = client.chat.send(
model="anthropic/claude-sonnet-4.6",
session_id="my-agent-session-abc123",
messages=[{"role": "system", "content": "..."}],
) import { OpenRouter } from '@openrouter/sdk';
const openRouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
const response = await openRouter.chat.send({
model: 'anthropic/claude-sonnet-4.6',
session_id: 'my-agent-session-abc123',
messages: [{ role: 'system', content: '...' }],
}); 请使用与工作单元相匹配的值:例如一个聊天线程、工单、工作流运行或智能体任务。不要为每一轮都创建新的 `session_id`,否则请求将无法继续落在持有缓存的供应商上。
如果你使用 Auto Router 或 Pareto Router 这类路由模型,会话粘性还会固定住路由器所选定的模型,而不仅仅是供应商。这可以防止对话在会话中途切换模型,从而保持行为一致性并让缓存保持温热。
我该如何确认提示词缓存是否真的在生效?
最快的检查方式是查看 usage 信息。
在响应中,`usage.prompt_tokens_details.cached_tokens` 会显示从缓存中读取了多少 token。如果该值大于零,说明请求命中了缓存。`cache_write_tokens` 则显示在一次缓存写入请求期间写入了多少 token。
{
"usage": {
"prompt_tokens": 10339,
"completion_tokens": 60,
"total_tokens": 10399,
"prompt_tokens_details": {
"cached_tokens": 10318,
"cache_write_tokens": 0
}
}
} 在这个示例中,大部分提示词 token 都来自缓存,而这一轮没有写入新的缓存条目。
你可以在三个地方检查缓存行为:Activity 页面的详情视图、`/api/v1/generation` API,以及 API 响应中返回的 `usage.prompt_tokens_details` 对象。
使用 `cache_discount` 来查看一次生成节省了多少成本。在按写入计费的供应商上,你可能会在写入轮次看到负折扣,因为缓存写入的成本高于普通输入。在后续的缓存读取轮次中,折扣应该会转为正值。
为什么你的缓存会未命中,又该如何避免?
当缓存看起来失效时,通常可以归结为以下 4 个原因之一:提示词太短、缓存已过期、开头内容发生变化,或者请求被转移到了不同的供应商。
提示词低于供应商的最低要求。
每个提供商都有最低提示词大小要求,低于该要求则不会缓存任何内容。在 Anthropic 上,Claude Opus 4.5 至 4.8 以及 Claude Haiku 4.5 需要 4,096 个 token;Claude Haiku 3.5 需要 2,048 个;Claude Sonnet 4、4.5 和 4.6(以及 Opus 4 / 4.1)需要 1,024 个。OpenAI 需要 1,024 个。Gemini 2.5 Pro 需要 4,096 个;Gemini 2.5 Flash 需要 1,024 个。
如果你的可复用内容低于该最低要求,缓存将不会启动。不要为了强行触发缓存而用填充文本给请求注水。请在你已经拥有大量可复用内容的地方使用缓存:工具、模式、检索到的文档、示例或策略文本。
缓存在两轮对话之间过期了
缓存的存活时间不长。Anthropic 的默认值是 5 分钟,并提供 1 小时选项用于更长的会话。Gemini 的隐式缓存大约持续 3-5 分钟,并且读取时不会重置计时。一旦缓存过期,下一个请求就必须写入新的缓存。
如果你的用户经常在轮次之间停顿,请在支持的情况下使用更长的 TTL,或者将智能体设计为在空闲期后接受新的缓存写入。
提示词的开头一直在变化
自动和隐式缓存在提示词开头保持不变时效果最佳。把稳定的内容放在前面:系统指令、工具、模式以及固定的参考资料。把变化的内容放在后面:用户问题、时间戳、临时状态、工具输出和短期元数据。
小细节在这里很重要。第一条系统消息中的时间戳会让提示词在每一轮看起来都是新的。如果时间戳不需要成为缓存内容的一部分,请将其移到后面的用户或工具消息中。
请求被路由到了不同的提供商
缓存放置在它被写入的地方。如果后续请求被路由到不同的提供商端点,该端点无法读取之前的缓存。
对于智能体工作流,请设置 `session_id`,并让粘性路由将会话保持在已预热(有缓存)的提供商上。有一点需要注意:如果你自己设置了 `provider.order`,你的顺序会优先于粘性路由。如果你需要特定的提供商顺序,请使用提供商路由控制。
将缓存和粘性路由结合用于智能体循环
如果你的智能体在每一轮都发送相同的内容,请遵循以下检查清单:
- 将稳定内容放在前面:系统提示词、工具定义、模式、策略和长期上下文。
- 将变化的内容放在后面:用户消息、工具结果、时间戳以及每次运行特有的状态。
- 为需要显式 `cache_control` 的提供商启用提示词缓存。
- 为对话或工作流运行设置稳定的 `session_id`。
- 检查 `cached_tokens` 和 `cache_discount`,确认缓存读取确实在发生。
粗略来说,可以想象一个智能体在 6 轮对话中重复使用相同的 10,000 个 token。
| 场景 | 第 1 轮 | 第 2-6 轮 | 总成本(对比 1 轮无缓存) |
|---|---|---|---|
| 无缓存 | 完整输入 | 每轮完整输入 | 6.0 倍 |
| Anthropic 5 分钟缓存 + 粘性路由 | 1.25 倍写入 | 0.1 倍读取 | 1.75 倍 |
| 免费写入提供商 + 0.25 倍读取 | 1.0 倍输入/写入 | 0.25 倍读取 | 2.25 倍 |
| 免费写入提供商 + 0.5 倍读取 | 1.0 倍输入/写入 | 0.5 倍读取 | 3.5 倍 |
此示例仅涵盖重复内容,忽略了较小的变化消息和模型的输出 token。节省的成本会随着轮数增加而增长。
何时使用哪种方式:
- 对于多轮对话,当复用内容随对话增长时,使用自动缓存。
- 当你确切知道哪些大块内容应被缓存时,使用显式缓存断点:检索到的文档、长参考文件、角色卡、CSV 数据或策略文本。
- 对于智能体会话、支持工单、聊天线程、工作流运行,以及任何开场消息可能在轮次之间变化的对话,使用 `session_id`。
- 对于更长的 Anthropic 会话,当默认的 5 分钟缓存可能在轮次之间过期时,使用 1 小时缓存。对于简短、密集的来回对话,使用默认设置。
当你的智能体反复发送相同的昂贵内容时,缓存读取和粘性路由可防止它成为循环中最昂贵的部分。
常见问题
OpenRouter 支持提示词缓存吗?
支持。OpenRouter 在支持的提供商和模型上支持提示词缓存。大多数提供商会自动启用,而 Anthropic 和阿里巴巴通义千问(Qwen)使用 `cache_control` 进行显式缓存。缓存读取的成本为正常输入定价的 0.1 倍到 0.5 倍,具体取决于提供商,因此在首次请求后,复用的前缀会便宜得多。
在 OpenRouter 上,缓存 token 的费用是多少?
缓存读取的价格为正常输入定价的 0.1 倍至 0.5 倍,具体取决于提供商。Anthropic、DeepSeek 和阿里云通义千问的读取价格为 0.1 倍。OpenAI 的读取价格为 0.25 倍至 0.50 倍。Gemini、Grok 和月之暗面的读取价格为 0.25 倍。Groq 的读取价格为 0.5 倍。
为什么通过 OpenRouter 使用提示词缓存不生效?
常见原因包括:提示词低于提供商的 token 最低要求、缓存已过期、提示词前缀不稳定,或各轮对话之间提供商发生漂移。对于智能体工作流,首先设置一个稳定的 session_id,然后检查 usage 响应中的 cached_tokens,只要该值大于零,即可确认缓存命中。
如何在智能体的多轮对话中保持缓存热度?
为对话、工单或工作流运行传入一个稳定的 session_id。OpenRouter 会将其用作粘性路由键,因此后续请求会路由回持有热缓存的同一提供商端点。设置 session_id 后,粘性会在首次成功请求后激活,此时尚未观察到任何缓存命中。
如何检查缓存是否节省了费用?
检查 usage.prompt_tokens_details.cached_tokens 以查看缓存读取情况,检查 cache_write_tokens 以查看缓存写入情况;cached_tokens 值大于零即确认命中。您还可以查看响应中的 cache_discount,以了解每次生成的成本影响,或者打开 Activity 页面或 /api/v1/generation API 中的详情视图。
缓存功能在 Auto Router 下是否可用?
可用。设置 session_id 后,Auto Router 和 Pareto Router 等路由模型会将解析后的模型和提供商固定到该对话,因此后续轮次会持续命中同一个热缓存。
Your agent sends the same system prompt, tool definitions, schemas, and policy instructions on every turn. In a 6-turn session, you can get billed for that same opening block 6 times, even though the only thing that changed is the user’s latest message or the agent’s latest tool result.
Prompt caching fixes that. The provider reads the repeated part of your prompt from cache instead of charging you full price for it every time. Sticky routing keeps that working across turns by sending a session back to the same provider that holds the warm cache.
This post covers the money side: what cached tokens cost, why cache reads and writes are priced differently, how session_id keeps an agent’s session warm from turn one, and how to check that caching is actually working.
Tl;dr
- A cache read costs 0.1x to 0.5x of a fresh input token, depending on the provider. On Claude Sonnet 4.6, a cache read runs at $0.30/M against $3.00/M input, exactly 0.1x.
- The first request pays a cache write. Anthropic writes cost 1.25x (5-minute TTL) or 2.0x (1-hour TTL) of input, so a single unreused write costs more than not caching at all.
- A warm cache only helps if your next request lands on the same provider endpoint. Across 70+ providers, turn two can hit a cold endpoint, and you pay full price.
- Our sticky routing pins follow-up requests to the provider holding the warm cache, and
session_idforces that from the first successful request, before any cache hit has happened. - Cache misses come from 4 causes: a prompt that’s too short, an expired cache, an opening block that keeps changing, or a request that moved to a different provider. Check
cached_tokensin the usage response to confirm a hit.
How much does prompt caching cut your token cost?
A cache read costs 0.1x to 0.5x of normal input pricing, depending on the provider. That range is why caching can make agent loops much cheaper.
The repeated part is usually the expensive part: a long system prompt, tool definitions, JSON schemas, guardrails, retrieved documents, or examples that keep the model consistent. Without caching, each turn pays full price for all of it again. With caching, the first request writes it to the cache, and later requests read it back at the cheaper rate.
Here’s the provider-level view:
| Provider | Cache read | Cache write | How to enable |
|---|---|---|---|
| Anthropic Claude (5-min TTL) | 0.1x input | 1.25x input | Automatic or explicit |
| Anthropic Claude (1-hour TTL) | 0.1x input | 2.0x input | Explicit (ttl: "1h") |
| OpenAI (before GPT-5.6) | 0.25x-0.50x input | Free | Automatic |
| OpenAI (GPT-5.6 and later) | 0.25x-0.50x input | 1.25x input | Automatic or explicit |
| Google Gemini (implicit) | 0.25x input | Free | Automatic |
| Grok (xAI) | 0.25x input | Free | Automatic |
| Moonshot AI | 0.25x input | Free | Automatic |
| Groq | 0.5x input | Free | Automatic (Kimi K2 models) |
| DeepSeek | 0.1x input | 1.0x input | Automatic |
| Alibaba Qwen | 0.1x input | 1.25x input | Explicit (cache_control) |
| Z.AI | ~0.2x input | Free | Automatic |
The prompt caching docs have the full breakdown. The exact dollar amount still depends on the model and provider route; the multiplier tells you how cached input compares with normal input for that provider.
For agent builders, the pattern is simple: the first turn may pay to set up the cache, but every turn after that gets much cheaper as long as the same opening block is reused.
Where does the cost go: cache writes versus cache reads?
Prompt caching has two costs: the write and the read.
The write happens when the provider stores the reusable part of the prompt. The read happens when a later request reuses that stored content. You come out ahead once the same content gets read enough times to cover the write.
On some providers, the write costs more than normal input. Anthropic cache writes cost 1.25x input for the default 5-minute TTL and 2.0x input for the 1-hour TTL. A single Anthropic cache write that’s never reused costs more than sending the same prompt without caching.
For a one-off request, caching may not help. For a multi-turn agent, repetition is the default: the agent carries the same instructions, tools, schemas, and policy context across the whole session. So the write pays for itself over a few turns.
Use the 5-minute cache lifetime (TTL) for short bursts where the next turn arrives quickly. Use the 1-hour one when a session may pause long enough for the default cache to expire, but the content is still worth keeping around.
Why doesn’t a warm cache always help on the next request?
A warm cache only helps if the next request lands on the provider endpoint that holds it.
When requests can route to many providers, turn one can write a cache on one provider while turn two lands somewhere else. The second provider has no warm cache to read from. The request still works, but you pay full price and cached_tokens stays low or zero.
That’s why we pair sticky routing with prompt caching. After a cached request, we route follow-up requests for the same model back to the same provider endpoint when that provider’s cache-read pricing is cheaper than normal input. If that sticky provider becomes unavailable, OpenRouter falls back to the next available provider instead of failing the request.
By default, OpenRouter recognizes a conversation by hashing its first system or developer message and its first non-system message. That works when those opening messages stay the same.
Agents often break that. Some rewrite their first messages as they summarize state, reorder tool context, or add new run metadata. When the opening messages change, the hash changes, and the conversation can land on a different provider. The fix is an explicit session_id.
Force a warm cache from turn one with session_id
For agent loops, set session_id. When you pass it, OpenRouter uses it directly as the sticky routing key instead of deriving a key from the opening messages.
With session_id, sticky routing kicks in after the first successful request, before any cache hit has happened. Without it, stickiness only starts after a cache hit is detected. For multi-turn agents, that’s the difference between a cache that’s reliable from turn one and one that’s only sometimes warm.
You can send session_id as a top-level request body field or through the x-session-id header. Keep it stable for the conversation or agent run, and keep it under 256 characters.
curl https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4.6",
"session_id": "my-agent-session-abc123",
"messages": [{"role": "system", "content": "..."}]
}' from openrouter import OpenRouter
client = OpenRouter()
resp = client.chat.send(
model="anthropic/claude-sonnet-4.6",
session_id="my-agent-session-abc123",
messages=[{"role": "system", "content": "..."}],
) import { OpenRouter } from '@openrouter/sdk';
const openRouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY });
const response = await openRouter.chat.send({
model: 'anthropic/claude-sonnet-4.6',
session_id: 'my-agent-session-abc123',
messages: [{ role: 'system', content: '...' }],
}); Use a value that matches the unit of work: a chat thread, ticket, workflow run, or agent task. Don’t create a new session_id for every turn, or requests stop landing on the provider that holds the cache.
If you use router models such as Auto Router or Pareto Router, session stickiness also pins the model the router picked, not just the provider. That keeps the conversation from switching models mid-session, so behavior stays consistent and the cache stays warm.
How do I confirm prompt caching is even working?
The fastest way to check is to inspect usage.
In the response, usage.prompt_tokens_details.cached_tokens shows how many tokens were read from cache. If it’s greater than zero, the request hit the cache. cache_write_tokens shows how many tokens were written during a cache-write request.
{
"usage": {
"prompt_tokens": 10339,
"completion_tokens": 60,
"total_tokens": 10399,
"prompt_tokens_details": {
"cached_tokens": 10318,
"cache_write_tokens": 0
}
}
} In this example, most of the prompt tokens came from cache, and this turn didn’t write a new cache entry.
You can inspect cache behavior in three places: the detail view on the Activity page, the /api/v1/generation API, and the usage.prompt_tokens_details object returned with API responses.
Use cache_discount to see what a generation saved. On providers with paid writes, you may see a negative discount on the write turn because the cache write costs more than normal input. On later cache-read turns, the discount should turn positive.
Why does your cache miss, and how do you stop it?
When caching looks broken, it usually comes down to one of 4 things: the prompt is too short, the cache expired, the opening content changed, or the request moved to a different provider.
The prompt is below the provider’s minimum
Every provider has a minimum prompt size, and below it nothing gets cached. On Anthropic, Claude Opus 4.5 through 4.8 and Claude Haiku 4.5 need 4,096 tokens; Claude Haiku 3.5 needs 2,048; Claude Sonnet 4, 4.5, and 4.6 (and Opus 4 / 4.1) need 1,024. OpenAI needs 1,024. Gemini 2.5 Pro needs 4,096; Gemini 2.5 Flash needs 1,024.
If your reusable content sits below that minimum, caching won’t start. Don’t pad the request with filler text just to force it. Use caching where you already have a lot of reusable content: tools, schemas, retrieved documents, examples, or policy text.
The cache expired between turns
Caches don’t live long. Anthropic’s default is 5 minutes, with a 1-hour option for longer sessions. Gemini’s implicit cache lasts about 3-5 minutes and doesn’t reset when you read from it. Once a cache expires, the next request has to write a new one.
If your users often pause between turns, use a longer TTL where supported, or build the agent to accept a new write after idle periods.
The start of the prompt keeps changing
Automatic and implicit caching work best when the start of the prompt stays the same. Put the stable stuff first: system instructions, tools, schemas, and fixed reference material. Put the changing stuff later: user questions, timestamps, temporary state, tool outputs, and short-lived metadata.
Small details count here. A timestamp in the first system message makes the prompt look new on every turn. Move it into a later user or tool message if it doesn’t need to be part of the cached content.
The request drifted to a different provider
A cache lives where it was written. If a later request routes to a different provider endpoint, that endpoint can’t read the earlier cache.
For agent workflows, set session_id and let sticky routing keep the session on the warm provider. One catch: if you set provider.order yourself, your order wins over sticky routing. Use provider routing controls if you need a specific provider order.
Putting caching and sticky routing together for an agent loop
If your agent sends the same content every turn, here’s the checklist:
- Put stable content first: system prompt, tool definitions, schemas, policies, and long-lived context.
- Put changing content later: user messages, tool results, timestamps, and run-specific state.
- Enable prompt caching for providers that need explicit
cache_control. - Set a stable
session_idfor the conversation or workflow run. - Inspect
cached_tokensandcache_discountto confirm that reads are happening.
For a rough picture, imagine an agent that repeats the same 10,000 tokens over 6 turns.
| Scenario | Turn 1 | Turns 2-6 | Total cost (vs. 1 uncached turn) |
|---|---|---|---|
| No caching | Full input | Full input each turn | 6.0x |
| Anthropic 5-minute cache + sticky routing | 1.25x write | 0.1x reads | 1.75x |
| Free-write provider + 0.25x reads | 1.0x input/write | 0.25x reads | 2.25x |
| Free-write provider + 0.5x reads | 1.0x input/write | 0.5x reads | 3.5x |
This example covers only the repeated content. It ignores the smaller changing messages and the model’s output tokens. The savings grow with the number of turns.
When to use what:
- Use automatic caching for multi-turn conversations where the reused content grows with the conversation.
- Use explicit cache breakpoints when you know exactly which large blocks should be cached: retrieved documents, long reference files, character cards, CSV data, or policy text.
- Use
session_idfor agent sessions, support tickets, chat threads, workflow runs, and any conversation where the opening messages may change between turns. - Use the 1-hour cache for longer Anthropic sessions where the default 5-minute one may expire between turns. Use the default for short, dense back-and-forths.
When your agent sends the same expensive content again and again, cached reads and sticky routing keep it from becoming the most expensive part of the loop.
FAQ
Does OpenRouter support prompt caching?
Yes. OpenRouter supports prompt caching across supported providers and models. Most providers enable it automatically, while Anthropic and Alibaba Qwen use cache_control for explicit caching. Cache reads cost 0.1x to 0.5x of normal input pricing depending on the provider, so a reused prefix gets much cheaper after the first request.
How much do cached tokens cost on OpenRouter?
Cache reads cost 0.1x to 0.5x of normal input pricing, depending on the provider. Anthropic, DeepSeek, and Alibaba Qwen can read at 0.1x. OpenAI reads at 0.25x to 0.50x. Gemini, Grok, and Moonshot read at 0.25x. Groq reads at 0.5x.
Why is prompt caching not working through OpenRouter?
The common causes are a prompt below the provider’s token minimum, an expired cache, an unstable prompt prefix, or provider drift between turns. For agent workflows, start by setting a stable session_id, then check cached_tokens in the usage response, where any value above zero confirms a cache hit.
How do I keep a cache warm across an agent’s turns?
Pass a stable session_id for the conversation, ticket, or workflow run. OpenRouter uses it as the sticky routing key, so follow-up requests route back to the same provider endpoint that holds the warm cache. With session_id set, stickiness activates after the first successful request, before any cache hit is observed.
How do I check whether caching saved money?
Inspect usage.prompt_tokens_details.cached_tokens for cache reads and cache_write_tokens for cache writes; a cached_tokens value above zero confirms a hit. You can also read cache_discount in the response to see the per-generation cost effect, or open the detail view on the Activity page or the /api/v1/generation API.
Does caching work with the Auto Router?
Yes. With a session_id set, router models such as Auto Router and Pareto Router pin both the resolved model and the provider for the conversation, so follow-up turns keep hitting the same warm cache.