LLM之RAG实战(三十三)| 探索RAG在Table的应用

       实现RAG是一个挑战,尤其是在有效解析和理解非结构化文档中的表格时,对于扫描的文档或图像格式的文档来说尤其困难。这些挑战至少有三个方面:

  • 扫描文档或图像文档的复杂性,如其多元化的结构、非文本元素以及手写和打印内容的组合,这给自动化准确提取表格信息带来了挑战。解析不准确会破坏表的结构,使用不完整的表进行嵌入不仅无法捕获表的语义信息,而且很容易破坏RAG结果;
  • 如何提取表格标题并将其有效地链接到各自的表格;
  • 如何设计索引结构来有效地存储表的语义信息。

       本文将介绍RAG中管理表格数据的关键技术,然后回顾一些现有的开源解决方案,最后实现一个解决方案。

一、关键技术

1.1 表格分析

       该模块的主要功能是从非结构化文档或图像中准确提取表结构。最好可以提取出相应的表标题,这样方便开发人员将表标题与表关联起来。

       根据我目前的理解,有几种方法,如图1所示:

(a)利用多模态LLM(如GPT-4V[1])来识别表格并从每个PDF页面中提取信息

输入:图像格式的PDF页面

输出:JSON或其他格式的表。如果多模态LLM无法提取表格数据,则应总结图像并返回摘要。

(b)利用专业的表格检测模型(如Table Transformer[2]),来辨别表格结构

输入:PDF页面作为图像

输出:表格作为图像

(c)使用开源框架(如unstructured[3]或者目标检测模型[4]。这些框架可以对整个文档进行全面的解析,并从解析的结果中提取与表相关的内容

输入:PDF或图像格式的文档

输出:纯文本或HTML格式的表,从整个文档的解析结果中获得

(d)使用Nougat[5]、Donut[6]等端到端模型来解析整个文档并提取与表相关的内容。这种方法不需要OCR模型

输入:PDF或图像格式的文档

输出:LaTeX或JSON格式的表,从整个文档的解析结果中获得

       值得一提的是,无论使用何种方法提取表格信息,都应包括表格标题。这是因为在大多数情况下,表格标题是文档或论文作者对表格的简短描述,可以在很大程度上概括整个表格。

       在上述四种方法中,方法(d)允许容易地检索表标题,这将在下面的实验中进一步解释。

1.2 索引结构

       根据索引的结构,大致可以分为以下几类:

(e)仅使用图像格式的索引表;

(f)仅使用纯文本或JSON格式的索引表;

(g)仅使用LaTeX格式的索引表;

(h)仅为表的摘要编制索引;

(i)“从小到大”或“文档摘要索引”结构,如图2所示:

  • 小块的内容可以是来自表的每一行的信息或表的摘要。
  • 大块的内容可以是图像格式、纯文本格式或LaTeX格式的表。

如上所述,表格摘要通常使用LLM生成:

输入:图像格式、文本格式或LaTeX格式的表格

输出:表格摘要

1.3 不需要表解析、索引或RAG的算法

下面介绍一些不需要表解析的算法:

(j)将相关图像(PDF页面)和用户查询发送到VQA模型(如DAN等)或多模态LLM,并返回答案;

要索引的内容:图像格式的文档

发送到VQA模型或多模态LLM的内容:查询+图像形式的相应页面

(k)将相关文本格式的PDF页面和用户的查询发送到LLM,然后返回答案;

要索引的内容:文本格式的文档

发送到LLM的内容:查询+文本格式的相应页面

(l)将相关图像(PDF页面)、文本块和用户的查询发送到多模态LLM(如GPT-4V等),并直接返回答案;

要索引的内容:图像格式的文档和文本格式的文档块

发送到多模态LLM的内容:查询+文档的相应图像形式+相应的文本块

以下是一些不需要索引的方法,如图3和图4所示:

(m)首先,应用类别(a)到(d)中的一种方法,将文档中的所有表格解析为图像形式,然后直接将所有表格图像和用户的查询发送到多模态LLM(如GPT-4V等)并返回答案。

要索引的内容:无

发送到多模态LLM的内容:查询+所有解析的表(图像格式)

(n)使用(m)提取的图像格式的表格,然后使用OCR模型识别表格中的所有文本,然后直接将表格中的全部文本和用户的查询发送到LLM并直接返回答案。

要索引的内容:无

发送到LLM的内容:用户查询+所有表内容(文本格式)

值得注意的是,有些方法不依赖于RAG过程:

       第一种方法不使用LLM,在特定的数据集上进行训练,并使模型(如类似BERT的transformer)能够更好地支持表理解任务,如TAPAS[7]。

       第二种方法使用LLM,采用预训练、微调方法或提示,使LLM能够执行表理解任务,如GPT4Table[8]。

二、现有的开源解决方案

       上一节总结并对RAG中表格关键技术进行了分类。在提出本文实现的解决方案之前,让我们探索一些开源解决方案。

LlamaIndex支持四种方法[9],前三种都是使用多模态模型:

  • 检索相关图像(PDF页面)并将其发送到GPT-4V以响应查询;
  • 将每个PDF页面视为一个图像,让GPT-4V对每个页面进行图像推理,为图像推理构建文本矢量存储索引,根据图像推理矢量存储查询答案;
  • 使用Table Transformer从检索到的图像中裁剪表信息,然后将这些裁剪的图像发送到GPT-4V以进行查询响应;
  • 对裁剪的表图像应用OCR,并将数据发送到GPT4/GPT-3.5以回答查询。

根据本文提出方法进行分类总结:

  • 第一种方法类似于本文中的类别(j),不需要表格解析。然而,结果表明,即使答案在图像中,也无法产生正确的答案;
  • 第二种方法涉及表格解析,对应于类别(a)。索引内容是基于GPT-4V返回的结果的表内容或摘要,其可以对应于类别(f)或(h)。这种方法的缺点是GPT-4V识别表格并从图像中提取其内容的能力是不稳定的,特别是当图像包括表格、文本和其他图像的混合时,这在PDF格式中很常见;
  • 第三种方法,类似于类别(m),不需要索引;
  • 第四种方法类似于类别(n),也不需要索引。其结果表明,由于无法从图像中提取表格信息,因此会产生不正确的答案。

通过试验发现,第三种方法的综合效果最好。然而,根据我的测试,第三种方法很难检测表格,更不用说正确地将表标题与表合并了。

Langchain还提出了一些解决方案,半结构化RAG[10]的关键技术包括:

  • 表格解析使用unstructured,即类别(c);
  • 索引方法是文档摘要索引,对应类别(i),小块内容:表摘要,大块内容:原始表内容(文本格式)。

如图5所示:

半结构化和多模态RAG[11]提出了三种解决方案,其架构如图6所示。

       可选方案1:类似于本文的类别(l)。它包括使用多模态嵌入(如CLIP)来嵌入图像和文本,使用相似性搜索进行检索,并将原始图像和块传递给多模式LLM进行答案合成。

       可选方案2:利用多模态LLM,如GPT-4V、LLaVA或FUYU-8b,从图像中生成文本摘要。然后,嵌入和检索文本,并将文本块传递给LLM进行答案合成。

  • 表解析使用非结构化,即类别(d);
  • 索引结构为文档摘要索引(catogery(i)),小块内容:表摘要,大块内容:文本格式的表。

      可选方案3:使用多模态LLM(如GPT-4V、LLaVA或FUYU-8b)从图像中生成文本摘要,然后嵌入并检索参考原始图像的图像摘要(catogery(i)),然后将原始图像和文本块传递给多模态LLM。

三、建议的解决方案

       本文对关键技术和现有解决方案进行了总结、分类和讨论。基于此,我们提出了以下解决方案,如图7所示。为了简单起见,省略了一些RAG模块,如重新排序和查询重写。

  • 表格解析:使用Nougat(catogery(d))。根据我的测试,它的表格检测比unstructured的更有效(catogery(c))。此外,Nougat可以很好地提取表格标题,非常方便与表格关联;
  • 文档摘要索引结构(catogery(i)):小块的内容包括表格摘要,大块的内容包括LaTeX格式的相应表格和文本格式的表格标题。我们使用多向量检索器[12]来实现它;

  • 表格摘要获取方法:将表格和表格标题发送给LLM进行摘要。

      这种方法的优点是,它可以有效地解析表,同时综合考虑表摘要和表之间的关系,而且还不需要多模型LLM的需求,从而节省了成本。

3.1 Nougat的原理

       Nougat[13]是在Donut[14]的基础上开发的。它通过网络隐式识别文本,不需要任何与OCR相关的输入或模块,如图8所示:

       Nougat不仅可以解析表格数据,而且还可以解析公式,也可以方便地关联表标题,如图9所示:

       Nougat是一个缺乏中间结果的端到端模型,它可能严重依赖于其训练数据。

      根据格式化训练数据的代码[15],对于表格,紧接在\end{table}后面的行是caption_parts,这似乎与所提供的训练数据的格式一致:

def format_element(    element: Element, keep_refs: bool = False, latex_env: bool = False) -> List[str]:    """    Formats a given Element into a list of formatted strings.    Args:        element (Element): The element to be formatted.        keep_refs (bool, optional): Whether to keep references in the formatting. Default is False.        latex_env (bool, optional): Whether to use LaTeX environment formatting. Default is False.    Returns:        List[str]: A list of formatted strings representing the formatted element.    """    ...    ...    if isinstance(element, Table):        parts = [            "[TABLE%s]\n\\begin{table}\n"            % (str(uuid4())[:5] if element.id is None else ":" + str(element.id))        ]        parts.extend(format_children(element, keep_refs, latex_env))        caption_parts = format_element(element.caption, keep_refs, latex_env)        remove_trailing_whitespace(caption_parts)        parts.append("\\end{table}\n")        if len(caption_parts) > 0:            parts.extend(caption_parts + ["\n"])        parts.append("[ENDTABLE]\n\n")        return parts    ...    ...

3.2 Nougat的优点和缺点

优势:

  • Nougat可以将以前解析工具(如公式和表格)具有挑战性的部分准确解析为LaTeX源代码;
  • Nougat的解析结果是一个类似markdown的半结构化文档;
  • 轻松获取表格标题,并方便地将其与表格关联。

缺点:

  • Nougat的解析速度较慢,这可能对大规模部署构成挑战;
  • 由于Nougat是在科学论文上训练的,它擅长于类似结构的文件。对于非拉丁文本文档,其性能会下降;
  • Nougat模型一次只在一篇科学论文的一页上训练,缺乏对其他页面的了解。这可能会导致解析的内容出现一些不一致。因此,如果识别效果不好,可以考虑将PDF分割成单独的页面,并逐一解析;
  • 在两列论文中分析表格不如在单列论文中有效。

3.3 代码实现

首先,安装相关的Python包

pip install langchainpip install chromadbpip install nougat-ocr

安装完成后,我们可以检查Python包的版本:

langchain                                0.1.12langchain-community                      0.0.28langchain-core                           0.1.31langchain-openai                         0.0.8langchain-text-splitters                 0.0.1chroma-hnswlib                           0.7.3chromadb                                 0.4.24nougat-ocr                               0.1.17

设置环境并导入:

import osos.environ["OPENAI_API_KEY"] = "YOUR_OPEN_AI_KEY"import subprocessimport uuidfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAIfrom langchain.retrievers.multi_vector import MultiVectorRetrieverfrom langchain.storage import InMemoryStorefrom langchain_community.vectorstores import Chromafrom langchain_core.documents import Documentfrom langchain_openai import OpenAIEmbeddingsfrom langchain_core.runnables import RunnablePassthrough

       下载论文《Attention Is All You Need》[16]到YOUR_PDF_PATH,使用Nougat解析PDF文件,从解析结果中获得latex格式的表格和文本格式的表格标题。第一次执行将下载必要的模型文件。

def june_run_nougat(file_path, output_dir):    # Run Nougat and store results as Mathpix Markdown    cmd = ["nougat", file_path, "-o", output_dir, "-m", "0.1.0-base", "--no-skipping"]    res = subprocess.run(cmd)     if res.returncode != 0:        print("Error when running nougat.")        return res.returncode    else:        print("Operation Completed!")        return 0def june_get_tables_from_mmd(mmd_path):    f = open(mmd_path)    lines = f.readlines()    res = []    tmp = []    flag = ""    for line in lines:        if line == "\\begin{table}\n":            flag = "BEGINTABLE"        elif line == "\\end{table}\n":            flag = "ENDTABLE"                if flag == "BEGINTABLE":            tmp.append(line)        elif flag == "ENDTABLE":            tmp.append(line)            flag = "CAPTION"        elif flag == "CAPTION":            tmp.append(line)            flag = "MARKDOWN"            print('-' * 100)            print(''.join(tmp))            res.append(''.join(tmp))            tmp = []    return resfile_path = "YOUR_PDF_PATH"output_dir = "YOUR_OUTPUT_DIR_PATH"if june_run_nougat(file_path, output_dir) == 1:    import sys    sys.exit(1)mmd_path = output_dir + '/' + os.path.splitext(file_path)[0].split('/')[-1] + ".mmd" tables = june_get_tables_from_mmd(mmd_path)

       函数june_get_tables_from_mmd用于从图10所示的mmd文件中提取从t\begin{table}到\end{table}的所有内容,包括\end{table}后面的行。

       值得注意的是,没有发现任何官方文件规定表格标题必须放在表格下方,或者表格应以\ begin{table}开头,以\ end{table}结尾。因此,june_get_tables_from_md是启发式的。

以下是解析PDF中表格的结果:

Operation Completed!----------------------------------------------------------------------------------------------------\begin{table}\begin{tabular}{l c c c} \hline \hline Layer Type & Complexity per Layer & Sequential Operations & Maximum Path Length \\ \hline Self-Attention & \(O(n^{2}\cdot d)\) & \(O(1)\) & \(O(1)\) \\ Recurrent & \(O(n\cdot d^{2})\) & \(O(n)\) & \(O(n)\) \\ Convolutional & \(O(k\cdot n\cdot d^{2})\) & \(O(1)\) & \(O(log_{k}(n))\) \\ Self-Attention (restricted) & \(O(r\cdot n\cdot d)\) & \(O(1)\) & \(O(n/r)\) \\ \hline \hline \end{tabular}\end{table}Table 1: Maximum path lengths, per-layer complexity and minimum number of sequential operations for different layer types. \(n\) is the sequence length, \(d\) is the representation dimension, \(k\) is the kernel size of convolutions and \(r\) the size of the neighborhood in restricted self-attention.----------------------------------------------------------------------------------------------------\begin{table}\begin{tabular}{l c c c c} \hline \hline \multirow{2}{*}{Model} & \multicolumn{2}{c}{BLEU} & \multicolumn{2}{c}{Training Cost (FLOPs)} \\ \cline{2-5}  & EN-DE & EN-FR & EN-DE & EN-FR \\ \hline ByteNet [18] & 23.75 & & & \\ Deep-Att + PosUnk [39] & & 39.2 & & \(1.0\cdot 10^{20}\) \\ GNMT + RL [38] & 24.6 & 39.92 & \(2.3\cdot 10^{19}\) & \(1.4\cdot 10^{20}\) \\ ConvS2S [9] & 25.16 & 40.46 & \(9.6\cdot 10^{18}\) & \(1.5\cdot 10^{20}\) \\ MoE [32] & 26.03 & 40.56 & \(2.0\cdot 10^{19}\) & \(1.2\cdot 10^{20}\) \\ \hline Deep-Att + PosUnk Ensemble [39] & & 40.4 & & \(8.0\cdot 10^{20}\) \\ GNMT + RL Ensemble [38] & 26.30 & 41.16 & \(1.8\cdot 10^{20}\) & \(1.1\cdot 10^{21}\) \\ ConvS2S Ensemble [9] & 26.36 & **41.29** & \(7.7\cdot 10^{19}\) & \(1.2\cdot 10^{21}\) \\ \hline Transformer (base model) & 27.3 & 38.1 & & \(\mathbf{3.3\cdot 10^{18}}\) \\ Transformer (big) & **28.4** & **41.8** & & \(2.3\cdot 10^{19}\) \\ \hline \hline \end{tabular}\end{table}Table 2: The Transformer achieves better BLEU scores than previous state-of-the-art models on the English-to-German and English-to-French newstest2014 tests at a fraction of the training cost.----------------------------------------------------------------------------------------------------\begin{table}\begin{tabular}{c|c c c c c c c c|c c c c} \hline \hline  & \(N\) & \(d_{\text{model}}\) & \(d_{\text{ff}}\) & \(h\) & \(d_{k}\) & \(d_{v}\) & \(P_{drop}\) & \(\epsilon_{ls}\) & train steps & PPL & BLEU & params \\ \hline base & 6 & 512 & 2048 & 8 & 64 & 64 & 0.1 & 0.1 & 100K & 4.92 & 25.8 & 65 \\ \hline \multirow{4}{*}{(A)} & \multicolumn{1}{c}{} & & 1 & 512 & 512 & & & & 5.29 & 24.9 & \\  & & & & 4 & 128 & 128 & & & & 5.00 & 25.5 & \\  & & & & 16 & 32 & 32 & & & & 4.91 & 25.8 & \\  & & & & 32 & 16 & 16 & & & & 5.01 & 25.4 & \\ \hline (B) & \multicolumn{1}{c}{} & & \multicolumn{1}{c}{} & & 16 & & & & & 5.16 & 25.1 & 58 \\  & & & & & 32 & & & & & 5.01 & 25.4 & 60 \\ \hline \multirow{4}{*}{(C)} & 2 & \multicolumn{1}{c}{} & & & & & & & & 6.11 & 23.7 & 36 \\  & 4 & & & & & & & & 5.19 & 25.3 & 50 \\  & 8 & & & & & & & & 4.88 & 25.5 & 80 \\  & & 256 & & 32 & 32 & & & & 5.75 & 24.5 & 28 \\  & 1024 & & 128 & 128 & & & & 4.66 & 26.0 & 168 \\  & & 1024 & & & & & & 5.12 & 25.4 & 53 \\  & & 4096 & & & & & & 4.75 & 26.2 & 90 \\ \hline \multirow{4}{*}{(D)} & \multicolumn{1}{c}{} & & & & & 0.0 & & 5.77 & 24.6 & \\  & & & & & & 0.2 & & 4.95 & 25.5 & \\  & & & & & & & 0.0 & 4.67 & 25.3 & \\  & & & & & & & 0.2 & 5.47 & 25.7 & \\ \hline (E) & \multicolumn{1}{c}{} & \multicolumn{1}{c}{} & & \multicolumn{1}{c}{} & & & & & 4.92 & 25.7 & \\ \hline big & 6 & 1024 & 4096 & 16 & & 0.3 & 300K & **4.33** & **26.4** & 213 \\ \hline \hline \end{tabular}\end{table}Table 3: Variations on the Transformer architecture. Unlisted values are identical to those of the base model. All metrics are on the English-to-German translation development set, newstest2013. Listed perplexities are per-wordpiece, according to our byte-pair encoding, and should not be compared to per-word perplexities.----------------------------------------------------------------------------------------------------\begin{table}\begin{tabular}{c|c|c} \hline**Parser** & **Training** & **WSJ 23 F1** \\ \hline Vinyals \& Kaiser et al. (2014) [37] & WSJ only, discriminative & 88.3 \\ Petrov et al. (2006) [29] & WSJ only, discriminative & 90.4 \\ Zhu et al. (2013) [40] & WSJ only, discriminative & 90.4 \\ Dyer et al. (2016) [8] & WSJ only, discriminative & 91.7 \\ \hline Transformer (4 layers) & WSJ only, discriminative & 91.3 \\ \hline Zhu et al. (2013) [40] & semi-supervised & 91.3 \\ Huang \& Harper (2009) [14] & semi-supervised & 91.3 \\ McClosky et al. (2006) [26] & semi-supervised & 92.1 \\ Vinyals \& Kaiser el al. (2014) [37] & semi-supervised & 92.1 \\ \hline Transformer (4 layers) & semi-supervised & 92.7 \\ \hline Luong et al. (2015) [23] & multi-task & 93.0 \\ Dyer et al. (2016) [8] & generative & 93.3 \\ \hline \end{tabular}\end{table}Table 4: The Transformer generalizes well to English constituency parsing (Results are on Section 23 of WSJ)* [5] Kyunghyun Cho, Bart van Merrienboer, Caglar Gulcehre, Fethi Bougares, Holger Schwenk, and Yoshua Bengio. Learning phrase representations using rnn encoder-decoder for statistical machine translation. _CoRR_, abs/1406.1078, 2014.

然后使用LLM对表格进行总结:

# Promptprompt_text = """You are an assistant tasked with summarizing tables and text. \ Give a concise summary of the table or text. The table is formatted in LaTeX, and its caption is in plain text format: {element}  """prompt = ChatPromptTemplate.from_template(prompt_text)# Summary chainmodel = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser()# Get table summariestable_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})print(table_summaries)

      以下是在Attention Is All You Need[16]中找到的四个表的摘要,如图11所示:

        使用Multi-Vector Retriever[12]构建文档摘要索引结构。

# The vectorstore to use to index the child chunksvectorstore = Chroma(collection_name = "summaries", embedding_function = OpenAIEmbeddings())# The storage layer for the parent documentsstore = InMemoryStore()id_key = "doc_id"# The retriever (empty to start)retriever = MultiVectorRetriever(    vectorstore = vectorstore,    docstore = store,    id_key = id_key,    search_kwargs={"k": 1} # Solving Number of requested results 4 is greater than number of elements in index..., updating n_results = 1)# Add tablestable_ids = [str(uuid.uuid4()) for _ in tables]summary_tables = [    Document(page_content = s, metadata = {id_key: table_ids[i]})    for i, s in enumerate(table_summaries)]retriever.vectorstore.add_documents(summary_tables)retriever.docstore.mset(list(zip(table_ids, tables)))

一切就绪,构建一个简单的RAG管道,并执行查询:

# Prompt templatetemplate = """Answer the question based only on the following context, which can include text and tables, there is a table in LaTeX format and a table caption in plain text format:{context}Question: {question}"""prompt = ChatPromptTemplate.from_template(template)# LLMmodel = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")# Simple RAG pipelinechain = (    {"context": retriever, "question": RunnablePassthrough()}    | prompt    | model    | StrOutputParser())print(chain.invoke("when layer type is Self-Attention, what is the Complexity per Layer?"))  # Query about table 1print(chain.invoke("Which parser performs worst for BLEU EN-DE"))  # Query about table 2print(chain.invoke("Which parser performs best for WSJ 23 F1"))  # Query about table 4

执行结果如下,表明几个问题得到了准确的回答,如图12所示:

整体代码如下:

import osos.environ["OPENAI_API_KEY"] = "YOUR_OPEN_AI_KEY"import subprocessimport uuidfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAIfrom langchain.retrievers.multi_vector import MultiVectorRetrieverfrom langchain.storage import InMemoryStorefrom langchain_community.vectorstores import Chromafrom langchain_core.documents import Documentfrom langchain_openai import OpenAIEmbeddingsfrom langchain_core.runnables import RunnablePassthroughdef june_run_nougat(file_path, output_dir):    # Run Nougat and store results as Mathpix Markdown    cmd = ["nougat", file_path, "-o", output_dir, "-m", "0.1.0-base", "--no-skipping"]    res = subprocess.run(cmd)     if res.returncode != 0:        print("Error when running nougat.")        return res.returncode    else:        print("Operation Completed!")        return 0def june_get_tables_from_mmd(mmd_path):    f = open(mmd_path)    lines = f.readlines()    res = []    tmp = []    flag = ""    for line in lines:        if line == "\\begin{table}\n":            flag = "BEGINTABLE"        elif line == "\\end{table}\n":            flag = "ENDTABLE"                if flag == "BEGINTABLE":            tmp.append(line)        elif flag == "ENDTABLE":            tmp.append(line)            flag = "CAPTION"        elif flag == "CAPTION":            tmp.append(line)            flag = "MARKDOWN"            print('-' * 100)            print(''.join(tmp))            res.append(''.join(tmp))            tmp = []    return resfile_path = "YOUR_PDF_PATH"output_dir = "YOUR_OUTPUT_DIR_PATH"if june_run_nougat(file_path, output_dir) == 1:    import sys    sys.exit(1)mmd_path = output_dir + '/' + os.path.splitext(file_path)[0].split('/')[-1] + ".mmd" tables = june_get_tables_from_mmd(mmd_path)# Promptprompt_text = """You are an assistant tasked with summarizing tables and text. \ Give a concise summary of the table or text. The table is formatted in LaTeX, and its caption is in plain text format: {element}  """prompt = ChatPromptTemplate.from_template(prompt_text)# Summary chainmodel = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser()# Get table summariestable_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})print(table_summaries)# The vectorstore to use to index the child chunksvectorstore = Chroma(collection_name = "summaries", embedding_function = OpenAIEmbeddings())# The storage layer for the parent documentsstore = InMemoryStore()id_key = "doc_id"# The retriever (empty to start)retriever = MultiVectorRetriever(    vectorstore = vectorstore,    docstore = store,    id_key = id_key,    search_kwargs={"k": 1} # Solving Number of requested results 4 is greater than number of elements in index..., updating n_results = 1)# Add tablestable_ids = [str(uuid.uuid4()) for _ in tables]summary_tables = [    Document(page_content = s, metadata = {id_key: table_ids[i]})    for i, s in enumerate(table_summaries)]retriever.vectorstore.add_documents(summary_tables)retriever.docstore.mset(list(zip(table_ids, tables)))# Prompt templatetemplate = """Answer the question based only on the following context, which can include text and tables, there is a table in LaTeX format and a table caption in plain text format:{context}Question: {question}"""prompt = ChatPromptTemplate.from_template(template)# LLMmodel = ChatOpenAI(temperature = 0, model = "gpt-3.5-turbo")# Simple RAG pipelinechain = (    {"context": retriever, "question": RunnablePassthrough()}    | prompt    | model    | StrOutputParser())print(chain.invoke("when layer type is Self-Attention, what is the Complexity per Layer?"))  # Query about table 1print(chain.invoke("Which parser performs worst for BLEU EN-DE"))  # Query about table 2print(chain.invoke("Which parser performs best for WSJ 23 F1"))  # Query about table 4

四、结论

       本文讨论了RAG过程中表个处理的关键技术和现有解决方案,并提出了一个解决方案及其实现。

       在本文中,我们使用Nougat来解析表。然而,如果有更快、更有效的解析工具,我们会考虑取代Nougat。我们对工具的态度是先有正确的想法,然后找到工具来实现它,而不是依赖于某个工具。

       在本文中,我们将所有表内容输入到LLM中。然而,在实际场景中,我们应该考虑表格内容超过LLM上下文长度的情况。我们可以通过使用一种有效的分块方法来解决这个问题。

参考文献:

[1] https://openai.com/research/gpt-4v-system-card

[2] https://github.com/microsoft/table-transformer

[3] https://unstructured-io.github.io/unstructured/best_practices/table_extraction_pdf.html

[4] https://pub.towardsai.net/advanced-rag-02-unveiling-pdf-parsing-b84ae866344e

[5] https://github.com/facebookresearch/nougat

[6] https://github.com/clovaai/donut/

[7] https://aclanthology.org/2020.acl-main.398.pdf

[8] https://arxiv.org/pdf/2305.13062.pdf

[9] https://docs.llamaindex.ai/en/stable/examples/multi_modal/multi_modal_pdf_tables.html

[10] https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_Structured_RAG.ipynb?ref=blog.langchain.dev

[11] https://github.com/langchain-ai/langchain/blob/master/cookbook/Semi_structured_and_multi_modal_RAG.ipynb

[12] https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector

[13] https://arxiv.org/pdf/2308.13418.pdf

[14] https://arxiv.org/pdf/2111.15664.pdf

[15] https://github.com/facebookresearch/nougat/blob/main/nougat/dataset/parser/markdown.py

[16] https://arxiv.org/pdf/1706.03762.pdf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/472285.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端基础篇-深入了解 Ajax 、Axios

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 Ajax 概述 2.0 Axios 概述 3.0 综合案例 1.0 Ajax 概述 通过 Ajax 可以给服务器发送请求,并获取服务器响应的数据。异步交互是指,可以在不…

InnoDB存储引擎中的锁(整理)

目录 什么是锁 InnoDB存储引擎中的锁 锁的类型 锁的兼容性 一致性非锁定读 一致性锁定读 锁的算法 行锁的三种算法 Phantom Problem(幻像问题) 锁问题 脏读 不可重复读 丢失更新 死锁 什么是锁 在数据库中锁是为了解决资源争抢的问题&…

Linux操作系统——多线程

1.线程特性 1.1线程优点 创建一个新线程的代价要比创建一个新进程小得多与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多线程占用的资源要比进程少很多能充分利用多处理器的可并行数量在等待慢速I/O操作结束的同时,程序可执行其他的计…

先进的人工智能促进更好的业务沟通

提升商务沟通效率:了解SaneBox智能电子邮件管理工具 在现代商业环境中,有效的沟通至关重要。 先进的人工智能技术,特别是在电子邮件管理方面,正在改变企业处理沟通的方式,提高效率和个性化。 下面,我们深入…

【1】THIS IS NOT PROLIFIC PL2303. PLEASE CPMTACT YOUR SUPPLIER

0x01 问题描述 连接COM口连接不上,出现THIS IS NOT PROLIFIC PL2303. PLEASE CPMTACT YOUR SUPPLIER.如下图 0x02 问题解决 1、分析后,因为是windows 11 系统,就装一下驱动。右键单击--》属性 2、更新驱动程序--》浏览我的电脑以查找驱动程序…

电脑中了.[nicetomeetyou@onionmail.org].faust勒索病毒,关于数据恢复

文件后缀变成.[nicetomeetyouonionmail.org].faust了怎么办? 当文件后缀变成.[nicetomeetyouonionmail.org].faust时,通常意味着你的计算机系统已经受到了Faust勒索病毒的攻击。这种病毒会利用先进的加密算法对你的文件进行加密,并将文件后缀…

整合qq邮箱发送

目录 &#x1f32e;1.获取qq授权码 &#x1fad3;2.引入依赖 &#x1f9c8;3.配置mail信息 &#x1f95e;4.创建实现类 &#x1f956;5.测试 1.获取qq授权码 点击开启服务&#xff0c;发送信息获取授权码 2.引入依赖 <!--邮件--><dependency><groupId&…

my2sql —— go语言版binlog解析及闪回工具

之前学习过python语言版binlog解析及闪回工具 MySQL闪回工具简介 及 binlog2sql工具用法 最近听同事介绍有了新的go语言版的my2sql。优点是不需要安装一大堆依赖包&#xff0c;直接可以安装使用&#xff0c;并且解析更高效&#xff0c;试用一下。 一、 下载安装 1. 软件下载 …

学习笔记-华为IPD转型2020:3,IPD的实施

3. IPD的实施 1999 年开始的 IPD 转型是计划中的多个转型项目中的第一个&#xff08;Liu&#xff0c;2015&#xff09;。华为为此次转型成立了一个专门的团队&#xff0c;从大约20人开始&#xff0c;他们是华为第一产业的高层领导。董事会主席孙雅芳是这个团队的负责人。该团…

minio 文件分片上传和下载

文件下载 文件分片下载&#xff1a; 计算文件开始字节位置&#xff0c;计算文件结束字节位置添加头部信息: Range:bytes0-2000表示开始字节位置&#xff0c;200表示结束字节位置 文件上传 生成

1058:求一元二次方程

【题目描述】 利用公式 求一元二次方程axbxc0的根&#xff0c;其中a不等于0。结果要求精确到小数点后5位。 【输入】 输入一行&#xff0c;包含三个浮点数a,b,c&#xff08;它们之间以一个空格分开&#xff09;&#xff0c;分别表示方程axbxc0的系数。 【输出】 输出一行&…

三款.NET代码混淆工具比较分析:ConfuserEx、Obfuscar和Ipa Guard

随着.NET应用程序的广泛应用&#xff0c;保护知识产权和防止逆向工程的需求逐渐增长。本文将详细介绍三款知名的.NET代码混淆工具&#xff1a;ConfuserEx、Obfuscar和Ipa Guard&#xff0c;帮助读者全面了解其功能特点和应用场景。 一、ConfuserEx ConfuserEx是一个.NET代码混…

SpringCloud-Nacos配置管理

在nacos中添加配置文件 如何在nacos中管理配置呢&#xff1f; 然后在弹出的表单中&#xff0c;填写配置信息&#xff1a;如&#xff1a;userservice-dev.yaml 注意&#xff1a;项目的核心配置&#xff0c;需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置…

【解决】Github Pages搭建的网页访问加载缓慢

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 文章目录 一、CDN技术简介二、基于Cloudflare平台使用CDN服务&#xff08;一&#xff09;添加网站&#xff08;二&#xff09…

基于springboot小区物业管理系统

摘 要 在网络信息的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个性的需求。在这种时代背景下&#xff0c;小区物业只能以客户为导向&#xff0c;以产品的持续创新作为小区物业最重要的竞争手段。 采取MyS…

蓝桥杯之简单数论冲刺

文章目录 取模快速幂 取模 这道题目有两个注意点&#xff1a; 1.当你的取模之后刚好等于0的话&#xff0c;后面就不用进行后面的计算 2.if sum detail[i] > q: 这个语句的等号也很重要 import os import sys# 请在此输入您的代码a,b,n map(int,input().split())week a*5 …

[linux]--关于进程概念(上)

目录 冯诺依曼体系结构 操作系统 概念 设计os的目的 定位 如何理解管理 总结 系统调用和库函数概念 进程 描述进程-pcb 组织进程 查看进程 通过系统调用获取进程标示符 通过系统调用创建进程-fork初识 进程状态 阻塞和挂起 Z(zombie)-僵尸进程 冯诺依曼体系结…

spring整合Sentinel

安装sentinel&#xff1a; 执行命令; java -jar sentinel-dashboard-1.8.6.jar 注:sentinel的默认端口为8080&#xff0c;容易出现tomcat的冲突。 当端口冲突&#xff0c;可以使用该指令修改sentinel的端口 默认账号和密码都为sentinel Springcloud整合sentinel&#xff1a;…

IDA反汇编工具详解之菜单栏和基本操作

文章目录 IDA 菜单栏FileEditJumpSearchViewDebuggerOptionsWindows 反汇编操作名称和命名IDA 中的注释基本代码转换修改exe文件并保存 IDA 菜单栏 File File菜单负责项目工程的管理&#xff0c;操作包括:打开项目、关闭项目、保存项目 Edit Edit菜单负责编辑和管理该项目中的…

matlab 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面

1、内容简介 略 65-可以交流、咨询、答疑 2、内容说明 matlab 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面 混沌系统李雅普洛夫指数谱相图分岔图和庞加莱界面 李雅普洛夫指数谱、相图、分岔图、庞加莱界面 3、仿真分析 略 4、参考论文 略