语义缓存
语义缓存让 AISIX 在新请求与先前请求含义相同、措辞不同时也能返回缓存的响应。它是响应缓存的扩展:精确匹配层始终先被检查,语义层负责处理精确层未命中的请求。
在本指南中,你将为缓存策略添加语义配置块,验证精确命中与语义命中,并清空缓存条目。你还将了解跨网关实例共享语义条目所需的 Redis 版本要求。
语义缓存的工作原理
配置了 semantic 块的缓存策略会对每个符合条件的请求依次运行两个匹配层:
- **精确层。**首先查找请求指纹——模型别名、规范化后的 messages、采样参数以及其他影响响应的选项。完全相同的重复请求在此命中,无需任何 embedding 调用。
- **语义层。**精确层未命中时,AISIX 使用策略配置的 embedding 模型将请求的消息文本向量化,并与已存储的条目比较。相似度达到或超过阈值的最近条目会被返回;否则请求继续发往上游,响应连同其向量一起被存储。
只有 messages 内容参与相似度匹配。模型别名、采样参数以及其他指纹字段仍必须精确一致——换了 temperature 的同义改写请求不会复用条目。消息中包含图片、音频或工具结果的请求永远不会做相似度匹配,它们只使用精确层。
语义命中也不会刷新条目:条目与精确条目一样按策略 TTL 过期。
Embedding 失败时放行
语义匹配是一种优化,绝不是一道闸门。如果 embedding 调用失败或超时,请求会不经缓存直接发往上游,失败会计入缓存指标。如果 embedding 模型被删除或配置错误,策略会记录一条警告并继续只提供精确匹配。
准备工作
开始之前,请准备以下内容:
- 一套可用的响应缓存环境:缓存策略管理路径(AISIX Cloud 或声明式资源文件)、模型别名和调用方 API Key。
- 同一环境中的一个 embedding 模型。在 AISIX Cloud 中这是 kind 为
embedding的模型;在资源文件中则是带embedding块的模型条目。它负责将请求文本向量化以做相似度比较;其dimensions值固定了该策略条目的向量维度。 - 使用 Redis 后端的策略还需要支持向量检索的 Redis 部署——见使用 Redis 共享语义条目。
导出共用的连接变量:
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export AISIX_MODEL="gpt-4o-mini"
配置语义缓存策略
semantic 块在缓存策略上启用相似度层。阈值为必填项:它是条目被返回所需的最小余弦相似度,取值 [0, 1],越高越严格。低于约 0.9 时返回错误答案的风险明显上升;0.92 是一个不错的起点。
AISIX Cloud
导出控制面连接信息:
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_BASE_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
查询 embedding 模型的 ID,然后创建带 semantic 块的策略。Admin API 通过资源 ID 引用 embedding 模型:
export EMBED_MODEL_ID=$(curl -sS "$AISIX_CP/environments/$ENV_ID/models" \
-H "Authorization: Bearer $AISIX_TOKEN" |
jq -r '.data[] | select(.kind == "embedding") | .id' | head -1)
curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/cache_policies" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF | jq
{
"name": "semantic-chat-cache",
"enabled": true,
"backend": "memory",
"applies_to": "model:${AISIX_MODEL}",
"ttl_seconds": 3600,
"semantic": {
"embedding_model_id": "${EMBED_MODEL_ID}",
"threshold": 0.92
}
}
EOF
同样的配置也可以在 AISIX Cloud 控制台的缓存策略页面管理:启用语义匹配、选择 embedding 模型并调整阈值。
之后若想在不重建策略的情况下关闭语义层,在 PATCH 请求中发送 "semantic": null;省略该字段则保持配置不变。
开源 AISIX 网关
在资源文件中,语义块通过 display_name 引用 embedding 模型:
models:
- display_name: text-embedder
provider: openai
model_name: text-embedding-3-small
provider_key: openai-prod
embedding:
dimensions: 1536
cache_policies:
- name: semantic-chat-cache
enabled: true
backend: memory
applies_to: "model:gpt-4o-mini"
ttl_seconds: 3600
semantic:
embedding_model: text-embedder
threshold: 0.92
校验完整的资源文件,然后重载网关。
可选语义参数
| 字段 | 默认值 | 行为 |
|---|---|---|
max_entries | 1000 | memory 后端下每个策略存储条目的上限(1–10000),最旧的条目先被淘汰。共享后端按 TTL 控制规模并忽略此值。 |
embedding_timeout_ms | 无 | embedding 调用的单次超时。超时后请求不经缓存直接发往上游。 |
验证语义命中
先发送一个请求,然后用不同的措辞重复同一个意思。响应头会区分两个匹配层:
curl -sSi -X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
--data '{"model": "'"$AISIX_MODEL"'", "messages": [{"role": "user", "content": "How do I reset my password?"}]}'
第一个请求报告未命中并存储响应:
x-aisix-cache: miss
重复完全相同的请求,它命中精确层:
x-aisix-cache: hit
x-aisix-cache-layer: exact
现在改写提示词:
curl -sSi -X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
--data '{"model": "'"$AISIX_MODEL"'", "messages": [{"role": "user", "content": "What are the steps to reset a password?"}]}'
如果相似度超过阈值,响应来自语义层,不产生上游调用:
x-aisix-cache: hit
x-aisix-cache-layer: semantic
x-aisix-cache-similarity: 0.9714
x-aisix-cache-similarity 报告匹配条目的余弦相似度。如果改写反而未命中,请谨慎调低阈值,或确认两个请求使用了完全相同的采样参数。
语义命中还会把新措辞回填到精确层,因此重复同一改写会直接命中精确层。
调优阈值
从 0.92 起步,用真实流量调整:
- 返回了错误答案(不同的问题被当成同一个):把阈值向
0.97–0.99调高。 - 同义改写未命中(同一个问题重复走上游):逐步调低并观察质量。开放式流量避免低于
0.9。 - 合适的取值取决于 embedding 模型。更换 embedding 模型后需要重新调优——不同模型的分数不可比。更换 embedding 模型同时会使既有语义条目失效,因为不同模型产生的向量无法比较。
用 x-aisix-cache-similarity 响应头做校准:发送已知等价和已知不同的提示词对,观察它们的分数。
选择共享范围
策略的 scope 决定谁可以共享缓存条目,对两个匹配层同时生效:
| Scope | 行为 |
|---|---|
api_key | 默认值。条目仅对写入它的调用方 API Key 可见——一个调用方的回答绝不会回放给另一个调用方。 |
env | 环境内所有调用方 API Key 共享条目。 |
除非所有调用方等价,否则保持默认的 api_key。语义匹配让跨调用方复用比精确匹配风险更高:对另一个用户问题的同义改写,可能命中为那个用户的上下文生成的响应。只有 FAQ、文档问答这类共享知识型流量——跨调用方复用正是其目的——才选择 env。
按请求绕过缓存
调用方可以用标准的 Cache-Control 请求指令为单个请求跳过缓存,无需改动策略——见按请求绕过缓存。no-cache 跳过两个匹配层并刷新存储的条目;no-store 还会抑制写入。
清空缓存条目
清空操作会使策略存储的所有条目失效——两个匹配层、所有网关实例——而不删除策略本身:
curl -sS -X POST \
"$AISIX_CP/environments/$ENV_ID/cache_policies/$CACHE_POLICY_ID/purge" \
-H "Authorization: Bearer $AISIX_TOKEN" | jq
响应返回 purge_generation 递增后的策略。更新后的配置一经传播,网关就把更早代次的条目视为已删除;存储空间在后台回收。控制台在每个策略行上以清空按钮提供同一操作。
资源文件部署方式下,在策略条目上添加 purge_generation 字段并在每次清空时递增:
cache_policies:
- name: semantic-chat-cache
# ...
purge_generation: 1
使用 Redis 共享语义条目
memory 后端下每个网关实例维护自己的条目。要跨实例共享两个缓存层,按使用 Redis 共享缓存条目的说明使用 backend: redis 加上网关的 cache.redis 启动配置。
语义层对 Redis 有额外要求:
- Redis 8 或更高版本(或带 search 模块的 Redis Stack 部署)。网关把向量存进向量索引并运行 KNN 相似度查询。
- **
single或sentinel模式。**语义条目不支持 Redis Cluster。
网关启动时会探测 Redis 部署是否支持向量检索。探测失败——旧版 Redis、缺少模块或 cluster 模式——时,该后端上的策略继续只提供精确匹配并记录一条警告。精确层共享不受影响,仅相似度层被禁用。
精确层与语义层在 Redis 上保持一致:条目存储在同一键空间下,清空代次同时作用于两层,TTL 与策略一致。
可观测性
缓存行为在三个层面可见:
- 响应头:
x-aisix-cache(hit/miss/bypass)、x-aisix-cache-layer(命中时为exact/semantic)、x-aisix-cache-similarity(仅语义命中)。见响应头与错误码。 - Prometheus 指标:
aisix_cache_requests_total按策略统计结果(hit_exact/hit_semantic/miss/bypass),aisix_cache_semantic_*系列跟踪 embedding 延迟与失败模式。命中率查询见指标参考。 - 用量事件:缓存响应把命中层记录在
cache_hit_layer,语义命中的相似度记录在cache_similarity,导出的记录可以据此归因节省的上游调用。
后续步骤
你已经启用语义缓存并验证了按层归因的缓存命中。接下来: