语义缓存
概述
语义缓存是 LLM Gateway 的高级功能,通过语义相似度匹配来缓存和复用 LLM 响应,显著降低 API 调用成本和响应延迟。与传统的精确匹配缓存不同,语义缓存能够识别语义相似的查询,即使文字表述不同也能命中缓存。
工作原理
核心概念
语义缓存 使用向量嵌入(Embeddings)技术将文本转换为高维向量,然后通过向量相似度比较来判断查询是否语义相似。
向量化
用户查询被转换为向量表示:
查询: "什么是人工智能?"
向量: [0.123, -0.456, 0.789, ..., 0.234] (1536 维)相似度搜索
在向量数据库中搜索最相似的历史查询:
历史查询: "AI 是什么?"
相似度: 0.95 (余弦相似度)阈值判断
如果相似度超过配置的阈值(如 0.90),判定为缓存命中:
相似度 0.95 >= 阈值 0.90 → 缓存命中返回缓存
直接返回历史查询的缓存响应,无需调用 LLM API。
技术架构
请求
↓
语义缓存中间件
↓
提取查询内容
↓
嵌入模型转换 → 查询向量
↓
Redis Stack 向量搜索
↓
找到相似查询? ──┐
│ │
是 否
↓ ↓
返回缓存 调用 LLM API
↑ ↓
│ 缓存响应+向量
│ ↓
└──────────────┘
返回响应
关键组件
语义缓存中间件
位置: middleware/semantic_cache.go
功能:
- 拦截 LLM 请求
- 提取查询内容
- 调用嵌入模型
- 执行向量相似度搜索
- 管理缓存生命周期
性能:
- 缓存命中延迟: < 100ms
- 未命中额外开销: 50-200ms(嵌入生成时间)
Redis Stack
作用: 向量数据库,存储查询向量和响应
特性:
- 支持向量相似度搜索(Redis Vector Search)
- 高性能内存存储
- 支持 TTL 自动过期
- 支持集群部署
要求:
- 必须使用 Redis Stack,不能使用普通 Redis
- 版本要求: >= 7.2
嵌入模型
作用: 将文本转换为向量
支持的模型:
- OpenAI text-embedding-ada-002 (1536 维)
- OpenAI text-embedding-3-small (1536 维)
- OpenAI text-embedding-3-large (3072 维)
- 其他兼容 OpenAI API 的嵌入模型
配置:
- 嵌入模型可以独立配置
- 支持使用不同的 API 密钥
- 可以使用本地嵌入服务
缓存策略
缓存键生成:
cache_key = hash(model + messages + parameters)
缓存内容:
- 查询向量
- 完整响应内容
- 元数据(时间戳、模型、token 使用等)
TTL 配置:
- 默认: 24 小时
- 可配置范围: 1 分钟 - 30 天
- 支持永久缓存(TTL = -1)
配置指南
启用语义缓存
安装 Redis Stack
语义缓存需要 Redis Stack 支持,不能使用普通 Redis:
- Docker
- Docker Compose
- 原生安装
docker run -d \
--name redis-stack \
-p 6379:6379 \
-p 8001:8001 \
redis/redis-stack:latest
version: '3.8'
services:
redis:
image: redis/redis-stack:latest
ports:
- "6379:6379"
- "8001:8001"
volumes:
- redis-data:/data
volumes:
redis-data:
# Ubuntu/Debian
curl -fsSL https://packages.redis.io/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] \
https://packages.redis.io/deb $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install redis-stack-server
配置 Redis 连接
在 .env 文件中配置 Redis 连接字符串:
REDIS_CONN_STRING=redis://localhost:6379
# 或带密码的连接
REDIS_CONN_STRING=redis://:password@localhost:6379
# 或使用 Redis Sentinel
REDIS_CONN_STRING=redis-sentinel://sentinel1:26379,sentinel2:26379/mymaster
创建语义缓存配置
登录管理后台,导航到 系统设置 > 语义缓存:
配置嵌入模型
设置用于生成向量的嵌入模型:
- 嵌入模型: 选择嵌入模型(推荐 text-embedding-3-small)
- API 密钥: 填写 OpenAI API 密钥
- API 端点: 自定义端点(可选)
设置缓存参数
配置缓存行 为:
- 相似度阈值: 0.85 - 0.95(推荐 0.90)
- 缓存 TTL: 3600 - 86400 秒(推荐 24 小时)
- 最大缓存条目: 10000 - 100000(根据内存调整)
- 向量维度: 1536(text-embedding-3-small)
启用缓存
勾选"启用语义缓存"选项,点击"保存"。
启用后立即生效,无需重启服务。
验证配置
使用测试工具验证语义缓存是否正常工作:
# 第一次请求(缓存未命中)
curl -X POST https://your-gateway.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "什么是机器学习?"}]
}'
# 第二次请求(语义相似,应该命中缓存)
curl -X POST https://your-gateway.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "机器学习是什么?"}]
}'
查看响应头,应该包含:
X-Cache-Status: HIT
X-Cache-Similarity: 0.92
配置参数详解
相似度阈值 (Similarity Threshold)
说明: 判定缓存命中的最低相似度,范围 0-1
推荐值:
- 严格匹配: 0.95 - 0.98
- 平衡模式: 0.88 - 0.93(推荐 0.90)
- 宽松匹配: 0.80 - 0.87
影响:
- 阈值越高: 命中率越低,准确性越高
- 阈值越低: 命中率越高,可能返回不相关结果
调优建议:
- 从 0.90 开始
- 监控缓存命中率和用户反馈
- 根据实际效果微调(每次调整 ±0.02)
缓存 TTL (Time To Live)
说明: 缓存条目的存活时间,单位秒
推荐值:
- 实时内容: 300 - 1800 秒(5-30 分钟)
- 一般内容: 3600 - 86400 秒(1-24 小时)
- 静态内容: 86400 - 604800 秒(1-7 天)
- 永久缓存: -1(不过期)
考虑因素:
- 内容时效性
- 内存容量
- 业务需求
示例:
{
"news_bot": {"ttl": 1800}, // 新闻内容 30 分钟
"customer_service": {"ttl": 3600}, // 客服 FAQ 1 小时
"knowledge_base": {"ttl": 86400} // 知识库 24 小时
}
最大缓存条目 (Max Cache Entries)
说明: Redis 中存储的最大缓存条目数
内存估算:
每条缓存 ≈ 5-10 KB(包括向量、响应、元数据)
10000 条 ≈ 50-100 MB
100000 条 ≈ 500 MB - 1 GB
淘汰策略:
- 使用 LRU(Least Recently Used)
- 达到上限时,淘汰最久未使用的条目
推荐值:
- 小规模部署: 10000 - 50000
- 中等规模: 50000 - 200000
- 大规模: 200000+
向量维度 (Vector Dimension)
说明: 嵌入向量的维度,取决于嵌入模型
常见维度:
- text-embedding-ada-002: 1536
- text-embedding-3-small: 1536
- text-embedding-3-large: 3072
性能影响:
- 维度越高: 语义表达越丰富,但搜索越慢,内存占用越大
- 维度越低: 性能越好,但语义表达能力受限
推荐:
- 大多数场景使用 1536 维(text-embedding-3-small)
- 对语义准确性要求极高时使用 3072 维
嵌入模型选择
对比:
| 模型 | 维度 | 性能 | 成本 | 适用场景 |
|---|---|---|---|---|
| ada-002 | 1536 | 好 | 低 | 通用,成本敏感 |
| embedding-3-small | 1536 | 较好 | 低 | 推荐,性价比高 |
| embedding-3-large | 3072 | 最好 | 中 | 高精度要求 |
建议:
- 开发/测试: text-embedding-ada-002
- 生产环境: text-embedding-3-small
- 高精度场景: text-embedding-3-large
使用指南
客户端使用
语义缓存对客户端是透明的,无需修改代码即可享受缓存加速:
import openai
openai.api_base = "https://your-gateway.com/v1"
openai.api_key = "YOUR_TOKEN"
# 正常调用,自动使用语义缓存
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "什么是深度学习?"}
]
)
print(response.choices[0].message.content)
# 检查缓存状态(通过响应头)
# response.headers['X-Cache-Status'] = 'HIT' or 'MISS'
import OpenAI from 'openai';
const openai = new OpenAI({
baseURL: 'https://your-gateway.com/v1',
apiKey: 'YOUR_TOKEN',
});
// 正常调用,自动使用语义缓存
const response = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
messages: [
{ role: 'user', content: '什么是深度学习?' }
],
});
console.log(response.choices[0].message.content);
# 正常调用
curl -X POST https://your-gateway.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{"role": "user", "content": "什么是深度学习?"}
]
}' -i
# 查看响应头中的缓存状态:
# X-Cache-Status: HIT 或 MISS
# X-Cache-Similarity: 0.92 (命中时显示)
跳过语义缓存
某些场景下可能需要跳过缓存,直接调用 LLM:
curl -X POST https://your-gateway.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Skip-Semantic-Cache: true" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "今天的新闻"}]
}'
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "今天的新闻"}],
headers={"X-Skip-Semantic-Cache": "true"}
)
const response = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
messages: [{ role: 'user', content: '今天的新闻' }],
}, {
headers: {
'X-Skip-Semantic-Cache': 'true'
}
});
适用场景:
- 实时数据查询(天气、新闻、股票等)
- 需要最新结果的请求
- 调试和测试
- 强制刷新缓存
详细的跳过缓存用法参考: docs/SEMANTIC_CACHE_SKIP.md
缓存状态响应头
每个响应都包含缓存状态信息:
| 响应头 | 可能值 | 说明 |
|---|---|---|
| X-Cache-Status | HIT | 缓存命中,返回缓存内容 |
| MISS | 缓存未命中,调用 LLM API | |
| BYPASS | 跳过缓存(使用 X-Skip-Semantic-Cache) | |
| DISABLED | 语义缓存未启用 | |
| X-Cache-Similarity | 0.00-1.00 | 缓存命中时的相似度分数 |
| X-Cache-Age | 整数(秒) | 缓存条目的年龄 |
| X-Embedding-Time | 整数(毫秒) | 生成嵌入向量的耗时 |
| X-Cache-Search-Time | 整数(毫秒) | 向量搜索耗时 |
示例响应头:
HTTP/1.1 200 OK
X-Cache-Status: HIT
X-Cache-Similarity: 0.92
X-Cache-Age: 3600
X-Embedding-Time: 120
X-Cache-Search-Time: 15
查看缓存统计
- Web 界面
- API 查询
- Redis CLI
在管理后台的"语义缓存"页面查看统计信息:
- 总缓存条目数
- 缓存命中率
- 节省的 API 调用次数
- 节省的成本估算
- 平均相似度分数
- 缓存大小(内存占用)
通过 API 获取缓存统计:
curl -X GET https://your-gateway.com/api/semantic_cache/stats \
-H "Authorization: Bearer YOUR_TOKEN"
响应:
{
"enabled": true,
"total_entries": 15234,
"total_hits": 45678,
"total_misses": 12345,
"hit_rate": 0.787,
"avg_similarity": 0.91,
"total_saved_requests": 45678,
"estimated_cost_saved_usd": 123.45,
"cache_size_mb": 76.5,
"oldest_entry_age_hours": 23.5,
"most_recent_hit": "2025-10-18T10:30:00Z"
}
直接查询 Redis:
# 连接 Redis
redis-cli
# 查看所有缓存键
KEYS semantic_cache:*
# 查看缓存条目数
DBSIZE
# 查看特定缓存的内容
HGETALL semantic_cache:abc123
# 查看 TTL
TTL semantic_cache:abc123
管理缓存
清空所有缓存
在管理后台或通过 API 清空所有缓存:
Web 界面:
- 导航到 系统设置 > 语义缓存
- 点击"清空缓存"