【高速缓存】使用 LangCache 作为 LLM 缓存后端指南
引言在前一篇文章中我们深入探讨了 RedisVL 的SemanticCache—— 一个基于自建 Redis 索引的语义缓存解决方案。但有时候你可能不想自己维护 Redis 集群和索引而是希望使用一个托管的语义缓存服务即开即用免去运维烦恼。这就是LangCache的用武之地。LangCache 是 Redis 官方提供的一项托管语义缓存服务它通过 HTTP API 提供与SemanticCache类似的check/store接口。RedisVL 中的LangCacheSemanticCache类正是这个服务的轻量级封装让你在使用习惯上与SemanticCache保持高度一致但底层却由 LangCache 服务代为管理所有缓存存储和向量搜索逻辑。本文将从零开始带你了解如何配置和使用LangCacheSemanticCache并指出它与自托管方案的异同。前置条件在开始之前请确保安装了带有langcache额外依赖的 RedisVLpip install redisvl[langcache]Python 版本 3.10与 RedisVL 要求一致拥有一个 LangCache 服务实例并获得Cache ID和API Key。你可以通过 Redis Cloud 快速创建 LangCache 服务。可选如果你打算使用元数据/属性进行过滤请先在 LangCache 控制台或 API 中配置好对应的属性字段名和类型。能做的完成本指南后你将能够根据实际场景在SemanticCache和LangCacheSemanticCache之间做出合适的选择使用凭证和默认 TTL 初始化LangCacheSemanticCache实现“读穿透”缓存模式先查缓存未命中再调用 LLM最后存储结果利用 LangCache 属性进行数据隔离和删除操作掌握按条目覆盖 TTL、使用异步 API 以及执行删除操作的方法了解当前版本与SemanticCache相比存在的限制选择SemanticCache还是LangCacheSemanticCache两者都提供语义缓存能力但架构和适用场景有明显区别。下表帮你快速决策特性SemanticCacheLangCacheSemanticCache数据存储位置你自己的 Redis 部署RedisVL 在 Redis 中创建并查询搜索索引LangCache 托管服务通过 HTTP API 访问最佳使用场景你掌控 Redis 基础设施需要完整的 RedisVL 查询/过滤能力或者希望缓存与应用程序数据放在一起你希望使用托管的语义缓存无需操心 Redis 运维和索引管理按原始向量搜索支持check中可传入vector不支持—— 搜索只能基于 prompt 文本通过 LangCache API 完成过滤表达式支持FilterExpression不支持—— 请使用 LangCache 属性需在服务端预先配置部分更新条目在后端允许时支持update/aupdate会抛出异常请改用“删除后重新存储”的方式补充说明SemanticCache的完整用法可参考前一篇指南。安装 LangCache 额外依赖你需要安装redisvl[langcache]以获取兼容的langcache客户端库pipinstallredisvl[langcache]如果在 Jupyter Notebook 中也可使用%pip install redisvl[langcache]初始化LangCacheSemanticCache创建LangCacheSemanticCache实例时需要提供 LangCache 服务的凭证信息。默认的server_url指向 Redis 官方托管服务如果你的服务提供商给出了不同的端点请自行覆盖。建议将凭证存储在环境变量中避免硬编码。importosfromredisvl.extensions.cache.llmimportLangCacheSemanticCache# 从环境变量读取凭证推荐做法CACHE_IDos.environ.get(LANGCACHE_CACHE_ID,YOUR_CACHE_ID)API_KEYos.environ.get(LANGCACHE_API_KEY,YOUR_API_KEY)cacheLangCacheSemanticCache(namemy_app_cache,# 仅用于本地标识不影响服务端server_urlhttps://aws-us-east-1.langcache.redis.io,# LangCache API 基础 URLcache_idCACHE_ID,# 你的缓存实例 IDapi_keyAPI_KEY,# API 密钥ttl3600,# 默认 TTL秒可选)关键参数说明参数作用cache_id,api_key必需。标识你的 LangCache 缓存并验证身份。server_urlLangCache API 基础地址。默认匹配官方托管服务若使用其他提供商请修改。ttl存储条目的默认生存时间秒可在每次store调用时单独覆盖。use_exact_search/use_semantic_search启用精确匹配和/或语义匹配至少一个必须为True。distance_threshold在check中配合distance_scale使用可设为normalized距离 0~1或redis余弦风格 0~2。属性和元数据属性Attributes是 LangCache 为每个条目附加的键值对元数据。你可以在查询check/acheck的attributes参数和删除delete_by_attributes/adelete_by_attributes时使用它们来限定范围。⚠️重要你必须在 LangCache 控制台或通过管理 API预先定义这些属性的名称和类型如字符串、数字等否则 RedisVL 调用时会收到错误。如果传递了未配置的属性LangCache API 会返回错误RedisVL 会抛出清晰的RuntimeError提示你配置属性或移除相关调用。字符串值在传输时会进行编码/解码以支持特殊字符。读穿透缓存模式Read-Through Caching这是最典型的使用流程先调用check查询缓存如果命中则直接返回若未命中则调用 LLM 生成答案然后调用store存入缓存供后续请求复用。defcall_your_llm(prompt:str)-str:替换为实际的 LLM 客户端调用OpenAI、Anthropic 等returnf对 {prompt} 的回答defanswer(user_prompt:str)-str:# 1. 查缓存hitscache.check(promptuser_prompt,num_results1)ifhits:returnhits[0][response]# 2. 未命中 → 调用 LLMresponsecall_your_llm(user_prompt)# 3. 存储到缓存cache.store(promptuser_prompt,responseresponse)returnresponse如果需要按租户或模型等维度隔离缓存可以传入attributes前提是这些属性已在 LangCache 中配置hitscache.check(promptuser_prompt,attributes{tenant_id:acme,model:gpt-4o},num_results1,)下面的流程图直观展示了这一过程是否用户输入问题调用 cache.check 查询缓存缓存命中返回缓存的响应调用 LLM 获取真实响应调用 cache.store 存储新条目返回新响应结束TTL生存时间控制默认 TTL在初始化时通过ttl参数设置所有新条目的默认有效期秒。按条目覆盖在调用store/astore时可以传入ttl参数为当前存储的条目单独指定过期时间。prompt什么是 RedisresponseRedis 是一种内存数据存储。# 此条目将在 5 分钟后过期覆盖构造函数的默认 TTLcache.store(promptprompt,responseresponse,ttl300)异步 APILangCacheSemanticCache也支持异步操作方法名前缀为a例如acheck、astore、adelete、adelete_by_id、adelete_by_attributes、aclear。这在构建高并发应用时非常有用。importasyncioasyncdefcall_your_llm_async(prompt:str)-str:returnf异步回答:{prompt}asyncdefanswer_async(user_prompt:str)-str:hitsawaitcache.acheck(promptuser_prompt,num_results1)ifhits:returnhits[0][response]responseawaitcall_your_llm_async(user_prompt)awaitcache.astore(promptuser_prompt,responseresponse)returnresponse# 运行异步函数resultasyncio.run(answer_async(你好世界))print(result)删除操作方法功能delete()/adelete()清空整个缓存所有条目。别名clear()/aclear()delete_by_id(entry_id)/adelete_by_id根据 LangCache 返回的entry_id删除单个条目。delete_by_attributes(attributes)/adelete_by_attributes根据指定的属性键值对删除所有匹配的条目属性字典不能为空。使用示例# 删除特定 ID 的条目cache.delete_by_id(abc123)# 删除所有 tenant_id 为 acme 的条目需在 LangCache 中预定义该属性cache.delete_by_attributes({tenant_id:acme})当前限制由于LangCacheSemanticCache是 LangCache HTTP API 的封装其能力受限于服务端接口。与SemanticCache相比存在以下限制不支持按原始向量搜索如果在check/acheck中传入vector参数会记录警告并忽略该参数搜索仍基于 prompt 文本。不支持FilterExpression无法使用 RedisVL 的复杂过滤器表达式请改用 LangCache 属性需预先配置。不支持update()/aupdate()LangCache API 没有提供更新单个条目的接口因此这些方法会抛出NotImplementedError。如需修改请先删除旧条目再存储新条目。store中的filters参数无效SemanticCache允许在store时传入filters但 LangCache 不支持该字段传入时会记录警告并被忽略。总结LangCacheSemanticCache是一个托管缓存方案让你无需维护 Redis 索引即可享受语义缓存的便利。它与SemanticCache在使用上高度相似但在过滤能力、更新操作等方面存在取舍。我们掌握了初始化、读穿透缓存、TTL 控制、异步 API 和删除操作等核心功能。清楚了当前版本的限制帮助你避开常见的误用场景。选择哪种缓存方案取决于你是否愿意自己管理 Redis 基础设施以及对高级查询如向量搜索、复杂过滤的需求。如果你希望轻装上阵LangCache 无疑是绝佳的搭档如果你需要深度定制SemanticCache则提供了更大的灵活性。