语义缓存
语义缓存让 AISIX 在新请求与先前请求含义相同、措辞不同时也能返回缓存的响应。它是响应缓存的扩展:精确匹配层始终先被检查,语义层负责处理精确层未命中的请求。
在本指南中,你将为缓存策略添加语义配置块,验证精确命中与语义命中,并清空缓存条目。你还将了解跨网关实例共享语义条目所需的 Redis 要求。
语义缓存的工作原理
配置了 semantic 块的缓存策略会对每个符合条件的请求依次运行两个匹配层:
- **精确层。**首先查找请求指纹——模型别名、规范化后的 messages、采样参数以及其他影响响应的选项。完全相同的重复请求在此命中,无需任何 embedding 调用。
- **语义层。**精确层未命中时,AISIX 使用策略配置的 embedding 模型将请求的消息文本向量化,并与已存储的条目比较。相似度达到或超过阈值的最近条目会被返回;否则请求继续发往上游,响应连同其向量一起被存储。
只有 messages 内容参与相似度匹配。模型别名和其他指纹字段仍必须匹配。如果存在 temperature 和 top_p,则以 0.001 的精度比较,因此同一千分位区间内的显式值视为相等。省略字段与显式设置该字段仍视为不同。消息中包含图片、音频或工具结果的 请求永远不会做相似度匹配,它们只使用精确层。
语义命中也不会刷新条目:条目与精确条目一样按策略 TTL 过期。
Embedding 失败时放行
语义匹配是一种优化,绝不是一道闸门。如果 embedding 调用失败或超时,请求会不经缓存直接发往上游,失败会计入缓存指标。如果 embedding 模型被删除或配置错误,策略会记录一条警告并继续只提供精确匹配。
准备工作
开始之前,请准备以下内容:
- 一套可用的响应缓存环境:缓存策略管理路径(AISIX Cloud 或声明式资源文件)、模型别名和调用方 API Key。
- 同一环境中的一个 embedding 模型。在 AISIX Cloud 中这是 kind 为
embedding的模型;在资源文件中则是带embedding块的模型条目。它负责将请求文本向量化以做相似度比较;其dimensions值固定了该策略条目的向量维度。 - 使用 Redis 后端的策略还需要支持向量检索的 Redis 部署——见使用 Redis 共享语义条目。
导出共用的连接变量:
# AISIX_PROXY 不含尾部斜杠或 /v1 等端点路径
# 本地快速入门使用 http://127.0.0.1:3000
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.92 作为初始基线,而不是通用建议。生产使用前,请用有代表性的提示词进行校准。
AISIX Cloud
导出控制面连接信息:
# AISIX_CP 包含 /api,且不含尾部斜杠
# 本地私有化部署快速入门使用 http://localhost:8080/api
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
保留响应缓存流程中的 CACHE_POLICY_ID。如果要为另一个现有策略添加语义功能,请导出该策略的 ID:
export CACHE_POLICY_ID="YOUR_EXISTING_CACHE_POLICY_ID"
列出环境中的模型,并选择用于此缓存策略的 embedding 模型。以下命令会输出每个 embedding 模型的显示名称和 ID,避免任意选择一条匹配结果:
curl -fsS "$AISIX_CP/environments/$ENV_ID/models" \
-H "Authorization: Bearer $AISIX_TOKEN" \
| jq -e '
[.data[] | select(.kind == "embedding") | {display_name, id}]
| if length == 0 then error("No embedding models found") else .[] end
'
导出所选模型的 ID:
export EMBED_MODEL_ID="YOUR_EMBEDDING_MODEL_ID"
如果环境中没有 embedding 模型,该命令会失败。请先创建一个模型,或确认 ENV_ID 指向配置了该模型的环境。
用 semantic 块修补现有策略。AISIX Cloud Admin API 通过资源 ID 引用 embedding 模型:
curl -sS -X PATCH \
"$AISIX_CP/environments/$ENV_ID/cache_policies/$CACHE_POLICY_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF | jq
{
"semantic": {
"embedding_model_id": "${EMBED_MODEL_ID}",
"threshold": 0.92
}
}
EOF
同样的配置也可以在 AISIX Cloud 控制台的 Cache Policies 页面管理。编辑现有策略,启用 Semantic matching,选择 embedding 模型并调整阈值。
之后若想在不重建策略的情况下关闭语义层,在 PATCH 请求中发送 "semantic": null;省 略该字段则保持配置不变。
开源 AISIX 网关
将 text-embedder 添加到 models,然后替换 default-chat-cache 策略。保持其他资源不变:
models:
- display_name: text-embedder
provider: openai
model_name: text-embedding-3-small
provider_key: openai-prod
embedding:
dimensions: 1536
cache_policies:
- name: default-chat-cache
enabled: true
backend: memory
applies_to: "model:gpt-4o-mini"
ttl_seconds: 3600
semantic:
embedding_model: text-embedder
threshold: 0.92
语义块通过 embedding 模型的 display_name 引用它。
校验完整的资源文件,然后重载网关。
该示例延续响应缓存流程中使用 Memory 后端的 default-chat-cache 策略。如果现有策略使用其他名称或 Redis 后端,请保持这些字段不变,只添加 semantic 块。
可选语义参数
| 字段 | 默认值 | 行为 |
|---|---|---|
max_entries | 1000 | memory 后端下每个策略存储条目的上限(1–10000),最旧的条目先被淘汰。共享后端按 TTL 控制规模并忽略此值。 |
embedding_timeout_ms | 无 | embedding 调用的单次超时。超时后请求不经缓存直接发往上游。 |
验证语义命中
先发送一个请求,然后用不同的措辞重复同一 个意思。响应头会区分两个匹配层。网关只有在启动配置将 proxy.expose_debug_headers 设为 true 时才会发送这些响应头,请在用于测试的网关上开启该设置。未开启时,可按请求的 x-aisix-request-id 从访问日志的 cache_status、cache_hit_layer 字段和使用事件的 cache_similarity 读取同样的值。
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 起步,再使用有代表性的流量进行调整:
- 返回了错误答案(不同的问题被当成同一个):调高阈值并重复评估。
- 同义改写未命中(同一个问题重复走上游):逐步调低,同时监控错误匹配。对于大多数 embedding 模型,低于
0.9会明显增加返回错误答案的风险。 - 合适的取值取决于 embedding 模型。更换 embedding 模型后需要重新调优——不同模型的分数不可比。更换 embedding 模型同时会使既有语义条目失效,因为不同模型产生的向量无法比较。
用 x-aisix-cache-similarity 响应头或使用事件的 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 按钮提供同一操作。
资源文件部署方式下,在现有策略条目上添加 purge_generation 字段并在每次清空时递增:
cache_policies:
- name: default-chat-cache
# ...
purge_generation: 1
请让该值单调递增。清空后绝不能降低或省略该值,否则可能会使更早的精确缓存条目重新可用,直至其过期。完整要求请参阅清空缓存条目。
使用 Redis 共享语义条目
memory 后端下每个网关实例维护自己的条目。要跨实例共享两个缓存层,按使用 Redis 共享缓存条目的说明使用 backend: redis 加上网关的 cache.redis 启动配置。
语义层对 Redis 有额外要求:
- Redis 8 或更高版本(或带 search 模块的 Redis Stack 部署)。网关把向量存进向量索引并运行 KNN 相似度查询。
- **
single或sentinel模式。**语义条目不支持 Redis Cluster。 - **RESP2。**不要在
cache.redisURL 中添加protocol=resp3。语义缓存探测会拒绝 RESP3,因为其向量检索响应解析器需要 RESP2。
网关启动时会探测 Redis 部署是否支持向量检索和 RESP2。Redis 版本过旧、缺少模块、使用 Cluster 模式或 RESP3 都会导致探测失败。此时,该后端上的策略继续只提供精确匹配并记录一条警告。精确层共享不受影响,仅相似度层被禁用。
上述结论是最终的,因为服务端明确给出了答案。而探测本身没有得到应答时——例如 Redis 不可达或响应过慢——网关会在后台重试,而不是就此判定不支持。重试成功后语义匹配随即启用;在问题尚未有答案期间,每个请求既不会触发向量化调用,也不会产生 Redis 往返。
精确层与语义层在 Redis 上保持一致:条目存储在同一键空间下,清空代次同时作用于两层,TTL 与策略一致。
可观测性
缓存行为在三个层面可见:
- 响应头:
x-aisix-cache(hit/miss/bypass)、x-aisix-cache-layer(命中时为exact/semantic)、x-aisix-cache-similarity(仅语义命中),仅在proxy.expose_debug_headers为true时发送。见响应头与错误码。 - Prometheus 指标:
aisix_cache_requests_total按策略统计结果(hit_exact/hit_semantic/miss/bypass),aisix_cache_semantic_*系列跟踪 embedding 延迟与失败模式。命中率查询见指标参考。 - 用量事件:缓存响应把命中层记录在
cache_hit_layer,语义命中的相似度记录在cache_similarity,导出的记录可以据此归因节省的上游调用。
后续步骤
你已经启用语义缓存并验证了按层归因的缓存命中。接下来: