系列文章
1. AI大语言模型LLM学习-入门篇
2. AI大语言模型LLM学习-Token及流式响应
3. AI大语言模型LLM学习-WebAPI搭建
4.AI大语言模型LLM学习-基于Vue3的AI问答页面
5.AI大语言模型LLM学习-语义检索(RAG前导篇)
前言
大语言模型(LLM)已经取得了显著的成功,尽管它们仍然面临重大的限制,特别是在特定领域或知识密集型任务中,尤其是在处理超出其训练数据或需要当前信息的查询时,常会产生“幻觉”现象。为了克服这些挑战,检索增强生成(RAG)通过从外部知识库检索相关文档并进行语义相似度计算,增强了LLM的功能。通过引用外部知识,RAG有效地减少了生成事实不正确内容的问题。RAG目前是基于LLM系统中最受欢迎的架构,有许多产品基于RAG构建,使RAG成为推动聊天机器人发展和增强LLM在现实世界应用适用性的关键技术。
在本专栏的上一篇《AI大语言模型LLM学习-语义检索(RAG前导篇)》中介绍了语义检索的相关知识及编码实现,这将帮助您更好的理解和掌握RAG技术,还没有看过的去看看吧。
一、RAG理论基础
1.什么是检索增强生成
检索增强生成(RAG)是指对大型语言模型输出进行优化,使其能够在生成响应之前引用训练数据来源之外的权威知识库。大型语言模型(LLM)用海量数据进行训练,使用数十亿个参数为回答问题、翻译语言和完成句子等任务生成原始输出。在 LLM 本就强大的功能基础上,RAG 将其扩展为能访问特定领域或组织的内部知识库,所有这些都无需重新训练模型。这是一种经济高效地改进 LLM 输出的方法,让它在各种情境下都能保持相关性、准确性和实用性。
2.RAG的演进
Lewis 于 2020 年提出的 RAG 概念迅速发展,标志着其研究历程的不同阶段。最初,该研究旨在通过在预训练阶段向语言模型注入额外的知识来增强语言模型。ChatGPT 的推出激发了人们对利用大型模型进行深入上下文理解的兴趣,加速了 RAG 在推理阶段的发展。随着研究人员深入研究大型语言模型 (LLM) 的功能,重点转向增强其可控性和推理技能,以满足不断增长的需求。GPT-4 的出现标志着一个重要的里程碑,它以一种新颖的方法彻底改变了 RAG,将其与微调技术相结合,同时继续完善预训练策略。
下图为RAG研究的时间轴树:
RAG的发展经历了三个主要阶段:原始(Native RAG)、高级(Advanced RAG)和模块化RAG(Modular RAG)
2.1 Naive RAG(原始RAG)
经典的RAG过程,主要包括三个基本步骤:
索引 - 将文档语料库分割成较短的块并通过编码器构建向量索引。
检索 - 根据问题和块之间的相似性检索相关文档片段。
生成 - 将原始问题和检索到的上下文一起输入到LLM中,生成最终答案。
2.2 Advanced RAG(高级RAG)
Naive RAG 在检索、生成和增强方面面临多重挑战。随后提出了高级 RAG 范式,并涉及Pre-Retrieval 和Post-Retrieval中的附加处理。在检索之前,可以使用查询重写、路由和扩展等方法来对齐问题和文档块之间的语义差异。检索后,对检索到的文档语料库进行重排可以避免“Lost in the Middle”现象,或者可以对上下文进行过滤和压缩以缩短窗口长度。
2.3 Modular RAG(模块化RAG)
随着RAG技术的进一步发展和演进,新的突破超越了传统的Naive RAG Retrieval-Generation框架,产生了Modular RAG的概念。结构上更加自由灵活,引入了更多具体的功能模块,比如查询搜索引擎、多种答案的融合等。从技术上讲,它集成了检索与微调、强化学习和其他技术。在流程方面,RAG 模块经过设计和编排,产生了各种 RAG 模式。
Modular RAG 的出现并不是突然的。三种范式之间存在着继承和发展的关系。
3.RAG和语义搜索有什么区别
- 语义搜索可以提高 RAG 结果,适用于想要在其 LLM 应用程序中添加大量外部知识源的组织。现代企业在各种系统中存储大量信息,例如手册、常见问题、研究报告、客户服务指南和人力资源文档存储库等。上下文检索在规模上具有挑战性,因此会降低生成输出质量。
- 语义搜索技术可以扫描包含不同信息的大型数据库,并更准确地检索数据。例如,他们可以回答诸如 “去年在机械维修上花了多少钱?”之类的问题,方法是将问题映射到相关文档并返回特定文本而不是搜索结果。然后,开发人员可以使用该答案为 LLM 提供更多上下文。
- RAG 中的传统或关键字搜索解决方案对知识密集型任务产生的结果有限。开发人员在手动准备数据时还必须处理单词嵌入、文档分块和其他复杂问题。相比之下,语义搜索技术可以完成知识库准备的所有工作,因此开发人员不必这样做。它们还生成语义相关的段落和按相关性排序的标记词,以最大限度地提高 RAG 有效载荷的质量。
二、代码实现(原始RAG)
本章节将结合代码介绍Naive RAG(原始RAG)处理流程,原始文档使用《证券法(2019修订).pdf》,可通过下面的链接进行下载。
注意:本章节的代码部分涉及的文档索引及检索已经在本专栏的《AI大语言模型LLM学习-语义检索(RAG前导篇)》中介绍,本文不再赘述
证券法(2019修订).pdf
下图以中文形式描述了原始RAG处理的核心步骤:
代码如下(以流式webAPI进行提供):
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
from flask import Flask, request
from langchain_openai import ChatOpenAI
from langchain import PromptTemplate
#加载pdf文档
def load_data(data_file):
loader = PyPDFLoader(data_file)
documents = loader.load_and_split()
text_splitter = RecursiveCharacterTextSplitter(separators=["。"], chunk_size=512, chunk_overlap=32)
texts_chunks = text_splitter.split_documents(documents)
return texts_chunks
app = Flask(__name__)
#原始知识文档路径
data_file = "E:\\SoureCode\\AI\\ai-study\\pdf\\证券法(2019修订).pdf"
# 第一步: 将文档语料库分割成较短的块并通过编码器构建向量索引
docs = load_data(data_file)
# embedding模型路径
embed_path = "E:\\SoureCode\\AI\\ai-study\\model\\bge-large-zh-v1.5"
embeddings = HuggingFaceEmbeddings(
model_name=embed_path,
model_kwargs={"device": "cuda"},
encode_kwargs={"normalize_embeddings": True},
)
vectordb = Chroma.from_documents(docs, embeddings)
#创建检索器,让它每次只返回5条最相关的文档
retriever = vectordb.as_retriever(search_kwargs={"k": 5})
def call(query):
# 第二步:根据问题和块之间的相似性检索相关文档片段
docs_out = retriever.get_relevant_documents(query)
print("找到记录数:"+str(len(docs_out)))
# 拼接检索到的内容
context = ""
for doc in docs_out:
context += doc.page_content + "\n\n"
print(context)
# 第三步:将原始问题和检索到的上下文一起输入到LLM中,生成最终答案
# ----------------- 构造提示模板 ----------------- #
template = """你是一名智能助手,根据上下文回答用户的问题,不需要回答额外的信息或捏造事实。
已知内容:
{context}
问题:
{question}
"""
prompt = PromptTemplate(template=template, input_variables=["context", "question"])
api_key = "api_key(平台注册获得)"
model = "qwen2-72b-instruct"
llm = ChatOpenAI(
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key=api_key,
model=model,
streaming=True,
)
# 使用|操作符将prompt_template和llm连接在一起,创建一个chain对象。
chain = prompt | llm
result = chain.stream({"context": docs_out, "question": query})
for token in result:
data = token.content
# web模型的流式输出
yield data
#定义请求路径为/chat,访问方法为post,本方法要求请求格式为json
@app.route('/chat', methods=['post'])
def chat():
data = request.json
# 接收用户输入的问题
question = ""
if (data["question"]):
question = data["question"]
print(question)
return call(question)
if __name__ == "__main__":
# 调用run方法,设定端口号,启动服务
app.run(port=2024, host="0.0.0.0", debug=True)
三、运行效果展示
问题选自文章:证券市场基本法律法规部分(共68个)
引用
1、Retrieval-Augmented Generation for Large Language Models: A Survey
2、百度智能云-RAG技术全解析:打造下一代智能问答系统
3、RAG系列|大模型之RAG扫盲