在大模型应用落地时,推理环节往往占据整个请求链路的大部分耗时,尤其当多个用户提出语义相近但措辞不同的问题时,后端若每次都调用模型,不仅增加费用,还让响应变慢。Redis语义缓存是一种把用户问题向量化后存入Redis,并通过相似度检索复用历史回答的方案,能显著减少重复推理。

语义缓存为什么比普通缓存更适合AI场景
普通缓存通常基于精确字符串匹配,例如把用户问句作为键,把模型回答作为值。这种方式在提问完全一致时有效,但现实里用户可能用“北京明天天气怎么样”和“明天北京天气如何”表达同一意图,普通缓存无法识别二者语义等价,只能再次推理。语义缓存先将文本通过embedding模型转为向量,再在向量空间比较距离,只要语义接近就判定命中,从根本上解决了表述差异问题。
从系统架构看,语义缓存处于接入层与模型服务之间。每次请求先走缓存查询,未命中才调用推理,并将新问题向量与回答写回缓存。这样高频相似问题会被拦截在模型之外,GPU或API调用次数下降,平均响应时间从秒级降到毫秒级。需要注意的是,语义缓存引入了向量检索组件和embedding计算开销,因此必须控制向量维度与检索算法复杂度,否则缓存本身可能成为瓶颈。
另一个常被忽略的点是缓存失效与准确性平衡。语义相近不等于业务答案一定相同,比如“怎么退订会员”和“会员怎么退款”虽语义靠近,但答案可能涉及不同流程。实践中应结合相似度阈值与业务规则,对低置信度命中做降级处理,而不是直接返回,以避免答非所问影响体验。
基于Redis的语义缓存实现方案
Redis本身提供多种结构可承载向量数据。较简单的做法是用Redis的HASH存回答文本,用有序集合或第三方模块如RediSearch、RedisJSON配合向量索引。若使用Redis 7.4以上并加载向量搜索能力,可直接用FT.CREATE建立带向量字段的索引,通过FT.SEARCH做KNN查询。对于中小规模应用,也可以自行用HASH存向量数组,在应用层计算余弦相似度,但这种方式查询效率随数据量线性下降,不适合万级以上条目。
下面示例展示用Python连接Redis,借助sentence-transformers生成向量,并使用哈希与集合模拟语义缓存读写。代码仅做演示,生产环境建议用专业向量库或Redis官方向量索引。
import redis
import numpy as np
from sentence_transformers import SentenceTransformer
r = redis.Redis(host='127.0.0.1', port=6379, db=0)
model = SentenceTransformer('paraphrase-MiniLM-L3-v2')
def get_embedding(text):
# 将文本转为归一化向量
vec = model.encode(text, normalize_embeddings=True)
return vec.astype(np.float32).tobytes()
def semantic_cache_get(query, threshold=0.92):
q_vec = get_embedding(query)
# 遍历缓存键,简单演示用,生产请用向量索引
for key in r.scan_iter('semcache:*'):
stored = r.hget(key, 'vec')
if not stored:
continue
s_vec = np.frombuffer(stored, dtype=np.float32)
sim = np.dot(q_vec, s_vec)
if sim >= threshold:
return r.hget(key, 'answer').decode('utf-8'), sim
return None, 0
def semantic_cache_set(query, answer):
key = 'semcache:' + str(abs(hash(query)))
vec = get_embedding(query)
r.hset(key, mapping={'vec': vec, 'answer': answer})
r.expire(key, 3600)
# 使用示例
ans, score = semantic_cache_get('北京明天天气怎么样')
if ans is None:
ans = '调用模型得到天气回答'
semantic_cache_set('北京明天天气怎么样', ans)
上述代码里我们把向量以二进制存入HASH,查询时全量计算内积。当缓存条数变多,扫描开销大,因此应在Redis侧使用向量索引。同时,设置过期时间可避免冷数据长期占用内存。相似度阈值threshold是关键参数,设太高命中少,设太低易误答,需要按业务测试调整。
命中率与准确性的调优实践
语义缓存效果核心看两个指标:命中率和误命中率。命中率衡量多少请求被缓存拦截,误命中率衡量命中里答案不正确的比例。二者通常负相关,阈值收紧误命中降但命中也降。建议先收集真实用户问句日志,离线计算不同阈值下的分布,再选定平衡点。例如客服场景可接受较低误命中以换高命中,医疗问答则必须严控误命中。
除了阈值,embedding模型选择也直接影响效果。轻量模型速度快但语义区分弱,大模型准确却增加缓存前置延迟。可在接入层用轻量模型做初筛,疑似的低置信度请求再走大模型复核。另外,对缓存内容做分类标签,如“天气”“退款”,查询时先按标签过滤再算向量,能减少无关比对,提升检索效率与准确性。
最后,监控不可忽视。应记录每次缓存查询的相似度分数、是否命中、最终是否人工修正,形成反馈闭环。当发现某类问题误命中集中,可针对性从缓存剔除或调高该类阈值。通过持续观察,Redis语义缓存能在控制成本的同时,稳定提升AI推理接口的响应速度。