14个文本转图像AI API
使用LlamaParse、Langchain和Groq在复杂PDF上进行RAG
检索增强生成 (RAG) 及其应用
检索增强生成 (RAG) 是一种利用大型语言模型 (LLM) 从非结构化数据源中自动进行知识搜索、综合、提取和规划的新方法。由于能够使用上下文信息增强 LLM 应用程序,该方法在过去一年中获得了越来越多的关注。RAG 数据堆栈包含几个关键组件:
- 加载数据: 首先,从各种来源(如文本文档、网站或数据库)获取数据。这些数据可以是原始格式或预处理格式。
- 处理数据: 对数据进行预处理步骤,以清理和构建数据以进行进一步分析。这可能包括诸如分词、词干提取和删除停用词之类的任务。
- 嵌入数据: 将每条数据转换为称为嵌入的数字表示形式。此嵌入捕获有关数据的语义信息,使 LLM 更容易理解和处理。
- 向量数据库: 将嵌入存储在向量数据库中,该数据库允许基于相似性度量进行有效检索。该数据库可在生成过程中快速访问相关数据点。
- 检索和提示: 在生成过程中,LLM 可以根据当前输入的上下文从向量数据库中检索相关数据点。此检索机制有助于 LLM 提供更准确和上下文相关的输出。
总的来说,RAG 方法通过使 LLM 能够以系统和有效的方式利用外部知识源,从而增强了 LLM 的能力。这可以导致在各个领域(例如自然语言理解、信息检索和决策)中出现更强大且上下文感知的应用程序。
构建生产级 RAG 仍然是一个复杂而微妙的问题。以下是一些相关的挑战:
- 结果不够准确: 该应用程序无法为长尾输入任务/查询生成令人满意的结果。
- 需要调整的参数数量过多: 不清楚数据解析、提取和检索中的哪些参数需要调整。
- PDF 是一个特别的问题: 我有包含大量混乱格式的复杂文档。如何以正确的方式表示这些文档,以便 LLM 能够理解它们?
- 数据同步是一个挑战: 生产数据通常会定期更新,持续同步新数据会带来一系列新的挑战。
为了解决上述问题,LlamaIndex 于 2024 年 2 月 20 日推出了 LlamaCloud 和 LlamaParse,这是一代新的托管解析、提取和检索服务,旨在为 LLM 和 RAG 应用程序带来生产级 上下文增强。
LlamaCloud 创立背后的主要直觉是专注于编写业务逻辑,而不是数据整理。处理大量的生产数据,立即带来更好的响应质量。它包含以下两个组件:
- LlamaParse: 专有的解析服务,用于解析包含嵌入对象(例如表格和图形)的复杂文档。LlamaParse 直接与 LlamaIndex 提取和检索集成,使您能够构建对复杂、半结构化文档的检索。它有望能够回答以前根本无法回答的复杂问题。
- 托管提取和检索 API: 一个 API,允许您轻松地加载、处理和存储 RAG 应用程序的数据,并以任何语言使用它。由 LlamaHub 中的数据源(包括 LlamaParse)和数据存储集成提供支持。
什么是 LlamaParse?
LlamaParse 是一种专有的解析服务,非常擅长将包含复杂表格的 PDF 解析为结构良好的 markdown 格式。
此服务以公开预览模式提供:每个人都可以使用,但有使用限制(每天 1k 页),每周 7,000 页免费。然后每页 0.003 美元(每 1,000 页 3 美元)。它作为一项独立服务运行,也可以插入托管提取和检索 API 中。
from llama_parse import LlamaParse
parser = LlamaParse(
api_key="llx-...",
result_type="markdown",
verbose=True
)
目前 LlamaParse 主要支持带有表格的 PDF,但他们也正在构建对图形的更好支持,并作为下一代增强功能的一部分扩展了最流行的文档类型集:.docx、.pptx、.html。
什么是 Groq?
Groq 成立于 2016 年,总部位于加利福尼亚州山景城,是一家专注于超低延迟 AI 推理的 AI 解决方案初创公司。该公司在 AI 计算性能方面取得了重大进展,是 AI 技术领域的知名参与者。Groq 已将其名称注册为商标,并组建了一个致力于普及 AI 访问的全球团队。
Groq 的语言处理单元 (LPU) 是一项尖端技术,旨在显着提高 AI 计算性能,尤其是对于大型语言模型 (LLM)。Groq LPU 系统的主要目标是提供具有卓越推理性能的实时、低延迟体验。Groq 的成就之一包括在 Meta AI 的 Llama-2 70B 模型上超过每秒 300 个令牌/用户的基准,这是该行业的一项重大进步。
Groq LPU 系统以其超低延迟能力而著称,这对于支持 AI 技术至关重要。它专为顺序和计算密集型 GenAI 语言处理而量身定制,优于传统的 GPU 解决方案。这使其在自然语言生成和理解等任务中非常高效。
Groq LPU 系统的核心是第一代 GroqChip,它采用张量流架构,针对速度、效率、准确性和成本效益进行了优化。该芯片在基础 LLM 速度方面创下了新纪录,以每秒每个用户的令牌数衡量,超过了市场上现有的解决方案。Groq 有着雄心勃勃的计划,即在两年内部署 100 万个 AI 推理芯片,展示其对推进 AI 加速技术的贡献。
什么是 LPU 推理引擎?
LPU 推理引擎,其中 LPU 代表语言处理单元™,是一种新型的端到端处理单元系统,为具有顺序组件的计算密集型应用程序(例如 AI 语言应用程序 (LLM))提供最快的推理。
为什么它比 GPU 更快?
LPU 旨在克服 LLM 的两个瓶颈:计算密度和内存带宽。在 LLM 方面,LPU 比 GPU 和 CPU 具有更大的计算能力。这减少了每个单词的计算时间,从而可以更快地生成文本序列。此外,消除外部内存瓶颈使 LPU 推理引擎能够在 LLM 上提供比 GPU 高几个数量级的性能。
要了解更多关于我们架构的技术信息,请下载我们获得 ISCA 奖的 2020 和 2022论文。
Groq 入门指南
目前,Groq 正在为运行在 Groq LPU(语言处理单元)上的大型语言模型提供免费使用的 API 端点。
Groq 保证其每百万 token 的价格将低于已发布的同类模型供应商的公开价格。其他模型,如 Mistral 和 CodeLlama,可根据特定客户请求提供。
要开始使用,请访问此页面 并点击登录。页面如下所示:
什么是 Langchain?
LangChain 是一个开源框架,旨在简化使用大型语言模型 (LLM) 创建应用程序的过程。它为链提供了一个标准接口,并与其他工具进行了大量集成,还提供了用于常见应用程序的端到端链。
Langchain 关键概念:
- 组件:组件是模块化的构建块,可以轻松地用于构建强大的应用程序。组件包括 LLM 包装器、提示模板和用于相关信息检索的索引。
- 链:链允许我们将多个组件组合在一起以解决特定任务。链通过使其更模块化且易于调试和维护,简化了复杂应用程序的实现。
- 代理:代理允许 LLM 与其环境交互。例如,使用外部 API 执行特定操作。
代码实现
代码在 Google Colab (cpu) 中实现
安装必要的依赖项
%%writefile requirements.txt
langchain
langchain-community
llama-parse
fastembed
chromadb
python-dotenv
langchain-groq
chainlit
fastembed
unstructured[md]
!pip install -r requirements.txt
设置环境变量
from google.colab import userdata
llamaparse_api_key = userdata.get('LLAMA_CLOUD_API_KEY')
groq_api_key = userdata.get("GROQ_API_KEY")
导入必要的依赖项
from llama_parse import LlamaParse
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings.fastembed import FastEmbedEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.document_loaders import DirectoryLoader
from langchain_community.document_loaders import UnstructuredMarkdownLoader
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
from groq import Groq
from langchain_groq import ChatGroq
import joblib
import os
import nest_asyncio
nest_asyncio.apply()
LlamaParse 参数
* api_key: str = Field(
default="",
description="LlamaParse API 的 API 密钥.",
)
* base_url: str = Field(
default=DEFAULT_BASE_URL,
description="Llama Parsing API 的基础 URL.",
)
* result_type: ResultType = Field(
default=ResultType.TXT, description="解析器的结果类型."
)
* num_workers: int = Field(
default=4,
gt=0,
lt=10,
description="用于发送 API 解析请求的 worker 数量.",
)
* check_interval: int = Field(
default=1,
description="检查解析是否完成的时间间隔(秒)。",
)
* max_timeout: int = Field(
default=2000,
description="等待解析完成的最大超时时间(秒)。",
)
* verbose: bool = Field(
default=True, description="是否打印解析进度。"
)
* language: Language = Field(
default=Language.ENGLISH, description="待解析文本的语言。"
)
* parsing_instruction: Optional[str] = Field(
default="",
description="解析器的解析指令。"
)
辅助函数:加载和解析输入数据
!mkdir data
def load_or_parse_data():
data_file = "./data/parsed_data.pkl"
if os.path.exists(data_file):
parsed_data = joblib.load(data_file)
else:
parsingInstructionUber10k = """The provided document is a quarterly report filed by Uber Technologies,
Inc. with the Securities and Exchange Commission (SEC).
This form provides detailed financial information about the company's performance for a specific quarter.
It includes unaudited financial statements, management discussion and analysis, and other relevant disclosures required by the SEC.
It contains many tables.
Try to be precise while answering the questions"""
parser = LlamaParse(api_key=llamaparse_api_key,
result_type="markdown",
parsing_instruction=parsingInstructionUber10k,
max_timeout=5000,)
llama_parse_documents = parser.load_data("./data/uber_10q_march_2022 (1).pdf")
print("Saving the parse results in .pkl format ..........")
joblib.dump(llama_parse_documents, data_file)
parsed_data = llama_parse_documents
return parsed_data
辅助函数:将块加载到向量存储中
def create_vector_database():
"""
使用文档加载器和嵌入创建向量数据库.
此函数加载 urls,
将加载的文档分割成块,使用 OllamaEmbeddings 将它们转换为嵌入,
最后将嵌入持久化到 Chroma 向量数据库中.
"""
llama_parse_documents = load_or_parse_data()
print(llama_parse_documents[0].text[:300])
with open('data/output.md', 'a') as f:
for doc in llama_parse_documents:
f.write(doc.text + '\n')
markdown_path = "/content/data/output.md"
loader = UnstructuredMarkdownLoader(markdown_path)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=100)
docs = text_splitter.split_documents(documents)
print(f"length of documents loaded: {len(documents)}")
print(f"total number of document chunks generated :{len(docs)}")
embed_model = FastEmbedEmbeddings(model_name="BAAI/bge-base-en-v1.5")
vs = Chroma.from_documents(
documents=docs,
embedding=embed_model,
persist_directory="chroma_db_llamaparse1",
collection_name="rag"
)
print('Vector DB created successfully !')
return vs,embed_model
处理数据并创建向量存储
vs,embed_model = create_vector_database()
实例化 LLM
chat_model = ChatGroq(temperature=0,
model_name="mixtral-8x7b-32768",
api_key=userdata.get("GROQ_API_KEY"),)
以上代码执行以下操作:
- 创建一个名为 chat_model 的 ChatGroq 对象
- 将 temperature 参数设置为 0,表示响应应该更可预测
- 将 model_name 参数设置为 “mixtral-8x7b-32768″,指定要使用的语言模型
实例化向量存储
vectorstore = Chroma(embedding_function=embed_model,
persist_directory="chroma_db_llamaparse1",
collection_name="rag")
retriever=vectorstore.as_retriever(search_kwargs={'k': 3})
创建自定义提示模板
custom_prompt_template = """Use the following pieces of information to answer the user's question.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
Context: {context}
Question: {question}
Only return the helpful answer below and nothing else.
Helpful answer:
"""
辅助函数:格式化提示
def set_custom_prompt():
"""
每个向量存储的 QA 检索的提示模板
"""
prompt = PromptTemplate(template=custom_prompt_template,
input_variables=['context', 'question'])
return prompt
prompt = set_custom_prompt()
prompt
PromptTemplate(input_variables=['context', 'question'], template="Use the following pieces of information to answer the user's question.\nIf you don't know the answer, just say that you don't know, don't try to make up an answer.\n\nContext: {context}\nQuestion: {question}\n\nOnly return the helpful answer below and nothing else.\nHelpful answer:\n")
实例化 Retrieval Question Answering Chain
qa = RetrievalQA.from_chain_type(llm=chat_model,
chain_type="stuff",
retriever=retriever,
return_source_documents=True,
chain_type_kwargs={"prompt": prompt})
这段代码实例化了一个 RetrievalQA 对象,它结合了语言模型和检索器来回答问题。chain_type="stuff"
指定了使用特定类型的链,而 retriever
则指定了用于检索相关文档的检索器。
调用 Retrieval QA Chain
response = qa.invoke({"query": "what is the Balance of UBER TECHNOLOGIES, INC.as of December 31, 2021?"})
这段代码使用 invoke
方法向 RetrievalQA 对象提问。查询内容为“截至 2021 年 12 月 31 日,UBER TECHNOLOGIES, INC. 的资产负债表是多少?”
响应已合成
response['result']
RESPONSE: 根据截至 2021 年 12 月 31 日 Uber Technologies, Inc. 提供的资产负债表,总资产为 387.74 亿美元,总负债为 234.25 亿美元,总权益为 96.13 亿美元。
问题 2
response = qa.invoke({"query": "What is the Cash flows from operating activities associated with bad expense specified in the document ?"})
response['result']
RESPONSE: 与坏账费用相关的经营活动产生的现金流量在 2021 年为 23,2022 年为 18。
问题 3
response = qa.invoke({"query": "what is Loss (income) from equity method investments, net ?"})
response["result"]
RESPONSE: 权益法投资净亏损的计算方法是将权益法投资减值和 MLU B.V. 认购期权重估相加,分别为 1.82 亿美元和 1.81 亿美元。这导致权益法投资净亏损总额为 3.63 亿美元。该损失包含在 Uber Technologies, Inc. 的 59 亿美元净亏损中。
问题 4
response = qa.invoke({"query": "What is the Total cash and cash equivalents, and restricted cash and cash equivalents for reconciliation ?"})
response['result']
RESPONSE: 用于调节的现金和现金等价物总额以及受限制的现金和现金等价物总额为 66.07 亿美元。该金额是通过将 48.36 亿美元的现金和现金等价物与 2.47 亿美元的流动性受限现金和现金等价物以及 15.24 亿美元的非流动性受限现金和现金等价物相加得到的。
问题 5
response = qa.invoke({"query":"Based on the CONDENSED CONSOLIDATED STATEMENTS OF REDEEMABLE NON-CONTROLLING INTERESTS AND EQUITY what is the Balance as of March 31, 2021?"})
print(response['result'])
RESPONSE: 截至 2021 年 3 月 31 日,可赎回非控股权益的余额为 473 美元,普通股为 1,867,369 股,额外实收资本为 — 美元,其他综合收益(亏损)为 36,182 美元,非控股权益为 654 美元,总权益为 654 美元。
问题 6
response = qa.invoke({"query":"Based on the condensed consolidated statements of comprehensive Income(loss) what is the Comprehensive income (loss) attributable to Uber Technologies, Inc.for the three months ended March 31, 2022"})
response['result']
RESPONSE: 截至 2022 年 3 月 31 日的三个月,归属于 Uber Technologies, Inc. 的综合收益(亏损)为 59.11 亿美元。此信息可在季度报告中提供的 Uber Technologies, Inc. – 综合收益(亏损)简明合并报表中找到。
问题 7
response = qa.invoke({"query":"Based on the condensed consolidated statements of comprehensive Income(loss) what is the Comprehensive income (loss) attributable to Uber Technologies?"})
response['result']
RESPONSE: 截至 2021 年 3 月 31 日的三个月,归属于 Uber Technologies, Inc. 的综合收益(亏损)为 10.81 亿美元,截至 2022 年 3 月 31 日的三个月为 -59.11 亿美元。
问题 8
response = qa.invoke({"query":"Based on the condensed consolidated statements of comprehensive Income(loss) what is the Net loss including non-controlling interests"})
response['result']
RESPONSE: 截至 2021 年 3 月 31 日的三个月,包括非控股权益在内的净亏损为 1.22 亿美元,截至 2022 年 3 月 31 日的三个月为 59.18 亿美元。
问题 9
response = qa.invoke({"query":"what is the Net cash used in operating activities for Mrach 31,2021? "})
response['result']
RESPONSE: 截至 2021 年 3 月 31 日,经营活动使用的现金净额为 6.11 亿美元。
问题 10
query = "Based on the CONDENSED CONSOLIDATED STATEMENTS OF CASH FLOWS What is the value of Purchases of property and equipment ?"
response = qa.invoke({"query":query})
response['result']
RESPONSE:
截至 2021 年和 2022 年 3 月 31 日的三个月,购置财产和设备的价值可以在现金流量简明合并报表中的“投资活动产生的现金流量”部分找到。
截至 2021 年 3 月 31 日的三个月:7100 万美元
截至 2022 年 3 月 31 日的三个月:6200 万美元
问题 11
query = "Based on the CONDENSED CONSOLIDATED STATEMENTS OF CASH FLOWS what is the Purchases of property and equipment for the year 2022?"
response = qa.invoke({"query":query})
response['result']
RESPONSE: 根据现金流量简明合并报表,2022 年购置财产和设备为 -62。
从上面的实现中,我们可以假设 LlamaParse 在解析复杂的 PDF 文档方面相对较好。虽然我们必须对不同的表格结构进行更多实验。以下是 LlamaParse 与 PyPDF 的比较
结论
LlamaParse 在解析包含复杂表格的 PDF 文档并将其转换为结构良好的 Markdown 格式方面表现出色。这种格式可以直接用于开源库中的高级 Markdown 解析和递归检索算法。最终,我们能够构建基于复杂文档的 RAG,从而可以回答关于表格数据和非结构化数据的各种问题。
文章转自微信公众号@知觉之门