【高速缓存】使用 LangCache 作为 LLM 缓存后端指南
2026/7/21 23:10:08 网站建设 项目流程

引言

在前一篇文章中,我们深入探讨了 RedisVL 的SemanticCache—— 一个基于自建 Redis 索引的语义缓存解决方案。但有时候,你可能不想自己维护 Redis 集群和索引,而是希望使用一个托管的语义缓存服务,即开即用,免去运维烦恼。

这就是LangCache的用武之地。LangCache 是 Redis 官方提供的一项托管语义缓存服务,它通过 HTTP API 提供与SemanticCache类似的check/store接口。RedisVL 中的LangCacheSemanticCache类正是这个服务的轻量级封装,让你在使用习惯上与SemanticCache保持高度一致,但底层却由 LangCache 服务代为管理所有缓存存储和向量搜索逻辑。

本文将从零开始,带你了解如何配置和使用LangCacheSemanticCache,并指出它与自托管方案的异同。


前置条件

在开始之前,请确保:

  • 安装了带有langcache额外依赖的 RedisVL:pip install redisvl[langcache]
  • Python 版本 3.10+(与 RedisVL 要求一致)
  • 拥有一个 LangCache 服务实例,并获得Cache IDAPI Key。你可以通过 Redis Cloud 快速创建 LangCache 服务。
  • (可选)如果你打算使用元数据/属性进行过滤,请先在 LangCache 控制台或 API 中配置好对应的属性(字段名和类型)。

能做的

完成本指南后,你将能够:

  • 根据实际场景,在SemanticCacheLangCacheSemanticCache之间做出合适的选择
  • 使用凭证和默认 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_ID=os.environ.get("LANGCACHE_CACHE_ID","YOUR_CACHE_ID")API_KEY=os.environ.get("LANGCACHE_API_KEY","YOUR_API_KEY")cache=LangCacheSemanticCache(name="my_app_cache",# 仅用于本地标识,不影响服务端server_url="https://aws-us-east-1.langcache.redis.io",# LangCache API 基础 URLcache_id=CACHE_ID,# 你的缓存实例 IDapi_key=API_KEY,# API 密钥ttl=3600,# 默认 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/acheckattributes参数)和删除(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. 查缓存hits=cache.check(prompt=user_prompt,num_results=1)ifhits:returnhits[0]["response"]# 2. 未命中 → 调用 LLMresponse=call_your_llm(user_prompt)# 3. 存储到缓存cache.store(prompt=user_prompt,response=response)returnresponse

如果需要按租户或模型等维度隔离缓存,可以传入attributes(前提是这些属性已在 LangCache 中配置):

hits=cache.check(prompt=user_prompt,attributes={"tenant_id":"acme","model":"gpt-4o"},num_results=1,)

下面的流程图直观展示了这一过程:

用户输入问题

调用 cache.check 查询缓存

缓存命中?

返回缓存的响应

调用 LLM 获取真实响应

调用 cache.store 存储新条目

返回新响应

结束


TTL(生存时间)控制

  • 默认 TTL:在初始化时通过ttl=参数设置所有新条目的默认有效期(秒)。
  • 按条目覆盖:在调用store/astore时,可以传入ttl=参数,为当前存储的条目单独指定过期时间。
prompt="什么是 Redis?"response="Redis 是一种内存数据存储。"# 此条目将在 5 分钟后过期,覆盖构造函数的默认 TTLcache.store(prompt=prompt,response=response,ttl=300)

异步 API

LangCacheSemanticCache也支持异步操作,方法名前缀为a,例如acheckastoreadeleteadelete_by_idadelete_by_attributesaclear。这在构建高并发应用时非常有用。

importasyncioasyncdefcall_your_llm_async(prompt:str)->str:returnf"异步回答:{prompt}"asyncdefanswer_async(user_prompt:str)->str:hits=awaitcache.acheck(prompt=user_prompt,num_results=1)ifhits:returnhits[0]["response"]response=awaitcall_your_llm_async(user_prompt)awaitcache.astore(prompt=user_prompt,response=response)returnresponse# 运行异步函数result=asyncio.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相比,存在以下限制:

  1. 不支持按原始向量搜索
    如果在check/acheck中传入vector=参数,会记录警告并忽略该参数,搜索仍基于 prompt 文本。

  2. 不支持FilterExpression
    无法使用 RedisVL 的复杂过滤器表达式,请改用 LangCache 属性(需预先配置)。

  3. 不支持update()/aupdate()
    LangCache API 没有提供更新单个条目的接口,因此这些方法会抛出NotImplementedError。如需修改,请先删除旧条目,再存储新条目。

  4. store中的filters参数无效
    SemanticCache允许在store时传入filters,但 LangCache 不支持该字段,传入时会记录警告并被忽略。


总结

  • LangCacheSemanticCache是一个托管缓存方案,让你无需维护 Redis 索引即可享受语义缓存的便利。
  • 它与SemanticCache在使用上高度相似,但在过滤能力、更新操作等方面存在取舍。
  • 我们掌握了初始化、读穿透缓存、TTL 控制、异步 API 和删除操作等核心功能。
  • 清楚了当前版本的限制,帮助你避开常见的误用场景。

选择哪种缓存方案,取决于你是否愿意自己管理 Redis 基础设施,以及对高级查询(如向量搜索、复杂过滤)的需求。如果你希望轻装上阵,LangCache 无疑是绝佳的搭档;如果你需要深度定制,SemanticCache则提供了更大的灵活性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询