文章目录
- 一、RAG基础
- 二、使用大语言模型LLMs
- 2.1 使用OpenAI大模型
- 2.2 本地大模型
- 三、构建RAG pipeline
- 3.1 加载数据
- 3.1.1 SimpleDirectoryReader
- 3.1.2 DatabaseReader
- 3.1.3 直接创建文档Document
- 3.2 转换数据
- 3.3 索引/嵌入 Indexing & Embedding
- 3.4 存储
- 3.5 查询
- 3.6 评估
- 3.6.1 生成结果质量评估
- 3.6.2 检索结果评估
- 三、RAG示例
- 参考资料
LlamaIndex是一个LLM文本增强的框架,其中包含完整的RAG解决方案。项目在2023年1月29日发布了第一个版本,当时叫做“GPT Index v0.2.17” ,项目作者Jerry Liu。
- Github地址:https://github.com/run-llama/llama_index
- 官方文档:https://docs.llamaindex.ai/en/stable/
一、RAG基础
LLM是在大量数据上训练的,但它们并没有在你的私有数据上训练。检索增强生成(RAG)通过将您的数据添加到LLM已经可以访问的数据中来解决这个问题。
RAG的工作流程如下:
RAG(检索增强生成)包括五个关键阶段:加载(Loading)、索引(Indexing)、存储(Storing)、查询(Querying)和评估(Evaluation)。
- 加载(Loading):加载阶段涉及从数据源获取数据,可以是文本文件、PDF、其他网站、数据库或API。LlamaHub提供了数百个连接器可供选择,用于将数据导入到数据处理流程中。
- 索引(Indexing):索引阶段意味着创建一个数据结构,以便对数据进行查询。对于LLM(大型语言模型)来说,这几乎总是意味着创建向量嵌入(vector embeddings),即数据含义的数值表示,以及许多其他元数据策略,使得可以轻松准确地找到上下文相关的数据。
- 存储(Storing):将数据存储到向量数据库中。
- 查询(Querying):对于任何给定的索引策略,可以利用LLM和LlamaIndex数据结构进行查询,包括子查询、多步查询和混合策略等多种方式。
- 评估(Evaluation):在任何流程中,评估都是至关重要的步骤,用于检查相对于其他策略或在进行更改时流程的有效性。评估提供了关于对查询的响应有多准确、忠实和快速的客观度量标准。
二、使用大语言模型LLMs
在LlamaIndex中,我们可以使用大语言模型的API接口或者本地大语言模型。
首先安装环境:
pip install llama-index
如果配置ollama本地模型,需要额外安装:
pip install llama-index-llms-ollama
pip install llama-index-embeddings-ollama
2.1 使用OpenAI大模型
from llama_index.llms.openai import OpenAI
from llama_index.core import SettingsSettings.llm = OpenAI(temperature=0.2, model="gpt-4")
在上述代码中,我们实例化了一个OpenAI的LLM并将其传递给Settings。其中,Settings设置是一组配置数据,您可以将其传递到LlamaIndex的不同部分。
2.2 本地大模型
LlamaIndex还支持本地大模型,Ollama是比较常用的本地大模型部署及提供服务的工具,具体使用可以参见本人之前的博客:【大模型】Ollama的安装部署及运行大模型教程
在基于Ollama部署好大模型后,就可以用 Settings.llm = Ollama(model="llama2")
来设置本地大模型了。
from llama_index.llms.ollama import Ollama
from llama_index.core import SettingsSettings.llm = Ollama(model="llama2", request_timeout=60.0)
三、构建RAG pipeline
我们首先介绍下LlamaIndex中的几个基本概念:
- 文档(document):文档是任何数据源的通用容器。 例如,PDF、API 输出或从数据库检索的数据。 它们可以手动构建,也可以通过数据加载器自动创建。 默认情况下,文档存储文本以及一些其他属性。
- 节点(node):节点代表源文档的“块(chunk)”,无论是文本块、图像还是更多。 它们还包含元数据以及与其他节点和索引结构的关系信息。可以选择直接定义节点及其所有属性。 还可以选择通过 NodeParser 类将源文档“解析”为节点。
- 元数据(metadata):每个文档/节点的元数据字典可以包含附加信息来帮助通知响应并跟踪查询响应的来源。 此信息可以是任何内容,例如文件名或类别。 此信息包含在节点中,使索引能够在查询和响应中利用它。 默认情况下,元数据会注入到嵌入和 LLM 模型调用的文本中。
3.1 加载数据
在我们选择的LLM对数据进行操作前,我们首先需要加载并处理数据。这与机器学习中的数据清理/特征工程管道或传统数据设置中的ETL管道相似。数据加载及处理由三个主要阶段组成:
- 加载数据 (Load the data)
- 转换数据 (Transform the data)
- 索引并存储数据 (Index and store the data)
3.1.1 SimpleDirectoryReader
LlamaIndex中最简单最常用的Reader是SimpleDirectoryReader
,它内置于LlamaIndex中,可以读取各种格式,包括Markdown、PDF、Word文档、PowerPoint幻灯片、图像、音频和视频。
from llama_index.core import SimpleDirectoryReaderdocuments = SimpleDirectoryReader("./data").load_data()
3.1.2 DatabaseReader
在这个例子中,LlamaIdex下载并安装了名为DatabaseReader的连接器,该连接器对SQL数据库运行查询,并将结果的每一行作为Document返回:
from llama_index.core import download_loaderfrom llama_index.readers.database import DatabaseReaderreader = DatabaseReader(scheme=os.getenv("DB_SCHEME"),host=os.getenv("DB_HOST"),port=os.getenv("DB_PORT"),user=os.getenv("DB_USER"),password=os.getenv("DB_PASS"),dbname=os.getenv("DB_NAME"),
)query = "SELECT * FROM users"
documents = reader.load_data(query=query)
3.1.3 直接创建文档Document
我们也可以不使用loader,而是直接创建 Document,代码如下:
from llama_index.core import Documentdoc = Document(text="text")
3.2 转换数据
加载数据后,在将数据存储入库前,需要对数据进行处理和转换。这些转换包括:
- 分块 (chunking)
- 提取元数据 (extracting metadata)
- 块嵌入 (embedding each chunk)
示例代码如下:
from llama_index.core import VectorStoreIndexvector_index = VectorStoreIndex.from_documents(documents)
vector_index.as_query_engine()
引擎(engine)提供了数据连接到自然语言的,LlamaIndex主要包含有两种引擎:
- 查询引擎(Query engine):用于检索查询任务。
- 聊天引擎(Chat engine):支持多轮对话。
3.3 索引/嵌入 Indexing & Embedding
在RAG(检索增强生成)中的索引阶段涉及以下内容:
- 索引(Indexes):在摄取数据后,LlamaIndex将数据索引到一个易于检索的结构中。通常这包括生成向量嵌入(vector embeddings),并将其存储在称为向量存储(vector store)的专门数据库中。索引还可以存储关于数据的各种元数据。
- 嵌入(Embeddings):LLM(大型语言模型)生成称为嵌入(embeddings)的数据的数值表示。在过滤与查询相关的数据时,LlamaIndex会将查询转换为嵌入,并且您的向量存储将找到与查询嵌入数值相似的数据。
LlamaIndex 提供了几种不同的索引类型。 在这里介绍最常见的VectorStoreIndex
。
- Vector Store Index:向量数据库索引获取文档document并将它们分成节点node。 然后,它创建每个节点文本的向量嵌入,以供LLM查询。要使用向量存储索引,将在加载阶段创建的文档列表或者Node 对象列表传递给它。
from llama_index.core import VectorStoreIndexindex = VectorStoreIndex.from_documents(documents)
3.4 存储
LlamaIndex 还支持可交换存储组件,包括:
- 文档存储:存储摄取的文档(即 Node 对象)的位置
- 索引存储:存储索引元数据的位置
- 向量存储:存储嵌入向量的位置
- 图存储:存储知识图的位置(即 KnowledgeGraphIndex)
- 聊天存储:存储和组织聊天消息的地方
3.5 查询
简单的查询只是对LLM的prompt调用:它可以是一个问题并获得答案,或者是一个总结请求。更复杂的查询可能涉及重复/链接prompt+ LLM 调用,甚至跨多个组件的推理循环。
在RAG(检索增强生成)中的查询阶段涉及以下内容:
- 检索器(Retrievers):检索器定义了如何在给定查询时从索引中高效检索相关上下文。检索策略对于检索到的数据的相关性和效率至关重要。
- 路由器(Routers):路由器确定将使用哪个检索器从知识库中检索相关上下文。更具体地说,RouterRetriever类负责选择一个或多个候选检索器来执行查询。它们使用选择器根据每个候选的元数据和查询选择最佳选项。
- 节点后处理器(Node Postprocessors):节点后处理器接收一组检索到的节点,并对它们应用转换、过滤或重新排序逻辑。
- 响应合成器(Response Synthesizers):响应合成器使用用户查询和一组检索到的文本块从LLM生成响应。
在下面的示例中,我们自定义检索器以对 top_k 使用不同的值,并添加一个后处理步骤,该步骤要求检索到的节点达到要包含的最小相似度分数。 当有相关结果时,这将提供大量数据,但如果没有任何相关结果,则可能不会提供任何数据。
from llama_index.core import VectorStoreIndex, get_response_synthesizer
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.postprocessor import SimilarityPostprocessor# build index
index = VectorStoreIndex.from_documents(documents)# configure retriever
retriever = VectorIndexRetriever(index=index,similarity_top_k=10,
)# configure response synthesizer
response_synthesizer = get_response_synthesizer()# assemble query engine
query_engine = RetrieverQueryEngine(retriever=retriever,response_synthesizer=response_synthesizer,node_postprocessors=[SimilarityPostprocessor(similarity_cutoff=0.7)],
)# query
response = query_engine.query("What did the author do growing up?")
print(response)
3.6 评估
LlamaIndex 提供了衡量生成结果质量和检索质量的关键模块。
3.6.1 生成结果质量评估
LlamaIndex 提供基于LLM的评估模块来衡量结果的质量。 这使用“黄金”LLM(例如 GPT-4)以多种方式决定预测答案是否正确。当前的评估模块不需要真实标签。 可以通过查询、上下文、响应的某种组合来完成评估,并将这些与 LLM 调用结合起来。
这些评估模块有以下形式:
- 正确性:生成的答案是否与给定查询的参考答案匹配(需要标签)。
- 语义相似度 预测答案在语义上是否与参考答案相似(需要标签)。
- 忠实性(Faithfulness):评估答案是否忠实于检索到的上下文(换句话说,是否存在幻觉)。
- 上下文相关性:检索到的上下文是否与查询相关。
- 答案相关性:生成的答案是否与查询相关。
- 准则遵守情况:预测答案是否遵守特定准则。
from llama_index.core import VectorStoreIndex
from llama_index.llms.openai import OpenAI
from llama_index.core.evaluation import FaithfulnessEvaluator# create llm
llm = OpenAI(model="gpt-4", temperature=0.0)# build index
...
vector_index = VectorStoreIndex(...)# define evaluator
evaluator = FaithfulnessEvaluator(llm=llm)# query index
query_engine = vector_index.as_query_engine()
response = query_engine.query("What battles took place in New York City in the American Revolution?"
)
eval_result = evaluator.evaluate_response(response=response)
print(str(eval_result.passing))
3.6.2 检索结果评估
给定问题数据集和真实排名,我们可以使用平均倒数排名(MRR)、命中率、精度等排名指标来评估检索器。核心检索评估步骤围绕以下内容:
- 数据集生成:给定非结构化文本语料库,综合生成(问题、上下文)对。
- 检索评估:给定检索器和一组问题,使用排名指标评估检索结果。
from llama_index.core.evaluation import RetrieverEvaluator# define retriever somewhere (e.g. from index)
# retriever = index.as_retriever(similarity_top_k=2)
retriever = ...retriever_evaluator = RetrieverEvaluator.from_metric_names(["mrr", "hit_rate"], retriever=retriever
)retriever_evaluator.evaluate(query="query", expected_ids=["node_id1", "node_id2"]
)
三、RAG示例
使用本地大模型实现一个简单的RAG的代码如下:
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.ollama import OllamaEmbedding# 加载本地数据
documents = SimpleDirectoryReader("./data").load_data()# Embedding模型
Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text")# 引入本地大模型
Settings.llm = Ollama(model="llama3.1:8b", request_timeout=360)# 构建索引
index = VectorStoreIndex.from_documents(documents)# 查询引擎
query_engine = index.as_query_engine()# 执行查询并获取响应
response = query_engine.query("霸王茶姬香港店什么时候开业?店长薪酬多少?")
print(response)
参考资料
- https://docs.llamaindex.ai/en/stable/
- LlamaIndex——RAG概述
- https://www.bilibili.com/video/BV1jE421A77u/?spm_id_from=333.1387.favlist.content.click&vd_source=87a3abdad251514e8efa36af41d3eba9