跳到主要内容

ai-cache

ai-cache 插件会缓存 LLM 服务的响应,使重复请求直接从缓存返回,而不再次调用上游模型。这可以降低重复提示词的响应延迟,并减少上游 Token 用量。

该插件支持精确匹配缓存:仅当规范化后的请求与此前缓存的某个请求完全相同时,才会复用其响应。它还可以启用语义缓存层,在精确匹配未命中后通过 RediSearch 比较提示词向量嵌入。

按请求格式处理

插件会将检测到的不同请求格式保存在不同的缓存条目中。

网关会先检查 URI 特定规则,再检查仅基于请求体的规则,以识别请求格式:

  • Bedrock Converse 要求 URI 以 /converse 结尾且包含 messages 数组。
  • Anthropic Messages 要求 URI 以 /v1/messages 结尾。
  • Responses API 要求 URI 以 /v1/responses 结尾且包含 input 字段。
  • Chat Completions 使用 messages 数组。
  • 当前面的规则均不匹配时,Embeddings 使用 input
  • 当前面的规则均不匹配时,其他非空 JSON 对象使用透传格式。
请求格式精确匹配缓存语义缓存
Bedrock Converse支持绕过
Anthropic Messages支持绕过
Responses API支持绕过
Chat Completions支持支持
Embeddings支持绕过
其他 JSON(透传)支持绕过

精确匹配缓存自 API7 企业版 3.9.16、3.10.2 以及 APISIX 3.18.0 起可用。

语义缓存和流式响应缓存自 API7 企业版 3.9.16、3.10.3 以及 APISIX 3.18.0 起可用。

工作原理

ai-cache 插件必须与同一路由上的 ai-proxyai-proxy-multi 插件一起使用,因为它缓存的是这些插件所代理的 LLM 流量。

对于每个请求,插件会根据检测到的请求格式、请求体以及所选 AI 实例的配置计算缓存键。缓存键的作用域由 cache_key 配置。精确缓存条目存储在 Redis 中,并具有可配置的存活时间。

对于 Chat Completions 请求,语义缓存会在精确缓存未命中后运行。插件对配置的提示词窗口生成向量嵌入,并在 RediSearch 向量索引中查询足够相似的缓存响应。

插件会将 X-AI-Cache-Status 响应头设置为以下值之一:

  • HIT:找到有效的缓存响应并直接返回,不调用上游。X-AI-Cache-Age 头会以秒为单位报告该缓存条目的存活时长。语义命中还会返回 X-AI-Cache-Similarity
  • MISS:未找到缓存响应。请求被代理到上游,且大小在 max_cache_body_size 以内的成功响应(HTTP 200)会被缓存以供后续请求使用。
  • BYPASS:此请求跳过缓存,例如因为它匹配了某条 bypass_on 规则、未选中任何 AI 实例,或响应无法安全捕获。

完整的 SSE 流式响应可以被缓存,并使用其流式内容类型重放。只有当插件收到客户端协议的终止事件后,流式响应才会被缓存,例如 OpenAI Chat Completions 的 [DONE]、Anthropic Messages 的 message_stop,或 OpenAI Responses API 的 response.completed。被中断或因限制而截断的流式响应不会被缓存。流式请求和非流式请求使用不同的缓存条目;缓存的流式响应会立即重放,而不会保留原始 Token 的时间间隔。使用其他帧格式的流(例如 Bedrock ConverseStream 的 AWS 事件流格式)会绕过缓存。

警告

缓存的提示词和响应可能包含敏感数据。请限制对 Redis 的访问,选择合适的缓存存活时间;如果缓存响应不应在不同消费者或请求上下文之间共享,请使用 cache_key.include_consumercache_key.include_vars

示例

以下示例使用 OpenAI 作为上游 LLM 服务,并使用一个 Redis 实例来存储缓存。在开始之前,请创建一个 OpenAI 账号API Key,并确保网关能够访问到一个 Redis 实例。你可以选择将密钥保存到环境变量中:

export OPENAI_API_KEY=YOUR_OPENAI_API_KEY # 替换为你的 API Key

如果你使用其他模型服务提供方,请参考该提供方的文档获取 API Key。

缓存 LLM 响应

以下示例演示如何将 ai-cacheai-proxy 配合配置,使重复的相同请求由 Redis 提供响应。

创建一个使用 ai-proxy 代理到 OpenAI、并使用 ai-cache 缓存响应的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
--data-binary @- <<EOF
{
"id": "ai-cache-route",
"uri": "/anything",
"methods": ["POST"],
"plugins": {
"ai-proxy": {
"provider": "openai",
"auth": {
"header": {
"Authorization": "Bearer $OPENAI_API_KEY"
}
},
"options": {
"model": "gpt-4"
}
},
"ai-cache": {
"redis_host": "127.0.0.1",
"redis_port": 6379,
"exact": {
"ttl": 3600
}
}
}
}
EOF

❶ 在 Authorization 请求头中以 Bearer Token 形式附带 OpenAI API Key。

❷ 指定模型名称。

❸ 将缓存指向你的 Redis 实例。

❹ 将每个响应缓存一小时。

向路由发送请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "user", "content": "What is 1+1?" }
]
}'

第一个请求是缓存未命中,会被代理到 OpenAI。你应该收到 HTTP/1.1 200 OK 响应,其中包含以下响应头:

X-AI-Cache-Status: MISS

再次发送相同的请求。这一次响应直接从缓存返回,不会调用上游,并包含缓存状态和存活时长响应头:

X-AI-Cache-Status: HIT
X-AI-Cache-Age: 2

缓存语义相似的提示词

语义缓存会在精确缓存未命中后发起向量嵌入请求,并使用 RediSearch 查找足够相似的已缓存提示词。以下示例同时使用 OpenAI 处理 LLM 请求和向量嵌入请求。

警告

语义缓存需要带有 RediSearch 模块的 Redis Stack。标准 Redis 服务器可以存储精确缓存条目,但无法执行语义缓存层所需的向量搜索。

创建一个同时启用两种缓存层并配置向量嵌入服务的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
--data-binary @- <<EOF
{
"id": "ai-cache-semantic-route",
"uri": "/anything",
"methods": ["POST"],
"plugins": {
"ai-proxy": {
"provider": "openai",
"auth": {
"header": {
"Authorization": "Bearer $OPENAI_API_KEY"
}
},
"options": {
"model": "gpt-4o-mini"
}
},
"ai-cache": {
"redis_host": "127.0.0.1",
"layers": ["exact", "semantic"],
"semantic": {
"similarity_threshold": 0.92,
"embedding": {
"openai": {
"model": "text-embedding-3-small",
"api_key": "$OPENAI_API_KEY"
}
},
"vector_search": {
"redis": {
"index": "ai-cache"
}
}
}
}
}
}
EOF

发送初始请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "What is Apache APISIX?"
}
]
}'

第一个请求的精确缓存和语义缓存均未命中。插件会将请求代理到 LLM、对提示词生成向量嵌入,并存储两种缓存条目。你应该会收到包含以下响应头的 HTTP/1.1 200 OK 响应:

X-AI-Cache-Status: MISS

使用不同表述发送一个语义相似的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "Can you explain what Apache APISIX is?"
}
]
}'

如果相似度分数达到所配置的阈值,请求的精确缓存会未命中,但会由语义缓存提供响应。你应该会收到包含类似以下响应头的 HTTP/1.1 200 OK 响应:

X-AI-Cache-Status: HIT
X-AI-Cache-Age: 12
X-AI-Cache-Similarity: 0.9487

相似度值取决于向量嵌入模型和提示词。如果请求未命中,请先比较应共享响应和不应共享响应的提示词分数,再降低阈值。