OpenRouter 集成与实践

OpenRouter 集成与实践

提示词缓存

7 分钟阅读

提示词缓存

缓存提示词消息

为了降低推理成本,你可以在受支持的模型服务提供商和模型上启用提示词缓存。

大多数模型服务提供商会自动启用提示词缓存,但请注意:有些提供商(见下文的 Alibaba 和 Anthropic)要求你按消息启用。

使用缓存时(无论是在受支持模型上自动启用,还是通过 cache_control 属性),OpenRouter 会使用模型服务提供商粘性路由来最大化缓存命中——详见下方的模型服务提供商粘性路由

模型服务提供商粘性路由

为了最大化缓存命中率,OpenRouter 使用模型服务提供商粘性路由,在一次已缓存请求之后,将你的后续请求路由到同一模型服务提供商端点。这对隐式缓存(例如 OpenAI、DeepSeek、Gemini 2.5)和显式缓存(例如 Anthropic 的 cache_control 断点)都自动生效。

工作原理:

  • 在一次使用提示词缓存的请求之后,OpenRouter 会记住是哪个模型服务提供商处理了你的请求。
  • 同一模型的后续请求会被路由到同一模型服务提供商,从而保持缓存处于热状态。
  • 仅当该模型服务提供商的缓存读取价格低于常规提示词价格时,粘性路由才会激活,以确保你始终能从成本节省中受益。
  • 如果粘性绑定的模型服务提供商不可用,OpenRouter 会自动回退到次优的模型服务提供商。
  • 当你通过 provider.order 指定了手动的模型服务提供商顺序时,不会使用粘性路由——此时以你显式指定的顺序为准。

粘性路由的粒度:

粘性路由按账户、按模型、按对话跟踪。默认情况下,OpenRouter 通过对每条请求中的第一条 system(或 developer)消息以及第一条非 system 消息做哈希来识别对话,因此共享相同开头消息的请求会被路由到同一模型服务提供商。这意味着不同对话会自然地粘到不同的模型服务提供商,在提升负载均衡和吞吐量的同时,保持各对话内部的缓存处于热状态。

使用 session_id 实现粘性会话

若要对粘性路由进行更显式的控制,可以在请求中传入 session_id。当存在 session_id 时,OpenRouter 会直接将其用作粘性路由键,而不再从消息哈希中派生。这对多轮智能体工作流尤其有用:即使请求之间的开头消息会变化,你仍希望路由到同一模型服务提供商。

你可以通过两种方式提供 session_id

  • 请求体:在请求体中把 session_id 作为顶层字段。如果两者都提供,以请求体中的值为准。
  • 请求头:设置 x-session-id HTTP 请求头。

session_id 最长为 256 个字符。

如果两者都未设置,OpenRouter 会回退到 OpenAI 风格的 prompt_cache_key 请求字段,将其作为粘性路由键。已经发送 prompt_cache_key 的客户端无需改动即可获得会话固定路由。

{
  "model": "anthropic/claude-sonnet-4",
  "session_id": "my-agent-session-abc123",
  "messages": [
    {
      "role": "user",
      "content": "Continue our conversation..."
    }
  ]
}

设置 session_id 后,粘性路由会在任何成功请求上激活——即使尚未观察到缓存用量——以便同一会话中的后续请求从一开始就能受益于提示词缓存。没有 session_id 时,粘性路由仅在检测到缓存命中之后才会激活。

使用 Auto RouterPareto Router 等路由模型时,粘性路由还会固定解析后的模型——而不仅仅是模型服务提供商。这可以防止路由模型在同一对话的每一轮选择不同的模型。详见 Auto Router — 会话粘性

跨模态分组请求

除粘性路由外,OpenRouter 还会使用 session_id日志页面的「会话」视图中对你的请求进行分组。同一个 session_id 会把对话轮次、重试以及不同模态的请求关联起来,让你可以在一处追踪完整的智能体会话。

这种分组适用于同步端点,而不仅仅是聊天补全:

  • Chat 和 Responses:在请求体中发送 session_id,或使用 x-session-id 请求头。
  • 嵌入、重排序、语音转文本、文本转语音、图像生成和视频生成:发送 x-session-id 请求头。这些端点不接受请求体中的 session_id。它们仅将该值用于分组,因此粘性路由不适用于这些端点。

256 字符限制对两种输入都适用。在多模态工作流中发送一致的 x-session-id,即可把所有这些生成归到同一会话下。例如:智能体先转写音频,再调用聊天模型,然后生成图像。

Batch API 目前尚未按其 session_id 对生成结果进行分组。

检查缓存用量

要查看每次生成因缓存节省了多少费用,你可以:

  1. 活动(Activity)页面点击详情按钮
  2. 使用 /api/v1/generation API,文档见此
  3. 检查每条 API 响应中用量响应里的 prompt_tokens_details 对象

响应体中的 cache_discount 字段会告诉你该响应在缓存用量上节省了多少。部分模型服务提供商(如 Anthropic)会在缓存写入上给出负折扣,但在缓存读取上给出正折扣(从而降低总成本)。

使用 Auto RouterPareto Router 等路由模型时,粘性路由还会固定解析后的模型——而不仅仅是模型服务提供商。这可以防止路由模型在同一对话的每一轮选择不同的模型。详见 Auto Router — 会话粘性

usage 对象字段

API 响应中的 usage 对象在 prompt_tokens_details 字段中包含详细的缓存指标:

{
  "usage": {
    "prompt_tokens": 10339,
    "completion_tokens": 60,
    "total_tokens": 10399,
    "prompt_tokens_details": {
      "cached_tokens": 10318,
      "cache_write_tokens": 0
    }
  }
}

关键字段包括:

  • cached_tokens:从缓存中读取的 Token 数量(缓存命中)。该值大于零时,说明你正在受益于已缓存内容。
  • cache_write_tokens:写入缓存的 Token 数量。在建立新缓存条目的首次请求上会出现此字段。

OpenAI

缓存价格变化:

  • 缓存写入:GPT-5.6 系列之前的模型无费用。GPT-5.6 及之后的模型即使使用自动缓存,也会按原始输入价格的 1.25 倍收取缓存写入费用——无需选择加入。
  • 缓存读取:(视模型而定)按原始输入价格的 0.25 倍或 0.50 倍计费

点击此处查看 OpenAI 各模型的缓存定价。

OpenAI 的提示词缓存是自动化的,无需任何额外配置。提示词最短长度为 1024 Token。

点击此处了解更多关于 OpenAI 提示词缓存及其限制的信息。

显式提示词缓存

缓存价格变化:

  • 缓存写入:按原始输入价格的 1.25 倍计费(与 GPT-5.6 及之后模型上的自动缓存写入费率相同)
  • 缓存读取:按该模型的折扣缓存读取费率计费,与自动缓存相同

显式提示词缓存同时适用于 Chat CompletionsResponses API,让你可以直接控制缓存边界,而不是依赖 OpenAI 自动放置断点。缓存前缀的最短 TTL 为 30 分钟。上游细节见 OpenAI 的显式提示词缓存文档

OpenAI 显式提示词缓存仅由 OpenAI GPT-5.6 及更新版本支持。

有两项控制:

  • prompt_cache_breakpoint:放在单个文本内容块上(Responses 中为 input_text,Chat Completions 中为 text),用于标记可复用前缀的结尾。到该块为止的全部内容成为候选缓存前缀。自动缓存仍然启用。
  • prompt_cache_options:放在请求根级。将 mode 设为 "explicit" 会禁用 OpenAI 托管的断点,因此只有标记了 prompt_cache_breakpoint 的块才会参与缓存。使用 ttl 请求缓存时长(例如 "30m")。

Responses API:

{
  "model": "openai/...",
  "prompt_cache_key": "my-session-key",
  "prompt_cache_options": {
    "mode": "explicit",
    "ttl": "30m"
  },
  "input": [
    {
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "<REUSABLE_PREFIX>",
          "prompt_cache_breakpoint": {
            "mode": "explicit"
          }
        },
        {
          "type": "input_text",
          "text": "<TASK_SPECIFIC_SUFFIX>"
        }
      ]
    }
  ]
}

Chat Completions API:

{
  "model": "openai/...",
  "prompt_cache_key": "my-session-key",
  "prompt_cache_options": {
    "mode": "explicit",
    "ttl": "30m"
  },
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "<REUSABLE_PREFIX>",
          "prompt_cache_breakpoint": {
            "mode": "explicit"
          }
        },
        {
          "type": "text",
          "text": "<TASK_SPECIFIC_SUFFIX>"
        }
      ]
    }
  ]
}

块级标记可以互换:带有 Anthropic 风格 cache_control 的文本块在路由到受支持的 OpenAI 模型时,会获得 prompt_cache_breakpoint;带有 prompt_cache_breakpoint 的块在路由到 Anthropic 或 Google 时,会获得默认(5 分钟)的 cache_control。TTL 不会被转换——发往 OpenAI 时会丢弃 cache_controlttl,而请求级的 prompt_cache_options 仅适用于 OpenAI。

缓存活动会报告在 usage.input_tokens_details(Responses)和 usage.prompt_tokens_details(Chat Completions)中:cache_write_tokens 统计写入缓存的提示词 Token,cached_tokens 统计从缓存读取的提示词 Token。

Grok

缓存价格变化:

  • 缓存写入:无费用
  • 缓存读取:按原始输入价格的 0.25 倍计费

点击此处查看 Grok 各模型的缓存定价。

Grok 的提示词缓存是自动化的,无需任何额外配置。

Moonshot AI

缓存价格变化:

  • 缓存写入:无费用
  • 缓存读取:按原始输入价格的 0.25 倍计费

Moonshot AI 的提示词缓存是自动化的,无需任何额外配置。

Groq

缓存价格变化:

  • 缓存写入:无费用
  • 缓存读取:按原始输入价格的 0.5 倍计费

Groq 的提示词缓存是自动化的,无需任何额外配置。目前可用于 Kimi K2 模型。

点击此处查看 Groq 文档。

Alibaba Qwen

显式缓存的价格变化:

  • 缓存写入:按原始输入价格的 1.25 倍计费
  • 缓存读取:按原始输入价格的 0.1 倍计费

Alibaba 提示词缓存需要显式缓存断点。在你想要缓存的内容块上添加 cache_control: { "type": "ephemeral" },语法与 Anthropic 显式缓存相同。缓存写入使用 5 分钟 TTL。

Alibaba 显式缓存可用于 deepseek/deepseek-v3.2qwen/qwen3-maxqwen/qwen-plusqwen/qwen3.6-plusqwen/qwen3-coder-plusqwen/qwen3-coder-flash。快照端点, 包括 qwen/qwen3.5-plus-02-15qwen/qwen3.5-flash-02-23,不支持显式缓存。

示例

{
  "model": "qwen/qwen3-coder-plus",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Use the reference below when answering."
        },
        {
          "type": "text",
          "text": "HUGE TEXT BODY",
          "cache_control": {
            "type": "ephemeral"
          }
        },
        {
          "type": "text",
          "text": "Summarize the main implementation details."
        }
      ]
    }
  ]
}

Anthropic Claude

缓存价格变化:

  • 缓存写入(5 分钟 TTL):按原始输入价格的 1.25 倍计费
  • 缓存写入(1 小时 TTL):按原始输入价格的 2 倍计费
  • 缓存读取:按原始输入价格的 0.1 倍计费

有两种方式为 Anthropic 启用提示词缓存:

  • 自动缓存:在请求顶层添加单个 cache_control 字段。系统会自动将缓存断点应用到最后一个可缓存块,并随着对话增长向前推进。最适合多轮对话。
  • 显式缓存断点:将 cache_control 直接放在各个内容块上,以精细控制究竟缓存什么。显式断点上限为四个。建议将缓存断点留给大段文本,例如角色卡、CSV 数据、检索增强生成(RAG)数据、书籍章节等。

自动缓存(顶层 cache_control)受 AnthropicGoogle Vertex AIAzureAmazon Bedrock 模型服务提供商以及 AWS 上的 Claude Platform 支持。在 Amazon Bedrock 上,OpenRouter 会把顶层字段转换为尾部缓存断点(Bedrock 的简化缓存管理),因为 Bedrock 的 InvokeModel API 不直接接受该顶层字段。显式的按块 cache_control 断点适用于所有兼容 Anthropic 的模型服务提供商,包括 Bedrock 和 Vertex。

Responses API 支持: Responses API 通过顶层 cache_control 支持自动缓存input 条目内部的 Anthropic 风格按块 cache_control 不会通过 Responses API 暴露——请改用 OpenAI 的按块 prompt_cache_breakpoint,当请求被路由到 Anthropic 或 Google 时,OpenRouter 会将其转换为默认的 cache_control 断点。注意 prompt_cache_breakpoint 不携带 ttl;若需要设置缓存 ttl,请使用带 cache_controlChat CompletionsAnthropic Messages API。

默认情况下,缓存会在 5 分钟后过期,但你可以在 cache_control 对象中指定 "ttl": "1h",将其延长至 1 小时。

点击此处了解更多关于 Anthropic 提示词缓存及其限制的信息。

最低 Token 要求

每个模型都有可缓存提示词的最短长度(见 Anthropic 的缓存限制):

  • 4,096 Token:Claude Opus 4.8、Claude Opus 4.7、Claude Opus 4.6、Claude Opus 4.5、Claude Haiku 4.5
  • 2,048 Token:Claude Haiku 3.5
  • 1,024 Token:Claude Sonnet 4.6、Claude Sonnet 4.5、Claude Opus 4.1、Claude Opus 4、Claude Sonnet 4

短于这些最低要求的提示词不会被缓存。

缓存 TTL 选项

OpenRouter 为 Anthropic 支持两种缓存 TTL 值:

  • 5 分钟(默认):"cache_control": { "type": "ephemeral" }
  • 1 小时"cache_control": { "type": "ephemeral", "ttl": "1h" }

1 小时 TTL 适用于更长的会话:你希望在多次请求之间保持已缓存内容,而不反复承担缓存写入成本。1 小时 TTL 的缓存写入更贵(基础输入价格的 2 倍,而 5 分钟 TTL 为 1.25 倍),但通过避免重复缓存写入,可以在较长会话中节省费用。显式缓存断点的 1 小时 TTL 适用于所有 Claude 模型服务提供商(Anthropic、Amazon Bedrock 和 Google Vertex AI)。

在 Batch API 中缓存

cache_control 断点在 Anthropic :batch 端点上的工作方式与同步 API 相同,但单个批次内的请求可能并发且以任意顺序处理——某行写入的缓存不保证对同一批次中的其他行可见。要获得可靠的缓存命中,请在共享前缀上使用 "ttl": "1h" 断点,并在连续批次中复用该前缀(或先用同步请求预热缓存):第一个批次支付缓存写入价格,后续批次在缓存保持热状态期间从缓存读取。

示例

使用自动缓存时,在请求顶层添加 cache_control。系统会自动缓存直到最后一个可缓存块的全部内容:

{
  "model": "~anthropic/claude-sonnet-latest",
  "cache_control": { "type": "ephemeral" },
  "messages": [
    {
      "role": "system",
      "content": "You are a historian studying the fall of the Roman Empire. You know the following book very well: HUGE TEXT BODY"
    },
    {
      "role": "user",
      "content": "What triggered the collapse?"
    }
  ]
}

随着对话增长,缓存断点会自动向前推进,以覆盖不断增长的消息历史。

使用 1 小时 TTL 的自动缓存:

{
  "model": "~anthropic/claude-sonnet-latest",
  "cache_control": { "type": "ephemeral", "ttl": "1h" },
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant."
    },
    {
      "role": "user",
      "content": "What is the meaning of life?"
    }
  ]
}

显式缓存断点(精细控制)

system 消息缓存示例(默认 5 分钟 TTL):

{
  "messages": [
    {
      "role": "system",
      "content": [
        {
          "type": "text",
          "text": "You are a historian studying the fall of the Roman Empire. You know the following book very well:"
        },
        {
          "type": "text",
          "text": "HUGE TEXT BODY",
          "cache_control": {
            "type": "ephemeral"
          }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "What triggered the collapse?"
        }
      ]
    }
  ]
}

带 1 小时 TTL 的 user 消息缓存示例:

{
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Given the book below:"
        },
        {
          "type": "text",
          "text": "HUGE TEXT BODY",
          "cache_control": {
            "type": "ephemeral",
            "ttl": "1h"
          }
        },
        {
          "type": "text",
          "text": "Name all the characters in the above book"
        }
      ]
    }
  ]
}

DeepSeek

缓存价格变化:

  • 缓存写入:按与原始输入价格相同的费率计费
  • 缓存读取:按原始输入价格的 0.1 倍计费

DeepSeek 的提示词缓存是自动化的,无需任何额外配置。

Z.AI

缓存价格变化:

  • 缓存写入:无费用(Z.AI 目前将缓存输入存储列为限时免费)
  • 缓存读取:按各模型页面上显示的折扣缓存输入费率计费(通常约为原始输入价格的 0.2 倍)

点击此处查看 Z.AI 各模型的缓存定价。

Z.AI 的提示词缓存是自动化的,无需任何额外配置。缓存读取会报告在用量响应中 prompt_tokens_detailscached_tokens 字段。

点击此处了解更多关于 Z.AI 上下文缓存的信息。

为提高缓存命中率,OpenRouter 会在每次请求中向 Z.AI 发送会话亲和键,该键由你的账户以及(若已提供)你的 session_id 派生。在多轮对话中传入 session_id,可使同一会话的请求落在同一缓存上。

Google Gemini

隐式缓存

Gemini 2.5 Pro 和 2.5 Flash 模型现在支持隐式缓存,提供与 OpenAI 自动缓存类似的自动缓存功能。隐式缓存可无缝工作——无需手动设置或额外的 cache_control 断点。

价格变化:

  • 无缓存写入或存储费用。
  • 缓存 Token 按原始输入 Token 成本的 0.25 倍计费。

请注意,TTL 平均为 3–5 分钟,但会有所变化。Gemini 2.5 Flash 的请求至少需要 1024 Token,Gemini 2.5 Pro 至少需要 4096 Token,才有资格被缓存。

Google 官方公告

为了最大化隐式缓存命中,请在请求之间保持消息数组的起始部分一致。 将变化部分(例如用户问题或动态上下文元素)放到提示词/请求的末尾。

缓存请求的价格变化

  • 缓存写入: 按输入 Token 成本加上 5 分钟的缓存存储计费,计算如下:
缓存写入成本 = 输入 Token 价格 +(缓存存储价格 ×(5 分钟 / 60 分钟))
  • 缓存读取: 按原始输入 Token 成本的 0.25× 计费。

支持的模型与限制

只有部分 Gemini 模型支持缓存。请查阅 Google 的 Gemini API 定价文档以获取最新详情。

缓存写入具有 5 分钟的生存时间(TTL),且不会更新。5 分钟后缓存过期,必须写入新缓存。

Gemini 模型通常需要至少 4096 Token 才会发生缓存写入。缓存 Token 会计入模型的最大 Token 用量。Gemini 2.5 Pro 的最低要求为 4096 Token,Gemini 2.5 Flash 的最低要求为 1024 Token。

Gemini 提示词缓存在 OpenRouter 上的工作方式

OpenRouter 简化了 Gemini 缓存管理,抽象掉其中的复杂性:

  • 不需要手动创建、更新或删除缓存。
  • 不需要显式管理缓存名称或 TTL。

如何启用 Gemini 提示词缓存

OpenRouter 上的 Gemini 缓存要求你在消息内容中显式插入 cache_control 断点,类似于 Anthropic。我们建议主要对大块内容使用缓存(例如 CSV 文件、较长的角色卡、RAG 数据,或大段文本来源)。

请求中可以包含的 cache_control 断点数量没有限制。 OpenRouter 只会使用最后一个断点,对普通消息内容进行 Gemini 缓存。 包含多个断点是安全的,并且有助于与 Anthropic 保持兼容,但只有最后一个会用于 Gemini。

Gemini 只有一个 systemInstruction 字段,且已缓存的 Gemini 内容 将该 systemInstruction 视为不可变。在 OpenRouter 上,这意味着 第一条 systemdeveloper 消息内部的 cache_control 可以缓存 归一化后的系统提示词,但不能在同一条消息内保留未缓存的动态尾部。 如果你需要提示词的某一部分保持动态,请把该动态内容移到后面的 user 消息中,而不是追加在第一条 system 消息的已缓存块之后。

示例

system 消息缓存示例

{
  "messages": [
    {
      "role": "system",
      "content": [
        {
          "type": "text",
          "text": "You are a historian studying the fall of the Roman Empire. Below is an extensive reference book:"
        },
        {
          "type": "text",
          "text": "HUGE TEXT BODY HERE",
          "cache_control": {
            "type": "ephemeral"
          }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "What triggered the collapse?"
        }
      ]
    }
  ]
}

当已缓存的 system 内容在请求之间保持稳定时,此模式有效。如果 你需要动态的提示词片段,请把它放在后面的 user 消息中,而不是 作为第一条 system 消息中未缓存的尾部内容。

user 消息缓存示例

{
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Based on the book text below:"
        },
        {
          "type": "text",
          "text": "HUGE TEXT BODY HERE",
          "cache_control": {
            "type": "ephemeral"
          }
        },
        {
          "type": "text",
          "text": "List all main characters mentioned in the text above."
        }
      ]
    }
  ]
}