OpenRouter 提示缓存 + 粘性路由 2026:Agent 成本实测
2026 年 7 月 21 日,OpenRouter 发布了一篇题为《The Cheapest Token Is a Cached One: Prompt Caching + Sticky Routing》的教程。这是迄今为止关于他们的聚合层如何在 70+ 上游服务商之间处理缓存读取、缓存写入与会话锁定最清晰的公开拆解。对任何跑多轮 Agent 的人来说,这篇博客里的成本数学就是同一个工作负载从月费 $5,000 降到 $500 的关键。
本文把 OpenRouter 那篇博客提炼成生产环境最在意的几个部分:
- 逐服务商的缓存价格矩阵(Anthropic、GPT-5.6 前后的 OpenAI、Gemini、Grok、Moonshot、Groq、DeepSeek、阿里 Qwen、Z.AI)。
- 6 轮 × 10,000 token 的具体算例:粘性路由究竟省了多少。
- 四种导致缓存不命中的原因及对应的修复。
session_id参数,以及为什么它能把粘性从「有时 warm」变成「稳定 warm」。cached_tokens、cache_discount、cache_write_tokens这三个确认缓存生效的字段。
所有价格事实都来自 2026-07-21 的 OpenRouter 博客及 OpenRouter 提示缓存文档(截至 2026 年 7 月底)。
OpenRouter 的提示缓存是什么?
OpenRouter 是一个统一 API,前接 300+ 模型、70+ 服务商。所谓「提示缓存」,是指 OpenRouter(或上游服务商)复用 prompt 的一部分,而不是每轮重新分词、重新计费完整的输入。复用部分通常是贵的部分 — 系统提示、工具定义、JSON schemas、护栏、检索到的文档、examples — 它们跨轮次保持不变。
两个成本要素要分开看:
- 缓存写入 — 第一次请求把可复用的前缀存下来。有些服务商写入价比正常输入还贵(Anthropic 5 分钟 TTL 收 1.25x,1 小时 TTL 收 2.0x),有些免费(Gemini、Grok、Moonshot、GPT-5.6 之前的 OpenAI、Groq)。
- 缓存读取 — 之后的每次请求复用存好的前缀。这是便宜的那部分:根据服务商不同,从正常输入价格的 0.1x 到 0.5x 不等。
0.1x 的缓存读取意味着:一个 10,000 token 的系统提示,在 Claude Sonnet 4.6 上正常输入花 $30,从缓存读取只要 $3。把它乘到长跑 Agent 的 6 轮,节省会快速累积。
逐服务商缓存价格矩阵(验证于 2026-07-21)
下表是 OpenRouter 公开的拆解,直接从博客抓取:
| 服务商 | 缓存读取倍率 | 缓存写入倍率 | 启用方式 |
|---|---|---|---|
| Anthropic Claude(5 分钟 TTL) | 0.1x input | 1.25x input | 自动或显式 |
| Anthropic Claude(1 小时 TTL) | 0.1x input | 2.0x input | 显式(ttl: "1h") |
| OpenAI(GPT-5.6 之前) | 0.25x–0.50x input | 免费 | 自动 |
| OpenAI(GPT-5.6 之后) | 0.25x–0.50x input | 1.25x input | 自动或显式 |
| Google Gemini(隐式) | 0.25x input | 免费 | 自动 |
| Grok(xAI) | 0.25x input | 免费 | 自动 |
| Moonshot AI | 0.25x input | 免费 | 自动 |
| Groq | 0.5x input | 免费 | 自动(Kimi K2 模型) |
| DeepSeek | 0.1x input | 1.0x input | 自动 |
| 阿里 Qwen | 0.1x input | 1.25x input | 显式(cache_control) |
| Z.AI | ~0.2x input | 免费 | 自动 |
三种模式值得注意:
- Anthropic、DeepSeek、阿里 Qwen 提供最低 0.1x 的缓存读取,但它们的写入都比正常输入贵。如果你的 Agent 复用前缀不足以摊薄写入,缓存反而烧钱。
- Google Gemini、Grok、Moonshot 写入免费、读取 0.25x。对偶尔命中缓存但很少需要多 hour TTL 的轻量 Agent 来说是最佳组合。
- OpenAI 在 GPT-5.6 之后改成付费写入。GPT-5.6 之前的 OpenAI 写入免费;GPT-5.6+ 缓存写入收 1.25x。如果你在 2026 年 6 月迁到 GPT-5.6,缓存经济已经悄悄变了。
具体节省:6 轮 Agent × 10K 缓存 token
OpenRouter 那篇博客用同一个假想 Agent:6 轮、每轮都重复同一段 10,000 token(系统提示 + 工具定义 + schemas + 策略上下文)。输出 token 与变化的消息不计入。
| 场景 | 第 1 轮 | 第 2–6 轮 | 相对 1 轮未缓存的总成本 |
|---|---|---|---|
| 不缓存 | 完整输入 | 每轮完整输入 | 6.0x |
| Anthropic 5 分钟缓存 + 粘性路由 | 1.25x 写入 | 0.1x 读取 | 1.75x |
| 免费写入 + 0.25x 读取 | 1.0x 输入/写入 | 0.25x 读取 | 2.25x |
| 免费写入 + 0.5x 读取 | 1.0x 输入/写入 | 0.5x 读取 | 3.5x |
表格的含义:「对于同一段重复内容,6 轮的总 token 成本是单轮未缓存成本的 N 倍。」
Anthropic + 粘性路由比未缓存基线便宜 3.4x。免费写入 + 0.5x 读取(Groq)仍然比未缓存好 1.7x,但比 Anthropic 激进的缓存读取价格差一截。
轮次越多,节省越大。一个 20 轮深度研究 Agent 配 30K token 前缀,差距还会再拉宽。
为什么 warm cache 不一定有用?
这是多数工程师第一次踩到的坑:warm cache 只有当下一请求落到同一个持有缓存前缀的服务商端点时才管用。OpenRouter 前接 70+ 服务商;每轮路由器挑一个。第二轮可能路由到另一个服务商 — 即便「理论上应该有缓存」,你仍然按全价付费。
OpenRouter 的粘性路由就是为了修这个坑。某服务商上缓存请求成功后,OpenRouter 把同模型的后续请求钉回那个端点,当该服务商的缓存读取价格低于正常输入时这么做。如果粘性服务商挂了,OpenRouter 回退到下一个可用服务商,而不是直接报错。
钉靠的是 key。默认情况下,OpenRouter 对第一条 system 或 developer 消息 + 第一条非 system 消息做哈希。只要这两段不变,钉就稳。system prompt 跨轮变、或者把每次请求的时间戳塞进前缀,钉就废。
用 session_id 从第 1 轮就强制 warm
对 Agent 循环来说,默认的哈希 key 太脆弱。OpenRouter 建议为会话、工单、或 workflow run 传一个稳定的 session_id:
- 没有
session_id,粘性路由只在观察到一次缓存命中后才生效。第一轮没缓存,路由器没东西可钉。第二轮可能落到冷端点。 - 有
session_id,OpenRouter 直接拿 session ID 当粘性路由 key。第一次成功请求之后,粘性就生效 — 早于任何缓存命中。对多轮 Agent 而言,这是「从第 1 轮就稳定 warm」和「只是偶尔 warm」之间的差别。
在你的 OpenRouter 客户端里就一行:
import requests
response = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"},
json={
"model": "anthropic/claude-sonnet-4.6",
"messages": [...], # 你的 Agent 完整消息历史
"session_id": "support-ticket-9821", # 每会话稳定的 key
# 可选:在 Anthropic 1 小时模型上显式设缓存 TTL
# "provider": {"cache_control": {"ttl": "1h"}}
}
)
对工单风格的 workflow(用稳定标识符:工单 ID、thread ID、用户 ID、对话 ID),session_id 是最便宜的优化。
如何确认提示缓存是否生效?
OpenRouter 返回里有三个字段可以直接确认缓存是否生效:
usage.prompt_tokens_details.cached_tokens— 从缓存读取的输入 token 数。大于 0 即命中。usage.prompt_tokens_details.cache_write_tokens— 写入那轮被存入的输入 token 数。usage.cache_discount— 单次生成的成本影响(写入付费时为负,读取轮次为正)。
也可以看 OpenRouter Dashboard 的 Activity 详情页,或调用 /api/v1/generation 拿完整每轮遥测。
生产环境里一个实用的健康检查:
import requests
def cache_health_check(response_json):
usage = response_json.get("usage", {})
details = usage.get("prompt_tokens_details", {})
cached = details.get("cached_tokens", 0)
discount = usage.get("cache_discount", 0)
return {
"cached_tokens": cached,
"cache_discount": discount,
"cache_active": cached > 0,
}
如果 cache_active 多轮都是 False,说明你踩到了下面四个常见 cache miss 原因之一。
为什么会 cache miss(以及每个原因的修复)
缓存看上去失效,几乎总逃不掉这四种情况:
- Prompt 太短。每个服务商都有最小可缓存 token 数 — Anthropic 要求 1,024,OpenAI 要求 1,024,Gemini 要求 4,096。Prompt 太短,无论多稳定都不会触发缓存。
- 缓存过期。Anthropic 默认 TTL 是 5 分钟;1 小时 TTL 需要显式
ttl: "1h"。如果一轮之间闲置超过 TTL,前缀就消失了。 - 开头内容变了。任何对 system prompt、工具定义、或第一条用户消息的修改都会让缓存前缀哈希失效。即使只是往系统消息里加了当前时间戳也会破坏缓存。
- 请求换到了别的服务商。没有
session_id,路由器可能把第二轮交给跟第一轮不同的服务商。缓存在服务商 A 上是 warm;你的请求落到服务商 B 上按全价付费。
修法都是机械的:
- 针对 (1):合并短 prompt,或者接受短请求不吃缓存红利。
- 针对 (2):挑一个匹配你 Agent 典型轮次节奏的 TTL。要 1 小时 Anthropic 缓存,设
provider: { cache_control: { ttl: "1h" } }。 - 针对 (3):把每次请求的动态数据(时间戳、request ID、用户 token)放到 prompt 末尾,不是开头。
- 针对 (4):设
session_id。没有它,粘性路由只在缓存命中后才启动 — 对第 1 轮来说已经太晚。
缓存能跟 Auto Router 一起用吗?
可以。设了 session_id 后,Auto Router 和 Pareto Router 同时锁定该会话的解析模型和服务商端点。不设 session_id,Auto Router 可以跨轮切换模型 — 这对探索没问题,但会让前一个模型持有的缓存失效。
如果你用 Auto Router 做成本优化,session_id 的价值更大。它告诉路由器「就用这次会话选的那个模型」。不设它,模型每轮切换,前缀每次都是新的,缓存写入成本会持续发生。
一个坑:如果自己设了 provider.order,你的显式顺序会覆盖粘性路由。要在多服务商模型上启用粘性路由,留空 provider.order,让 OpenRouter 自己挑。除非你有特定服务商顺序需求并愿意放弃缓存收益,否则不要用 provider 路由控制。
合在一起:Agent 循环 checklist
对任何每轮都重复同一段贵内容的 Agent:
- 稳定内容放最前 — system prompt、工具定义、JSON schemas、策略、长生命周期上下文。
- 变化内容放后面 — 用户消息、工具结果、时间戳、运行期元数据。
- 为会话、工单、或 workflow run 设一个稳定的
session_id。 - 检查 response 里的
cached_tokens和cache_discount,确认读取确实在发生。 - 要 1 小时 Anthropic TTL,设
provider: { cache_control: { ttl: "1h" } }。 - 不要设
provider.order— 让粘性路由挑 warm 端点。
便宜 token 这件事是机械的,但顺序重要。如果修了缓存读取但开头前缀还在变,再多 session_id 也救不了。稳定前缀 + 稳定 session ID + 提供低读取价的服务商 — 这三件事一起把 6.0x 变 1.75x。
联盟推荐:FreeModel 多服务商 Agent 路由
如果你的多轮 Agent 跨多个模型服务商,FreeModel 提供一个统一 API 表面,聚合 OpenRouter 同类的多家服务商,并自带路由和缓存层。对不需要 OpenRouter 全部服务商、但又想要类似缓存路由行为的场景,FreeModel 是值得拿来跟当前方案做基准对比的轻量替代。
OpenRouter 自己的公开联盟计划在 openrouter.ai/affiliates — 如果你在自己的产品或 newsletter 里讲 OpenRouter,可以把读者链到该页面。
FAQ
OpenRouter 缓存读取价格是多少?
缓存读取价格为正常输入价格的 0.1x 到 0.5x,取决于服务商。Anthropic、DeepSeek、阿里 Qwen 可低至 0.1x。OpenAI 在 0.25x-0.50x。Gemini、Grok、Moonshot 为 0.25x。Groq 为 0.5x。写入价格在免费(Gemini、Grok、Moonshot、GPT-5.6 之前的 OpenAI、Groq)和 2.0x(Anthropic 1 小时 TTL)之间。以上来自 2026-07-21 OpenRouter 博客。
为什么通过 OpenRouter 的提示缓存没有生效?
常见原因:prompt 长度低于服务商最低要求(Anthropic 1024,Gemini 4096);缓存过期(Anthropic 默认 5 分钟 TTL);prompt 前缀不稳定(任何对第一条 system/developer 消息的修改都会破坏哈希);轮次间切换了服务商。设置稳定的 session_id,把每次请求的动态数据放到 prompt 末尾,inspect cached_tokens 确认命中。
OpenRouter 在所有服务商都支持提示缓存吗?
凡是实现了缓存机制的服务商和模型,OpenRouter 都透传支持。大多数服务商自动启用 — Anthropic 和阿里 Qwen 通过 cache_control 显式启用。详细模型清单见 OpenRouter 提示缓存文档;并非每个服务商上的每个模型都实现该功能。
如何确认缓存确实省了钱?
检查 usage.prompt_tokens_details.cached_tokens(缓存读取的 token 数)和 cache_write_tokens(缓存写入的 token 数)。cached_tokens 大于 0 即确认命中。也可以读 response 中的 cache_discount 字段看单次生成的成本影响。写入需要付费的服务商,写入那轮 discount 可能为负(写入比正常输入贵);后续读取轮次 discount 会转正。
什么是 OpenRouter 的粘性路由(Sticky Routing)?
粘性路由把后续请求锁定到持有 warm cache 的服务商。缓存请求在某个服务商成功后,OpenRouter 把同模型的下一轮请求路由回该服务商,当该服务商的缓存读取价格低于正常输入时这么做。如果粘性服务商不可用,OpenRouter 回退到下一个可用服务商,而不是直接报错。
缓存能跟 OpenRouter Auto Router 一起用吗?
可以。设置 session_id 后,Auto Router 和 Pareto Router 会同时锁定该会话的解析模型和服务商端点。没有 session_id 时,Auto Router 可能在不同轮次切换模型,让缓存失效。session_id + Auto Router 的组合提供成本最优模型选择 + 可靠缓存复用。
缓存读取最便宜应该选 Anthropic 还是 DeepSeek?
Anthropic 和 DeepSeek 都提供 OpenRouter 上最低的 0.1x 缓存读取。Anthropic 写入 1.25x(5 分钟 TTL)或 2.0x(1 小时)。DeepSeek 写入 1.0x。如果 agent 节奏密集(每隔几分钟一轮),Anthropic 较高的写入成本很快摊薄;会话稀疏时,DeepSeek 较低的写入成本可能更划算。
如果我自己设置了 provider.order 会怎样?
你显式的服务商顺序会覆盖粘性路由。请求总会落到你的第一个可用服务商,哪怕缓存前缀在另一个端点上。除非你有特定的服务商偏好且愿意放弃缓存收益,否则不要设 provider.order — 让粘性路由自己挑 warm 端点。
OpenRouter 缓存能持续多久?
取决于服务商和你设置的 TTL。Anthropic 默认 5 分钟;设 ttl: 1h 可延长到 1 小时。GPT-5.6 之前的 OpenAI 约 5-10 分钟。Gemini 隐式缓存 TTL 约 1 小时。阿里 Qwen 的 cache_control TTL 按请求配置。对长跑 agent,Anthropic 1 小时或 Gemini 1 小时隐式缓存覆盖大多数会话模式,无需每轮重新写入。
能关闭 OpenRouter 的提示缓存吗?
可以。在 Anthropic 或阿里 Qwen 上设 provider: { cache_control: { ttl: no-cache } } 即可关闭。其他隐式免费缓存的服务商没有单次请求级别的关闭开关 — 缓存自动发生,但只有真正命中读取时才省钱。如果完全不想用缓存,可以路由到不支持缓存的服务商(代价是每轮都付全价输入)。