基于Redis的LLM语义缓存
让我们面对现实——大型语言模型(LLMs)非常强大,但它们可能会非常缓慢。如果你曾经等待超过10秒来回答一个你几乎之前问过的问题,你就知道这种挫败感了。这就是语义缓存发挥作用的地方:你的模型可以快速回忆起对类似查询的回答,而不是从头开始生成答案。
我在实验带有LLM的聊天机器人时遇到了这个问题。用户会用稍微不同的方式问同一个问题,而机器人则会浪费时间(和计算资源)来生成新的回复。因此,我决定用Redis和Ollama来解决这个问题,这个组合证明是非常有效的(而且是免费的)。让我们来分解一下。
1、什么是语义缓存?
传统的缓存通过存储精确查询的确切响应来工作。如果你先问“Redis是什么?”然后问“告诉我关于Redis”,标准缓存将无法匹配。语义缓存通过存储向量嵌入——意义的数值表示——来解决这个问题,这样它就可以检索对类似查询的响应。
这种方法代替了每次重新生成文本:
- 加快响应速度(毫秒 vs 秒)
- 减少LLM的工作负载(降低成本,提高效率)
- 感觉更智能(用户获得快速、一致的答案)
2、为什么选择Redis和Ollama?
我选择了这些工具,因为它们配合得非常好:
- Redis:一个闪电般快速的内存数据存储。通过RedisVL扩展,它支持向量搜索,这正是我们需要的。
- Ollama:一种简单的方法来本地运行LLM并生成嵌入。我使用Llama 3.2进行响应,使用nomic-embed-text进行嵌入。
一起,它们使LLM感觉更快,而不增加不必要的复杂性。
3、开始使用
所有代码文件都在我的GitHub仓库中,并且还提供了如何设置它们的方法。
你需要安装以下内容:
pip install langchain-ollama redis redisvl
确保Redis在本地运行——我使用的是redis://localhost:6379
。你可以按照给定仓库中的README文件中的详细设置说明进行操作。
4、代码解析:逐步拆解
我把设置分为两个主要部分:一个用于生成嵌入,另一个用于管理缓存。
4.1 向量化器(cache_vectorizer.py)
RedisVL需要一个自定义向量化器来生成和检索嵌入。这是如何将Ollama的nomic-embed-text模型包装成Redis可以使用的东西:
from langchain_ollama import OllamaEmbeddings
from redisvl.utils.vectorize import CustomTextVectorizer
import asyncio
from typing import List
def create_vectorizer():
ollama_embedder = OllamaEmbeddings(model='nomic-embed-text')
def sync_embed(text: str) -> List[float]:
return ollama_embedder.embed_query(text)
def sync_embed_many(texts: List[str]) -> List[List[float]]:
return ollama_embedder.embed_documents(texts)
async def async_embed(text: str) -> List[float]:
return await asyncio.to_thread(sync_embed, text)
async def async_embed_many(texts: List[str]) -> List[List[float]]:
return await asyncio.to_thread(sync_embed_many, texts)
return CustomTextVectorizer(
embed=sync_embed,
aembed=async_embed,
embed_many=sync_embed_many,
aembed_many=async_embed_many
)
vectorizer = create_vectorizer()
4.2 主事件(test.py)
此脚本处理缓存逻辑——首先检查Redis,如果需要再调用LLM。
import time
from langchain_ollama import ChatOllama
from redisvl.extensions.llmcache import SemanticCache
from cache_vectorizer import vectorizer
import os
from dotenv import load_dotenv
---
load_dotenv()
redis_url = os.getenv('REDIS_URL', 'redis://localhost:6379')
llmcache = SemanticCache(
name="OllamaLLMCache",
redis_url=redis_url,
distance_threshold=0.1,
vectorizer=vectorizer,
connection_kwargs={'decode_responses': True, 'socket_timeout': 5, 'retry_on_timeout': True},
dimension=768
)
question = input("请输入您的问题:")
client = ChatOllama(model="llama3.2", verbose=True)
def ask_ollama(question: str) -> str:
response = client.invoke(input=question)
return response.content
start_time = time.time()
cached_response = llmcache.check(prompt=question)
cache_time = time.time() - start_time
if cached_response:
print("命中缓存!")
print("提示:", cached_response[0]['prompt'])
print("回复:", cached_response[0]['response'])
print(f"所用时间:{cache_time:.4f}秒")
else:
start_time = time.time()
response = ask_ollama(question)
llm_time = time.time() - start_time
print("未命中缓存。LLM回复:")
print("提示:", question)
print("回复:", response)
print(f"所用时间:{llm_time:.4f}秒")
llmcache.store(prompt=question, response=response)
print("已存储在缓存中!")
5、看看效果
启动test.py
并尝试:
- 问“Ollama是什么?”→ LLM回复(几秒钟延迟)。
- 问“定义Ollama?”→ 命中缓存!即时回复。
这就是语义缓存的力量——不需要不必要的LLM调用,只有快速的回答。你可以调整距离阈值参数,以期望的即时回答为准。
使用这种设置,我看到了:
- 重复问题的LLM查询减少了80-90%。
- 响应时间缩短到不到一秒,而不是等待10秒以上。
- 更聪明的聊天机器人,不会卡在重复回答类似问题上。
想要调整吗?
- 调整阈值:我设置
distance_threshold=0.1
,但将其提高到0.2
可能会匹配更多查询(以轻微的不准确为代价)。 - 尝试不同的嵌入模型:Ollama支持多种模型——实验看看哪种最适合。
6、结束语
使用Redis和Ollama的语义缓存是一个改变游戏规则的方案。它使LLMs更快,降低成本,并在实际应用中感觉更流畅。如果你正在处理AI聊天机器人、知识库或任何文本密集型应用,你必须尝试一下。
试一试,调整代码,看看它能多大程度提升你的设置。我很想知道你是如何使用它的!
原文链接:Redis Semantic Caching with Ollama
汇智网翻译整理,转载请标明出处