Press "Enter" to skip to content

LlamaIndex:最终的LLM框架,用于索引和检索

LlamaIndex介绍

LlamaIndex,之前被称为GPT指数,是一个卓越的数据框架,旨在通过提供必要的工具来帮助您构建具有LLM的应用程序,以便促进数据摄取、结构化、检索和与各种应用程序框架的集成。LlamaIndex提供的功能众多且非常有价值:

✅ 使用数据连接器(Llama Hub)从不同的数据源和数据格式进行摄取。✅ 启用文档操作,例如插入、删除、更新和刷新文档索引。✅ 支持异构数据和多个文档的综合。✅ 使用“路由器”在不同的查询引擎之间选择。✅ 允许使用假设文档嵌入来提高输出质量。✅ 提供各种与各种向量存储、ChatGPT插件、追踪工具和LangChain等的集成。✅ 支持全新的OpenAI函数调用API。

这些仅是LlamaIndex提供的广泛功能的几个示例。在本博客文章中,我们将探索一些我认为在LlamaIndex中非常有用的功能。

数据连接器(LlamaHub)

在开发LLM应用程序时,使LLM能够有效地与外部数据源交互非常重要。如何摄取数据是关键。Llama Hub提供了广泛的100多种数据源和格式,允许LlamaIndex或LangChain以一致的方式进行数据摄取。

LlamaHub。来源:https://llama-hub-ui.vercel.app/。

默认情况下,您可以pip install llama-hub并将其用作独立包。您还可以选择使用我们的download_loader方法来单独下载数据加载器,以供LlamaIndex使用。

这里是一个示例,我们从llama-hub包中加载维基百科数据加载器。一致的语法非常好。

from llama_hub.wikipedia.base import WikipediaReaderloader = WikipediaReader()documents = loader.load_data(pages=['Berlin', 'Rome', 'Tokyo', 'Canberra', 'Santiago'])

检查输出:

LlamaIndex:最终的LLM框架,用于索引和检索 人工智能 第2张

Llama Hub还支持多模态文档。例如,ImageReader加载器使用pytesseract或Donut变换器模型从图像中提取文本。

基本查询功能

索引、检索器和查询引擎

索引、检索器和查询引擎是询问数据或文档的三个基本组件:

  • 索引是一种数据结构,它允许我们从外部文档中快速检索相关信息。索引通过将文档解析成文本块(称为“节点”对象),然后从这些块中构建索引来工作。
  • 检索器用于提取和检索相关信息,给定用户查询。
  • 查询引擎是建立在索引和检索器之上的,提供了一个通用的接口来查询您的数据。

这是有关文档的最简单的询问方式。首先从文档创建一个索引,然后使用查询引擎作为您的问题界面:

from llama_index import VectorStoreIndexindex = VectorStoreIndex.from_documents(docs)query_engine = index.as_query_engine()response = query_engine.query("Who is Paul Graham.")

您可以在LlamaIndex文档上阅读各种类型的索引、检索器方法和查询引擎。在本文剩余部分,我想介绍一些我认为很有用的酷功能。

处理文档更新

通常情况下,一旦我们为文档创建索引,就可能需要定期更新文档。如果我们要重新创建整个文档的嵌入,这个过程可能很昂贵。LlamaIndex索引结构通过启用高效的插入、删除、更新和刷新操作来提供解决方案。例如,可以将新文档作为附加节点(文本块)插入,而无需重新创建前面文档的节点:

# 来源:https://gpt-index.readthedocs.io/en/latest/how_to/index/document_management.html
from llama_index import ListIndex, Document
index = ListIndex([])
text_chunks = ['text_chunk_1', 'text_chunk_2', 'text_chunk_3']
doc_chunks = []
for i, text in enumerate(text_chunks):
    doc = Document(text, doc_id=f"doc_id_{i}")
    doc_chunks.append(doc)
# 插入
for doc_chunk in doc_chunks:
    index.insert(doc_chunk)

查询多个文档

使用LlamaIndex,可以轻松地查询多个文档。这一功能是通过`SubQuestionQueryEngine`类实现的。当给定一个查询时,查询引擎会生成一个“查询计划”,其中包括对子文档进行的子查询,然后合成以提供最终答案。

# 来源:https://gpt-index.readthedocs.io/en/latest/examples/usecases/10q_sub_question.html
# 加载数据
march_2022 = SimpleDirectoryReader(input_files=["../data/10q/uber_10q_march_2022.pdf"]).load_data()
june_2022 = SimpleDirectoryReader(input_files=["../data/10q/uber_10q_june_2022.pdf"]).load_data()
sept_2022 = SimpleDirectoryReader(input_files=["../data/10q/uber_10q_sept_2022.pdf"]).load_data()
# 构建索引
march_index = VectorStoreIndex.from_documents(march_2022)
june_index = VectorStoreIndex.from_documents(june_2022)
sept_index = VectorStoreIndex.from_documents(sept_2022)
# 构建查询引擎
march_engine = march_index.as_query_engine(similarity_top_k=3)
june_engine = june_index.as_query_engine(similarity_top_k=3)
sept_engine = sept_index.as_query_engine(similarity_top_k=3)
query_engine_tools = [
    QueryEngineTool(
        query_engine=sept_engine,
        metadata=ToolMetadata(name='sept_22', description='提供有关2022年9月结束的Uber季度财务信息的信息')
    ),
    QueryEngineTool(
        query_engine=june_engine,
        metadata=ToolMetadata(name='june_22', description='提供有关2022年6月结束的Uber季度财务信息的信息')
    ),
    QueryEngineTool(
        query_engine=march_engine,
        metadata=ToolMetadata(name='march_22', description='提供有关2022年3月结束的Uber季度财务信息的信息')
    ),
]
# 运行查询
s_engine = SubQuestionQueryEngine.from_defaults(query_engine_tools=query_engine_tools)
response = s_engine.query('分析Uber在最近两个季度的收入增长情况。')

如下所示,LlamaIndex将一个复杂的查询分解成了2个子查询,并能够比较来自多个文档的信息以获得最终答案。

LlamaIndex:最终的LLM框架,用于索引和检索 人工智能 第3张

使用“路由器”在不同的查询引擎间选择

假设您正在构建一个从Notion和Slack中检索信息的机器人,语言模型如何知道使用哪个工具来搜索信息?LlamaIndex就像一个聪明的助手,可以帮助您查找东西,即使它们位于不同的位置。具体来说,LlamaIndex的“路由器”是一个超级简单的抽象,允许在不同的查询引擎之间“选择”。

在这个例子中,我们有来自Notion和Slack的两个文档索引,并为它们创建了两个查询引擎。之后,我们把所有的工具放在一起,创建一个超级工具叫做RouterQueryEngine,根据我们给每个工具的描述来选择使用哪个工具。这样,当我们询问关于Notion的问题时,路由器将自动从Notion文档中查找信息。

# 来源:https://gpt-index.readthedocs.io/en/latest/use_cases/queries.html#routing-over-heterogeneous-data
from llama_index import TreeIndex, VectorStoreIndex
from llama_index.tools import QueryEngineTool
# 定义子索引
index1 = VectorStoreIndex.from_documents(notion_docs)
index2 = VectorStoreIndex.from_documents(slack_docs)
# 定义查询引擎和工具
tool1 = QueryEngineTool.from_defaults(query_engine=index1.as_query_engine(),description="使用此查询引擎进行……",)
tool2 = QueryEngineTool.from_defaults(query_engine=index2.as_query_engine(),description="使用此查询引擎进行其他操作……",)
from llama_index.query_engine import RouterQueryEngine
query_engine = RouterQueryEngine.from_defaults(query_engine_tools=[tool1, tool2])
response = query_engine.query("在Notion中,给我产品路线图的摘要。")

这方面有许多令人兴奋的用例。以下是一个完整的例子,使用路由器在SQL和向量数据库之间进行选择:https://gpt-index.readthedocs.io/en/latest/examples/query_engine/SQLRouterQueryEngine.html 。

假设性文档嵌入(HyDE)

通常,当我们询问有关外部文档的问题时,我们通常使用文本嵌入来为问题和文档创建向量表示。然后,我们使用语义搜索来找到与问题最相关的文本块。但是,问题的答案可能与问题本身有很大不同。如果我们首先生成假设答案,然后找到与假设答案最相关的文本块,会怎样呢?这就是假设性文档嵌入(HyDE)发挥作用并有望提高输出质量的地方。

# 来源:https://gpt-index.readthedocs.io/en/latest/examples/query_transformations/HyDEQueryTransformDemo.html# 加载文档documents = SimpleDirectoryReader('llama_index/examples/paul_graham_essay/data').load_data()index = VectorStoreIndex.from_documents(documents)query_str = "what did paul graham do after going to RISD"#现在,我们使用HyDEQueryTransform生成假设文档,并将其用于嵌入查找。hyde = HyDEQueryTransform(include_original=True)hyde_query_engine = TransformQueryEngine(query_engine, hyde)response = hyde_query_engine.query(query_str)display(Markdown(f"<b>{response}</b>"))#在这个例子中,HyDE显着提高了输出质量,准确地幻想出Paul Graham在RISD之后做了什么(见下文),从而提高了嵌入质量和最终输出。query_bundle = hyde(query_str)hyde_doc = query_bundle.embedding_strs[0]

支持OpenAI函数调用

OpenAI最近发布了函数调用功能,以更可靠地将GPT的能力与外部工具和API连接起来。查看我的先前视频,了解它的确切工作方式。

LlamaIndex迅速集成了这个功能,并添加了全新的OpenAIAgent。查看此笔记本以了解更多信息。

如果有太多功能怎么办?使用RetrieverOpenAIAgent!查看这个笔记本。

将LlamaIndex与LangChain一起使用

LlmaIndex提供了与各种向量存储、ChatGPT插件、跟踪工具和LangChain的广泛集成。

Source: https://imgflip.com/memegenerator .

LlamaIndex与LangChain有何不同?

如果您使用过LangChain,您可能想知道LlamaIndex与LangChain有何不同。如果您不熟悉LangChain,请查看我的先前博客文章和视频。您会发现LIamaIndex和LangChain在其功能方面有着惊人的相似之处,包括索引、语义搜索、检索和向量数据库。它们都擅长于问题回答、文档摘要和构建聊天机器人等任务。

然而,它们各自都有其独特的关注领域。LangChain具有广泛的功能列表,投放更广泛的网,专注于使用链和代理与外部API连接。另一方面,LlamaIndex的关注点较窄,主要在数据索引和文档检索方面表现出色。

如何将LlamaIndex与LangChain一起使用?

有趣的是,LIamaIndex和LangChain并不是相互排斥的。事实上,您可以在LLM应用程序中同时使用两者。您可以同时使用LlamaIndex的数据加载器和查询引擎以及LangChain的代理。我知道很多人实际上在他们的项目中同时使用这两个工具。

以下是一个例子,我们在使用LangChain代理时使用LlamaIndex来保留聊天历史记录。当我们在第二轮对话中询问“我的名字是什么?”时,语言模型从第一轮对话中知道“我是Bob”:

# 来源:https://github.com/jerryjliu/llama_index/blob/main/examples/langchain_demo/LangchainDemo.ipynb# 使用LlamaIndex作为内存模块
from langchain import OpenAI
from langchain.llms import OpenAIChat
from langchain.agents import initialize_agent

from llama_index import ListIndex
from llama_index.langchain_helpers.memory_wrapper import GPTIndexChatMemory

index = ListIndex([])
memory = GPTIndexChatMemory(
    index=index,
    memory_key="chat_history",
    query_kwargs={"response_mode": "compact"},    # return_source返回源节点而不是查询索引
    return_source=True,    # return_messages以消息格式返回上下文
    return_messages=True)

llm = OpenAIChat(temperature=0)# llm=OpenAI(temperature=0)

agent_executor = initialize_agent([], llm, agent="conversational-react-description", memory=memory)

LlamaIndex:最终的LLM框架,用于索引和检索 人工智能 第5张

结论

总之,LlamaIndex是一个非常强大的工具,可以通过自己的数据增强大型语言模型的功能。它的各种数据连接器、先进的查询接口和灵活的集成使其成为开发具有LLM的应用程序的重要组成部分。

致谢

感谢Jerry Liu提供的建议和反馈!

Photo by Danielle Barnes on Unsplash

作者:Sophia Yang,2023年6月19日

Sophia Yang是一位高级数据科学家。在LinkedIn、Twitter和YouTube上与我联系,加入DS/ML图书俱乐部❤️

Leave a Reply

Your email address will not be published. Required fields are marked *