LLM之RAG实战(八)| 使用Neo4j和LlamaIndex实现多模态RAG
人工智能和大型语言模型领域正在迅速发展。一年前,没有人使用LLM来提高生产力。时至今日,很难想象我们大多数人或多或少都在使用LLM提供服务,从个人助手到文生图场景。由于大量的研究和兴趣,LLM每天都在变得越来越好、越来越聪明。不仅如此,他们的理解也开始跨越多种模态。随着GPT-4-Vision和随后的其他LLM的引入,今天的LLM似乎可以很好地处理和理解图像。以下是ChatGPT描述图像中内容的一个示例。

正如所观察到的,ChatGPT非常善于理解和描述图像。我们可以在RAG应用程序中使用其理解图像的能力,在该应用程序中,我们现在可以将文本和图片中的信息结合起来,生成比以往任何时候都更准确的答案,而不仅仅依靠文本来生成准确和最新的答案。使用LlamaIndex,实现多模态RAG pipeline非常容易。受(https://github.com/run-llama/llama_index/blob/main/docs/examples/multi_modal/gpt4v_multi_modal_retrieval.ipynb)的启发,来测试是否可以使用Neo4j作为数据库来实现多模态RAG应用程序。
要使用LlamaIndex实现多模态RAG管道,只需实例化两个矢量存储,一个用于图像,另一个用于文本,然后查询这两个矢量,以便检索相关信息以生成最终答案。

多模态RAG首先需要将数据分为图像和文本,然后分别进行embedding并单独构建索引。对于文本,我们将使用ada-002文本嵌入模型;而对于图像,我们将采用[双编码器模型CLIP](https://github.com/openai/CLIP),CLIP可以将文本和图像嵌入到同一嵌入空间中。当最终用户提出问题时,执行两个向量的相似性搜索:一个用于查找相关图像,另一个用于文档。结果被输入到多模态LLM中,该LLM为用户生成答案,展示了处理和利用混合媒体进行信息检索和响应生成的综合方法。
数据预处理
我们将使用[Medium](https://github.com/tomasonjo/blog-datasets/blob/main/articles.zip)作为RAG应用程序的基础数据集。这些文章包含了关于Neo4j图形数据科学库以及将Neo4j与LLM框架相结合的大量信息。从Medium下载的文章是HTML格式。因此,我们需要使用一些编码来分别提取文本和图像。
def process_html_file(file_path):with open(file_path, "r", encoding="utf-8") as file:soup = BeautifulSoup(file, "html.parser")# Find the required sectioncontent_section = soup.find("section", {"data-field": "body", "class": "e-content"})if not content_section:return "Section not found."sections = []current_section = {"header": "", "content": "", "source": file_path.split("/")[-1]}images = []header_found = Falsefor element in content_section.find_all(recursive=True):if element.name in ["h1", "h2", "h3", "h4"]:if header_found and (current_section["content"].strip()):sections.append(current_section)current_section = {"header": element.get_text(),"content": "","source": file_path.split("/")[-1],}header_found = Trueelif header_found:if element.name == "pre":current_section["content"] += f"```{element.get_text().strip()}```\n"elif element.name == "img":img_src = element.get("src")img_caption = element.find_next("figcaption")caption_text = img_caption.get_text().strip() if img_caption else ""images.append(ImageDocument(image_url=img_src))elif element.name in ["p", "span", "a"]:current_section["content"] += element.get_text().strip() + "\n"if current_section["content"].strip():sections.append(current_section)return images, sections
不会详细介绍解析代码,但我们根据标题h1–h4分割文本并提取图像链接。然后,我们只需通过此函数运行所有文章,即可提取所有相关信息。
all_documents = []all_images = []# Directory to search in (current working directory)directory = os.getcwd()# Walking through the directoryfor root, dirs, files in os.walk(directory):for file in files:if file.endswith(".html"):# Update the file path to be relative to the current directoryimages, documents = process_html_file(os.path.join(root, file))all_documents.extend(documents)all_images.extend(images)text_docs = [Document(text=el.pop("content"), metadata=el) for el in all_documents]print(f"Text document count: {len(text_docs)}") # Text document count: 252print(f"Image document count: {len(all_images)}") # Image document count: 328
总共得到252个文本块和328个图像。
对数据创建索引
如前所述,我们必须实例化两个矢量存储,一个用于图像,另一个用于文本。CLIP嵌入模型的尺寸为512,而ada-002的尺寸为1536。
text_store = Neo4jVectorStore(url=NEO4J_URI,username=NEO4J_USERNAME,password=NEO4J_PASSWORD,index_name="text_collection",node_label="Chunk",embedding_dimension=1536)image_store = Neo4jVectorStore(url=NEO4J_URI,username=NEO4J_USERNAME,password=NEO4J_PASSWORD,index_name="image_collection",node_label="Image",embedding_dimension=512)storage_context = StorageContext.from_defaults(vector_store=text_store)
现在向量索引已经创建好了,我们使用MultiModalVectorStoreIndex来索引这两种模态的信息。
# Takes 10 min without GPU / 1 min with GPU on Google collabindex = MultiModalVectorStoreIndex.from_documents(text_docs + all_images, storage_context=storage_context, image_vector_store=image_store)
MultiModalVectorStoreIndex使用文本和图像嵌入模型来计算嵌入,并在Neo4j中存储和索引结果。仅为图像存储URL,而不是实际的base64或图像的其他表示。
多模态RAG pipeline
这段代码是直接从LlamaIndex多模式烹饪书中复制的。我们首先定义一个多模态LLM和prompt template,然后将所有内容组合为一个查询引擎。
openai_mm_llm = OpenAIMultiModal(model="gpt-4-vision-preview", max_new_tokens=1500)qa_tmpl_str = ("Context information is below.\n""---------------------\n""{context_str}\n""---------------------\n""Given the context information and not prior knowledge, ""answer the query.\n""Query: {query_str}\n""Answer: ")qa_tmpl = PromptTemplate(qa_tmpl_str)query_engine = index.as_query_engine(multi_modal_llm=openai_mm_llm, text_qa_template=qa_tmpl)
现在我们可以继续测试它的性能了。
query_str = "How do vector RAG application work?"response = query_engine.query(query_str)print(response)

我们还可以可视化检索提取的图像以及用于帮助提供最终答案的图像。

LLM得到了两个相同的图像作为输入,说明数据集中有重复的图。然而,我对CLIP嵌入感到惊喜,因为他们能够检索到该系列中最相关的图像。在生产环境中,一般需要对数据做预处理,去除重复数据,本文不做此介绍。
结论
LLM的发展速度比我们历史上习惯的要快,并且跨越了多种模态。我坚信,到明年年底,LLM将很快能够理解视频,因此能够在与你交谈时获得非语言提示。另一方面,我们可以使用图像作为RAG管道的输入,并增强传递给LLM的各种信息,使响应更好、更准确。使用LlamaIndex和Neo4j实现多模式RAG管道非常简单。
参考文献:
[1] https://blog.llamaindex.ai/multimodal-rag-pipeline-with-llamaindex-and-neo4j-a2c542eb0206
[2] https://github.com/tomasonjo/blogs/blob/master/llm/neo4j_llama_multimodal.ipynb
相关文章:
LLM之RAG实战(八)| 使用Neo4j和LlamaIndex实现多模态RAG
人工智能和大型语言模型领域正在迅速发展。一年前,没有人使用LLM来提高生产力。时至今日,很难想象我们大多数人或多或少都在使用LLM提供服务,从个人助手到文生图场景。由于大量的研究和兴趣,LLM每天都在变得越来越好、越来越聪明。…...
【SpringCloud笔记】(10)消息总线之Bus
Bus 前言 戳我了解Config 学习Config中我们遇到了一个问题: 当我们修改了GitHub上配置文件内容,微服务需要配置动态刷新并且需要手动向客户端发送post请求刷新微服务之后才能获取到GitHub修改过后的内容 假如有多个微服务客户端3355/3366/3377…等等…...
超酷的爬虫可视化界面
大家好,本文主要介绍使用tkinter获取本地文件夹、设置文本、创建按钮下拉框和对界面进行布局。 1.导入tkinter库 导入tkinter的库,可以使用ttkbootstrap美化生成的界面 ttkbootstrap官网地址:https://ttkbootstrap.readthedocs.io/en/late…...
【kafka消息里会有乱序消费的情况吗?如果有,是怎么解决的?】
文章目录 什么是消息乱序消费了?顺序生产,顺序存储,顺序消费如何解决乱序数据库乐观锁是怎么解决这个乱序问题吗 保证消息顺序消费两种方案固定分区方案乐观锁实现方案 前几天刷着视频看见评论区有大佬问了这个问题:你们的kafka消…...
【PID精讲12】基于MATLAB和Simulink的仿真教程
文章目录 写在前面一、基于Simulink的仿真1. 新建Simulink模型2. 保存Simulink模型3. 建模4. 运行二、基于MATLAB的仿真1. 编码2. 运行3. 调整曲线格式4. 导出图窗写在前面 第11讲介绍的连续系统的数字PID仿真是基于 Matlab的 M 语言实现的,对于初学者或者工程应用人员来说,…...
手机无人直播:解放直播的新方式
现如今,随着科技的迅猛发展,手机已经成为我们生活中不可或缺的一部分。除了通讯、娱乐等功能外,手机还能够通过直播功能将我们的生活实时分享给他人。而针对传统的直播方式,使用手机进行无人直播成为了一种全新的选择。 手机无人…...
ios 之 数据库、地理位置、应用内跳转、推送、制作静态库、CoreData
第一节:数据库 常见的API SQLite提供了一系列的API函数,用于执行各种数据库相关的操作。以下是一些常用的SQLite API函数及其简要说明:1. sqlite3_initialize:- 初始化SQLite库。通常在开始使用SQLite之前调用,但如果没有调用&a…...
Django(三)
1.快速上手 确保app已注册 【settings.py】 编写URL和视图函数对应关系 【urls.py】 编写视图函数 【views.py】 启动django项目 命令行启动python manage.py runserverPycharm启动 1.1 再写一个页面 2. templates模板 2.1 静态文件 2.1.1 static目录 2.1.2 引用静态…...
vscode括号颜色突然变成白色的了,怎么解决
更新版本后发现vscode的各种括号都变成了白色,由于分色括号已经使用习惯,突然变成白色非常不舒服,尝试多次后,为大家提供一下几种解决方式,希望能帮到同样受到此种困惑的你: 第一种: 首先打开…...
测试服务器带宽(ubuntu)
apt install python3 python3-pippip3 install speedtest-clispeestest-cli...
【WPF】使用Behavior以及ValidationRule实现表单校验
文章目录 使用ValidationRule实现检测用户输入EmptyValidationRule 非空校验TextBox设置非空校验TextBox设置非空校验并显示校验提示 结语 使用ValidationRule实现检测用户输入 EmptyValidationRule是TextBox内容是否为空校验,TextBox的Binding属性设置ValidationRu…...
ArcGIS渔网的多种用法
在ArcGIS中有一个渔网工具,顾名思义,可以用来创建包含由矩形像元所组成网络的要素类。不太起眼,但它的用途却有很多,今天跟大家分享一篇关于渔网的多种用途。 1.马赛克地图制作 2.基于网格的设施密度统计制作马赛克地图 准备材…...
C++ 中使用 std::map 的一个示例
std::map 是一个容器,可以用来存储键值对,其中键是唯一的,每个键都映射到一个值 #include <iostream> #include <map>int main() {// 声明了一个 std::map<std::string, int> 类型的变量 myMap,它可以将字符串…...
python虚拟环境及其在项目实践中的应用
文章目录 1.问题的提出1.什么是python虚拟环境2.如何创建2.1第1步-为共享同一虚拟环境的项目创建共同的父目录2.2第2步-在父目录下创建虚拟python环境2.3在父目录下创建各个项目文件夹 1.问题的提出 假设我正在开发若干python项目,这里假定项目名分别为Project1&am…...
普中STM32-PZ6806L开发板(烧录方式)
前言 有两种方式, 串口烧录和STLink方式烧录;串口烧录 步骤 开发板USB转串口CH340驱动板接线到USB连接PC使用自带工具普中自动下载软件.exe烧录程序到开发板 ST Link方式 这种方式需要另外进行供电, 我买的如下,当年用于调试STM8的,也可…...
基于单片机设计的指纹锁(读取、录入、验证指纹)
一、前言 指纹识别技术是一种常见的生物识别技术,利用每个人指纹的唯一性进行身份认证。相比于传统的密码锁或者钥匙锁,指纹锁具有更高的安全性和便利性,以及防止钥匙丢失或密码泄露的优势。 基于单片机设计的指纹锁项目是利用STC89C52作为…...
HarmonyOS - 基础组件绘制
文章目录 所有组件开发 tipsBlankTextImageTextInputButtonLoadingProgress 本文改编自:<HarmonyOS第一课>从简单的页面开始 https://developer.huawei.com/consumer/cn/training/course/slightMooc/C101667360160710997 所有组件 在 macOS 上,组…...
AR智慧校园三维主电子沙盘系统研究及应用
一 、概述 易图讯科技(www.3dgis.top)自主研发的智慧校园三维主电子沙盘系统,采用B/S架构模式,采用自主可控高性能WebGIS可视化引擎,支持多用户客户端通过网络请求访问服务器地图和专题数据,提供地理信息数据、专题数据的并发访问…...
web前端项目-七彩夜空烟花【附源码】
web前端项目-七彩动态夜空烟花【附源码】 本项目仅使用了HTML,代码简单,实现效果绚丽,且本项目代码直接运行即可实现,无需图片素材,接下来让我们一起实现一场美丽的烟花秀叭 运行效果:鼠标点击和移动可控制…...
在k8s中将gitlab-runner的运行pod调度到指定节点
本篇和前面的 基于helm的方式在k8s集群中部署gitlab 具有很强的关联性,因此如果有不明白的地方可以查看往期分享: 基于helm的方式在k8s集群中部署gitlab - 部署基于helm的方式在k8s集群中部署gitlab - 备份恢复基于helm的方式在k8s集群中部署gitlab - 升…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
