菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > AI资讯新闻 > 从零开始多模态RAG系统构建:视觉文档详细分步实战(附完整代码)
技术资讯

从零开始多模态RAG系统构建:视觉文档详细分步实战(附完整代码)

2026-05-30
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

以GPT-4o为基础构建视觉文档多模态RAG系统,利用Unstructured库解析PDF中的文本、表格和图像,

导言

多模态检索增强生成(RAG)架构在充分发挥大模型能力的同时,可有效抑制幻觉,解决垂直业务领域的数据整合难题。构建融合音频、视频、文档等多种数据源的多模态RAG系统,是深度集成异构信息的关键路径。本文完整演示了视觉文档多模态RAG系统的搭建步骤,并附可运行代码。

通过阅读本文,你将掌握:

  1. 如何构建融合视觉文档的多模态RAG管道
  2. 如何获取完整实现代码

概述

本教程基于OpenAI的GPT-4o模型,指导你构建一个多模态RAG聊天应用。核心内容包括:

  • 多模态RAG聊天应用:实现从PDF文档中检索信息,并支持视觉问答。
  • 一步式解析:利用Unstructured库同步提取文本、表格与图像。
  • 性能评估:借助DeepEval库的多样化指标评测聊天机器人表现。
  • Streamlit交互界面:通过Streamlit快速搭建演示前端。

为什么要阅读本文?

如果你希望利用GPT-4o等前沿基础模型的多模态能力,打造自己的AI应用,这篇文章正是为你量身定制。无论你是需要从市场研究报告中提炼洞察的营销专家,还是需分析多模态病历的医疗从业者,抑或是处理复杂法律文档的法律工作者,本文都会提供有价值的思路与可直接复用的代码。每个概念都将被彻底拆解,代码段也会逐行讲解。

多模态RAG的崛起

从纯文本RAG向多模态RAG的演进,标志着AI能力的质变。简要回顾:

  1. 起源:RAG概念于2021年4月提出,最初通过文本知识增强语言生成。
  2. 进展:2024年5月GPT-4o等模型发布后,系统能够同时处理图像、表格与文本,整合视觉信息。
  3. 新可能性:这一进化催生了更全面、上下文更丰富的AI应用场景。

本文将通过一个案例展示多模态RAG框架:基于本人发表于Neurocomputing的研究论文(包含文本、表格与图表),利用GPT-4o的视觉能力回答复杂问题。

目录

  1. 配置虚拟环境并安装Python库
  2. 非结构化数据预处理
  3. 文本、表格与图像摘要生成
  4. 多模态检索器构建
  5. 多模态RAG链实现
  6. 大模型评估
  7. Streamlit用户界面开发

配置虚拟环境并安装Python库

首先,用以下命令创建虚拟环境:

python3.10 -m venv venv

然后安装必要的包。你可以在GitHub仓库根目录下的requirements.txt中找到它们。

pip install -r requirements.txt

接着,打开一个Jupyter Notebook(例如your-project.ipynb)开始编码。至此准备工作完成,可以进入正题。


非结构化数据预处理

构建RAG应用的第一步,是将上下文加载到数据库中——这里使用的是PDF文档。由于大语言模型(LLM)的上下文窗口限制,我们不能直接把整个文档塞进提示词里,那样大概率会超过最大token数导致报错。

解决方法是提取文档中的不同元素:图像、文本和表格。这里使用Unstructured库来完成。

安装

如果尚未安装,先用pip安装(同时需要系统中已安装tesseractpoppler库,以便提取图像中的文本):

# brew install tesseract poppler  (macOS上先安装这两个库)
%pip install -q "unstructured[all-docs]"

分区与分块

from unstructured.partition.pdf import partition_pdf

elements = partition_pdf(
    filename="TAGIV.pdf",  # 必填
    strategy="hi_res",     # 必填,使用高分辨率策略
    extract_images_in_pdf=True,  # 必填,设置为True
    extract_image_block_types=["Image", "Table"],  # 可选
    extract_image_block_to_payload=False,           # 可选
    extract_image_block_output_dir="sa ved_images",  # 可选,仅在extract_image_block_to_payload=False时生效
)

这里使用partition_pdf模块对文档进行分区,并从TAGIV.pdf中提取不同元素。设置hi_res策略可以提取高质量的图像和表格。可选参数extract_image_block_typesextract_image_block_output_dir指定只提取图像和表格,并保存到sa ved_images目录中。

接下来,用chunk_by_title方法对元素进行分块。这个方法会根据“标题”将提取的元素分成块,对研究文章尤其适用——这类文章通常有独立的章节和子章节,比如引言、方法、结果等。

from unstructured.chunking.title import chunk_by_title
from typing import Any

chunks = chunk_by_title(elements)

# 查看文档中的不同类别
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(表格的一部分或片段)。文档中实际有四个表格,但只有三个被完整解析到了。????

过滤

接下来简化文档元素,把文本和表格数据分开处理。先定义一个Pydantic模型来规范化文档元素:

from pydantic import BaseModel

class Element(BaseModel):
    type: str
    text: 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})

# 应用到表格
tables = [i.text for i in table_elements]
table_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})

图像摘要

接下来定义三个关键函数来总结图像:encode_imageimage_summarizegenerate_img_summaries

  • encode_image:以二进制读取模式打开图像文件,返回base64编码字符串。
  • image_summarize:使用包含提示和base64图像数据的HumanMessage调用模型生成摘要。
  • generate_img_summaries:遍历目录中的JPG图像,为每个图像生成摘要并返回base64编码列表和摘要列表。

完整代码如下:

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文件列表的路径
    """
    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 = "sa ved_images"
img_base64_list, image_summaries = generate_img_summaries(fpath)

多模态检索器

有了摘要,就可以构建多模态检索器了。

多向量检索器

我们将建立一个多向量检索器(MultiVectorRetriever),它接受向量存储、文档存储、id_keysearch_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 in enumerate(doc_summaries)
        ]
        retriever.vectorstore.add_documents(summary_docs)
        retriever.docstore.mset(list(zip(doc_ids, doc_contents)))

    # 添加文本、表格和图像(非空才添加)
    if text_summaries:
        add_documents(retriever, text_summaries, texts)
    if table_summaries:
        add_documents(retriever, table_summaries, tables)
    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

完整代码已整理在GitHub仓库中,你可以直接下载使用(仓库地址:https://github.com/bhargobdeka/advanced-RAG-app——该仓库包含本文涉及的所有代码文件)。

接下来我们还会继续介绍多模态RAG链的构建、LLM性能评估以及Streamlit界面的具体实现,敬请期待。

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多