一文搞定检索增强生成(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%免费】🆓

相关推荐
古希腊掌管学习的神36 分钟前
[机器学习]XGBoost(3)——确定树的结构
人工智能·机器学习
ZHOU_WUYI1 小时前
4.metagpt中的软件公司智能体 (ProjectManager 角色)
人工智能·metagpt
靴子学长2 小时前
基于字节大模型的论文翻译(含免费源码)
人工智能·深度学习·nlp
AI_NEW_COME3 小时前
知识库管理系统可扩展性深度测评
人工智能
海棠AI实验室3 小时前
AI的进阶之路:从机器学习到深度学习的演变(一)
人工智能·深度学习·机器学习
hunteritself3 小时前
AI Weekly『12月16-22日』:OpenAI公布o3,谷歌发布首个推理模型,GitHub Copilot免费版上线!
人工智能·gpt·chatgpt·github·openai·copilot
IT古董4 小时前
【机器学习】机器学习的基本分类-强化学习-策略梯度(Policy Gradient,PG)
人工智能·机器学习·分类
centurysee4 小时前
【最佳实践】Anthropic:Agentic系统实践案例
人工智能
mahuifa4 小时前
混合开发环境---使用编程AI辅助开发Qt
人工智能·vscode·qt·qtcreator·编程ai
四口鲸鱼爱吃盐4 小时前
Pytorch | 从零构建GoogleNet对CIFAR10进行分类
人工智能·pytorch·分类