微信扫码
与创始人交个朋友
我要投稿
导言
RAG是使用大模型,同时避免大模型幻觉, 且解决垂直业务领域的高效方式,而多模态的RAG构建又是融合多种数据, 包括音频,视频,文档的信息和知识构建RAG的有效手段,本文介绍了视觉文档多模态RAG系统的构建方式, 并附上完整代码。
通过阅读本文,你能够了解:
如何构建增加视觉文档的多模态RAG
获取完整代码
关注公众号,复制"视觉多模态RAG源码下载"并后台发送,获取 完整代码
概述
在本文中,我将指导使用OpenAI的GPT-4o模型构建一个多模式RAG聊天应用程序。以下是你将学到的内容:
多模式RAG聊天应用程序:创建一个应用程序,通过从PDF文档中检索信息来实现视觉问题回答。
无缝解析:使用Unstructured库无缝解析文本、表格和图像。
性能评估:使用DeepEval库提供的各种指标评估聊天机器人的性能。
Streamlit用户界面:通过Streamlit应用程序演示该应用程序。
为什么要阅读本文?
你是否对利用像GPT-4o这样的先进基础模型的多模态能力来构建自己的AI应用程序感兴趣?那么你需要阅读该文章。
无论您是一名市场营销专业人士,寻求从市场研究报告中获取见解,还是一名医疗从业者分析多模态医疗文件,或者一名法律专业人士处理复杂的法律文件,本文都为提供了宝贵的见解。
我将对每个概念进行彻底解释,并提供所有代码的详细解释。
多模态 RAG 的崛起
从基于文本的 RAG 模型向多模态 RAG 系统的转变代表了人工智能能力的重大飞跃。以下是一个快速概述:
起源:RAG 这个术语是在 2021 年 4 月创造的,通过基于文本的知识增强语言输出。
进展:随着像 GPT-4o 这样的模型在 2024 年 5 月发布,我们现在可以整合视觉信息,实现图像、表格和文本的同时处理。
新可能性:这种演变使得更全面和具有上下文丰富的人工智能应用成为可能。
在本文中,我将展示一个案例研究,使用多模态 RAG 框架对我在 Neurocomputing 上的一篇研究文章进行问答。该文章包括文本、表格和图表,我们将探讨 GPT-4o 的视觉能力如何回答复杂问题。
目录
设置虚拟环境并安装Python库
预处理非结构化数据
文本、表格和图像摘要
多模态检索器
多模态RAG链
LLM评估
使用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", # mandatory
strategy="hi_res", # mandatory to use ``hi_res`` strategy
extract_images_in_pdf=True,# mandatory to set as ``True``
extract_image_block_types=["Image", "Table"],# optional
extract_image_block_to_payload=False,# optional
extract_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_types 和 extract_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] += 1
else:
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 StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from 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 base64
import os
from 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 InMemoryStore
from langchain_chroma import Chroma
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
def 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+中大型企业
2024-11-25
糟糕!LLM输出半截Json的答案,还有救吗!
2024-11-24
解读GraphRAG
2024-11-24
RAGChecker:显著超越RAGAS,一个精细化评估和诊断 RAG 系统的创新框架
2024-11-23
FastRAG半结构化RAG实现思路及OpenAI O1-long COT蒸馏路线思考
2024-11-23
检索增强生成(RAG):解密AI如何融合记忆与搜索
2024-11-23
如何提高RAG系统准确率?12大常见痛点及巧妙解!
2024-11-23
RAG 2.0性能提升:优化索引与召回机制的策略与实践
2024-11-22
RAG技术在实际应用中的挑战与解决方案
2024-07-18
2024-05-05
2024-07-09
2024-05-19
2024-07-09
2024-06-20
2024-07-07
2024-07-07
2024-07-08
2024-07-09
2024-11-06
2024-11-06
2024-11-05
2024-11-04
2024-10-27
2024-10-25
2024-10-21
2024-10-21