Skip to main content

概览

GoModel 内置两层响应缓存,适用于以下端点上的流式和非流式请求:
  • /v1/chat/completions
  • /v1/responses
  • /v1/messages
  • /v1/embeddings
  • /v1/systemone(以及 Kev 的 /permute 和 /separate)
同一请求的流式和非流式版本会分别缓存:流式请求未命中时会存储原始 SSE 字节,流式请求命中时会以 text/event-stream 原样重放这些字节。 精确匹配缓存返回逐字节相同的响应,并带有:
语义缓存使用嵌入(Embeddings)加向量检索,使语义相同的提示词可以复用已存储的响应:
/v1/embeddings 只参与精确缓存。嵌入必须表示所请求的确切文本,因此为仅仅相似的输入重放向量,会得到一个错误的答案,而不是一个等价的答案。嵌入请求也从不使用流式传输,因此只缓存 JSON 响应。System One 决策同理:相似的状态并不意味着相同的决策。

启用精确缓存

将响应缓存指向 Redis:
您也可以通过环境变量进行配置:
  • REDIS_URL
  • REDIS_KEY_RESPONSES
  • REDIS_TTL_RESPONSES

启用语义缓存

添加一个 semantic 配置块,并指定嵌入提供商和向量存储:
支持的向量存储:
  • qdrant
  • pgvector
  • pinecone
  • weaviate
两层缓存都在工作流和护栏修补之后运行,因此它们作用于最终发送到上游的请求。使用 Cache-Control: no-cache 或 Cache-Control: no-store 可以针对单个请求绕过缓存。插件也可以在其决策中使用 NoStore,使某个响应不进入两层缓存;将请求特定数据恢复到回复中的护栏就是这样做的,以确保恢复后的文本绝不会被重放给其他调用方。/v1/responses 上的 background: true 请求同样会绕过两层缓存:它的 queued 响应体携带一个只属于某个调用方响应的 id。 有关语义缓存的完整设计和存储选项,请参阅 ADR-0006。

精确缓存键的组成

精确缓存会对以下内容计算哈希:
  • 请求路径
  • 用于执行的已解析工作流上下文,具体为执行模式、提供商类型和解析后的模型
  • 请求解析到的护栏链,涵盖提示词、响应和流三个阶段
  • 最终的请求体
这意味着,当护栏和工作流改变了解析后的工作流或经过执行发送的最终请求体时,它们会影响缓存键。 缓存命中时会重放已存储的响应,而不会重新运行响应和流护栏链,因此一个缓存条目只会提供给护栏链与生成它时相同的请求。编辑、添加或删除某个护栏步骤,或者使用另一个护栏链不同的工作流,都会导致缓存未命中,而不是返回这些护栏从未检查过的回复。因此,更改护栏配置会使旧护栏链下存储的条目失效。 在计算哈希之前,JSON 对象成员的顺序和无意义的空白会被规范化。因此,仅格式不同的请求会共用同一个精确缓存条目。并发的相同未命中请求也会在进程内合并:只有一个请求到达提供商,其他等待的请求会重放它的响应。失败的或其他不可缓存的响应绝不会被分发给等待者。

提供商提示词缓存规划

在路由解析出具体的提供商和模型之后,如果稳定前缀达到该提供商的最小长度,且客户端尚未提供缓存指令,GoModel 会添加一个缓存计划:
  • OpenAI 会收到一个稳定的 prompt_cache_key;支持显式缓存的模型还会收到一个断点和显式缓存模式。
  • Anthropic 会收到顶层的自动临时缓存(ephemeral caching)。
  • Amazon Bedrock Converse 会在稳定前缀之后收到一个缓存点。
  • 原生 Gemini AI Studio 会创建并复用一个五分钟有效的缓存内容对象,并按前缀和稳定凭据合并并发创建。
该计划在路由之后应用,因此仅属于特定提供商的字段不会在回退到其他后端时泄漏出去。缓存键包含具体的提供商实例和模型,并且调用方提供的缓存控制始终优先。 提供商提示词缓存规划默认启用。要禁用 GoModel 的自动规划,同时继续透传兼容的客户端缓存指令,请设置:
该标志接受 Go 布尔值。缺失、为空或无效的值会保持安全的默认值(true),无效值会在启动时输出警告。

user_path 行为

对于精确缓存,user_path 本身不会被加入缓存键。 这是有意为之。如果两个请求最终具有相同的路径、解析后的工作流和最终请求体,即使它们来自不同的 user_path 值,也可以共用同一个精确缓存条目。
如果您需要按租户或路径区分缓存行为,请使用带作用域的工作流,或以其他方式使该作用域的最终请求有所不同。仅靠 user_path 并不能作为精确缓存的分区键。
常见做法:
  • 在带作用域的工作流中禁用缓存
  • 为不同的 user_path 值使用不同的带作用域工作流
  • 加入特定于作用域的上下文,使最终请求体有所不同

通过故障转移返回的响应不会被缓存

当请求由某个故障转移目标而不是路由最初选择的目标应答时,该响应不会被存储。精确缓存键是根据故障转移之前的解析结果计算的,因此如果存储备用目标的应答,在主目标恢复后,这个应答会以主目标的缓存键被返回。 实际影响是:如果某个虚拟模型的第一个目标长期不可用,在其不可用期间,该虚拟模型将不再积累缓存条目。每个未命中的请求都会故障转移并获得新的响应,而这些响应都不会被存储。故障之前写入的条目在 TTL 过期前会继续提供服务:缓存查找在分发之前进行,因此命中时直接返回,不会触及任何目标。如果某个目标将在一段时间内不可用,请调整链的顺序(或将虚拟模型指向健康的目标),使应答请求的响应重新可被缓存。 同一目标内的重试不受影响:只有在切换到其他目标之后产生的响应,才会被排除在两层缓存之外。

缓存分析

当启用了响应缓存和用量追踪时,Admin API 会在以下位置提供仅包含缓存数据的概览:
缓存命中也会记录为用量条目,并带有调用方的 user_path,以及值为 exact 或 semantic 的 cache_type。用量端点(/admin/usage/* 和 /v1/usage)默认不包含这些条目,使总量和成本反映的是提供商支出;传入 cache_mode=all 可包含它们,传入 cache_mode=cached 则只查看命中条目。/admin/usage/sessions 是例外:会话的请求数和 Token 总数始终包含缓存命中,而其成本字段仍只统计提供商支出。
参阅 Admin 端点和 Usage API。
最后修改于 2026年10月24日