一文搞定检索增强生成(RAG)的理解和LangChain实现(附详细代码)

最近,周围的人都在讨论如何更有效地利用大型语言模型(LLM)与我们的专有数据之间的桥梁。对于如何实现这一点,有两种主流的思路:微调(Fine-Tuning)和检索增强生成(Retrieval-Augmented Generation,简称RAG)。而事实上,这两种方法都有其独特的优势。

今天,我想和大家聊聊这个被称为RAG的概念。首先,我们来看看它的理论基础。然后,我会展示如何使用LangChain来协调操作、结合OpenAI的语言模型和Weaviate向量数据库来实现一个简单的RAG流程。

【如何理解检索增强生成(RAG)

简单来说,RAG就是让LLM通过外部知识源获取额外信息,从而生成更准确、更符合上下文的答案,并减少错误信息(或称为"幻觉")的产生。

我们都知道,最先进的LLM是通过训练大量数据来获得广泛的通用知识,这些知识被储存在神经网络的权重(参数记忆)中。但是,当我们让LLM生成需要训练数据之外的知识(比如最新的、专有的或特定领域的信息)时,就可能导致事实上的不准确,也就是我们所说的"幻觉"。

因此,让模型适应特定的行业或私有信息就变得非常重要。我们通常会对模型进行微调。这个方法虽然行得通,但它既耗费大量计算资源,又花费不菲,还得需要技术高手来操刀,因此在迅速适应信息更新上就显得有些笨重了。

那么,有没有更加灵活的办法呢?早在2020年,Lewis和他的团队在一篇名为《知识密集型NLP任务的检索增强生成》的论文中给出了答案。他们提出了一种新技术,叫做检索增强生成(RAG)。这个方法的亮点在于,它把一个能生成内容的模型和一个能进行信息检索的模块结合在一起。这样,模型就可以直接从一个容易更新的外部知识源那里获得所需信息了。

对大型语言模型(LLM)来说,检索增强生成(RAG)就像是开卷考试一样。在开卷考试中,学生可以携带参考资料,比如教科书或笔记,用它们来查找回答问题所需的相关信息。开卷考试的理念在于,考试重点在于考察学生的推理能力,而不是记忆特定信息的能力。

类似地,在RAG中,事实知识从LLM的推理能力中分离出来,存储在一个容易访问和更新的外部知识源中:

  • 参数化知识:在训练期间学习,隐式地存储在神经网络的权重中。

  • 非参数化知识:存储在外部知识源中,比如向量数据库。

检索增强生成(RAG)的基本工作流程如下:

  1. 检索:使用用户的查询来从外部知识源检索相关上下文。为此,需要用嵌入模型将用户查询嵌入到与向量数据库中额外上下文相同的向量空间。这样就可以进行相似性搜索,从向量数据库中返回最接近的前k个数据对象。

  2. 增强:将用户查询和检索到的额外上下文放入一个提示模板中。

  3. 生成:最后,将增强后的提示输入到大型语言模型(LLM)中进行生成。

这个流程就像是让LLM在处理查询时,先去查阅一下外部的"参考资料",然后再基于这些信息给出回答。这样的做法让LLM在回答问题时更加准确和丰富,因为它不仅仅依赖于训练时学到的知识,还可以利用最新的、来自外部的信息。

【基于Langchain实现】

要实现检索增强生成(RAG)流程,我们可以使用LangChain来协调整个过程,结合OpenAI的大型语言模型(LLM)、Weaviate向量数据库和OpenAI嵌入模型。以下是实现此流程所需的准备工作和具体步骤:

准备工作------Python环境配置

python 复制代码
pip install langchain openai weaviate-client
  • langchain:用于协调整个流程。

  • openai:提供嵌入模型和LLM。

  • weaviate-client:用于操作Weaviate向量数据库。

此外,在根目录的 .env 文件中定义相关的环境变量。要获取 OpenAI API 密钥,我们需要一个 OpenAI 的API 密钥(没有的小伙伴可以关注公众号并私信我免费领取)。

python 复制代码
OPENAI_API_KEY="<YOUR_OPENAI_API_KEY>"

然后,运行以下命令以加载相关的环境变量。

python 复制代码
import dotenv``dotenv.load_dotenv()

准备工作------数据加载及处理

除了Python环境,我们还需要准备一个向量数据库作为包含所有其他信息的外部知识源。首先是收集和加载数据,可以使用LangChain的众多内置 DocumentLoader 之一,比如 TextLoader 。

python 复制代码
import requests
from langchain.document_loaders import TextLoader

with open("xxxxx.txt", "w") as f:
    f.write(res.text)

loader = TextLoader('./xxxxx.txt')
documents = loader.load()

接下来,由于文档可能太长,需要进行分块,否则无法加载入 LLM 的上下文窗口,LangChain提供了许多内置的文本分割工具来帮助完成这个任务。示例如下,我们可以使用CharacterTextSplitter来分割文本,设置chunk_size大约为500,chunk_overlap为50,这样可以确保文本在各个块之间的连贯性。

python 复制代码
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = text_splitter.split_documents(documents)

最后一步是嵌入和存储这些小块。为了实现跨文本块的语义搜索,我们需要为每个块生成向量嵌入,然后将它们连同嵌入一起存储。生成向量嵌入时,我们可以使用OpenAI的嵌入模型;存储它们时,可以使用Weaviate向量数据库。通过调用.from_documents(),向量数据库会自动填充这些文本块。

python 复制代码
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Weaviate
import weaviate
from weaviate.embedded import EmbeddedOptions

client = weaviate.Client(
  embedded_options = EmbeddedOptions()
)

vectorstore = Weaviate.from_documents(
    client = client,    
    documents = chunks,
    embedding = OpenAIEmbeddings(),
    by_text = False
)

步骤1------检索

填充向量数据库后,可以将其定义为检索器组件,该组件根据用户查询和嵌入块之间的语义相似性,在Weaviate数据库中进行相似性搜索,找到最相关的内容。

python 复制代码
retriever = vectorstore.as_retriever()

步骤2------增强

接下来,将检索到的内容与用户查询结合,形成一个新的提示,需要准备一个提示模板。可以从提示模板轻松自定义提示,如下所示。

python 复制代码
from langchain.prompts import ChatPromptTemplate

template = """You are an assistant for question-answering tasks. 
Use the following pieces of retrieved context to answer the question. 
If you don't know the answer, just say that you don't know. 
Use three sentences maximum and keep the answer concise.
Question: {question} 
Context: {context} 
Answer:
"""
prompt = ChatPromptTemplate.from_template(template)

print(prompt)

步骤3------生成

最后,我们可以将这个增强后的提示输入到OpenAI的LLM中,生成最终的回答。

python 复制代码
from langchain.chat_models import ChatOpenAI
from langchain.schema.runnable import RunnablePassthrough
from langchain.schema.output_parser import StrOutputParser

llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

rag_chain = (
    {"context": retriever,  "question": RunnablePassthrough()} 
    | prompt 
    | llm
    | StrOutputParser() 
)

query = "What did the president say about the business? "
rag_chain.invoke(query)

这样我们就构建了一个高效且定制化的RAG系统,可以根据具体需求进行调整,例如改变嵌入模型、调整检索策略或者优化生成的提示模板,适用各种复杂的查询和任务。

你学会(废)了吗?

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

自己也整理很多AI大模型资料:AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

👉学会后的收获:👈

• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:

😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

相关推荐
CV学术叫叫兽4 分钟前
快速图像识别:落叶植物叶片分类
人工智能·分类·数据挖掘
WeeJot嵌入式30 分钟前
卷积神经网络:深度学习中的图像识别利器
人工智能
脆皮泡泡40 分钟前
Ultiverse 和web3新玩法?AI和GameFi的结合是怎样
人工智能·web3
机器人虎哥43 分钟前
【8210A-TX2】Ubuntu18.04 + ROS_ Melodic + TM-16多线激光 雷达评测
人工智能·机器学习
码银1 小时前
冲破AI 浪潮冲击下的 迷茫与焦虑
人工智能
用户37791362947551 小时前
【循环神经网络】只会Python,也能让AI写出周杰伦风格的歌词
人工智能·算法
敲上瘾1 小时前
操作系统的理解
linux·运维·服务器·c++·大模型·操作系统·aigc
何大春1 小时前
【弱监督语义分割】Self-supervised Image-specific Prototype Exploration for WSSS 论文阅读
论文阅读·人工智能·python·深度学习·论文笔记·原型模式
uncle_ll1 小时前
PyTorch图像预处理:计算均值和方差以实现标准化
图像处理·人工智能·pytorch·均值算法·标准化
宋138102797201 小时前
Manus Xsens Metagloves虚拟现实手套
人工智能·机器人·vr·动作捕捉