照片由 Indira Tjokorda 在 Unsplash 提供
看看如何利用大模型缓存显著提升AI性能并最多减少80%的响应时间!在这份全面的指南中,我们将深入了解大型语言模型的缓存技术(LLM缓存技术),这项颠覆性的技术正在彻底改变AI的性能。
你将了解什么是大模型缓存,为什么它对现代AI系统如此重要,以及如何有效地实现它。我们将研究不同的缓存策略,比较AI代理与RAG架构中的缓存方式,并提供实用的示例,使用常用的库如LangChain和GPTCache。通过本文,你将学到如何加快AI系统的速度、减少成本并提升用户体验的知识。
什么是缓存呢?缓存是一种在计算中使用的技术,用于将频繁访问的数据或计算存储在更快且更易访问的位置。这使得信息检索更快,减少了重复执行相同操作或获取相同数据的需求。本质上,缓存就像一种短期记忆功能,有助于提升系统的性能和效率。
缓存的好处有哪些“把常用的东西放得近一些”
- 更快的响应时间:缓存的数据可以比重新计算或从原始来源获取快得多,尤其是在LLM系统中。
- 减轻服务器压力:通过从缓存中提供频繁请求的数据,主服务器的压力会减轻。
- 节省带宽:缓存可以显著减少网络上传输的数据量。
- 改善用户体验:更快的响应时间带来更流畅的体验和更高的用户满意度。
- 成本效益:通过减少计算和网络资源的使用,缓存可以降低运营费用。
从架构的角度来看,LLM系统中的缓存与传统的软件缓存有相似之处:
两者都通过存储频繁访问的数据来提升性能。
他们使用了类似的时间和空间局部性的原理。
在这两种情况下,缓存过期和更新策略都至关重要。
不过,LLM缓存通常处理更复杂、与上下文相关的数据,可能需要更复杂的缓存策略。
- 关键词缓存:虽然简单,但灵活性较差,这种方法是基于输入查询的精确匹配来缓存响应。
- 语义缓存:更高级的方法,根据查询的意义缓存响应,即使措辞略有不同也能匹配。
请看以下查询。
- 法国的首都是哪里?
- 告诉我法国的首都是哪?
为了实现关键词的缓存,首先,我们将对查询进行分词处理。
- 法国的首都叫什么呢
2. [告诉我一下,法国的首都 是 巴黎]
然后去掉停用词,进行词干提取或词形还原以规范化这些标记:
- 法国的首都是巴黎
- 法国的首都是巴黎
现在我们可以用这些标准化的词来生成缓存键。
语义缓存使用像句子嵌入技术(比如S-BERT)这样的方法将查询语句转化为向量。
计算这些向量表示法之间的相似度。
如果相似度超过阈值,则认为查询是相似的,并使用相同的缓存键。
AI代理中的缓存机制与检索增强生成架构的区别- AI 代理:AI 代理的缓存可能更侧重于存储中间推理步骤或常用决策路径,使表达更加准确。这能让代理在类似情形中更快地做出决策。
- 检索增强生成(RAG)架构:在 RAG 系统中,缓存可能会优先存储经常检索的文档或段落或片段,与查询频繁相关的部分,从而减少从知识库中重复检索的需求。
我们现在来看看使用LangChain库进行缓存的代码,以及GPTCache包的缓存示例。
一个用 LangChain 的缓存许多流行框架,例如 LangChain、llama_index 和 llama.cpp,都支持某种形式的原生缓存。
Langchian支持多种流行的缓存集成方式,包括Redis、Elasticsearch、(点击这里查看GPTCache:GPTCache)等。完整指南请参阅这里。
在以下示例中,我们将使用 SQLite 数据库来存储缓存键,Milvus 向量存储来存储嵌入向量,我们的嵌入模型将使用 OpenAI 的嵌入 API。我们将通过 LangChain 使用来自 OpenAI 的模型,整个缓存工作流程将由 GPTCache 来管理,
先导入所需的库
# 导入gptcache缓存库
from gptcache import cache
# 导入gptcache的嵌入Onnx模型
from gptcache.embedding import Onnx
# 导入gptcache的管理器
from gptcache.manager import CacheBase, VectorBase, get_data_manager
# 导入基于距离的相似度评估器
from gptcache.similarity_evaluation.distance import SearchDistanceEvaluation
# 导入gptcache适配器中的LangChainLLMs模型
from gptcache.adapter.langchain_models import LangChainLLMs # LangChainLLMs用于适配LangChain中的模型
# 导入LangChain的文档加载器
from langchain.document_loaders import TextLoader
# 导入LangChain的文本分割器
from langchain.text_splitter import CharacterTextSplitter
# 导入LangChain的向量存储Milvus
from langchain.vectorstores import Milvus
# 导入OpenAI的嵌入模型
from langchain.embeddings.openai import OpenAIEmbeddings
# 导入LangChain中的问答链
from langchain.chains.question_answering import load_qa_chain
# 导入OpenAI的语言模型
from langchain.llms import OpenAI
# 导入openai库
import openai
启动 Milvus 的单机服务器。参照 此处的 Milvus 页面 中提供的 Docker Compose 指令。
然后,初始化好 sqlite 数据库和 Milvus 向量客户端。您还可以配置其他向量存储库,VectorBase API。
onnx = Onnx()
cache_base = CacheBase('sqlite')
vector_base = VectorBase(
'milvus',
host='192.168.1.6',
port='19530',
dimension=onnx.dimension,
collection_name='chatbot'
)
data_manager = get_data_manager(cache_base, vector_base)
cache.init(
pre_embedding_func=get_content_func,
embedding_func=onnx.to_embeddings,
data_manager=data_manager,
similarity_evaluation=SearchDistanceEvaluation(),
)
openai.api_key="YOUR OPENAI KEY"
cache.set_openai_key()
然后我们将准备数据。您可能需要使用更复杂的预处理步骤,因为您的工作流程可能需要更复杂的预处理。
loader = TextLoader('./f1-wikipedia.txt') # 加载器加载文件
documents = loader.load() # 加载文档
text_splitter = CharacterTextSplitter(字符分割器(chunk_size=1000, chunk_overlap=0)) # 设置分割参数
docs = text_splitter.split_documents(documents) # 分割文档
embeddings = OpenAIEmbeddings() # 使用OpenAI的嵌入模型
注释:CharacterTextSplitter
是一个字符级别的文本分割器,chunk_size
表示每个分割块的大小,chunk_overlap
表示每个块之间的重叠字符数,这里设为0,表示没有重叠。OpenAIEmbeddings
表示使用OpenAI提供的嵌入模型进行文本向量化。
例如,我们在这个向量数据库中搜索相似性,但这些文档可以用任何方法获取。
vector_db = Milvus.from_documents(
docs,
embeddings,
connection_args={"host": "192.168.1.6", "port": "19530"},
)
query = "谁拿过最多的冠军?"
docs = vector_db.similarity_search(query)
调用一下 run
接口。
llm = LangChainLLMs(llm=OpenAI(temperature=0))
chain = load_qa_chain(llm, chain_type="链类型")
query = "谁赢得的冠军最多?"
chain.run(input_documents=docs, question=query)
运行相同的或类似的查询时,第一次运行后你会看到性能会有显著提升。在第一次,系统会首次缓存未命中并准备缓存。再次运行时,系统将命中缓存。
使用GPT缓存在下面的例子中,缓存时间会更容易被注意到。
咱们先来启动一下OpenAI的客户端,不用缓存的时候测一下响应速度怎么样。
import time
import os
from openai import OpenAI
import openai
os.environ["OPENAI_API_KEY"] = "YOUR OPENAI KEY"
client = OpenAI(
# 注:默认使用环境变量中的 'OPENAI_API_KEY'
)
def response_text(openai_resp):
return openai_resp.choices[0].message.content
question = '什么是 GitHub'
# 原始的 OpenAI API 用法
start_time = time.time()
chat_completion = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": question}]
)
print(f'问题:\'{question}\'')
print(f"耗时:{time.time() - start_time:.2f} 秒")
print(f'回答:\'{response_text(chat_completion)}\'\n')
使用OpenAI的 GPT-4o-mini 模型,我的平均响应时间大约为2.9秒。
GPT-4o-mini 一次查询的响应时长,未使用缓存
现在我们将使用GPTCache功能,并在Github上提出4个类似的问题,以观察第一个问题之后的其他问题回答时间。
加载必要的函数:
import time
from gptcache import cache
from gptcache.adapter import openai
from gptcache.embedding import Onnx
from gptcache.manager import CacheBase, VectorBase, get_data_manager
from gptcache.similarity_evaluation.distance import SearchDistanceEvaluation
初始化缓存层。这次我们将使用sqlite数据库来存储缓存键,并采用FAISS的内存向量存储。您还可以配置其他的向量存储选项,参见VectorBase API。
onnx = Onnx()
data_manager = get_data_manager(CacheBase("sqlite"), VectorBase("faiss", dimension=onnx.dimension))
cache.init(
embedding_func=onnx.to_embeddings,
data_manager=data_manager,
similarity_evaluation=SearchDistanceEvaluation(),
)
openai.api_key = "请替换为您的OpenAI密钥" # Please replace with your OpenAI key
cache.set_openai_key()
调用 ChatCompletion
API 来处理 4 个类似的问题。
def response_text(openai_resp):
return openai_resp['choices'][0]['message']['content']
questions = [
"什么是GitHub",
"你能解释一下GitHub是什么吗",
"你能多说一些关于GitHub的事情吗",
"GitHub的目的是什么"
]
for question in questions:
start_time = time.time()
response = openai.ChatCompletion.create(
model='gpt-4o-mini',
messages=[
{
'role': 'user',
'content': question
}
],
)
print(f'问题: {question}')
print("耗时: {:.2f}秒".format(time.time() - start_time))
print(f'回复: {response_text(response)}\n')
首个查询“什么是GitHub”的响应时长 = 4.48s
第一次查询的响应时间
第二次请求“你能解释什么是GitHub吗” 的响应时间为 5.89 秒
第二次查询的回复时间是
第三和第四条查询分别是“你能告诉我更多关于GitHub的事吗”和“GitHub是用来做什么的”,它们的响应时间分别为0.93秒及1.14秒。
第三个和第四个查询的响应时间
你也可以看看 sqlite 数据库里面存了哪些信息,用来管理缓存。
遇到的大模型缓存方面的挑战- 缓存一致性:确保缓存的数据与底层大规模语言模型保持一致,即使其不断更新。
- 上下文敏感性:大语言模型的输出高度依赖于上下文,这使得判断缓存响应是否适用变得困难。
- 缓存大小管理:在保证缓存有用性的同时,避免过度占用系统资源。
- 隐私问题:确保敏感或个人信息不会不小心存储在缓存中。
- 自适应缓存:开发策略以根据查询和响应模式的变化动态调整缓存。
— 定期检查缓存:持续监控和分析缓存性能以优化方法。
— 混合方法:结合不同类型的缓存技术(例如,关键词和语义)以达到最佳效果。
在实现缓存时,特别关注数据隐私,确保对存储的数据的使用合乎伦理。
你可以在LinkedIn上通过这个链接联系我:https://linkedin.com/in/maheshrajput
快乐学吧!😃
共同学习,写下你的评论
评论加载中...
作者其他优质文章