一、前言
在过去的一年中,RAG(Retrieval-Augmented Generation)模型在信息检索和自然语言处理领域取得了显著的进展,但同时也面临着一系列挑战。尤其是在处理复杂PDF文档时,RAG模型的局限性变得尤为明显。这些文档通常包含多样化的格式、图片、表格等元素,使得检索效果并不理想。由于RAG对数据的标准化和准确性有很高的依赖性,因此在解析结构化文档内容时,往往需要投入大量的精力和成本。
在这样的背景下,LlamaIndex 凭借其在数据处理和解析方面的深厚经验,不断挑战自我,通过实践和创新,最终推出了 LlamaParse 技术。LlamaParse专为解决上述痛点而设计,它能够有效地解析和理解那些格式复杂、内容丰富的PDF文档,无论它们包含的是文本、图片还是表格数据。
LlamaParse 的引入,不仅提高了解析的准确性和效率,还大大降低了前期处理结构化文档所需的成本。这一技术的进步,标志着我们在处理复杂数据方面迈出了重要的一步,为各行各业提供了更为强大和灵活的PDF解析解决方案。通过 LlamaParse,我们能够更好地理解和利用大量的PDF文档资源,从而在信息的海洋中更高效地寻找到我们需要的宝贵知识。
二、LlamaParse 简介
LlamaParse 是由 LlamaIndex 创建的一项技术,专门用于高效地解析和表示PDF文件,以便通过 LlamaIndex 框架进行高效检索和上下文增强,特别适用于复杂的PDF文档。它基于RAG(Rule-based Approach with Grammar)技术,能够准确地提取文本、图像、表格等元素,同时保持良好的性能。这项技术的设计初衷是为了处理那些包含嵌入式对象(如表格和图形)的复杂文档,这类文档的处理在以往往往是个挑战。通过与 LlamaIndex 的直接整合,LlamaParse不仅能够支持对这些复杂、半结构化文档的解析,还能够在检索时提供支持,从而让用户能够回答之前难以解决的复杂问题。
LlamaParse 的核心优势在于它的专有解析技术,这使得它能够理解和处理PDF文件中的复杂结构。此外,由于它与LlamaIndex 的紧密整合,用户可以非常方便地将解析后的数据用于增强检索和上下文理解,从而大大提高了信息检索的效率和准确性。
LlamaParse 目前是免费提供的,这意味着我们可以自由地利用这项技术来开发和改进他们的应用程序,无需担心成本问题。这种开放性可能会促进更多的创新和应用场景的探索,进一步推动了信息检索和数据处理领域的发展。
三、在LlamaCloud中使用LlamaParse
LlamaParse 已经集成到 LlamaCloud 平台中,使得用户可以轻松地使用这一强大的解析工具。(免费计划每天最多 1000 页。付费计划是每周免费 7k 页 + 每增加一页 $0.003。)
以下是在 LlamaCloud 中使用 LlamaParse 的步骤:
登录LlamaCloud:首先,您需要登录到LlamaCloud的控制台。点击链接 https://cloud.llamaindex.ai/,选择合适的方法登录。
登录后,你会看到两个选项 Goto Index & Goto Parse。单击“Goto Parse”按钮。然后你会看到这样的屏幕。
将 PDF 拖放到右侧上传文档区域中,然后会自动打开PDF浏览页面,点击预览按钮查看文档解析后的内容。 LlamaParse 默认将 PDF 转换为 Markdown,如下图所示,文档的内容准确的解析出来了,主要官网 LlamaCloud 因为不能设置解析文档的语言,所以默认只能识别英文的文档,中文的解析识别我们在下文 Python 代码中指定。
四、在Python代码中使用LlamaParse
在本文中,我们将使用 Python 代码展示 LlamaParse,在开始之前,你将需要一个 API 密钥。它是免费的。你可以从下图中看到设置密钥的链接,因此现在单击该链接并设置您的 API 密钥。由于我使用 OpenAI 进行 LLM 和嵌入,因此我也需要获取 OpenAI API 密钥。
如果你想查看一些示例代码片段,请单击屏幕主页的 Use with LlamaIndex 按钮。如果需要更深入的了解 LlamaParse 的使用示例,可以访问 LlamaParse GitHub 页面,在那里你会看到很多示例代码。
4.1、解析PDF文档
首先还是安装 LlamaParse 及相关依赖,如果第一次安装,直接执行以下的脚本即可。
pip install -qU llama-index llama-parse
如果从v0.9. x或更早版本升级,请执行以下的脚本来完成 LlamaParse 的安装。
pip uninstall llama-index # 如果从v0.9. x或更早版本升级,请运行此操作
pip install -U llama-index --upgrade --no-cache-dir --force-reinstall
pip install llama-parse
# LlamaParse 是异步优先的,在 Notebook 中运行同步代码需要使用 nest_asyncio
import nest_asyncionest_asyncio.apply()import osos.environ["LLAMA_CLOUD_API_KEY"] = "llx-..."
下载一个中文pdf文档
!wget "https://www.dropbox.com/scl/fi/g5ojyzk4m44hl7neut6vc/chinese_pdf.pdf?rlkey=45reu51kjvdvic6zucr8v9sh3&dl=1" -O chinese_pdf.pdf
from llama_parse import LlamaParseparser = LlamaParse(result_type="markdown",language="ch_sim",verbose=True,num_workers=1,
)documents = parser.load_data("./chinese_pdf.pdf")
在这里我们可以初始化我们的 LlamaParse 对象。
请注意,有一些参数值得关注:
- result_type 选项仅限于 "text" 和 "markdown" 。 这里我们选择 Markdown 格式输出,因为它将很好地保留结构化信息。
- num_workers 设置工作线程的数量。一般来说,我们可以根据需要解析的文件数量来设定工作线程的数量。 (最大值为 10 )
配置工作线程的数量:你可以根据需要解析的文件数量来设定工作线程的数量。这样做可以让你根据任务的规模来优化资源的使用和提高处理效率。
根据文件数量设定:通常,你会希望设置的工作线程数量与你打算解析的文件数量相匹配。例如,如果你有5个文件需要解析,那么设置5个工作线程可能是合理的,这样可以确保每个文件都有一个专门的线程来处理。
最大限制:LlamaParse对于工作线程的数量有一个最大限制,这里是设置为10。这意味着你最多可以同时设置10个工作线程来并行处理解析任务。这个限制可能是为了确保系统的稳定性和防止资源过度消耗。
执行以上代码,会启动一个PDF解析的异步任务。
Started parsing the file under job_id f4046c7c-cc99-483e-a517-9bd5bdef0b6a
解析完我们查看一下解析后的结果,这里分别输出文档中的两部分内容。从结果可以看到,质量还是很高的。
print(documents[0].text[:1000])
print(documents[0].get_content()[1000:10000])
4.2、多语言支持
LlamaParse 支持用户在上传文档之前指定 language 参数,为用户提供比非英语 PDF 更好的 OCR 功能,将图像解析为更准确的表示形式。
您可以指定 80 多种不同的语言:请参阅此文件以获取支持的语言的完整列表:https://github.com/run-llama/llama_parse/blob/main/llama_parse/base.py。
from llama_parse import LlamaParseparser = LlamaParse(result_type="markdown",language="ch_sim",verbose=True,num_workers=1,
)documents = parser.load_data("./chinese_pdf.pdf")
4.3、LlamaIndex 递归查询引擎
前面我们已经使用 LlamaParse 将PDF中的文档内容提取出来为 Markdown 格式的文本了,接下来就可以结合 LlamaInde 中的高级查询引擎结合大模型和向量检索完成一些更高级更复杂的任务,比如图片内容检索,表格检索及数据比对等。
接下来我们需要上传一些文件来测试我们的解析器!
这里我们使用 《NVIDIA 的 10-K年度报告》 和教育技术办公室的《人工智能教育报告》2个报告来测试。
上传文件并设置了 LlamaParser ,接下来我们开始准备好解析这两个文件了。
documents = parser.load_data(["./nvidia-earnings.pdf", "./ai-report.pdf"])
解析完我们可以查看一下两个文件解析的内容和结构是否正确
print(documents[0].text[:1000])
print(documents[1].text[:1000])
在LlamaIndex的查询引擎中,解析对象的利用是通过高级查询引擎来实现的。这个查询引擎能够处理复杂的查询,并且能够充分利用已经解析的结构化数据。在这个上下文中,ServiceContext已经被新的Settings所取代,这是LlamaIndex在其v0.10版本更新中的一个重要变化。
4.3.1、设置查询引擎
为了设置查询引擎,你需要指定一些关键的参数,包括LLM(Language Model)和嵌入模型(embedding model)。在这个例子中,建议将LLM指向gpt-3.5-turbo-16k,这是一个高性能的语言模型,能够提供快速且准确的文本处理能力。同时,嵌入模型被设置为text-embedding-3-small,这是一个小型的文本嵌入模型,适用于需要处理大量数据但对资源消耗有限制的场景。
首先需要设置OpenAI API Key。
os.environ["OPENAI_API_KEY"] = "sk-"
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbeddingSettings.llm = OpenAI(model="gpt-3.5-turbo-16k")
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
通过这样的设置,你可以确保查询引擎能够高效地处理和分析文本数据,同时保持对资源的合理使用。这些设置对于优化查询性能和结果的准确性至关重要。
from llama_index.core.node_parser import MarkdownElementNodeParsernode_parser = MarkdownElementNodeParser(llm=OpenAI(model="gpt-3.5-turbo-16k"), num_workers=2)
在 LlamaParse 技术中,MarkdownElementNodeParser是一个专门的解析器,它能够识别Markdown文档中的各种元素,如标题(H1, H2, H3等)、列表(有序或无序列表)、代码块、链接、图片、强调文本等。这个解析器的目标是将Markdown文档中的这些元素转换成可操作的数据结构,从而使得开发者可以进一步利用这些结构化信息。
接下来开始解析文档
nodes = node_parser.get_nodes_from_documents(documents=[documents[0]])
现在我们可以提取 base_nodes 和 objects 来创建 VectorStoreIndex 。
base_nodes, objects = node_parser.get_nodes_and_objects(nodes)
开始建立索引
from llama_index.core import VectorStoreIndexrecursive_index = VectorStoreIndex(nodes=base_nodes+objects)
4.3.2、递归查询引擎
现在我们可以构建带有重排(reranking)功能的递归查询引擎了!
我们需要执行几个步骤:
- 使用由BAAI/bge-reranker-large提供支持的FlagEmbeddingReranker初始化我们的重排器。
- 搭建我们的递归查询引擎!
首先,让我们安装一些必要的依赖。
!pip install -qU llama-index-postprocessor-flag-embedding-reranker git+https://github.com/FlagOpen/FlagEmbedding.git
首先,我们将初始化重新排名器 - 我们将利用此存储库来利用我们的 BAAI/bge-reranker-large 。
一旦完成,我们就可以遵循创建查询引擎的相当标准的流程!
from llama_index.postprocessor.flag_embedding_reranker import FlagEmbeddingRerankerreranker = FlagEmbeddingReranker(top_n=5,model="BAAI/bge-reranker-large",
)recursive_query_engine = recursive_index.as_query_engine(similarity_top_k=15,node_postprocessors=[reranker],verbose=True
)
4.3.3、在NVIDIA 的 10-K上测试
OK,我们开始对《NVIDIA 的 10-K年度报告》文档上的内容进行提问。
query = "Who is the E-VP, Operations - and how old are they?"
response = recursive_query_engine.query(query)
从输出日志可以看到查询引擎在进行递归查询,我们打印检索的结果。
print(response)
检索结果:Debora Shoquist is the Executive Vice President of Operations, and she is 69 years old.
从输出的结果我们发现在报告的表格中非常精确的搜索到了我们需要的结果。
注意:在CPU上运行的系统处理一个查询需要2到3分钟的时间,主要是因为重排序过程在CPU上运行时效率较低。建议用户在GPU支持的系统上运行相同的查询,以期望获得更好的性能表现。
4.3.4、在人工智能教育报告上测试
继续根据前面的步骤先解析文档,创建索引,初始化重新排序器
# 解析文档
ai_report_nodes = node_parser.get_nodes_from_documents(documents=[documents[1]])
# 提取 base_nodes 和 objects 来创建 VectorStoreIndex
ai_base_nodes, ai_objects = node_parser.get_nodes_and_objects(ai_report_nodes)
# 创建索引
ai_recursive_index = VectorStoreIndex(nodes=ai_base_nodes+ai_objects)# 初始化重新排名器
reranker = FlagEmbeddingReranker(top_n=5,model="BAAI/bge-reranker-large",
)ai_recursive_query_engine = ai_recursive_index.as_query_engine(similarity_top_k=15,node_postprocessors=[reranker],verbose=True
)
开始输入问题进行检索:
query = "How many AI publications on pattern recognition was there in 2020?"
response = ai_recursive_query_engine.query(query)
检索结果:There were 30.07 AI publications on pattern recognition in 2020.
从图表上可以看到,虽然查询引擎确实检索了图中字面上的上下文 - 但结果却不是正确的,说明 LlamaParse 还有进一步提升的空间,基本上大部分场景都能比较好的获取正确的结果。
五、总结
LlamaParse作为RAG技术中的佼佼者,为解析复杂PDF文档提供了高效、准确的解决方案。无论您是开发者还是普通用户,LlamaParse都值得您的关注。
本文通过案例代码介绍了 LlamaParse 在复杂PDF文件的解析中的优秀表现,通过实践案例我们发现 LlamaParse 在大部分场景和复杂PDF的解析检索都表现的非常好,但在一些统计图表的理解上还存在一定的优化空间,但是相比较传统的RAG方案和PyPdf解析方案,准确率和成功率已经高非常多了。
六、References
[1]. LlamaParse官方文档
https://docs.llamaindex.ai/en/stable/module_guides/loading/connector/llama_parse.html
[2]. RAG技术介绍
https://github.com/run-llama/llama_parse
[3]. MarkdownElementNodeParser
https://docs.llamaindex.ai/en/stable/api/llama_index.core.node_parser.MarkdownElementNodeParser.html