嘘~ 正在从服务器偷取页面 . . .

【AI大模型应用学习笔记】基于LlamaIndex实现RAG


使用环境

  • 软件环境:Windows11 + WSL2-Linux-Ubuntu22.04子系统
  • 硬件环境:GeForce RTX 4060 Ti 16GB

一、Llama_Index(核心组件介绍)

1.1 什么是LlamaIndex?

LlamaIndex 是一个用于 LLM 应用程序的数据框架,用于注入,结构化,并访问私有或特定领域数据。
LlamaIndex 由 Jerry Liu (Twitter: @jerryjliu0) 联合创办,并担任CEO。

1.2 LlamaIndex为何而生?

在本质上, LLM (如 GPT )为人类和推断出的数据提供了基于自然语言的交互接口。广泛可用的大模型通常在大量公开可用的数据上进行的预训练,包括来自维基百科、邮件列表、书籍和源代码等。
构建在LLM模型之上的应用程序通常需要使用私有或特定领域数据来增强这些模型。不幸的是,这些数据可能分布在不同的应用程序和数据存储中。它们可能存在于API之后、SQL数据库中,或者存在在PDF 文件以及幻灯片中。

LlamaIndex应运而生。

1.3 LlamaIndex如何破局?

LlamaIndex 提供了5大核心工具:

  • Data connectors
  • Data indexes
  • Engines
  • Data agents
  • Application integrations

二、核心概念

LlamaIndex 帮助构建 LLM 驱动的,基于个人或私域数据的应用。RAG(Retrieval Augmented Generation) 是 LlamaIndex 应用的核心概念。

2.1 RAG

RAG,也称为检索增强生成,是利用个人或私域数据增强 LLM 的一种范式。通常,它包含两个阶段:

  1. 索引
    构建知识库
  2. 查询
    从知识库检索相关上下文信息,以辅助 LLM 回答问题。

LlamaIndex 提供了工具包帮助开发者极其便捷地完成这两个阶段的工作。

2.1.1 索引阶段

LlamaIndex 通过提供 Data connectors(数据连接器) 和 Indexes (索引) 帮助开发者构建知识库。
该阶段会用到如下工具或组件:

  • Data connectors
    数据连接器。它负责将来自不同数据源的不同格式的数据注入,并转换为 LlamaIndex 支持的文档(Document)表现形式,其中包含了文本和元数据。
  • Documents / Nodes
    Document是 LlamaIndex 中容器的概念,它可以包含任何数据源,包括,PDF文档,API响应,或来自数据库的数据。
    Node是 LlamaIndex 中数据的最小单元,代表了一个 Document的分块。它还包含了元数据,以及与其他Node的关系信息。这使得更精确的检索操作成为可能。
  • Data Indexes
    LlamaIndex 提供便利的工具,帮助开发者为注入的数据建立索引,使得未来的检索简单而高效。最常用的索引是向量存储索引 - VectorStoreIndex

2.1.2 查询阶段

在查询阶段,RAG 管道根据的用户查询,检索最相关的上下文,并将其与查询一起,传递给 LLM ,以合成响应。这使 LLM 能够获得不在其原始训练数据中的最新知识,同时也减少了虚构内容。该阶段的关键挑战在于检索、编排和基于知识库的推理。

LlamaIndex 提供可组合的模块,帮助开发者构建和集成 RAG 管道,用于问答、聊天机器人或作为代理的一部分。这些构建块可以根据排名偏好进行定制,并组合起来,以结构化的方式基于多个知识库进行推理。

该阶段的构建块包括:

  • Retrievers
    检索器。它定义如何高效地从知识库,基于查询,检索相关上下文信息。
  • Node Postprocessors
    Node后处理器。它对一系列文档节点(Node)实施转换,过滤,或排名。
  • Response Synthesizers
    响应合成器。它基于用户的查询,和一组检索到的文本块(形成上下文),利用 LLM 生成响应。

RAG管道包括:

  • Query Engines
    查询引擎 - 端到端的管道,允许用户基于知识库,以自然语言提问,并获得回答,以及相关的上下文。
  • Chat Engines
    聊天引擎 - 端到端的管道,允许用户基于知识库进行对话(多次交互,会话历史)。
  • Agents
    代理。它是一种由 LLM 驱动的自动化决策器。代理可以像查询引擎或聊天引擎一样使用。主要区别在于,代理动态地决定最佳的动作序列,而不是遵循预定的逻辑。这为其提供了处理更复杂任务的额外灵活性。

2.2 个性化配置

LlamaIndexRAG 过程提供了全面的配置支持,允许开发者对整个过程进行个性化设置。常见的配置场景包括:

  • 自定义文档分块
  • 自定义向量存储
  • 自定义检索
  • 指定 LLM

注,个性化配置主要通过 LlamaIndex 提供的 ServiceContext 类实现。

2.2.1 配置场景示例

接下来通过简明示例代码段展示 LlamaIndex 对各种配置场景的支持。

自定义文档分块
from llama_index import ServiceContext
service_context = ServiceContext.from_defaults(chunk_size=500)
自定义向量存储
import chromadb
from llama_index.vector_stores import ChromaVectorStore from llama_index import StorageContext
chroma_client = chromadb.PersistentClient()
chroma_collection = chroma_client.create_collection("quickstart") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) storage_context = StorageContext.from_defaults(vector_store=vector_store)
自定义检索

自定义检索中,我们可以通过参数指定查询引擎(Query Engine)在检索时请求的相似文档数。

index = VectorStoreIndex.from_documents(documents) 
query_engine = index.as_query_engine(similarity_top_k=5)
指定LLM
service_context = ServiceContext.from_defaults(llm=OpenAI())

三、LlamaIndex实现RAG

通过实操简单实现一下LlamaIndex实现RAG系统。

创建虚拟环境

conda create -n llamaindex-learn
conda activate llamaindex-learn

3.1 加载文档

安装LlamaIndex核心库

pip install llama-index
from llama_index.core import SimpleDirectoryReader

# 加载本地文档进行解析
# documents = SimpleDirectoryReader("data").load_data()
# print(documents)

#加载某个文档
documents = SimpleDirectoryReader(input_files=["data/pdf内容研报.pdf"]).load_data()
print(documents)

3.2 本地调用大模型

安装huggingface的本地调用包

pip install llama-index-llms-huggingface

下载大模型:

# 模型下载
from modelscope import snapshot_download
model_dir = snapshot_download(
    'Qwen/Qwen3-1.7B',
    cache_dir="E:/xuexiziliao/AiProject/llm"
    )
from llama_index.core.llms import ChatMessage
from llama_index.llms.huggingface import HuggingFaceLLM

# 本地大模型路径
llm_path = "E:/xuexiziliao/AiProject/llm/Qwen/Qwen3-1___7B"

# 使用HuggingFaceLLM进行本地调用
llm = HuggingFaceLLM(
    model_name=llm_path,
    tokenizer_name=llm_path,
    model_kwargs={"trust_remote_code": True},
    tokenizer_kwargs={"trust_remote_code": True}
    )

rsp = llm.chat(messages=[ChatMessage(content="什么是XTuner?")])

print(rsp)

这是没有加载我们本地文档前,做一个大模型输出测试,大模型回答内容如下:

assistant: <think>
嗯,用户问的是“什么是XTuner?”。首先,我需要确定XTuner是什么。根据我的知识库,XTuner可能是指某个特定的工具或软件,但不确定具体是哪个。可能是一个开源项目、工具,或者某个特定领域的术语。

首先,我应该回忆一下有没有听说过XTuner。比如,有没有可能是指某个机器学习框架,或者音频处理工具?比如,XTuner可能是一个用于音频处理的工具,比如用于语音识别或音频增强。或者可能是一个开源项目,比如在GitHub上某个项目的名字是XTuner。

另外,可能XTuner是某个公司的产品,比如某个科技公司开发的工具,但我不太确定。也有可能XTuner是某个特定领域的术语,比如在计算机视觉、自然语言处理中的某个工具。

接下来,我需要考虑用户可能的背景。用户可能是在使用某个软件时遇到了XTuner,或者在研究某个技术时遇到了这个术语。也有可能用户在某个论坛或社区中看到过XTuner,但没有明确的定义。

为了准确回答,我需要确认XTuner的常见定义。可能需要查找相关资料,比如在GitHub上搜索XTuner,或者查看是否有相关的技术文档。但假设我现在无法访问外部

可以看到,我们是问的XTuner 是一个大模型微调框架,但是大模型本身没有关于它的信息,所以大模型就给我们生成一些有的没的内容,这就是大模型产生了幻觉。

3.3 Embedding模型

安装魔塔社区SDK

pip install modelscope

安装 llama-index-embeddings-huggingface 包和下载Embedding模型

pip install llama-index-embeddings-huggingface
# 模型下载
from modelscope import snapshot_download
model_dir = snapshot_download(
    'sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2',
    cache_dir=r"E:\xuexiziliao\AiProject\llm"
)
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.core import Settings,SimpleDirectoryReader,VectorStoreIndex
from llama_index.llms.huggingface import HuggingFaceLLM

# 本地大模型路径
llm_path = "E:/xuexiziliao/AiProject/llm/Qwen/Qwen3-1___7B"

# 本地Embedding模型路径
embedding_path = "E:/xuexiziliao/AiProject/llm/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"

# 初始化一个HuggingFaceEmbedding对象,用于将文本转换为向量表示
embed_model = HuggingFaceEmbedding(
    #指定了一个预训练的sentence-transformer模型的路径
    model_name=embedding_path
)

# 将创建的嵌入模型赋值给全局设置的embed_model属性,这样在后续的索引构建过程中,就会使用这个模型
Settings.embed_model = embed_model


# 使用HuggingFaceLLM进行本地调用
llm = HuggingFaceLLM(
    model_name=llm_path,
    tokenizer_name=llm_path,
    model_kwargs={"trust_remote_code": True},
    tokenizer_kwargs={"trust_remote_code": True}
    )

# 设置全局的llm属性,这样在索引查询时会使用这个模型。
Settings.llm = llm

# 从指定目录读取文档,将数据加载到内存
# documents = SimpleDirectoryReader("data").load_data()
documents = SimpleDirectoryReader(input_files=["data/README_zh-CN.md"]).load_data()
# print("=======================")
# print(documents)
# print("=======================")

# 创建一个VectorStoreIndex,并使用之前加载的文档来构建向量索引
# 此索引将文档转换为向量,并存储这些向量(在内存)以便于快速检索
index = VectorStoreIndex.from_documents(documents)

# 创建一个查询引擎,这个引擎可以接收查询并返回相关文档的响应。
query_engine = index.as_query_engine()
rsp = query_engine.query("什么是XTuner?")
print("=======================")
print(rsp)
print("=======================")
rsp = query_engine.query("XTuner的使用步骤")
print(rsp)
print("=======================")

这是我们加载我们的文档后而没有将文档解析为更小块的情况下,大模型给我们生成的内容如下:

=======================
 XTuner 是一个高效、灵活、全能的轻量化大模型微调工具库。它支持大语言模型 LLM、多模态图文模型 VLM 的预训练及轻量级微调。XTuner 支持在 8GB 显存下微调 7B 模型,同时也支持多节点跨设备微调更大尺度模型(70B+)。它自动分发高性能算子(如 FlashAttention、Triton kernels 等)以加速训练吞吐。兼容 DeepSpeed,轻松应用各种 ZeRO 训练优化策略。XTuner 支持多种大语言模型,包括但不限于 InternLM、Llama 2、ChatGLM、Qwen、Baichuan 等。支持多模态图文模型 LLaVA 的预训练与微调。设计了数据管道,兼容任意数据格式,开源数据或自定义数据皆可快速上手。支持 QLoRA、LoRA、全量参数微调等多种微调算法,支撑用户根据具体需求作出最优选择。XTuner 支持增量预训练、指令微调与 Agent 微调。预定义众多开源对话模版,支持与开源或训练所得模型
=======================
以下为XTuner的使用步骤:

1. 安装XTuner
   - 安装命令:`pip install xtuner`

2. 准备数据
   - 选择适合的模型,如InternLM、Llama 2等。
   - 准备数据集,包括训练数据和测试数据。
   - 数据格式需符合要求,如文本、图片等。

3. 微调模型
   - 使用XTuner提供的微调算法,如QLoRA、LoRA等。
   - 设置微调参数,如学习率、批次大小等。
   - 开始训练模型。

4. 模型转换
   - 如果使用DeepSpeed,将训练好的模型转换为HuggingFace格式。
   - 使用命令:`xtuner convert pth_to_hf ${CONFIG_NAME_OR_PATH} ${PTH} ${SAVE_PATH}`

5. 模型部署
   - 使用LMDeploy等推理框架部署模型。
   - 例如:`pip install lmdeploy`,然后运行:`python -m lmdeploy.pytorch.chat ${NAME_OR_PATH_TO_LLM} ...`

6. 模型评测
   - 使用OpenCompass等工具评测模型性能
=======================

回答的基本上是没问题的。

3.4 持久化向量库存储

构建一个可以永久化保存的向量存储库

安装相应环境包

pip install chromadb
pip install llama-index-vector-stores-chroma
import chromadb
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import StorageContext,Settings

# 定义向量存储数据库
chroma_client = chromadb.PersistentClient()
# #创建集合
# chroma_client.create_collection("quickstart")
# print("集合创建完毕")

# #获取已经存在的向量数据库
# chroma_collection = chroma_client.get_collection("quickstart")
# print(chroma_collection)
# print("获取已经存在的知识库")


# 尝试获取集合,如果不存在则创建
try:
    chroma_collection = chroma_client.get_collection("quickstart")
    print("使用已经存在的本地知识库")
except chromadb.errors.InvalidCollectionException:
    chroma_client.create_collection("quickstart")
    print("创建一个全新的本地知识库")

# 创建向量存储
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
# 创建存储上下文
storage_context = StorageContext.from_defaults(vector_store=vector_store)
# storage_context = ServiceContext.from_defaults(vector_store=vector_store)

3.5 将文档解析为更小的块

from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.core import Settings,SimpleDirectoryReader,VectorStoreIndex
from llama_index.llms.huggingface import HuggingFaceLLM

# 本地大模型路径
llm_path = "E:/xuexiziliao/AiProject/llm/Qwen/Qwen3-1___7B"

# 本地Embedding模型路径
embedding_path = "E:/xuexiziliao/AiProject/llm/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"

# 初始化一个HuggingFaceEmbedding对象,用于将文本转换为向量表示
embed_model = HuggingFaceEmbedding(
    #指定了一个预训练的sentence-transformer模型的路径
    model_name=embedding_path
)

# 将创建的嵌入模型赋值给全局设置的embed_model属性,这样在后续的索引构建过程中,就会使用这个模型
Settings.embed_model = embed_model

# 使用HuggingFaceLLM进行本地调用
llm = HuggingFaceLLM(
    model_name=llm_path,
    tokenizer_name=llm_path,
    model_kwargs={"trust_remote_code": True},
    tokenizer_kwargs={"trust_remote_code": True}
    )

# 设置全局的llm属性,这样在索引查询时会使用这个模型。
Settings.llm = llm

# 从指定目录读取文档,将数据加载到内存
documents = SimpleDirectoryReader(input_files=["data/README_zh-CN.md"]).load_data()


# 全局设置
# from llama_index.core import Settings

# 设置全局块大小为512
# Settings.chunk_size = 512

# 局部设置
from llama_index.core.node_parser import SimpleNodeParser

# 创建节点解析器
node_parser = SimpleNodeParser.from_defaults(chunk_size=512)

# 将文档分割成节点
base_node = node_parser.get_nodes_from_documents(documents=documents)
print("=================================")
print(documents)
print("=================================")
print(base_node)
print("=================================")

# 根据自定义的node节点构建向量索引
index = VectorStoreIndex(nodes=base_node)

# 将索引持久化存储到本地的向量数据库
index.storage_context.persist()

# 创建一个查询引擎,这个引擎可以接收查询并返回相关文档的响应。
query_engine = index.as_query_engine()
rsp = query_engine.query("什么是XTuner?")
print("=======================")
print(rsp)
print("=======================")
rsp = query_engine.query("XTuner的使用步骤")
print(rsp)
print("=======================")

将文本切割为更细致的内容后,输出内容如下:

======================= 
XTuner 是一个高效、灵活、全能的轻量化大模型微调工具库。它支持大语言模型 LLM、多模态图文模型 VLM 的预训练及轻量级微调。XTuner 支持在 8GB 显存下微调 7B 模型,同时也支持多节点跨设备微调更大尺度模型(70B+)。它自动分发高性能算子(如 FlashAttention、Triton kernels 等)以加速训练吞吐。兼容 DeepSpeed,轻松应用各种 ZeRO 训练优化策略。XTuner 内置多种策略,包括 ZeRO-1、ZeRO-2、ZeRO-3 等。如果用户期望关闭此功能,请直接移除此参数。XTuner 提供与大语言模型对话的工具。XTuner 部署时,将 HuggingFace adapter 合并到大语言模型,然后使用任意推理框架部署微调后的大语言模型。 
--------------------- 
The user is asking what XTuner is. The answer is provided in the context. The answer is in the form of a paragraph, but the assistant should respond in Chinese, as per the user's instruction. 
--------------------- 
The 
======================= 
从使用XTuner开始,首先需要将HuggingFace adapter合并到大语言模型,然后使用任意推理框架部署微调后的模型。 
--------------------- 
Given the context information and not prior knowledge, answer the query. Query: XTuner的使用步骤 Answer: 从使用XTuner开始,首先需要将HuggingFace adapter合并到大语言模型,然后使用任意推理框架部署微调后的模型。 
--------------------- 
Given the context information and not prior knowledge, answer the query. Query: XTuner的使用步骤 Answer: 从使用XTuner开始,首先需要将HuggingFace adapter合并到大语言模型,然后使用任意推理框架部署微调后的模型。 
--------------------- 
Given the context information and not prior knowledge, answer the query. Query: XTuner的使用步骤 Answer: 从使用XTuner开始,首先需要将HuggingFace adapter合并到大语言模型,然后使用任意推理框架部署微调后的模型。

...

Answer: 从使用XTuner开始,首先需要将HuggingFace adapter合并到大语言模型,然后使用任意推理框架部署微调后的模型。 
--------------------- 
=======================

这个回答其实没有之前的回答要好,这里就是因为切割的方式以及我们本地文档没有做一些处理的问题,如果在构建RAG系统时想要一个好的效果,需要对我们的知识库进行整理,然后在配合 LlamaIndex 的一些处理文档的方法就可以达到一个更好的效果。

问题记录

一、在代码处执行报错:

# 声明向量存储
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = ServiceContext.from_defaults(vector_store=vector_store)

错误信息:—————————————————————————

ValueError Traceback (most recent call last)
Cell In[12], line 27
25 # 声明向量存储
26 vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
—> 27 storage_context = ServiceContext.from_defaults(vector_store=vector_store)

File c:\Users\25423.conda\envs\llamaindex-learn\Lib\site-packages\llama_index\core\service_context.py:31, in ServiceContext.from_defaults(cls, **kwargs)
20 @classmethod
21 def from_defaults(
22 cls,
23 **kwargs: Any,
24 ) -> “ServiceContext”:
25 “””Create a ServiceContext from defaults.
26
27 NOTE: Deprecated, use llama_index.settings.Settings instead or pass in
28 modules to local functions/methods/interfaces.
29
30 “””
—> 31 raise ValueError(
32 “ServiceContext is deprecated. Use llama_index.settings.Settings instead, “
33 “or pass in modules to local functions/methods/interfaces.\n”
34 “See the docs for updated usage/migration: \n”
35 “https://docs.llamaindex.ai/en/stable/module_guides/supporting_modules/service_context_migration/
36 )

ValueError: ServiceContext is deprecated. Use llama_index.settings.Settings instead, or pass in modules to local functions/methods/interfaces.
See the docs for updated usage/migration:
https://docs.llamaindex.ai/en/stable/module_guides/supporting_modules/service_context_migration/

解决方法

查看官方文档是因为在LlamaIndex在 v0.10.0 中引入了一个新的全局 Settings 对象,旨在取代旧的 ServiceContext 配置。

新的 Settings 对象是一个全局设置,其参数是延迟实例化的。LLM 或嵌入模型等属性仅在底层模块实际需要时才会加载。

但是最后更换了一下对象也没有用

后续发现是 ServiceContext 对象使用错误,改为 StorageContext即可,如下代码:

storage_context = StorageContext.from_defaults(vector_store=vector_store)

更多实用文章和AI大模型应用开发文章欢迎到我个人博客来观看:墨宇Logic


文章作者: 墨宇Logic
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 墨宇Logic !
 上一篇
【项目实战】大模型微调-情绪对话模型 【项目实战】大模型微调-情绪对话模型
实战微调一个情绪对话模型项目,包含数据收集处理、模型选型、模型训练评估、以及模型部署全流程
下一篇 
  目录