LLM之RAG实战(十三)| 利用MongoDB矢量搜索实现RAG高级检索

news2024/12/23 23:46:57

       想象一下,你是一名侦探,身处庞大的信息世界,试图在堆积如山的数据中找到隐藏的一条重要线索,这就是检索增强生成(RAG)发挥作用的地方,它就像你在人工智能和语言模型世界中的可靠助手。但即使是最好的助理也有其局限性,因此,让我们开始探索RAG的高级方法,重点关注大规模文档检索中的精度和上下文。

一、基本RAG

       想象一下,有一本和地平线一样宽百科全书。基本的RAG试图将这些丰富的知识提炼成一个单一的“嵌入”——本质上是一个数字。但是,当你在一个特定的主题上寻求智慧时,比如神秘的百慕大三角,基本的RAG的粗笔画会覆盖更多细节,给你留下一幅不完整的画面。这种限制就像试图用一张只显示大陆的地图来寻找隐藏的宝藏,而不是通往标有“X”的地点的复杂路径。

       另一方面,如果我们只拥有带有嵌入的单个页面,我们可能会找出具体的事实,但当它们交织在一起时,我们就会失去它们所讲述的故事。如果没有叙事,大型语言模型(LLM)很难找到一个能抓住我们探究的真正本质的答案。

       基本RAG,虽然是一个值得称赞的里程碑,但没有做的更好。基本RAG只是一个基础,需要跨越通用知识和精确见解之间的距离,我们需要做更细致的优化工作。

二、路径的细化:父子文档关系

       我们不是对整个百科全书进行单一的总结,而是为每一页(子文档)进行简洁的概述,注意包含的章节(父文档)。该方法在我之前的LLM之RAG实战(五)| 高级RAG 01:使用小块检索,小块所属的大块喂给LLM,可以提高RAG性能博客中有所介绍,这里略过。

2.1 步骤1:父子文档关系

       想象一下,你有一本又大又笨重的书——一本关于所有电器的用户手册。现在,有人问了一个特定的问题:“为什么我的洗衣机显示错误代码2?”,对于基本的RAG,我们要么得到缺乏上下文的小块,要么得到搜索不够准确的大块。然而,高级RAG采用了更聪明的方法。

       首先,手册被分解成大块——这些是我们的“父”文档。每一节都涉及更大的信息。在这些部分中,我们拆分了涵盖特定问题的“子”文档,如洗衣机的错误代码。

       现在,来看看矢量化的魔力。每个子文档都通过嵌入模型进行处理,该模型分析文本并将其转换为向量——一系列表示文本本质的数字。这就像为每一小段信息创建一个DNA图谱。

       每个子文档的文本都被提取到一个向量中,然后将其存储在向量存储中,其父文档也存储在这个向量存储中——这也是一个通用数据库。这使我们不仅可以快速检索最相关的小信息,还可以保留父文档提供的上下文。

2.2 步骤二:问答

       当关于洗衣机的问题出现时,它就变成了一个“嵌入”——把它想象成一个独特的数字签名。然后使用矢量搜索将这些嵌入与类似的子文档进行匹配。如果它与“洗衣机”部分的子文档嵌入紧密对齐,我们就找到了匹配项。

       有了我们的矢量存储和准备,当出现问题时,我们可以迅速找到最相关的子文档。但是,我们没有提供狭义的回应,而是引入了母文档,它提供了更多的背景和上下文。这个准备好的提示富含特定信息和广泛的上下文,然后被输入到大型语言模型(LLM)中,该模型生成精确的上下文感知答案。

       如图所示,这种先进的RAG过程确保LLM具有生成准确响应所需的所有上下文,就像侦探拼凑线索来解开谜团一样。借助MongoDB矢量搜索的强大功能,我们可以以超级计算机的速度和精度浏览这一过程,确保每个问题都得到尽可能好的答案。

三、MongoDB矢量搜索:高级RAG背后的动力

       从父子关系和矢量化的复杂关系中走出来,我们直接进入了MongoDB的矢量搜索领域,该引擎为我们的高级RAG过程提供了动力。让我们深入研究一下MongoDB矢量搜索是如何将筛选堆积如山的数据这一艰巨任务转变为一个精简高效的过程的。

3.1 矢量搜索:快速寻找答案

       MongoDB中的矢量搜索就像在浩瀚的数据海洋中拥有一盏高功率探照灯。当我们的洗衣机爱好者询问那个令人讨厌的错误代码时,矢量搜索不仅仅是梳理数据,它还可以精确定位信息的确切位置,这要归功于我们早些时候创建的独特的“数字签名”。最棒的部分?它以惊人的速度做到了这一点,使得搜索答案的速度就像翻阅一个组织良好的文件柜一样快。

3.2 结构与速度想结合

       MongoDB的矢量搜索将结构和速度和谐地结合在一起。父文档和子文档的存储,以及它们的矢量化本质,使MongoDB能够快速识别最相关的数据片段,而不会被不太相关的信息所困扰。这是一位一丝不苟的图书管理员和一位侦探大师的完美结合,确保了没有遗漏任何线索,每个答案都切中要害。

3.3 语境丰富性:增加的层次

       在这里,事情变得更加有趣。一旦矢量搜索精确定位了相关的子文档,它就不会止步于此。通过检索父文档,它确保了上下文的丰富性不会丢失。这意味着我们的LLM不仅了解“什么”,还了解“为什么”和“如何”,提供了超出表面水平的答案。

3.4 MongoDB:不仅仅是一个数据库

       MongoDB不仅仅是一个存储数据的地方;这是一个动态的生态系统,支持先进的RAG过程的每一步。它可以轻松管理复杂的父文档和子文档网络,并促进快速矢量搜索,使高级RAG功能强大。使用MongoDB,我们不仅仅是在寻找答案;我们正在制定既能提供信息又能与上下文相关的回应。

3.5 结果:知情、准确的回答

       由于高级RAG和MongoDB矢量搜索之间的强大协作,生成的响应不仅准确,而且信息丰富。当我们的用户询问洗衣机上的错误代码时,他们会收到一个既准确又充满有用上下文的回复,类似于为他们量身定制的全面指南。

       MongoDB矢量搜索是这一高级RAG过程的支柱,提供了在复杂的数据检索环境中导航所需的速度和精度。在下一节中,我们将探索这一过程的实际实施,展示如何将先进的RAG系统应用到生活中,为用户提供人工智能所能提供的最佳答案。请继续关注我们将理论转化为实践,并充分发挥先进RAG的潜力。

四、用MongoDB矢量搜索实现高级RAG

      将Advanced RAG与MongoDB Vector Search集成到我们的系统中,首先是几个技术组件的和数据处理流程。下面看一下具体步骤:

4.1 步骤1:设置和初始化

       我们通过设置环境和建立必要的联系来启动工作,这包括加载环境变量,初始化OpenAI和MongoDB客户端,以及定义我们的数据库和集合名称。

import osfrom dotenv import load_dotenvfrom pymongo import MongoClientfrom langchain.embeddings import OpenAIEmbeddings# Load environment variables from .env fileload_dotenv(override=True)# Set up MongoDB connection detailsOPENAI_API_KEY = os.environ["OPENAI_API_KEY"]MONGO_URI = os.environ["MONGO_URI"]DB_NAME = "pdfchatbot"COLLECTION_NAME = "advancedRAGParentChild"# Initialize OpenAIEmbeddings with the API keyembeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)# Connect to MongoDBclient = MongoClient(MONGO_URI)db = client[DB_NAME]collection = db[COLLECTION_NAME]

4.2 步骤2:数据加载和分块

       接下来,我们将重点处理作为数据源的PDF文档。文档被加载并拆分为“父”和“子”块,以准备嵌入和向量化。

from langchain.document_loaders import PyPDFLoaderfrom langchain.text_splitter import RecursiveCharacterTextSplitter# Initialize the text splitters for parent and child documentsparent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)child_splitter = RecursiveCharacterTextSplitter(chunk_size=200)# Function to process PDF document and split it into chunksdef process_pdf(file):    loader = PyPDFLoader(file.name)    docs = loader.load()    parent_docs = parent_splitter.split_documents(docs)        # Process parent documents    for parent_doc in parent_docs:        parent_doc_content = parent_doc.page_content.replace('\n', ' ')        parent_id = collection.insert_one({            'document_type': 'parent',            'content': parent_doc_content        }).inserted_id                # Process child documents        child_docs = child_splitter.split_documents([parent_doc])        for child_doc in child_docs:            child_doc_content = child_doc.page_content.replace('\n', ' ')            child_embedding = embeddings.embed_documents([child_doc_content])[0]            collection.insert_one({                'document_type': 'child',                'content': child_doc_content,                'embedding': child_embedding,                'parent_ref': parent_id            })    return "PDF processing complete"

4.3 步骤3:查询嵌入和矢量搜索

       当提交查询时,我们将其转换为嵌入,并执行向量搜索以找到最相关的子文档,链接回它们的父文档以获取上下文。

# Function to embed a query and perform a vector searchdef query_and_display(query):    query_embedding = embeddings.embed_documents([query])[0]        # Retrieve relevant child documents based on query    child_docs = collection.aggregate([{        "$vectorSearch": {            "index": "vector_index",            "path": "embedding",            "queryVector": query_embedding,            "numCandidates": 10        }    }])        # Fetch corresponding parent documents for additional context    parent_docs = [collection.find_one({"_id": doc['parent_ref']}) for doc in child_docs]    return parent_docs, child_docs

4.4 步骤4:通过上下文感知生成响应

       在识别出相关文档后,我们为LLM创建一个提示,其中包括用户的查询和匹配文档中的内容。这确保了响应具有信息性和上下文相关性。

from langchain.llms import OpenAI# Initialize the OpenAI clientopenai_client = OpenAI(api_key=OPENAI_API_KEY)# Function to generate a response from the LLMdef generate_response(query, parent_docs, child_docs):    response_content = " ".join([doc['content'] for doc in parent_docs if doc])    chat_completion = openai_client.chat.completions.create(        messages=[{"role": "user", "content": query}],        model="gpt-3.5-turbo"    )    return chat_completion.choices[0].message.content

4.5 第五步:串联所有组件

       最后,我们将这些元素组合成一个连贯的界面,用户可以在其中上传文档并提出问题。这是使用Gradio实现的,它提供了一种用户友好的方式来与我们先进的RAG系统交互。

with gr.Blocks(css=".gradio-container {background-color: AliceBlue}") as demo:    gr.Markdown("Generative AI Chatbot - Upload your file and Ask questions")    with gr.Tab("Upload PDF"):        with gr.Row():            pdf_input = gr.File()            pdf_output = gr.Textbox()        pdf_button = gr.Button("Upload PDF")    with gr.Tab("Ask question"):        question_input = gr.Textbox(label="Your Question")        answer_output = gr.Textbox(label="LLM Response and Retrieved Documents", interactive=False)        question_button = gr.Button("Ask")    question_button.click(query_and_display, inputs=[question_input], outputs=answer_output)    pdf_button.click(process_pdf, inputs=pdf_input, outputs=pdf_output)demo.launch()

4.6 步骤6:在MongoDB Atlas上创建索引

{  "fields": [    {      "numDimensions": 1536,      "path": "embedding",      "similarity": "cosine",      "type": "vector"    },    {      "path": "document_type",      "type": "filter"    }  ]}

参考文献:

[1] https://ai.gopubby.com/byebye-basic-rag-embracing-advanced-retrieval-with-mongodb-vector-search-47b550be2c59

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

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

相关文章

外包干了4个月,技术退步明显了...

先说一下自己的情况,大专生,18年通过校招进入武汉某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四…

Java 并发之 wait、notify 机制三问

1. 调用 notify/notifyAll 之后,会立马释放锁吗? 不会。那么什么时候才释放掉锁从而使得在 WaitSet 中的被唤醒的线程能够有机会重新竞争到锁呢?例如: synchronized(obj) {obj.notify();foo(); }在这段代码中,就是 f…

【建议收藏】一文全面解读Linux最常用的解压缩命令(tar、zip、unzip、gzip、guznip、bzip2、bunzip2)

一文全面解读Linux最常用的解压缩命令(tar、zip、unzip、gzip、guznip、bzip2、bunzip2),建议收藏 文章目录 一文全面解读Linux最常用的解压缩命令(tar、zip、unzip、gzip、guznip、bzip2、bunzip2),建议收…

正定矩阵的四个重要性质(附例子)

目录 一. 写在前面 二. 正定矩阵的基本定义 三. 从正定矩阵 到 特征值 四. 从特征值 到 正定矩阵 五. 从正定矩阵 到 行列式 六. 从正定矩阵 到 矩阵的主元 七. 从矩阵的主元 到 正定矩阵 八. 简单的讨论 8.1 行列式检验 8.2 特征值检验 总结 一. 写在前面 在格密码…

springboot + vue3实现增删改查分页操作

springboot vue3实现增删改查分页操作 环境最终实现效果实现功能主要框架代码实现数据库后端前端 注意事项 环境 jdk17 vue3 最终实现效果 实现功能 添加用户,禁用,启用,删除,编辑,分页查询 主要框架 后端 spri…

【机器学习:余弦相似度 】机器学习中余弦相似度的理解和应用

【机器学习:余弦相似度 】机器学习中余弦相似度的理解和应用 定义余弦距离角距离和相似度 L 2 L_2 L2​归一化欧几里得距离Otsuka–Ochiai 系数属性余弦相似度的三角不等式软余弦测量应用示例扩展GPT图像示例 在数据分析领域,余弦相似度用于度量内积空间…

残疾大学生找工作好难

有点肢体残疾且普通话不太标准的大学生好难找工作啊,怎么办?难道得去捡垃圾了?求学多年,好容易读了个大学(省内一本),我咋这么命苦,找了800多家,面试好几家,都没一个要我的。

《剑指 Offer》专项突破版 - 面试题 3 :前 n 个数字二进制形式中 1 的个数(C++ 实现)

目录 前言 方法一 方法二 方法三 前言 题目链接:338. 比特位计数 - 力扣(LeetCode) 题目: 输入一个非负数 n,请计算 0 到 n 之间每个数字的二进制形式中 1 的个数,并输出一个数组。例如&#xff0…

【python爬虫开发实战 情感分析】利用爬虫爬取城市评论并对其进行情感分析

🚀个人主页:为梦而生~ 关注我一起学习吧! 💡专栏: python网络爬虫从基础到实战 带你学习爬虫从基础到实战 深度学习带你感受AI的魅力 💡往期推荐: ⭐️前面比较重要的基础内容: 【Py…

日常测试工作中哪些是必须知道的 SQL 语句?

SQL 简介 SQL(Structured Query Language,结构化查询语言)是一套用于管理关系数据库管理系统(RDBMS),基于 ANSI(American National Standards Institute 美国国家标准化组织)标准的计算机语言,比较重要的版本是 SQL92…

2023 最火的是什么? 超维计算 + 神经网络

从chatgpt开始,人工智能进步的步伐似乎势不可挡,但支撑这些程序的人工神经网络遇到了一些重大限制,其他的很难推理但是人类的大脑能够通过类比进行推理,当我们看到新事物时,我们不必生长新的神经元,我们可以…

飞凌全志T113-i开发板视频编码测试

前言 本文测试OK113i-S开发板-视频编解码的功能 OK113i-S开发板是支持视频的编解码的,下面是官方介绍的编解码功能 T113-i 是一种为多媒体解码平台设计的高级应用处理器。T113-i 集成了64位玄铁C906 RISC-V CPU, 双核 Cortex - A7 CPU 和 HiFi4 DSP&a…

Java反射篇----第三篇

系列文章目录 文章目录 系列文章目录前言一、反射使用步骤(获取 Class 对象、调用对象方法)二、获取 Class 对象有几种方法三、利用反射动态创建对象实例前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章…

所有单片机使用的汇编语言是统一的吗?

所有单片机使用的汇编语言是统一的吗? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!&…

跑通大模型领域的 hello world

跑通书生浦语大模型的 3 个趣味 demo(InternLM-Chat-7B 智能对话、Lagent工具调用解简单数学题、浦语灵笔多模态图文创作和理解)视频和文档。 1、两个框架 InternLM 是⼀个开源的轻量级训练框架,旨在⽀持⼤模型训练⽽⽆需⼤量的依赖。 Lage…

TSINGSEE青犀智能分析网关V4在智慧园区车辆违停检测场景中的应用

一、背景与需求 园区作为企业办公、生产制造的重要场所,主要道路车辆违停等违规行为会对园区的安全造成隐患,并且在上下班高峰期内,由于发现不及时,车辆违停行为会造成出入口拥堵现象,这也成为园区管理的棘手问题。为了…

提升软件质量与效率:UI自动化测试的重要性

在软件开发领域,UI自动化测试工具被广泛应用,其意义不仅仅体现在节省时间和资源上,更关系到软件质量的提升、团队效率的增加,以及用户体验的改善。本文将探讨使用UI自动化测试工具的重要性,以及它在软件开发生命周期中…

JVM知识总结(简单且高效)

1. JVM内存与本地内存 JVM内存:受虚拟机内存大小的参数控制,当大小超过参数设置的大小时会报OOM。本地内存:本地内存不受虚拟机内存参数的限制,只受物理内存容量的限制;虽然不受参数的限制,如果所占内存超过…

C语言学习NO.13-字符函数(三)-strncpy,strncat,strncmp长度受限制的字符串函数

长度受限制的字符串函数介绍 一、strncpy函数的使用 &#xff08;一&#xff09;strncpy使用 #include <stdio.h> #include <string.h>int main() {char arr1[20] "asdfgdfv";char arr2[7] "zxcvbn";strncpy(arr1, arr2, 4);printf("…

Origin无法使用主题管理器相关功能或报错:Err, Save Theme dialog error!

问题描述 在使用origin绘图时&#xff0c;往往需要进行大批量绘制同样类型的图。如果每个图都不断地去修改相关设置&#xff0c;无疑是浪费了许多宝贵的时间。为了提高绘图效率&#xff0c;了解到了主题管理器&#xff0c;可在“工具–主题管理器”找到。 然而&#xff0c;当我…