为了账号安全,请及时绑定邮箱和手机立即绑定

大型语言模型缓存:你可能忽视的制胜法宝

照片由 Indira TjokordaUnsplash 提供

看看如何利用大模型缓存显著提升AI性能并最多减少80%的响应时间!

在这份全面的指南中,我们将深入了解大型语言模型的缓存技术(LLM缓存技术),这项颠覆性的技术正在彻底改变AI的性能。

你将了解什么是大模型缓存,为什么它对现代AI系统如此重要,以及如何有效地实现它。我们将研究不同的缓存策略,比较AI代理与RAG架构中的缓存方式,并提供实用的示例,使用常用的库如LangChain和GPTCache。通过本文,你将学到如何加快AI系统的速度、减少成本并提升用户体验的知识。

什么是缓存呢?

缓存是一种在计算中使用的技术,用于将频繁访问的数据或计算存储在更快且更易访问的位置。这使得信息检索更快,减少了重复执行相同操作或获取相同数据的需求。本质上,缓存就像一种短期记忆功能,有助于提升系统的性能和效率。

“把常用的东西放得近一些”

缓存的好处有哪些
  • 更快的响应时间:缓存的数据可以比重新计算或从原始来源获取快得多,尤其是在LLM系统中。
  • 减轻服务器压力:通过从缓存中提供频繁请求的数据,主服务器的压力会减轻。
  • 节省带宽:缓存可以显著减少网络上传输的数据量。
  • 改善用户体验:更快的响应时间带来更流畅的体验和更高的用户满意度。
  • 成本效益:通过减少计算和网络资源的使用,缓存可以降低运营费用。
大型语言模型缓存

从架构的角度来看,LLM系统中的缓存与传统的软件缓存有相似之处:

两者都通过存储频繁访问的数据来提升性能。

他们使用了类似的时间和空间局部性的原理。

在这两种情况下,缓存过期和更新策略都至关重要。

不过,LLM缓存通常处理更复杂、与上下文相关的数据,可能需要更复杂的缓存策略。

  • 关键词缓存:虽然简单,但灵活性较差,这种方法是基于输入查询的精确匹配来缓存响应。
  • 语义缓存:更高级的方法,根据查询的意义缓存响应,即使措辞略有不同也能匹配。
关键词缓存技术

请看以下查询。

  1. 法国的首都是哪里?
  2. 告诉我法国的首都是哪?

为了实现关键词的缓存,首先,我们将对查询进行分词处理。

  1. 法国的首都叫什么呢

2. [告诉我一下,法国的首都 是 巴黎]

然后去掉停用词,进行词干提取或词形还原以规范化这些标记:

  1. 法国的首都是巴黎
  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 数据库里面存了哪些信息,用来管理缓存。

遇到的大模型缓存方面的挑战
  • 缓存一致性:确保缓存的数据与底层大规模语言模型保持一致,即使其不断更新。
  • 上下文敏感性:大语言模型的输出高度依赖于上下文,这使得判断缓存响应是否适用变得困难。
  • 缓存大小管理:在保证缓存有用性的同时,避免过度占用系统资源。
  • 隐私问题:确保敏感或个人信息不会不小心存储在缓存中。
  • 自适应缓存:开发策略以根据查询和响应模式的变化动态调整缓存。
实现LLM缓存的一些最佳实践

— 定期检查缓存:持续监控和分析缓存性能以优化方法。

— 混合方法:结合不同类型的缓存技术(例如,关键词和语义)以达到最佳效果。

在实现缓存时,特别关注数据隐私,确保对存储的数据的使用合乎伦理。

你可以在LinkedIn上通过这个链接联系我:https://linkedin.com/in/maheshrajput

快乐学吧!😃

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消