AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


视觉文档多模态RAG系统构建-Step by Step(附完整代码)
发布日期:2024-08-17 06:33:53 浏览次数: 2053 来源:颠覆式创新


导言

RAG是使用大模型,同时避免大模型幻觉, 且解决垂直业务领域的高效方式,而多模态的RAG构建又是融合多种数据, 包括音频,视频,文档的信息和知识构建RAG的有效手段,本文介绍了视觉文档多模态RAG系统的构建方式, 并附上完整代码。

通过阅读本文,你能够了解:

  1. 如何构建增加视觉文档的多模态RAG

  2. 获取完整代码


关注公众号,复制"视觉多模态RAG源码下载"并后台发送,取 完整代码

概述

在本文中,我将指导使用OpenAI的GPT-4o模型构建一个多模式RAG聊天应用程序。以下是你将学到的内容:

多模式RAG聊天应用程序:创建一个应用程序,通过从PDF文档中检索信息来实现视觉问题回答。

  1. 无缝解析:使用Unstructured库无缝解析文本、表格和图像。

  2. 性能评估:使用DeepEval库提供的各种指标评估聊天机器人的性能。

  3. Streamlit用户界面:通过Streamlit应用程序演示该应用程序。


为什么要阅读本文?

你是否对利用像GPT-4o这样的先进基础模型的多模态能力来构建自己的AI应用程序感兴趣?那么你需要阅读该文章。    

无论您是一名市场营销专业人士,寻求从市场研究报告中获取见解,还是一名医疗从业者分析多模态医疗文件,或者一名法律专业人士处理复杂的法律文件,本文都为提供了宝贵的见解。

我将对每个概念进行彻底解释,并提供所有代码的详细解释。

多模态 RAG 的崛起

从基于文本的 RAG 模型向多模态 RAG 系统的转变代表了人工智能能力的重大飞跃。以下是一个快速概述:

  1. 起源:RAG 这个术语是在 2021 年 4 月创造的,通过基于文本的知识增强语言输出。

  2. 进展:随着像 GPT-4o 这样的模型在 2024 年 5 月发布,我们现在可以整合视觉信息,实现图像、表格和文本的同时处理。

  3. 新可能性:这种演变使得更全面和具有上下文丰富的人工智能应用成为可能。    

在本文中,我将展示一个案例研究,使用多模态 RAG 框架对我在 Neurocomputing 上的一篇研究文章进行问答。该文章包括文本、表格和图表,我们将探讨 GPT-4o 的视觉能力如何回答复杂问题。

目录

  1. 设置虚拟环境并安装Python库

  2. 预处理非结构化数据

  3. 文本、表格和图像摘要

  4. 多模态检索器

  5. 多模态RAG链

  6. LLM评估

  7. 使用Streamlit的用户界面


设置虚拟环境并安装Python库

首先,让我们使用以下命令设置虚拟环境:

python3.10 -m venv venv


现在,让我们安装必要的包。您可以在GitHub存储库的主目录中的'requirements.txt'中找到它们。

pip install -r requirements.txt


现在,打开一个jupyter笔记本,比如说"your-project.ipynb"来开始编写您的代码。就是这样!我们现在已经准备好进入主要细节了。

这是多模式RAG项目的GitHub存储库:

GitHub - bhargobdeka/advanced-RAG-app: This repository will consist of advanced RAG applications.    

预处理非结构化数据

构建 RAG 应用程序的第一步是将上下文加载到数据库中,在这种情况下是使用 PDF 文档。

由于大型语言模型(LLM)的上下文窗口限制,我们无法直接将整个文档存储并传递到提示符中。这样做很可能会导致错误,因为它超过了最大token数。

为了克服这个问题,我们将从文档中提取不同的元素 - 图像、文本和表格。对于这个任务,我们将使用 Unstructured 库。

安装

首先,让我们安装该软件包(如果尚未通过pip安装)


#%brew install tesseract poppler%pip install -q "unstructured[all-docs]"


请注意,系统中还需要 'tesseract' 和 'poppler' 库,以便无结构库能够处理文本提取以及从图像中提取文本。您可以使用 homebrew 安装这两个软件包(参见注释行)。

分区和分块


from unstructured.partition.pdf import partition_pdf


elements = partition_pdf(filename="TAGIV.pdf", # mandatorystrategy="hi_res", # mandatory to use ``hi_res`` strategyextract_images_in_pdf=True,# mandatory to set as ``True``extract_image_block_types=["Image", "Table"],# optionalextract_image_block_to_payload=False,# optionalextract_image_block_output_dir="saved_images",# optional - only works when ``extract_image_block_to_payload=False``)


我们将使用 partition_pdf 模块来对文档进行分区,并从我们的文件 'TAGIV.pdf' 中提取不同的元素。我们将设置一个 hi_res 策略来提取高质量的图像和表格。可选参数 extract_image_block_typesextract_image_block_output_dir 指定只提取并保存图像和表格到名为 "saved_images" 的目录中。

现在,我们将使用 chunk_by_title 方法来对元素进行分块,该方法用于根据 '标题或标题' 将提取的元素分成块。这适用于研究文章,通常包括独立部分和子部分的内容,如介绍、方法、结果等。


from unstructured.chunking.title import chunk_by_title # might be better for an article from typing import Any
chunks = chunk_by_title(elements)Output:# 文档中的不同类别category_counts = {}
for element in chunks:category = str(type(element))if category in category_counts:category_counts[category] += 1else:category_counts[category] = 1{"": 200, "": 3, "": 2}


分块显示有三个唯一的类别:

•CompositeElements

•Table

•TableChunk

'CompositeElements' 是不同文本的集合,可能是段落、章节、页脚、公式等。还有三个 'Table' 结构以及两个 'TableChunk',通常表示表格的一部分或片段。因此,可能表格跨页,只有一部分被分块。

文档中有四个表,只有三个被完全解析。?

过滤

接下来,我们将简化文档元素,以便将文本和表格数据分开处理。为此,我们将定义一个 Pydantic 模型来标准化文档元素,并根据它们的类型将它们分类为“文本”或“表格”。


from pydantic import BaseModelclass Element(BaseModel):type: strtext: Any

   

按类型分类

categorized_elements = []for element in chunks:

if "unstructured.documents.elements.CompositeElement" in str(type(element)):

categorized_elements.append(Element(type="text", text=str(element)))

elif "unstructured.documents.elements.Table" in str(type(element)):

categorized_elements.append(Element(type="table", text=str(element)))

文本

text_elements = [e for e in categorized_elements if e.type == "text"]

表格

table_elements = [e for e in categorized_elements if e.type == "table"]

           
我们将遍历文档元素的块,识别每个元素的类型,并将其附加到一个分类列表中。最后,我们将这个列表过滤成分别用于文本和表格元素的两个列表。有了这个,预处理步骤现在已经结束。

           
           
文本、表格和图片摘要            
           

为了在本文后面使用多向量检索器,我们需要为文本、表格和图片元素创建摘要。这些摘要将存储在向量存储器中,当我们将输入查询传递到提示时,将实现语义搜索。            
           
文本和表格摘要            
           
让我们从文本和表格摘要开始。首先,我们将设置一个提示模板,指示AI充当专家研究助理,负责总结表格和文本。接下来,我们将创建一个链,通过这个提示和GPT-4o模型处理每个文本和表格元素,生成简洁的摘要。            
           
为了提高效率,我们将使用`max_concurrency`参数同时批处理五个文本或表格元素。
           
           
        

%pip install -q langchain langchain-chroma unstructured[all-docs] pydantic lxml langchainhub langchain-openai
from langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAI

检索器

提示

prompt_text = """您是一名专家研究助理,负责总结研究文章中的表格和文本。给出文本的简洁总结。文本块:{element}"""

prompt = ChatPromptTemplate.from_template(prompt_text)


摘要链

model = ChatOpenAI(temperature=0, model="gpt-4o")summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser()


应用到文本

texts = [i.text for i in text_elements]text_summaries = summarize_chain.batch(texts, {"max_concurrency": 5})Apply to tablestables = [i.text for i in table_elements]table_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})


           
图像摘要            
           

接下来,我们将设置函数来帮助我们总结我们的图像。我们将定义三个关键函数:`encode_image`,`image_summarize` 和 `generate_img_summaries`。            
           
1. encode_image:此函数以二进制读取模式('rb')打开图像文件,并返回其 base64 编码的字符串表示。            
           
2. image_summarize:此函数使用包含指示模型如何总结图像的提示的 HumanMessage 对象。它还包括 base64 编码的图像数据,格式化为数据 URL 以直接嵌入内容中的图像。            
           
3. generate_img_summaries:此函数处理给定目录中的所有 JPG 图像,为每个图像生成摘要并返回 base64 编码的图像。            
           
这些函数将使我们能够高效地总结和处理图像,并将它们无缝集成到我们的多模态 RAG 应用程序中。            
           
以下是完整的代码:
           
                    

## 获取图像摘要import base64import osfrom langchain_core.messages import HumanMessage
def encode_image(image_path):"""获取base64字符串"""with open(image_path, "rb") as image_file:return base64.b64encode(image_file.read()).decode("utf-8")def image_summarize(img_base64, prompt):"""生成图像摘要"""chat = ChatOpenAI(model="gpt-4o", max_tokens=1024)
msg = chat.invoke([HumanMessage(content=[{"type": "text", "text": prompt},{"type": "image_url","image_url": {"url": f"data:image/jpg;base64,{img_base64}"},},])])return msg.content
def generate_img_summaries(path):"""生成图像摘要和base64编码字符串path: 通过Unstructured提取的.jpg文件列表的路径"""
# 存储base64编码的图像img_base64_list = []
# 存储图像摘要image_summaries = []
# 提示prompt = """您是一名助手,负责为检索摘要图像。\这些摘要将被嵌入并用于检索原始图像。\给出一份简洁的图像摘要,以便更好地进行检索。"""
# 应用于图像for img_file in sorted(os.listdir(path)):if img_file.endswith(".jpg"):img_path = os.path.join(path, img_file)base64_image = encode_image(img_path)img_base64_list.append(base64_image)image_summaries.append(image_summarize(base64_image, prompt))
return img_base64_list, image_summaries





fpath = "saved_images" 图像摘要img_base64_list, image_summaries = generate_img_summaries(fpath)


多模态检索器

有了我们的摘要准备好了,我们可以创建我们的多模态检索器。

多向量检索器

我们将建立一个多向量检索器,它接受向量存储、文档存储、id_key 和 search_kwargs 作为输入。这种方法允许我们单独索引内容摘要,同时存储原始内容,从而实现高效的检索。请注意,这只是执行多模态 RAG 的一种方式;另一种方法可能涉及使用多模态嵌入来使用CLIP嵌入文本和图像,然后将原始图像和文本块传递给多模态 LLM。我可能会在未来的博客文章中探索这一点。?

我们的检索器利用 Chroma 向量存储来存储内容摘要的嵌入,并使用 InMemoryStore 来存储完整内容。这种设置使得通过摘要进行语义搜索,同时在需要时检索相应的完整内容成为可能。每个文档都使用 UUID 分配一个唯一标识符,这是检索器所必需的。

为了简化向向量存储添加摘要和向文档存储添加原始内容的过程,我们将添加一个名为 add_documents 的辅助函数。该函数确保只添加可用的摘要。


import uuid
from langchain.retrievers.multi_vector import MultiVectorRetriever from langchain.storage import InMemoryStorefrom langchain_chroma import Chromafrom langchain_core.documents import Documentfrom langchain_openai import OpenAIEmbeddingsdef create_multi_vector_retriever(vectorstore, text_summaries, texts, table_summaries, tables, image_summaries, images):"""创建检索器,索引摘要,但返回原始图像、表格或文本"""


# 初始化存储层store = InMemoryStore()id_key = "doc_id"
# 创建多向量检索器retriever = MultiVectorRetriever(vectorstore=vectorstore,docstore=store,id_key=id_key,search_kwargs={"k": 2}# 限制为前 2 个结果)
# 添加文档到向量存储和文档存储的辅助函数def add_documents(retriever, doc_summaries, doc_contents):doc_ids = [str(uuid.uuid4()) for _ in doc_contents]summary_docs = [Document(page_content=s, metadata={id_key: doc_ids[i]}) for i, s inenumerate(doc_summaries)]retriever.vectorstore.add_documents(summary_docs)retriever.docstore.mset(list(zip(doc_ids, doc_contents)))


# 添加文本、表格和图像# 在添加之前检查 text_summaries 不为空if text_summaries:add_documents(retriever, text_summaries, texts)# 在添加之前检查 table_summaries 不为空if table_summaries:add_documents(retriever, table_summaries, tables)# 在添加之前检查 image_summaries 不为空if image_summaries:add_documents(retriever, image_summaries, images)


return retriever


创建检索器


# 用于索引摘要的向量存储vectorstore = Chroma(collection_name="mm_tagiv_paper", embedding_function=OpenAIEmbeddings())


# 创建检索器retriever_multi_vector_img = create_multi_vector_retriever(vectorstore,text_summaries,texts,table_summaries,tables,image_summaries,img_base64_list,)

             
               
测试以及完整代码              
               

代码组织结构如下:

advanced-RAG-app/              
             
├── utils/              
│ ├── __init__.py              
│ ├── image_processing.py              
│ ├── rag_chain.py              
│ ├── rag_evaluation.py              
│ └── retriever.py              
             
└── main.py              
└── requirements.txt

关注公众号,复制"视觉多模态RAG源码下载"并后台发送,取 完整代码


53AI,企业落地应用大模型首选服务商

产品:大模型应用平台+智能体定制开发+落地咨询服务

承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询