【高速缓存】RedisVL嵌入缓存完全指南:加速语义应用 在构建语义搜索、RAG、推荐系统等应用时文本嵌入Embedding计算往往是最耗时的环节之一。尤其是当大量文本重复出现或相似查询频繁发生时重复计算同样的向量会造成巨大的资源浪费和延迟。RedisVL 提供的EmbeddingsCache专门解决这一问题——它基于 Redis 实现了一个高性能的嵌入缓存系统能够存储和快速检索文本对应的向量并支持 TTL、批量操作、异步调用等高级特性帮助大幅提升应用性能并降低 API 调用成本。前置准备已安装 RedisVLpip install redisvl有运行的 Redis 实例Redis 8 或 Redis Cloud准备使用的向量化器如 HuggingFace 模型或 OpenAI 等要点使用EmbeddingsCache存储和检索嵌入向量利用批量操作高效处理大量文本配置缓存条目的生存时间TTL将缓存与向量化器集成实现自动缓存理解缓存的工作机制及最佳实践整体工作流程下图展示了嵌入缓存的核心工作流命中未命中输入文本检查缓存返回缓存的向量调用向量化器生成向量存入缓存返回向量后续业务逻辑缓存层充当了“加速器”角色有效避免了重复计算。下面我们从零开始搭建一个完整的缓存系统。安装与导入首先导入所需模块并创建一个 HuggingFace 向量化器也可以使用其他 Provider。importosimporttimeimportnumpyasnp# 避免多线程死锁os.environ[TOKENIZERS_PARALLELISM]Falsefromredisvl.extensions.cache.embeddingsimportEmbeddingsCachefromredisvl.utils.vectorizeimportHFTextVectorizer# 初始化向量化器这里使用一个轻量级模型vectorizerHFTextVectorizer(modelredis/langcache-embed-v1,cache_folderos.getenv(SENTENCE_TRANSFORMERS_HOME)# 可选指定缓存目录)初始化 EmbeddingsCache缓存对象需要一个 Redis 连接并可以设置全局默认 TTL。cacheEmbeddingsCache(nameembedcache,# Redis 键的前缀redis_urlredis://localhost:6379,ttlNone# 默认不过期也可设为秒数)缓存键的生成逻辑内部使用{prefix}:{hash(contentmodel_name)}作为键确保相同文本和模型产生相同键从而避免冲突。基本操作1. 存储嵌入使用set方法将一个文本及其向量存入缓存。参数包括content原始文本字符串model_name嵌入模型名称用于区分不同模型的向量embedding向量列表或 numpy 数组metadata可选附加信息字典ttl针对该条目的自定义过期时间覆盖全局默认textWhat is machine learning?model_nameredis/langcache-embed-v1# 生成向量embeddingvectorizer.embed(text)# 附加元数据方便后续过滤或溯源metadata{category:ai,source:user_query}# 存入缓存返回生成的 Redis 键keycache.set(contenttext,model_namemodel_name,embeddingembedding,metadatametadata)print(fStored with key:{key})2. 检索嵌入使用get方法通过文本和模型名取出缓存的条目。若不存在则返回None。resultcache.get(contenttext,model_namemodel_name)ifresult:print(fContent:{result[content]})print(fModel:{result[model_name]})print(fMetadata:{result[metadata]})print(fEmbedding shape:{np.array(result[embedding]).shape})返回的字典包含content、model_name、embedding、metadata、created_at等字段。3. 检查存在性避免不必要的网络传输只检查是否存在。existscache.exists(contenttext,model_namemodel_name)print(fExists?{exists})4. 删除条目使用drop方法删除指定条目。cache.drop(contenttext,model_namemodel_name)高级操作基于键的操作如果你已经知道 Redis 键可以直接使用get_by_key、exists_by_key、drop_by_key。这在需要精确控制或与其他系统集成时很有用。keycache.set(contenttext,model_namemodel_name,embeddingembedding)resultcache.get_by_key(key)cache.drop_by_key(key)批量操作Multi当需要处理多个文本时批量操作能显著减少网络往返次数提升吞吐量。所有批量方法都以m开头如mset、mget、mexists、mdrop。texts[What is machine learning?,How do neural networks work?,What is deep learning?]embeddings[vectorizer.embed(t)fortintexts]# 准备批量数据batch_items[{content:texts[0],model_name:model_name,embedding:embeddings[0],metadata:{category:ai,type:question}},# ... 其他条目]# 一次性存入keyscache.mset(batch_items)print(fStored{len(keys)}entries)# 批量检查存在性exist_resultscache.mexists(texts,model_name)# 批量获取resultscache.mget(texts,model_name)# 批量删除cache.mdrop(texts,model_name)原理这些方法内部使用 Redis 的管道Pipeline或 MGET/MSET 命令将多个操作打包发送有效降低网络延迟。对于异步编程同样提供amset、amget等前缀。配置 TTL生存时间TTL 是缓存管理的关键参数可以防止数据无限膨胀。你可以在初始化时设置全局默认 TTL也可以在每次set时单独指定。# 创建一个默认 TTL 5 秒的缓存ttl_cacheEmbeddingsCache(namettl_cache,redis_urlredis://localhost:6379,ttl5)# 存储时使用默认 TTLkey1ttl_cache.set(contentfoo,model_namemodel_name,embeddingembedding)# 存储时覆盖为 1 秒key2ttl_cache.set(contentbar,model_namemodel_name,embeddingembedding,ttl1)time.sleep(2)print(ttl_cache.exists_by_key(key1))# True仍有效print(ttl_cache.exists_by_key(key2))# False已过期TTL 的实现原理Redis 对每个键设置EXPIRE到达时间后自动删除。这非常适合临时性数据如会话级缓存。异步支持对于异步应用如 FastAPI所有方法都有异步版本以a开头aset、aget、aexists、adrop等。asyncdefdemo():keyawaitcache.aset(contentAsync text,model_namemodel_name,embeddingembedding)resultawaitcache.aget_by_key(key)awaitcache.adrop_by_key(key)awaitdemo()与向量化器自动集成大多数向量化器如HFTextVectorizer支持传入cache参数使得embed方法内部自动检查缓存。这样你无需手动调用cache.get/set代码更简洁。# 创建带有缓存功能的向量化器vectorizer_with_cacheHFTextVectorizer(modelmodel_name,cachecache# 传入缓存实例)# 第一次调用计算并缓存emb1vectorizer_with_cache.embed(What is AI?)# 第二次调用直接从缓存返回emb2vectorizer_with_cache.embed(What is AI?)# 速度极快embed方法内部逻辑大致如下命中 ✅未命中 ❌ 输入文本 缓存检查 返回缓存向量 调用嵌入模型生成 存入缓存这样一来你在业务代码中几乎无需感知缓存的存在就能自动享受加速效果。实战示例查询流处理设想一个处理用户查询流的场景其中许多查询可能重复。我们可以统计缓存命中率直观感受性能提升。queries[What is artificial intelligence?,How does machine learning work?,What is artificial intelligence?,# 重复What are neural networks?,How does machine learning work?# 重复]cache_hits0forqinqueries:ifcache.exists(contentq,model_namemodel_name):cache_hits1# 无论是否命中都获取 embedding此处为演示实际可先检查再决定是否计算embvectorizer.embed(q)hit_ratecache_hits/len(queries)*100print(f命中率:{hit_rate:.1f}%)# 输出 40%在真实场景中重复查询比例越高缓存收益越大。性能基准测试我们对比 10 次相同文本的嵌入生成时间直观感受缓存带来的数量级提升。benchmark_cacheEmbeddingsCache(namebench,redis_urlredis://localhost:6379)vectorizer.cachebenchmark_cache textBenchmark text# 不使用缓存skip_cacheTrue 强制绕过starttime.time()for_inrange(10):vectorizer.embed(text,skip_cacheTrue)no_cache_timetime.time()-start# 使用缓存第二次起命中starttime.time()for_inrange(10):vectorizer.embed(text)cache_timetime.time()-startprint(f无缓存:{no_cache_time:.4f}s, 有缓存:{cache_time:.4f}s, 加速比:{no_cache_time/cache_time:.2f}x)典型结果无缓存约 0.45s有缓存约 0.06s加速 7 倍以上。实际中如果使用远程 API如 OpenAI加速比可能达到数十倍同时节省费用。常见使用场景场景缓存收益搜索引擎查询缓存热门查询的嵌入直接复用响应时间大幅缩短推荐系统内容缓存内容项嵌入稳定缓存后相似度计算更快API 服务如 OpenAI避免重复调用付费 API降低成本和延迟批量数据处理去重重复文本只计算一次节省计算资源聊天机器人常见问题标准问题缓存在本地快速响应用户清理缓存演示完毕记得清理避免 Redis 中残留无用数据cache.clear()# 清空整个前缀下的所有键# 或逐个删除特定条目cache.drop(contenttext,model_namemodel_name)实践缓存键的生成采用{name}:{sha256(contentmodel_name)}形式确保唯一性且碰撞概率极低。model_name的引入使得同一文本使用不同模型时可分别缓存互不干扰。为什么批量操作更快每个单独的get/set都会发起一次网络往返RTT。批量操作将多个命令打包利用 Redis 的管道或原生命令如 MGET减少总体网络开销尤其在高并发场景下效果显著。TTL 的设置策略对于变化频繁的数据如实时趋势设置较短的 TTL如几分钟。对于静态数据如知识库文档可设置较长 TTL如数天甚至永不过期。合理的 TTL 既能控制内存占用又能保证数据的新鲜度。缓存与向量化器集成推荐使用vectorizer.embed(text, skip_cacheFalse)的默认行为让缓存透明化。若需要强制重新计算如模型更新可传skip_cacheTrue并手动调用cache.drop清理旧条目。总结RedisVL 的EmbeddingsCache为语义应用提供了轻量而强大的缓存层它简单易用几行代码即可启用。性能卓越通过 Redis 高速存取配合批量操作和异步支持轻松应对高并发。灵活可控支持 TTL、元数据、独立键操作满足多样需求。无缝集成与向量化器结合自动缓存对业务代码侵入性极低。通过合理使用嵌入缓存可以显著提升应用响应速度降低计算成本。