经过检索增强生成(RAG) 增强LLM的实战演练
译文 作者: 李睿 本文关键引见如何经过检索增强生成(RAG)增强LLM,并经常使用LlamaIndex和LangChain作为数据场景,将运行程序部署到Heroku。想了解更多AIGC的内容,请访问:
AI.x社区
领有正确的数据来支持用例关于在任何业务中成功驳回大型言语模型(LLM)都是至关关键的。只管大少数现成的LLM在成功普通义务上体现杰出,但它们在处置特定的业务疑问时或许会遇到艰巨。它们没有针对开发人员的业务疑问启动数据训练,因此没有足够的场景来处置疑问。
企业通常领有少量的外部数据和文档,可以满足特定场景的需求。然而有一个疑问:如何将一切这些有用的数据(场景)集成到LLM中,而不须要启动资源密集型和耗时的再培训或微调LLM?
其答案是检索增强生成(RAG),这是一种经过实时检索严密场景消息来增强LLM的技术。
本文将引见如何经常使用LlamaIndex和LangChain来成功LLM场景数据的存储和检索。将经过经常使用LlamaIndex处置一个特定于场景的RAG疑问,而后将处置方案轻松地部署到Heroku。
在开局编码之前,首先简明引见一下**概念。
RAG和LlamaIndex简介
当向LLM提出一个须要场景来回答的疑问时,RAG会检索场景数据协助LLM给出更准确、更详细的回答。这就像让厨师迅速返回农贸市场去洽购贮藏室没有的最新颖的食材一样,这样厨师长就可以驳回一切必要的食材烹制出完美的菜肴。
RAG上班流如何提供场景的一个关键是经常使用矢量数据库和矢量搜查索引。以下了解一些**概念以及成功这一切所蕴含的内容。
在RAG场景中,经常使用原始揭示符对矢量数据库中的一切文档口头矢量搜查。而后,将这些婚配的文档作为场景发送到LLM运行程序。LLM如今有一组详细的注释,在对原始揭示启动回答时可以参考。
LlamaIndex是一个关键的框架,它简化了集成、组织和检索私有或公用数据的环节。它将协助开发人员创立文档嵌入和矢量搜查索引。而后,将依托LangChain将其拼凑在一同,口头相似性搜查并将结果发送到LLM以失掉照应。LlamaIndex和LangChain独特为处置RAG上班流提供了一个安保牢靠的处置方案。
预备好做些什么了吗?如今开局吧!
演示名目简介
经常使用LlamaIndex和Heroku学习RAG的最好方法是构建一个小型的示例运行程序。出于开发人员的目的,假定正在与“古登堡方案”(Project Gutenberg)协作,这是一个领有70000多本收费电子书的图书馆。假构想要构建一个基于LLM的聊天机器人,它可以回答关于名目中收费书籍的特定疑问。
这是经常使用RAG的完美用例,可以经常使用LlamaIndex取得的少量书籍文本。为了使名目便捷,将经常使用公元401年问世的《圣奥古斯丁的忏悔录》书中的内容。
成功的名目代码库可以在这个GitHub存储库(中找到。假设情愿的话,可以克隆repo并将运行程序部署到Heroku。或许,可以逐渐了解如何取得代码。
构建这个演示名目将遵照以下一些步骤:
步骤1:设置名目
为Python名目创立一个新文件夹,而后激活venv并装置须要的初始依赖项。
Shell1 (venv) ~/project$ pip install llama-index langchain langchain-openai
接上去,将加载要索引的数据。
步骤2:加载数据
在构建用于RAG的外部数据索引时,必需将一切数据(文本)搜集到一个中央。在这个例子中,该名目驳回了《圣奥古斯丁的忏悔录》的文本。将经常使用LlamaIndex将这个场景转换为嵌入的矢量索引。
在典型的用例中,其场景数据将是适宜试图处置的业务疑问的大型文本语料库。
关于这个小型演示名目,将创立一个名为data的子文件夹,而后将该书作为单个文件下载到该文件夹中。
Shell1(venv) ~/project$ mkdir>
步骤3:构建索引
在一个目录中搜集了一切数据之后,就可以构建索引了。将编写一个便捷的Python运行程序,它将经常使用LlamaIndex为数据建设索引,而后查问索引。
为此,须要一个OpenAI帐户和API密钥。这是由于LlamaIndex经常使用OpenAI的text-embedding-3-small作为自动嵌入模型 (更改这些自动值超出了本文的讨论范围) 。
在这个名目的根文件夹中,创立了一个名为index.py的文件。初始内容如下所示:
Python1 # index.py23 from llama_index.core import VectorStoreIndex, SimpleDirectoryReader4 import os56 if os.environ.get('OPENAI_API_KEY') is None:7exit('You must provide an OPENAI_API_KEY env var.')89 documents = SimpleDirectoryReader("data").load_data()10 index = VectorStoreIndex.from_documents(documents)1112 query_engine = index.as_query_engine()13 response = query_engine.query("In which city is Saint Augustine the Bishop?")14 print(response)
运转文件并收到预期的照应:
Shell1 (venv) ~/project$ OPENAI_API_KEY=sk-******** python index.py2 Hippo
当然,可以再次审核数据。看看这本书的前几行,可以看到:
Shell1 THE CONFESSIONS OF SAINT AUGUSTINE23 By Saint Augustine45 Bishop of Hippo
正如人们所看到的,LlamaIndex成功了它的上班。Python运行程序完全依照开发人员对向量索引数据的希冀回答了疑问。
步骤4:存储索引
须要留意的是,在上方的示例中,只将索引数据存储在内存中,而不是磁盘上。索引(如今是内存中的一系列向量嵌入)将在调用OpenAI模型并成功上班流后完全失落。
为文本创立向量索引(嵌入)不是收费的,所以不想每次调用模型时都从新计算这些结果。最好有一个独自的上班流将索引耐久化到磁盘。而后,可以在任何时刻援用它。
一种经常出现的方法是将嵌入存储在PostgreSQL数据库中,并经常使用pgvector口头相似性搜查。为了使演示便捷,只将索引数据存储为平面文件。
因此,将这个便捷的步骤增加到index.py文件中:
Python1 PERSIST_DIR='./my_vector_indexes/gutenberg/'2 index.storage_context.persist(persist_dir=PERSIST_DIR)
如今,在运转文件之后,可以审核存储的索引。
Shell1 (venv) ~/project$ OPENAI_API_KEY=sk-******** python index.py2 Hippo34 (venv) ~/project$ tree5 .6├──>
步骤5:整合LangChain
曾经了解矢量索引存储的基础常识,以及构建一个矢量索引存储是如许容易。然而,为了真正构建一个将一切内容链接在一同的端到端运行程序,可以经常使用LangChain。这样,就可以将处置方案部署为API。可以重写index.py代码,使其更适宜消费环境。
以下将展现代码,而后解释接上去要做的事件。它或许看起来像很多代码,但只增加了一些新步骤。
Python1 # index.py23 import os4 from langchain_openai import ChatOpenAI5 from langchain.chains import ConversationalRetrievalChain6 from langchain.memory import ConversationBufferWindowMemory7 from llama_index.core import VectorStoreIndex, SimpleDirectoryReader8 from langchain_community.retrievers import LlamaIndexRetriever9 from fastapi import FastAPI10 from pydantic import BaseModel1112 if os.environ.get('OPENAI_API_KEY') is None:13exit('You must provide an OPENAI_API_KEY env var.')1415 documents = SimpleDirectoryReader("data").load_data()16 index = VectorStoreIndex.from_documents(documents)1718 # For this demo, we will not persist the index.192021 retriever = LlamaIndexRetriever(index=index.as_query_engine())2223 llm = ChatOpenAI(model_name="gpt-3.5-turbo", max_tokens=2048)2425 memory = ConversationBufferWindowMemory(26memory_key='chat_history',27return_messages=True,28k=329 )3031 conversation = ConversationalRetrievalChain.from_llm(32llm=llm,33retriever=retriever,34memory=memory,35max_tokens_limit=153636 )3738 class Prompt(BaseModel):39question: str4041 app = FastAPI()4243 @app.post("/prompt")44 async def query_chatbot(prompt: Prompt):45response = conversation.invoke({'question': prompt.question})46return response['answer']4748 if __name__=='__main__':49import uvicorn50uvicorn.run(app, host="localhost", port=8000)
首先,要留意的是,如今间接经常使用了LangChain和OpenAI。将LLM与一些内存一同设置,以便在后续查问中“记住”对话。如今有一个真正的聊天机器人,可以与之互动。
从这里,经常使用FastAPI创立一个API主机,该主机监听/prompt端点上的POST恳求。对该端点的恳求估量具有带有疑问的恳求体,而后将其(连同来自向量索引的场景)传递给LLM。
经常使用uvicorn在端口8000上启动主机。
在启动主机之前,增加这些新的Python依赖项:
Shell1(venv) ~/project$ pip install fastapi pydantic uvicorn
如今是测试的时刻了。首先启动主机。
Shell1 (venv) ~/project$ OPENAI_API_KEY=sk-******** python index.py2INFO:Started server process [1101807]3 INFO:Waiting for application startup.4 INFO:Application startup complete.5 INFO:Uvicorn running on(Press CTRL+C to quit)
在另一个终端中,向端点发送一个curl恳求。
Shell1 $ curl -X POST \2--header "Content-type:application/json" \3--data '{"question":"Who is Ambrose?"}' \4"Ambrose is a person mentioned in the text provided. He is described as a respected8 and celibate man who was esteemed by the author. Ambrose is depicted as a figure of9 great honor and excellence, particularly known for his dedication to reading and10 studying."11
取得成功!向量索引仿佛曾经启动并运转,这个聊天机器人配置完全,是部署的时刻了。
步骤6:部署到Heroku
在成功了关键的上班之后,只有要采取几个便捷的步骤将运行程序部署到Heroku。
(1)用Python依赖项创立requirements.txt文件
Heroku须要知道在构建名目时要装置哪些Python依赖项。它在一个名为requirements.txt的文件中查找这个列表。可以用上方的命令轻松地生成:
Shell1(venv) ~/project$ pip freeze > requirements.txt
(2)创立Procfile
还须要通知Heroku如何启动Python运行程序。在一个名为Procfile的文件中口头这一操作。
Shell1 (venv) ~/project$ echo \2'web: uvicorn index:app --host=0.0.0.0 --port=${PORT}' > Procfile
(3)创立runtime.txt文件
最后,runtime.txt将通知Heroku宿愿经常使用哪种Python运转时版本。
Shell1 (venv) ~/project$ echo 'python-3.11.8' > runtime.txt
这些都是须要的文件。这时名目文件夹结构应该看起来像(曾经删除了耐久化的矢量索引):
Shell1 ~/project$ tree2 .3├──>
假设开发人员是从头开局上班,并且没有为这个演示名目克隆GitHub仓库,那么将这些文件提交到自己的Git存储库。
(4)创立Heroku运行程序
下载并装置Heroku CLI后,口头如下命令。开发人员可以为其运行程序选用任何名字,须要提供惟一的OpenAI API密钥。
Shell1 ~/project$ heroku login23 ~/project$ heroku apps:create my-llamaindex-app45 ~/project$ heroku git:remote -a my-llamaindex-app67 ~/project$ heroku config:add OPENAI_API_KEY=replaceme -a my-llamaindex-app89 ~/project$ git push heroku main10 …11 remote: -----> Building on the Heroku-22 stack12 remote: -----> Determining which buildpack to use for this app13 remote: -----> Python app detected14 remote: -----> Using Python version specified in runtime.txt15 …16 remote: -----> Launching...17 remote:Released v418 remote:deployed to Heroku19
部署运行程序后,经过向API主机发送curl恳求启动测试:
Shell1 $ curl -X POST \2--header "Content-type:application/json" \3--data '{"question":"Who is Ambrose?"}' \4"Ambrose is a significant figure in the text provided. He is being described as a7 respected and happy man, known for his celibacy and his dedication to reading and8 studying. He is referred to as a holy oracle and a person of great influence and9 wisdom."10
须要记住的是,上方的curl调用在部署中经常使用了惟一的Heroku运行URL。
如今曾经在Heroku上运转了!
论断
如今曾经清楚地了解了LlamaIndex的弱小配置,以及它在构建RAG运行程序与LLM交互时所表演的关键角色。当可以很容易地增加特定的数据源作为LLM的场景,而不需驳回老本低廉的模型再训练时,这是一个渺小的胜利。而关于宿愿进一步推动LLM上班流程的公司和开发人员来说,这也是一个胜利。
将LlamaIndex与其余LangChain工具集联合起来也是无缝且间接的,构建聊天机器人只有要几行额外的代码。最后,能够极速轻松地将处置方案部署到Heroku,使运行程序可以立刻访问,而不会有任何费事。像这样的便捷部署使开发人员能够专一于构建基于LLM的处置方案这一更复杂、更关键的义务。
原文题目:How To Implement RAG: A Simple Walkthrough,作者:Alvin Lee
链接:。
想了解更多AIGC的内容,请访问:
AI.x社区