《AI Agent智能应用从0到1定制开发》学习笔记:使用RAG技术增强大模型能力,实现与各种文档的对话

思维导图

在这里插入图片描述

📚 引言

大型语言模型(如ChatGPT)虽然功能强大,但它们存在一些明显的局限性。这些模型的知识库更新较慢,无法实时学习最新内容,而且对私有数据或特定领域的专业知识了解有限。例如,ChatGPT的知识截止到特定时间点,无法感知用户本地电脑或内网中的数据。这就是为什么当我们询问非常具体或专业的内容时,它的回答可能显得泛泛而谈。

那么,如何让大模型变得更"聪明",能够获取最新知识并回答更专业的问题呢?这就是本文要介绍的RAG(检索增强生成)技术。

🔍 RAG技术概述

什么是RAG?

RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合检索和生成两种技术的方法,旨在帮助计算机更好地理解和回答问题。简单来说,它让AI模型能够在回答问题前先"查阅资料",从而提供更准确、更专业的回答。

RAG的基本流程

在这里插入图片描述

RAG技术的典型流程包括:

  1. 加载数据(Loader):从各种来源加载文档数据
  2. 处理文档(Transform):对文档进行切割、整理等处理
  3. 向量化(Embedding):将文本转换为向量表示
  4. 存储(Store):将向量数据存储在向量数据库中
  5. 检索(Retrieve):根据问题检索相关文档片段
  6. 生成回答(Generate):基于检索结果生成答案

🔧 LangChain中的RAG实现

Loader:让大模型具备实时学习的能力

LangChain包装了各种Loader,使大模型能够加载各种格式的文档:

  • CSV Loader:加载表格数据
  • Directory Loader:加载整个目录的文件
  • HTML Loader:加载网页内容
  • JSON Loader:加载JSON格式数据
  • Markdown Loader:加载Markdown文档
  • PDF Loader:加载PDF文件

除此之外,LangChain还支持超过100种不同的数据源接口,包括B站、YouTube、GitHub等平台的数据。

# 加载Markdown文件示例
from langchain.document_loaders import UnstructuredMarkdownLoaderloader = UnstructuredMarkdownLoader("path/to/file.md")
data = loader.load()# 加载CSV文件示例
from langchain.document_loaders import CSVLoaderloader = CSVLoader("path/to/file.csv")
data = loader.load()# 加载目录中的文件
from langchain.document_loaders import DirectoryLoaderloader = DirectoryLoader("path/to/directory", glob="**/*.pdf")
data = loader.load()

文档转换:切割、总结和翻译

加载文档后,通常需要对其进行处理,以便更好地利用文档内容:

文档切割

文档切割的目的是:

  1. 降低成本,适应大模型的上下文窗口限制
  2. 将文档转换为结构化数据,便于查询

LangChain提供了多种切割器:

# 字符串分割
from langchain.text_splitter import CharacterTextSplittertext_splitter = CharacterTextSplitter(separator="\n\n",chunk_size=1000,chunk_overlap=200,length_function=len
)
docs = text_splitter.split_documents(documents)# 按代码分割
from langchain.text_splitter import RecursiveCharacterTextSplitterpython_splitter = RecursiveCharacterTextSplitter.from_language(language="python",chunk_size=1000,chunk_overlap=200
)
文档总结、精炼和翻译

LangChain还提供了文档总结、精炼和翻译的功能:

# 文档总结
from langchain.chains.summarize import load_summarize_chain
from langchain_openai import ChatOpenAIllm = ChatOpenAI(temperature=0)
chain = load_summarize_chain(llm, chain_type="map_reduce")
summary = chain.run(docs)# 文档翻译
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplatetemplate = """Translate the following text from {source_language} to {target_language}:
{text}"""prompt = PromptTemplate(input_variables=["source_language", "target_language", "text"],template=template
)chain = LLMChain(llm=llm, prompt=prompt)
translated = chain.run(source_language="English", target_language="Chinese", text=text)

解决"Lost in the Middle"问题

研究表明,当处理长文本时,检索性能会出现"迷失在中间"的现象:当相关信息位于输入上下文的开头或结尾时,模型表现最佳;而当相关信息位于中间位置时,即使对于专门设计的上下文模型,性能也会显著下降。

解决方案包括:

  1. 通过检索找到相关文本块
  2. 对检索结果进行重新排序,将最相关的内容放在开头和结尾
  3. 使用排序后的文本进行生成
# 排序检索结果的示例代码
def reorder_results(results):# 按相关性排序sorted_results = sorted(results, key=lambda x: x.score, reverse=True)# 重新排列,将高相关度的放在头尾reordered = []for i in range(len(sorted_results)):if i % 2 == 0:reordered.append(sorted_results[i//2])else:reordered.append(sorted_results[len(sorted_results) - 1 - i//2])return reordered

文本向量化

为什么需要文本向量化?主要有两个原因:

  1. 纯文本形式难以进行语义相关性搜索
  2. 文本处理效率低且占用空间大

文本向量化(Embedding)将文本转换为高维向量空间中的点,使得语义相似的文本在向量空间中距离更近。

# 使用OpenAI的文本嵌入模型
from langchain_openai import OpenAIEmbeddingsembeddings = OpenAIEmbeddings()
query_vector = embeddings.embed_query("How does RAG work?")# 使用HuggingFace的文本嵌入模型
from langchain_huggingface import HuggingFaceEmbeddingsembeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")

向量数据库:存储和检索

向量数据库是RAG技术中不可或缺的组成部分,它能够高效地存储和检索高维向量数据。向量数据库的主要作用包括:

  1. 管理数据:以原始形式有效管理数据
  2. 存储向量:存储AI需要的高维数据
  3. 高效检索:快速找到语义相似的内容

市面上有多种向量数据库可供选择:

  • Milvus:开源向量数据库,功能完善,性能强大
  • Pinecone:云原生向量数据库,易于使用
  • Chroma:轻量级向量数据库,适合本地开发
  • FAISS:Facebook AI开发的相似性搜索库
  • Qdrant:开源向量搜索引擎
# 使用Chroma向量数据库
from langchain_community.vectorstores import Chromavectordb = Chroma.from_documents(documents=docs,embedding=embeddings,persist_directory="./chroma_db"
)# 检索相似文档
docs = vectordb.similarity_search("What is RAG technology?", k=3)

🛠️ 实战项目:ChatDoc智能文档助手

下面,我们将学习如何构建一个名为ChatDoc的智能文档助手,它能够:

  1. 加载PDF、DOCX或Excel等格式的文档
  2. 对文档进行适当切分
  3. 使用OpenAI进行向量化
  4. 使用Chroma DB实现本地向量存储
  5. 实现与文档的对话功能

实现步骤

1. 初始化ChatDoc类
import os
from langchain.document_loaders import PDFMinerLoader, CSVLoader
from langchain.document_loaders import Docx2txtLoader, UnstructuredExcelLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQAclass ChatDoc:def __init__(self):self.file_path = Noneself.file_content = Noneself.db = Noneself.embeddings = OpenAIEmbeddings()self.llm = ChatOpenAI(temperature=0)
2. 实现文件加载功能
def get_file(self, file_path):self.file_path = file_path_, file_extension = os.path.splitext(file_path)try:if file_extension == '.pdf':loader = PDFMinerLoader(file_path)elif file_extension == '.csv':loader = CSVLoader(file_path)elif file_extension == '.docx':loader = Docx2txtLoader(file_path)elif file_extension == '.xlsx' or file_extension == '.xls':loader = UnstructuredExcelLoader(file_path)else:print(f"不支持的文件格式: {file_extension}")return Noneself.file_content = loader.load()print(f"文件 {file_path} 加载成功!")return self.file_contentexcept Exception as e:print(f"加载文件时出错: {e}")return None
3. 文本切分与向量化
def separate_and_embed(self):if self.file_content is None:print("没有加载文件内容,请先加载文件。")return None# 文本切分text_splitter = CharacterTextSplitter(separator="\n",chunk_size=1000,chunk_overlap=200,length_function=len)chunks = text_splitter.split_documents(self.file_content)# 向量化存储self.db = Chroma.from_documents(documents=chunks,embedding=self.embeddings,persist_directory="./chroma_db")print(f"文本已切分为 {len(chunks)} 个块并完成向量化存储。")return self.db
4. 实现基本问答功能
def ask_and_find(self, question):if self.db is None:print("向量数据库未初始化,请先处理文档。")return None# 检索相关文档docs = self.db.similarity_search(question, k=3)# 构建上下文context = "\n\n".join([doc.page_content for doc in docs])# 创建提示prompt = f"""根据以下信息回答问题:{context}问题: {question}"""# 生成回答response = self.llm.predict(prompt)return response
5. 使用多重查询优化检索效果
from langchain.retrievers.multi_query import MultiQueryRetrieverdef improved_ask_and_find(self, question):if self.db is None:print("向量数据库未初始化,请先处理文档。")return None# 创建多重查询检索器retriever = MultiQueryRetriever.from_llm(retriever=self.db.as_retriever(),llm=self.llm)# 进行检索docs = retriever.get_relevant_documents(question)# 构建上下文context = "\n\n".join([doc.page_content for doc in docs])# 创建提示prompt = f"""根据以下信息回答问题:{context}问题: {question}"""# 生成回答response = self.llm.predict(prompt)return response
6. 实现对话功能
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChaindef chat_with_doc(self):if self.db is None:print("向量数据库未初始化,请先处理文档。")return None# 创建对话记忆memory = ConversationBufferMemory(memory_key="chat_history",return_messages=True)# 创建对话链qa_chain = ConversationalRetrievalChain.from_llm(llm=self.llm,retriever=self.db.as_retriever(),memory=memory)# 开始对话print("开始与文档对话,输入'exit'退出")while True:question = input("你: ")if question.lower() == 'exit':breakresult = qa_chain({"question": question})print(f"AI: {result['answer']}")

使用示例

# 使用ChatDoc
chat_doc = ChatDoc()# 加载文档
chat_doc.get_file("example.pdf")# 处理文档
chat_doc.separate_and_embed()# 问答示例
response = chat_doc.ask_and_find("这个文档主要讲了什么?")
print(response)# 启动交互式对话
chat_doc.chat_with_doc()

📈 RAG技术的优化方法

多重查询优化

多重查询(Multi-query)通过扩展原始问题,从不同角度生成多个相关查询,然后综合检索结果。这种方法可以提高检索的召回率和准确性。

# 多重查询示例
from langchain.retrievers.multi_query import MultiQueryRetrieverretriever = MultiQueryRetriever.from_llm(retriever=vectordb.as_retriever(),llm=ChatOpenAI(temperature=0)
)# 原始问题
question = "如何实现RAG技术?"# 生成的多重查询可能包括:
# 1. "RAG技术的实现步骤是什么?"
# 2. "如何在项目中使用检索增强生成?"
# 3. "实现RAG需要哪些组件?"
# 4. "RAG的代码实现示例"

上下文压缩

上下文压缩(Context compression)通过筛选和压缩检索到的文档,确保只有最相关的内容被包含在上下文中,从而提高回答质量并降低成本。

from langchain.retrievers.document_compressors import LLMChainExtractor
from langchain.retrievers import ContextualCompressionRetriever# 创建压缩器
compressor = LLMChainExtractor.from_llm(llm)# 创建压缩检索器
compression_retriever = ContextualCompressionRetriever(base_retriever=vectordb.as_retriever(),doc_compressor=compressor
)# 使用压缩检索器获取文档
compressed_docs = compression_retriever.get_relevant_documents(query)

基于重排序的优化

针对"迷失在中间"问题,可以对检索结果进行重新排序,将最相关的文档放在上下文的开头和结尾:

def rerank_documents(docs, query):# 计算每个文档与查询的相关性分数# 这里可以使用更复杂的相关性评分方法scored_docs = [(doc, doc.metadata.get("score", 0)) for doc in docs]# 按分数排序sorted_docs = sorted(scored_docs, key=lambda x: x[1], reverse=True)# 重新排列文档,使最相关的在开头和结尾result = []for i in range(len(sorted_docs)):if i % 2 == 0 and i//2 < len(sorted_docs):result.append(sorted_docs[i//2][0])elif i//2 < len(sorted_docs) // 2:result.append(sorted_docs[len(sorted_docs) - 1 - i//2][0])return result

🌟 总结与展望

通过本文,我们深入学习了RAG技术及其在LangChain中的实现。RAG技术通过将检索与生成相结合,有效解决了大模型知识时效性和专业性不足的问题,使AI能够访问最新的、专业的、私有的信息。

我们详细探讨了RAG的实现步骤:

  1. 使用各种Loader加载文档
  2. 通过文本切割、总结等方法处理文档
  3. 将文本向量化并存储在向量数据库中
  4. 根据用户问题检索相关文档
  5. 基于检索结果生成回答

同时,我们还介绍了多重查询、上下文压缩和重排序等优化技术,以提高RAG系统的性能。

最后,我们通过构建ChatDoc智能文档助手,将学到的知识应用到实践中,实现了与任意文档对话的功能。

未来,随着大模型和向量数据库技术的不断发展,RAG技术将变得更加高效、准确,并在更多领域发挥作用。通过掌握RAG技术,我们可以充分发挥大模型的潜力,构建更智能、更专业的AI应用。

💡 小提示:如果你想要进一步提升RAG系统的性能,可以考虑:

  • 尝试不同的文本嵌入模型
  • 优化文档切割策略
  • 使用混合检索方法
  • 引入用户反馈机制

希望本文能够帮助你理解和应用RAG技术,构建属于自己的智能文档助手!


🔗 参考资料

  • AI Agent智能应用从0到1定制开发
  • LangChain官方文档:https://python.langchain.com/docs/
  • “Lost in the Middle: How Language Models Use Long Contexts” 研究论文
  • 向量数据库官方文档:Milvus、Chroma、Pinecone等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/73217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 爬虫(4)HTTP协议

文章目录 一、HTTP协议1、HTTP特点2、HTTP工作原理3、HTTP与HTTPS的区别 前言&#xff1a; HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是互联网上应用最为广泛的一种网络协议&#xff0c;用于在客户端和服务器之间传输超文本&#xf…

测试工程 常用Python库

以下是测试工程师在Python中必须掌握的常用库、框架以及提升日常工作效率的技巧总结&#xff1a; 一、必须掌握的Python库与框架 1. 测试框架 unittest Python内置的单元测试框架&#xff0c;提供测试用例、测试套件、断言等功能&#xff0c;适合单元测试和集成测试。核心组件…

【线程安全问题的原因和方法】【java形式】【图片详解】

在本章节中采用实例图片的方式&#xff0c;以一个学习者的姿态进行描述问题解决问题&#xff0c;更加清晰明了&#xff0c;以及过程中会发问的问题都会一一进行呈现 目录 线程安全演示线程不安全情况图片解释&#xff1a; 将上述代码进行修改【从并行转化成穿行的方式】不会出…

Infinite you:flexible photo recrafting while preserving your identity

基于DiT的id保留图像生成面临着多种挑战,缺乏定制模块设计,模型扩展的困难以及高质量数据的匮乏,因此基于flux的解决方案是相对稀缺的,pulid-flux是基于flux的id保留的初步尝试,包括instantx和xlabs-ai的flux.1-dev ip-adapters,现有方法在三个关键方面保险不足:1.身份相…

Unity 实现一个简易可拓展性的对话系统

本人能力有限,一切实现仅供参考,如有不足还请斧正 起因是我看到学校社团内有人做了对话系统的分享,我想了想之前没写过这种东西,而Fungus插件教程太老了,NodeCanvas插件学习成本又比较高,我就干脆寻找资料 加上自己迭代一下,花了一天时间完成了这个对话系统 目录 1.介绍 2.核…

linux常用指令(6)

今天我们继续学习一些linux常用指令,丰富我们linux基础知识,那么话不多说,来看. 1.cp指令 功能描述&#xff1a;拷贝文件到指定目录 基本语法&#xff1a;cp [选项] source dest 常用选项&#xff1a;-r&#xff1a;递归复制整个文件夹 拷贝文件&#xff1a; 拷贝文件夹&am…

Vue 3 中的路由传参详解※※※※

前言 在Vue应用中&#xff0c;路由传参是非常常见的需求&#xff0c;它允许我们在不同的组件之间传递数据。Vue Router提供了两种主要的方式来传递参数&#xff1a;query参数和params参数。下面我们将详细探讨这两种传参方式的使用方法和注意事项。 一、query参数 Query参数…

如何创建一个socket服务器?

1. 导入必要的库 首先&#xff0c;需要导入Python的socket库&#xff0c;它提供了创建和管理socket连接的功能。 python import socket 2. 创建服务器端socket 使用socket.socket()函数创建一个服务器端的socket对象&#xff0c;指定协议族&#xff08;如socket.AF_INET表示…

lua垃圾回收

lua垃圾回收 lua 垃圾回收 lua 垃圾回收 collectgarbage(“count”)获取当前lua脚本占用内存字节数(单位为KB)。 collectgarbage(“collect”)执行一次垃圾回收。 xxxnil 将变量置为空&#xff0c;会释放内存。 lua中的机制和c#中回收机制很类似 解除羁绊(置为空)。 --垃圾回…

友思特应用 | 行业首创:基于深度学习视觉平台的AI驱动轮胎检测自动化

导读 全球领先的轮胎制造商 NEXEN TIRE 在其轮胎生产检测过程中使用了基于友思特伙伴Neurocle开发的AI深度学习视觉平台&#xff0c;实现缺陷检测率高达99.96%&#xff0c;是该行业首个使用AI平台技术推动缺陷检测自动化流程的企业。 将AI应用从轮胎开发扩展到制造过程 2024年…

前后端+数据库的项目实战:hbu迎新网-较复杂(下)javaweb

目录 十一、实现对内容的富文本编辑&#xff08;换行、图片颜色等等样式&#xff09; &#xff08;1&#xff09;下载富文本编辑器&#xff0c;引入资源 &#xff08;2&#xff09;将原项目的内容部分替换为富文本编辑器 1、替换添加页面 2、替换修改页面&#xff08;和添…

脚本语言 Lua

概念 Lua由标准C编写而成&#xff0c;几乎在所有操作系统和平台上都可以编译、运行。Lua脚本可以很容易地被C/C 代码调用&#xff0c;也可以反过来调用C/C的函数&#xff0c;这使得Lua在应用程序中可以被广泛应用。Lua并没有提供强大的库&#xff0c;它是不适合作为开发独立应…

【数据分享】2000—2024年我国乡镇的逐月归一化植被指数(NDVI)数据(Shp/Excel格式)

之前我们分享过2000—2024年我国省市县三级逐月归一化植被指数&#xff08;NDVI&#xff09;数据&#xff0c;该数据是基于NASA定期发布的MOD13A3数据集中的月度NDVI栅格数据&#xff08;可查看之前的文章获悉详情&#xff09;计算得出。很多小伙伴拿到数据后反馈是否可以处理出…

【负载均衡系列】HAProxy

HAProxy(High Availability Proxy)是一款高性能的 ​TCP/HTTP 负载均衡器,专注于提供高可用性、灵活性和可靠性。以下是关于HAProxy的详细解析,涵盖其工作原理、工作机制、工作模式等核心方面: 一、HAProxy 工作原理 HAProxy的核心职责是将客户端请求高效、可靠地分发到后…

轻松迁移 Elasticsearch 数据:如何将自建索引导出并导入到另一个实例

概述 在日常的 Elasticsearch 运维和数据管理中&#xff0c;数据迁移是一个常见的需求。无论是为了备份、升级&#xff0c;还是将数据从一个集群迁移到另一个集群&#xff0c;导出和导入索引数据都是至关重要的操作。本文将详细介绍如何将自建 Elasticsearch 实例中的索引数据…

JVM 类加载器之间的层次关系,以及类加载的委托机制

JVM 类加载器之间存在一种层次关系&#xff0c;通常被称为双亲委派模型 (Parent Delegation Model)。这种层次关系和委托机制是 Java 类加载机制的核心&#xff0c;对于保证 Java 程序的安全性和避免类冲突至关重要。 1. 类加载器的层次关系: JVM 中的类加载器&#xff08;Cl…

基于 Vue 3 的PDF和Excel导出

以下是基于 Vue 3 Composition API 的完整实现&#xff0c;包括 PDF 和 Excel 导出。 一、PDF 导出 (Vue 3) 安装依赖 在项目中安装相关库&#xff1a; npm install html2canvas jspdf Vue 3 代码实现 <template><div><div ref"pdfContent" cla…

【Jupyter】notebook无法显示tqdm进度条

错误描述 from tqdm.notebook import tqdm 用的时候报错&#xff1a; Error displaying widget解决方式 # 先装nodejs conda install -c conda-forge nodejs20# 重装ipywidgets pip uninstall ipywidgets pip install ipywidgets jupyter labextension install jupyter-wid…

ubuntu20如何升级nginx到最新版本(其它版本大概率也可以)

前言&#xff1a; Nginx非常常用&#xff0c;所以在网络安全方面备受“关注”。其漏洞非常多&#xff0c;要经常保持软件更新版本才能更好的保证安全。但是Ubuntu官网适配nginx非常慢&#xff0c;所以nginx官方也会推出针对主流Linux操作系统的包管理工具安装方式。 步骤&…

word插入Mathtype公式居中和自动更新

word插入公式自动更新 前提&#xff1a;安装Mathtype 1.word中查看页的宽度 出现如下 2.设置样式 出现这个窗口 给样式随便起个名字 3.修改样式 3.1 设置两个制表位 第二个 3.2 修改公式字体 如下所示 4. 修改公式格式 4.1在word中打开 Mathtype 4.2 修改公式的格式 变成…