多模态RAG实战:Python代码实现AI对图片、表格和文本的综合理解

探索多模态RAG!本文介绍如何用Python实现AI同时理解图片、表格和文本,提升信息检索精度,解锁RAG新境界。

原文标题:多模态RAG实战指南:完整Python代码实现AI同时理解图片、表格和文本

原文作者:数据派THU

冷月清谈:

本文深入探讨了多模态RAG系统的构建,该系统旨在有效处理包含图像、表格和文本等多种信息载体的文档。文章核心在于介绍一种结合模态特定处理和后期融合的技术架构,该架构在信息保留、灵活性和检索精度方面表现出色。关键步骤包括:

1. **结构保留的文档分割**:将文档分解为可管理的片段,同时保持逻辑结构和内容关联,确保相关内容在分割后依然关联。
2. **模态特定内容提取**:针对不同模态(文本、图像、表格)采用专用工具进行内容提取,避免通用方法可能导致的次优结果。
3. **关系保留的HTML转换**:将提取的多模态内容转换为结构化HTML格式,利用语义HTML5标签保留内容元素间的语义含义,为后续处理提供统一的数据基础。
4. **关系保留的语义分块**:将HTML内容划分为语义完整的片段,同时维护元素间的关联关系。使用图数据结构显式表示块间关系,支持沿关系链查找相关内容。
5. **多模态向量化与存储**:将语义块转换为向量表示,并存储在向量数据库中。采用模态特定的向量化方法,有效捕获各种模态的语义内容特征。

此外,文章还介绍了如何进行查询处理以及系统集成实现,并对比分析了该方案的优势,强调其在混合模态处理能力、关系保留机制、自适应检索能力和实际可行性等方面的突出表现。最后,文章展望了多模态RAG系统从实验阶段向生产阶段迁移的关键技术问题,为构建能够有效处理复杂文档的RAG系统提供了有价值的参考。

怜星夜思:

1、文章中提到,相比于统一嵌入方法,该多模态RAG系统处理复杂查询时的性能提升了23%。这个提升是如何量化的?实际应用中,哪些类型的复杂查询能更明显地体现这种优势?
2、文章提到了使用HTML作为多模态内容的标准化表示,这样做有什么优缺点?有没有其他更适合多模态RAG的标准化格式?
3、文章中提到,对于图像嵌入,使用了`clip-ViT-B-32`模型。在实际应用中,如何选择合适的图像嵌入模型?除了`clip-ViT-B-32`,还有哪些值得尝试的模型?

原文内容

源:DeepHub IMBA
本文共5600字,建议阅读10+分钟
本文提出的多模态RAG方法采用模态特定处理、后期融合和关系保留的技术架构,在性能表现、准确性指标和实现复杂度之间实现了最佳平衡。


传统RAG系统在处理纯文本应用场景中已展现出显著效果,然而现实世界的信息载体往往呈现多模态特征。文档中普遍包含图像、表格、图表等承载关键信息的视觉元素,这些多模态内容的有效处理正是多模态RAG系统的核心价值所在。

多模态RAG最优方案选择

经过系统性研究和实验验证,我们将介绍一个在RAG系统中处理多模态内容的最佳实现方案。该方案在性能表现、准确性指标和实现复杂度之间实现了优化平衡。

图1:多模态RAG系统整体架构图,展示从文档处理到向量化存储的完整工作流程

架构优势分析

架构采用模态特定处理与后期融合相结合的技术路线。相比其他技术方案,该架构具有以下显著优势:

首先,在模态信息保留方面,该方法避免了统一嵌入方法可能导致的模态特有信息丢失问题,通过针对各模态优化的专用工具实现精确的内容类型处理。其次,系统具备良好的灵活性和模块化特征,支持单独组件的升级优化(例如更换更高性能的图像理解模型),而无需重构整个系统架构。

在检索精度方面,研究数据表明,该方法在处理复杂多模态查询时的性能相比统一方法提升23%。同时,该架构基于广泛可用的开源工具和模型构建,确保了大多数组织的技术可达性和实施可行性。

多模态文档处理工作流程

以下详细阐述推荐工作流程的各个环节,说明各组件如何协同工作以构建统一的系统架构:

图2:多模态RAG方法的连接工作流程图

1、结构保留的文档分割

该模块的核心功能是将文档分解为可管理的片段,同时保持其逻辑结构和不同内容类型之间的关联关系。

结构感知分割对于系统性能至关重要,它确保相关内容(如图像及其标题)在分割过程中保持关联,这对准确理解和检索具有决定性作用。

 importfitz  # PyMuPDF  

defsplit_pdf_by_structure(pdf_path):  
    “”“根据PDF文档的逻辑结构进行拆分。”“”  
    doc=fitz.open(pdf_path)  
    sections=  
      
    # 提取文档结构(简化示例)
    toc=doc.get_toc()  
    iftoc:  
        # 使用目录进行结构化拆分
        fori, (level, title, page) inenumerate(toc):  
            next_page=toc[i+1][2] ifi<len(toc)-1elselen(doc)  
            section= {  
                “title”: title,  
                “start_page”: page-1,  # 0 索引
                “end_page”: next_page-1,  
                “level”: level  
            }  
            sections.append(section)  
    else:  
        # 回退到页面级拆分
        foriinrange(len(doc)):  
            sections.append({  
                “title”: f"Page {i+1}",  
                “start_page”: i,  
                “end_page”: i,  
                “level”: 1  
            })  
      
     returnsections, doc


研究结果表明,在分割过程中保持文档结构能够显著提升多模态内容的检索质量指标。

2、模态特定内容提取

该模块采用针对特定模态优化的专用工具处理各类内容(文本、图像、表格)。

不同内容类型需要采用相应的处理技术才能有效提取其信息内容,通用方法往往产生次优结果。 

 defextract_multimodal_content(sections, doc):  
    """使用专用工具从每种模态中提取内容。"""  
    extracted_content= []  
      
    forsectioninsections:  
        section_content= {  
            "title": section["title"],  
            "level": section["level"],  
            "text_elements": [],  
            "images": [],  
            "tables": []  
        }  
          
        # 处理节中的每个页面
        forpage_numinrange(section["start_page"], section["end_page"] +1):  
            page=doc[page_num]  
              
            # 使用 PyMuPDF 的文本提取功能提取文本
            text_blocks=page.get_text("blocks")  
            forblockintext_blocks:  
                ifblock[6] ==0:  # 文本块
                    section_content["text_elements"].append({  
                        "text": block[4],  
                        "bbox": block[:4],  
                        "page": page_num  
                    })  
              
            # 使用 PyMuPDF 的图像提取功能提取图像
            image_list=page.get_images(full=True)  
            forimg_index, img_infoinenumerate(image_list):  
                xref=img_info[0]  
                base_image=doc.extract_image(xref)  
                image_data= {  
                    "image_data": base_image["image"],  
                    "extension": base_image["ext"],  
                    "bbox": page.get_image_bbox(img_info),  
                    "page": page_num  
                }  
                section_content["images"].append(image_data)  
              
            # 使用专门的表格提取工具提取表格
            # 在此示例中,我们将使用简化方法
            tables=extract_tables_from_page(page)  
            fortableintables:  
                section_content["tables"].append({  
                    "data": table,  
                    "page": page_num  
                })  
          
        extracted_content.append(section_content)  
      
    returnextracted_content  

defextract_tables_from_page(page):  
    “”"  
    使用专门的表格检测从页面中提取表格。
    在生产系统中,您将使用专用的表格提取
    库,如 Camelot、Tabula 或深度学习模型。
    “”"  
    # 为说明目的简化实现
    tables=  
    # 使用启发式或机器学习来识别表格区域
    # 然后从这些区域提取结构化数据
     returntables


3、关系保留的HTML转换

该模块将提取的多模态内容转换为结构化HTML格式,同时保留内容元素间的关联关系。

HTML作为标准化格式能够有效表示混合模态内容并保持结构完整性,为后续处理提供理想的数据基础。

frombs4importBeautifulSoup  
importos  
importbase64  

defconvert_to_structured_html(extracted_content, output_dir):  
    “”“将提取的多模态内容转换为保留关系的结构化 HTML。”“”  
    os.makedirs(output_dir, exist_ok=True)  
    html_files=  
      
    forsectioninextracted_content:  
        # 为此部分创建一个新的 HTML 文档
        soup=BeautifulSoup(“<article></article>”, “html.parser”)  
        article=soup.find(“article”)  
          
        # 添加节标题
        header=soup.new_tag(f"h{section[‘level’]}“)  
        header.string=section[“title”]  
        article.append(header)  
          
        # 按页面和位置对所有元素进行排序
        all_elements=  
          
        # 添加文本元素
        fortext_eleminsection[“text_elements”]:  
            all_elements.append({  
                “type”: “text”,  
                “data”: text_elem,  
                “page”: text_elem[“page”],  
                “y_pos”: text_elem[“bbox”][1]  # 用于排序的 y 坐标
            })  
          
        # 添加图像
        fori, img_data_iteminenumerate(section[“images”]):  
            # 将图像保存到文件
            img_filename=f”{section[‘title’].replace(’ ', ‘‘)}img{i}.{img_data_item[‘extension’]}"  
            img_path=os.path.join(output_dir, img_filename)  
            withopen(img_path, “wb”) asf:  
                f.write(img_data_item[“image_data”])  
              
            all_elements.append({  
                “type”: “image”,  
                “data”: {  
                    “path”: img_path,  
                    “bbox”: img_data_item[“bbox”]  
                },  
                “page”: img_data_item[“page”],  
                “y_pos”: img_data_item[“bbox”][1]  # 用于排序的 y 坐标
            })  
          
        # 添加表格
        fori, tableinenumerate(section[“tables”]):  
            all_elements.append({  
                “type”: “table”,  
                “data”: table[“data”],  
                “page”: table[“page”],  
                “y_pos”: 0  # 在生产环境中会使用实际位置
            })  
          
        # 按页面然后按 y 位置对元素进行排序
        all_elements.sort(key=lambdax: (x[“page”], x[“y_pos”]))  
          
        # 按正确顺序将元素添加到 HTML
        foreleminall_elements:  
            ifelem[“type”] ==“text”:  
                p=soup.new_tag(“p”)  
                p.string=elem[“data”][“text”]  
                article.append(p)  
              
            elifelem[“type”] ==“image”:  
                figure=soup.new_tag(“figure”)  
                img_tag=soup.new_tag(“img”, src=elem[“data”][“path”])  
                figure.append(img_tag)  
                  
                # 查找潜在的标题(图像正下方的文本元素)
                idx=all_elements.index(elem)  
                ifidx+1<len(all_elements) andall_elements[idx+1][“type”] ==“text”:  
                    next_elem=all_elements[idx+1]  
                    ifnext_elem[“page”] ==elem[“page”] andnext_elem[“y_pos”] -elem[“y_pos”] <50:  
                        # 这段文字很可能是一个标题
                        figcaption=soup.new_tag(“figcaption”)  
                        figcaption.string=next_elem[“data”][“text”]  
                        figure.append(figcaption)  
                  
                article.append(figure)  
              
            elifelem[“type”] ==“table”:  
                # 将表格数据转换为 HTML 表格
                table_tag=soup.new_tag(“table”)  
                forrow_datainelem[“data”]:  
                    tr=soup.new_tag(“tr”)  
                    forcellinrow_data:  
                        td=soup.new_tag(“td”)  
                        td.string=str(cell)  
                        tr.append(td)  
                    table_tag.append(tr)  
                  
                article.append(table_tag)  
          
        # 保存 HTML 文件
        html_filename=f"{section[‘title’].replace(’ ', '
’)}.html"  
        html_path=os.path.join(output_dir, html_filename)  
        withopen(html_path, “w”, encoding=“utf-8”) asf:  
            f.write(str(soup))  
          
        html_files.append(html_path)  
      
     returnhtml_files


在实施过程中,建议使用语义HTML5标签(如<figure><figcaption><table><section>)来保留不同内容元素的语义含义,而非仅关注其视觉呈现效果。

4、关系保留的语义分块

HTML转换为多模态内容的标准化表示提供了统一的处理基础,同时保持了结构完整性。

该模块将HTML内容划分为语义完整的片段,同时维护不同元素间的关联关系。

有效的分块策略对检索质量具有决定性影响。过大的块会降低检索精度,而过小的块则会丢失重要的上下文信息。

frombs4importBeautifulSoup  
importnetworkxasnx  

defcreate_semantic_chunks_with_relationships(html_files, max_chunk_size=1000):  
    “”“创建语义块,同时保留元素之间的关系。”“”  
    chunks=  
    relationship_graph=nx.DiGraph()  
      
    forhtml_fileinhtml_files:  
        withopen(html_file, “r”, encoding=“utf-8”) asf:  
            html_content=f.read()  
          
        soup=BeautifulSoup(html_content, “html.parser”)  
          
        # 提取节标题
        section_title=soup.find([“h1”, “h2”, “h3”, “h4”, “h5”, “h6”]).get_text()  
        section_id=f"section_{len(chunks)}"  
          
        # 将节节点添加到关系图
        relationship_graph.add_node(section_id, type=“section”, title=section_title)  
          
        # 查找用于分块的语义边界
        boundaries=soup.find_all([“h1”, “h2”, “h3”, “h4”, “h5”, “h6”, “section”])  
          
        iflen(boundaries) <=1:  
            # 没有内部分界线,处理整个部分
            current_chunk= {  
                “id”: f"chunk_{len(chunks)}“,  
                “html”: str(soup),  
                “text”: soup.get_text(separator=” “, strip=True),  
                “parent”: section_id  
            }  
            chunks.append(current_chunk)  
            relationship_graph.add_node(current_chunk[“id”], type=“chunk”)  
            relationship_graph.add_edge(section_id, current_chunk[“id”], relation=“contains”)  
        else:  
            # 处理每个子部分
            foriinrange(len(boundaries) -1):  
                start=boundaries[i]  
                end=boundaries[i+1]  
                  
                # 收集开始和结束之间的所有元素
                elements=  
                current=start.next_sibling  
                whilecurrentandcurrent!=end:  
                    ifcurrent.name:  # 跳过 NavigableString
                        elements.append(current)  
                    current=current.next_sibling  
                  
                # 从这些元素创建块
                ifelements:  
                    chunk_soup=BeautifulSoup(”<div></div>“, “html.parser”)  
                    chunk_div=chunk_soup.find(“div”)  
                      
                    # 添加标题
                    chunk_div.append(start.copy())  
                      
                    # 添加所有元素
                    forelementinelements:  
                        chunk_div.append(element.copy())  
                      
                    # 检查块是否太大
                    chunk_text=chunk_div.get_text(separator=” “, strip=True)  
                    iflen(chunk_text) >max_chunk_size:  
                        # 进一步拆分此块
                        sub_chunks=split_large_chunk(chunk_div, max_chunk_size)  
                        forsub_chunkinsub_chunks:  
                            sub_id=f"chunk_{len(chunks)}”  
                            sub_chunk_obj= {  
                                “id”: sub_id,  
                                “html”: str(sub_chunk),  
                                “text”: sub_chunk.get_text(separator=" “, strip=True),  
                                “parent”: section_id  
                            }  
                            chunks.append(sub_chunk_obj)  
                            relationship_graph.add_node(sub_id, type=“chunk”)  
                            relationship_graph.add_edge(section_id, sub_id, relation=“contains”)  
                    else:  
                        # 按原样添加块
                        chunk_id=f"chunk_{len(chunks)}”  
                        chunk_obj= {  
                            “id”: chunk_id,  
                            “html”: str(chunk_div),  
                            “text”: chunk_text,  
                            “parent”: section_id  
                        }  
                        chunks.append(chunk_obj)  
                        relationship_graph.add_node(chunk_id, type=“chunk”)  
                        relationship_graph.add_edge(section_id, chunk_id, relation=“contains”)  
          
        # 为图像和表格添加特殊处理,以确保它们正确连接
        process_special_elements(soup, chunks, relationship_graph)  
      
    returnchunks, relationship_graph  

defsplit_large_chunk(chunk_div, max_chunk_size):  
    “”“根据段落将大块拆分为较小的块。”“”  
    # 为简洁起见,省略了实现细节
    return [chunk_div]  # 占位符

defprocess_special_elements(soup, chunks, graph):  
    “”“处理图像和表格以确保正确的••关系。”“”  
    # 为简洁起见,省略了实现细节
     pass


在实施中,建议使用图数据结构显式表示块间关系。这种方法支持更复杂的检索策略,能够沿着关系链路查找相关内容。

5、多模态向量化与存储

该模块将语义块转换为向量表示,并将其存储在向量数据库中以实现高效检索。

不同模态需要采用相应的向量化方法才能有效捕获其语义内容特征。

图3:推荐方法采用模态特定处理和后期融合的技术架构

fromsentence_transformersimportSentenceTransformer  
fromPILimportImage  
importtorch  
importchromadb  
importjson  

defvectorize_and_store_multimodal_chunks(chunks, relationship_graph, output_dir):  
    “”“使用特定模态模型对块进行矢量化,并与关系一起存储。”“”  
    # 初始化嵌入模型
    text_embedder=SentenceTransformer(“all-MiniLM-L6-v2”)  
    image_embedder=SentenceTransformer(“clip-ViT-B-32”)  
      
    # 初始化向量数据库
    client=chromadb.Client()  
    collection=client.create_collection(name=“multimodal_docs”)  
      
    # 处理每个块
    forchunkinchunks:  
        # 解析 HTML
        soup=BeautifulSoup(chunk[“html”], “html.parser”)  
          
        # 提取用于嵌入的文本
        text_content=soup.get_text(separator=" “, strip=True)  
          
        # 提取用于多模态嵌入的图像
        images=soup.find_all(“img”)  
        image_embeddings=  
          
        forimg_taginimages:  
            try:  
                # 加载图像并生成嵌入
                img_path=img_tag[“src”]  
                img_embedding=image_embedder.encode(Image.open(img_path))  
                image_embeddings.append(img_embedding)  
            exceptExceptionase:  
                print(f"Error processing image {img_tag.get(‘src’, ‘unknown’)}: {e}”)  
          
        # 生成文本嵌入
        text_embedding=text_embedder.encode(text_content)  
          
        # 合并嵌入(简化方法)
        # 在生产环境中,您将使用更复杂的融合技术
        final_embedding=text_embedding  
        ifimage_embeddings:  
            # 平均图像嵌入
            avg_img_embedding=sum(image_embeddings) /len(image_embeddings)  
            # 与文本嵌入连接并规范化
            final_embedding=torch.cat([  
                torch.tensor(text_embedding),   
                torch.tensor(avg_img_embedding)  
            ]).mean(dim=0).numpy()  
          
        # 获取关系元数据
        relationships=  
        foredgeinrelationship_graph.edges(chunk[“id”]):  
            source, target=edge  
            relationships.append({  
                “source”: source,  
                “target”: target,  
                “relation”: relationship_graph.edges[edge].get(“relation”, “related”)  
            })  
          
        # 存储在向量数据库中
        collection.add(  
            ids=[chunk[“id”]],  
            embeddings=[final_embedding.tolist()],  
            metadatas=[{  
                “html_content”: chunk[“html”],  
                “parent”: chunk.get(“parent”, “”),  
                “relationships”: json.dumps(relationships)  
            }],  
            documents=[text_content]  
        )  
      
    # 保存关系图以供检索
    nx.write_gpickle(relationship_graph, f"{output_dir}/relationships.gpickle")  
      
     returncollection


对于生产系统,建议考虑使用更复杂的融合方法(如交叉注意力机制或门控融合),以替代简单的串联或平均方法来组合不同模态的嵌入向量。

检索流程:系统集成实现

在完成多模态RAG系统构建后,以下展示其查询处理机制:

 defretrieve_multimodal_content(query, collection, relationship_graph, k=5):  
    """根据查询检索相关的多模态内容。"""  
    # 分析查询以确定相关模态
    query_modalities=analyze_query_modalities(query)  
      
    # 生成查询嵌入
    if"image"inquery_modalities:  
        # 对于有关图像的查询,请使用图像感知嵌入器
        query_embedding=image_text_embedder.encode(query)  # 假设 image_text_embedder 已定义
    else:  
        # 对于纯文本查询,请使用文本嵌入器
        query_embedding=text_embedder.encode(query)  # 假设 text_embedder 已定义
      
    # 执行初始检索
    results=collection.query(  
        query_embeddings=[query_embedding.tolist()],  
        n_results=k  
    )  
      
    # 利用关系感知增强结果
    enhanced_results=enhance_with_relationships(  
        results, relationship_graph, query, collection  
    )  
      
    returnenhanced_results  

defanalyze_query_modalities(query):  
    “”“分析查询以确定其针对的模态。”“”  
    # 基于关键字的简单方法
    image_keywords= [“image”, “picture”, “photo”, “figure”, “diagram”, “chart”]  
    table_keywords= [“table”, “data”, “row”, “column”, “cell”]  
      
    modalities= [“text”]  
      
    ifany(keywordinquery.lower() forkeywordinimage_keywords):  
        modalities.append(“image”)  
      
    ifany(keywordinquery.lower() forkeywordintable_keywords):  
        modalities.append(“table”)  
      
    returnmodalities  

defenhance_with_relationships(results, graph, query, collection):  
    “”“使用关系信息增强检索结果。”“”  
    enhanced_results=  
    retrieved_ids=set()  
      
    fori, result_idinenumerate(results[“ids”][0]):  
        retrieved_ids.add(result_id)  
        enhanced_results.append({  
            “id”: result_id,  
            “text”: results[“documents”][0][i],  
            “metadata”: results[“metadatas”][0][i],  
            “score”: results[“distances”][0][i] if"distances"inresultselse1.0-i/len(results[“ids”][0])  
        })  
      
    # 查找可能相关的相关块
    forresultinenhanced_results[:]:  # 复制以避免在迭代期间修改
        # 从元数据中获取关系
        relationships=json.loads(result[“metadata”].get(“relationships”, “”))  
          
        forrelinrelationships:  
            related_id=rel[“target”]  
            ifrelated_idnotinretrieved_ids:  
                # 检查此相关块是否与查询相关
                related_metadata=collection.get(ids=[related_id])  
                ifrelated_metadataandrelated_metadata[“ids”]:  
                    related_text=related_metadata[“documents”][0]  
                      
                    # 简单相关性检查(在生产环境中会更复杂)
                    ifany(terminrelated_text.lower() forterminquery.lower().split()):  
                        retrieved_ids.add(related_id)  
                        enhanced_results.append({  
                            “id”: related_id,  
                            “text”: related_text,  
                            “metadata”: related_metadata[“metadatas”][0],  
                            “score”: result[“score”] *0.9,  # 相关内容的得分略低
                            “relation”: "related to "+result[“id”]  
                        })  
      
    # 按分数排序
    enhanced_results.sort(key=lambdax: x[“score”], reverse=True)  
      
     returnenhanced_results


方法优势对比分析

推荐方案相比其他技术路线在以下关键维度具有显著优势:

在混合模态处理能力方面,通过使用专用工具处理各模态后进行结果整合,能够捕获每种内容类型的独特特征。在关系保留机制上,通过显式建模和保留内容元素间的关系,维护了准确理解和检索所需的上下文信息。

在自适应检索能力方面,检索过程能够根据查询的模态需求进行适应性调整,确保无论内容格式如何都能检索到最相关的信息。在实际可行性层面,该方法基于广泛可用的工具和模型实现,为大多数组织提供了良好的技术可达性。

总结

本文提出的多模态RAG方法采用模态特定处理、后期融合和关系保留的技术架构,在性能表现、准确性指标和实现复杂度之间实现了最佳平衡。通过遵循该技术路线,能够构建一个有效处理复杂文档中全部信息的RAG系统。

在后续研究中,我们将重点探讨多模态RAG系统从实验阶段向生产就绪阶段的迁移方法,着重关注系统可扩展性、监控机制和持续优化策略等关键技术问题。

参考文献

Lang Mei, Siyu Mo, Zhihan Yang, Chong Chen. “A Survey of Multimodal  Retrieval-Augmented Generation.” arXiv:2504.08748, March 2025.

“Multimodal Queries Require Multimodal RAG: Researchers from KAIST and DeepAuto.ai  Propose UniversalRAG.” MarkTechPost, May 2025.

Shah, Suruchi and Dharmapuram, Suraj. “Bridging Modalities: Multimodal RAG  for Advanced Information Retrieval.” InfoQ, April 2025.

“How Multimodal RAG unlocks human-like reasoning in real-time.” LinkedIn Pulse, March 2025.

“Trends in Active Retrieval Augmented Generation: 2025 and Beyond.” Signity Solutions, February 2025.

作者:Ashwindevelops


辑:黄继彦



关于我们

数据派THU作为数据科学类公众号,背靠清华大学大数据研究中心,分享前沿数据科学与大数据技术创新研究动态、持续传播数据科学知识,努力建设数据人才聚集平台、打造中国大数据最强集团军。




新浪微博:@数据派THU

微信视频号:数据派THU

今日头条:数据派THU


23%的提升,我持保留态度。除非他们公布了详细的实验设置、数据集和评估方法,否则这个数字可能只是一个“实验室指标”。不过,多模态RAG在特定场景下的优势是毋庸置疑的。比如说,在法律文档分析中,需要同时理解合同文本和相关的扫描件印章,这种场景下,多模态RAG肯定比只处理文本的RAG更有效。

我猜这23%的提升可能是基于一个专门设计的多模态数据集benchmark得出的。他们可能定义了一系列评估指标,例如准确率、召回率、MRR(Mean Reciprocal Rank)等。实际应用中,我认为在需要跨模态推理的场景下,这种优势会更加明显。例如,用户提问“这张图表说明了什么趋势,和报告正文中的哪一部分相关?”,这种问题需要系统能够理解图表中的数据,并将其与文本信息关联起来。

HTML的优点在于它的通用性和结构性,几乎所有编程语言和工具都支持HTML的解析和生成。缺点也很明显,HTML主要还是为网页设计服务的,对于表格这种结构化数据的表示可能不够简洁高效。我觉得可以考虑使用Markdown或者reStructuredText,它们更注重内容本身,而且可以方便地嵌入各种类型的媒体。

HTML挺好的,要啥自行车?都2024年了,还在纠结格式?能跑就行!实在不行,把所有内容都塞到JSON里,简单粗暴!

好问题!文章里提到的23%的性能提升,应该是通过对比实验量化的。具体来说,可能是用一系列包含多种模态信息(比如图文结合的问题)的查询,分别用统一嵌入方法和这个多模态RAG系统进行检索,然后比较两种方法返回结果的准确率、召回率或者F1值等指标得出的。这种提升在处理需要结合图片和文字上下文理解的复杂查询时会更明显,例如,“这张图里的产品是什么,它的主要参数有哪些?”

我认为选择HTML主要是考虑到它的可扩展性和兼容性。HTML5支持各种多媒体元素,而且可以通过CSS进行灵活的样式控制。当然,如果追求更高的效率,可以考虑使用Apache Arrow这种列式存储格式,它特别适合处理表格数据,而且可以与多种数据处理框架无缝集成。不过,Arrow的缺点在于对非结构化数据的支持可能不够好。

除了clip-ViT-B-32,还可以考虑OpenAI的CLIP更大版本,或者Google的ALIGN模型。这些模型通常在更大的数据集上进行预训练,能够学习到更丰富的图像特征。另外,如果你的计算资源有限,可以尝试MobileNet这种轻量级的模型,虽然精度可能稍逊,但速度更快。

图像嵌入这块水太深了,各种模型层出不穷。我的建议是,先用clip-ViT-B-32跑通流程,然后根据实际效果再考虑是否更换模型。别一开始就追求“最佳模型”,很容易陷入调参地狱。

选择图像嵌入模型主要看应用场景和需求。clip-ViT-B-32是一个不错的通用选择,因为它在多个视觉任务上表现良好,而且有开源实现。如果你的应用对图像的细粒度特征有更高的要求,可以尝试ResNet、EfficientNet等更深层的模型。另外,如果你的数据集包含特定领域的图像(比如医学影像),最好使用在该领域预训练过的模型。