前言
在大模型(如 GPT、LLaMA 等)快速发展的今天,生成式 AI 的能力已经令人惊叹,但其固有的“幻觉问题”仍然是一个重要挑战。大模型在生成文本时,可能会输出与事实不符、逻辑错误或无关的内容,这严重限制了其在关键场景(如问答系统、知识检索等)中的可靠性和实用性。

为了解决这一问题,检索增强生成(Retrieval-Augmented Generation, RAG) 技术应运而生。RAG 通过将大模型与外部知识库结合,在生成答案前先检索相关事实信息,从而显著提升生成内容的准确性和可信度。而 LlamaIndex 作为一个强大的工具,能够快速构建 RAG 系统,帮助开发者高效地将大模型与外部数据源(如文档、数据库)连接,实现更精准的知识检索与生成。

本文将通过 LlamaIndex,展示如何快速构建 RAG 系统,有效缓解大模型的幻觉问题,为生成式 AI 的应用提供更可靠的解决方案。

一、概念介绍

1. LlamaIndex

LlamaIndex 是一个开源框架,用于快速构建检索增强生成(RAG)应用。它可以帮助开发者将检索组件(如向量数据库)与语言生成模型(如 LLM)结合,高效地处理和检索文档数据,从而生成更准确、更有依据的内容

2. RAG

RAG 是一种技术,通过检索相关文档来增强语言模型的生成能力。它结合了信息检索和语言生成,让模型在生成内容之前先找到相关的证据或上下文,从而提高生成内容的准确性和可靠性

3. 大模型幻觉

大模型幻觉是指大型语言模型生成看似合理但不符合事实或现实的内容的现象。这是由于模型基于概率生成内容,有时会编造或虚构信息,导致生成的结果与真实情况不符

二、llama_index加载本地大模型

1. 下载大模型(DeepSeek-R1)

下载一个deepseek-R1蒸馏过的模型,如果没有蒸馏的都非常大,也可以选参数量更大的,在魔塔社区下载就行。

#模型下载
from modelscope import snapshot_download
model_dir = snapshot_download('deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B')

2. 加载

使用HuggingFaceLM加载模型,问个简单问题

from llama_index.core.llms import ChatMessage
from llama_index.llms.huggingface import HuggingFaceLLM

#使用HuggingFaceLLM加载本地大模型
llm = HuggingFaceLLM(model_name="/root/autodl-tmp/llm/deepseek-ai/DeepSeek-R1-Distill-Qwen-1___5B",
               tokenizer_name="/root/autodl-tmp/llm/deepseek-ai/DeepSeek-R1-Distill-Qwen-1___5B",
               model_kwargs={"trust_remote_code":True},
               tokenizer_kwargs={"trust_remote_code":True})
#调用模型chat引擎得到回复
rsp = llm.chat(messages=[ChatMessage(content="你叫什么名字?")])

print(rsp)

运行后回答如下

(llamaindex) root@autodl-container-565243b323-b324df38:~/autodl-tmp# python test01.py
Setting `pad_token_id` to `eos_token_id`:151643 for open-end generation.
assistant: <think>
我是由深度求索公司独立开发的DeepSeek-R1。关于不同模型的差异,建议您参考官方信息或亲自体验。我会继续专注于以诚实专业的态度为您提供最好的帮助。
</think>

我是由深度求索公司独立开发的DeepSeek-R1。关于不同模型的差异,建议您参考官方信息或亲自体验。我会继续专注于以诚实专业的态度为您提供最好的帮助。
(llamaindex) root@autodl-container-565243b323-b324df38:~/autodl-tmp# 

3. GPU使用

在运行上面代码,模型推理的时候大概需要8G显存,我这个12G的,所以模型选择根据自己显存大小。
在这里插入图片描述

三、复现幻觉

1. 两次调用回答专业术语

直接加载本地大模型,然后对它提问。

from llama_index.core.llms import ChatMessage
from llama_index.llms.huggingface import HuggingFaceLLM

#使用HuggingFaceLLM加载本地大模型
llm = HuggingFaceLLM(model_name="/root/autodl-tmp/llm/deepseek-ai/DeepSeek-R1-Distill-Qwen-1___5B",
               tokenizer_name="/root/autodl-tmp/llm/deepseek-ai/DeepSeek-R1-Distill-Qwen-1___5B",
               model_kwargs={"trust_remote_code":True},
               tokenizer_kwargs={"trust_remote_code":True})
#调用模型chat引擎得到回复
rsp = llm.chat(messages=[ChatMessage(content="xtuner是什么?")])

print(rsp)

2. 第一次运行

模型的回答,第一次运行

(llamaindex) root@autodl-container-565243b323-b324df38:~/autodl-tmp# python test01.py
Setting `pad_token_id` to `eos_token_id`:151643 for open-end generation.
assistant: <think>

</think>

xtuner 是一个用于 PyTorch 中的自适应优化算法(Adam 优化器)的工具包,旨在优化模型的训练过程。它通过自适应调整学习率来加速收敛和提高模型性能。

### 主要特点:
1. **自适应学习率**:xtuner 通过分析参数的梯度分布来动态调整学习率,避免过快下降或 overshoot。
2. **适用于多种模型**:支持在各种模型架构下工作,包括全连接层、卷积层和循环层。
3. **高效训练**:通过自适应调整,加快收敛速度,减少训练时间。

### 主要函数:
- **AdamW**:结合了 Adam 优化器的 AdamW(包括权重衰减)。
- **L2和L1**:分别支持 L2 和 L1 正则化。
- **LayerNorm**:支持 Layer Normalization 模块的自适应调整。

### 下载与安装:
- **PyTorch 版本要求**:xtuner 需要 PyTorch 1.9+ 版本。
- **安装方法**1. 下载 PyTorch 安装包

3. 第二次运行

(llamaindex) root@autodl-container-565243b323-b324df38:~/autodl-tmp# python test01.py
Setting `pad_token_id` to `eos_token_id`:151643 for open-end generation.
assistant: <think>

</think>

xtuner 是一个用于 TensorFlow 中的自适应优化算法(Adaptive Gradient Descent),旨在自动调整学习率,从而提高训练模型的收敛速度和性能。自适应优化算法通过分析梯度分布来动态调整学习率,而非简单的固定或者线性调整。

### 主要特点
1. **自适应学习率**:xtuner 非常快地调整学习率,根据训练过程中梯度的分布情况来动态调整。
2. **适用于各种模型**:可以适用于各种深度学习模型,包括卷积神经网络(CNN)、长短期记忆网络(LSTM)、循环神经网络(RNN)等。
3. **无参数调整**:自适应学习率的调整不需要额外的参数,减少了模型的复杂性。

### 适用场景
- **训练速度**:在训练过程中,xtuner 可以显著提高训练速度,特别是在模型收敛较慢的情况下。
- **优化性能**:通过自动调整学习率,可以提升模型的收敛稳定性,避免过拟合或训练过程中出现的梯度爆炸或消失梯度问题。

### 与其他优化算法的区别
- **SGD**:xtuner 不是基于随机梯度
(llamaindex) root@autodl-container-565243b323-b324df38:~/autodl-tmp# 

4. 结果对比

可以看到2次运行差异非常大,而且是一本正经胡说八道,这就是大模型的幻觉,对于不知道的东西,并不是说我不了解,而且每次东拼西凑,回答出一堆貌似很正经,但其实完全不相关的东西。

四、使用RAG

怎么把模型和本地数据库结合起来,这里就用到了RAG.

1. 本地数据

如何解决大模型环境,就需要给它本地数据库,先学习,搜索出需要的知识,再喂给大模型,这里给它一个xtuner的markdown格式文件。
在这里插入图片描述

2. 向量模型

将检索后的数据给大模型,然后再看看大模型输出
首先是需要一个把文本转换成向量的模型,目的就是把文本转成一个词向量存储到数据库,方面大模型的查询.

#模型下载
from modelscope import snapshot_download
model_dir = snapshot_download('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2',cache_dir="/root/autodl-tmp/llm/")

下载词向量模型

Downloading Model to directory: /root/public/llm/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
2025-02-10 09:11:48,764 - modelscope - INFO - Got 28 files, start to download ...
Downloading [configuration.json]: 100%|████████████████████████████████████████████████████████████████████████████████| 77.0/77.0 [00:00<00:00, 146B/s]
Downloading [config_sentence_transformers.json]: 100%|███████████████████████████████████████████████████████████████████| 122/122 [00:00<00:00, 176B/s]
[00:53<00:00, 2.20MB/s]
Downloading [onnx/model_qint8_avx512_vnni.onnx]: 100%|███████████████████████████████████████████████████████████████| 113M/113M [01:16<00:00, 1.54MB/s]
Downloading [modules.json]: 100%|████████████████████████████████████████████████████████████████████████████████████████| 
Downloading [onnx/model.onnx]:  45%|████████████████████████████████████                                             | 200M/449M [02:07<02:28, 1.76MB/s]
Downloading [onnx/model_O3.onnx]:  23%|█████████████████▉                                                             | 102M/448M [02:06<13:32, 447kB/s]
Downloading [onnx/model_O1.onnx]:  33%|██████████████████████████▏                                                    | 149M/448M [02:07<09:49, 532kB/

3. 调用query引擎

下面是全部代码,也就是全局变量Settings,需要2个模型,一个是文本转向量模型,一个是基座大模型。然后把数据读到内存种,创建一个query引擎,还有chat引擎,那个是多轮对话。

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

#初始化一个HuggingFaceEmbedding对象,用于将文本转换为向量表示
embed_model = HuggingFaceEmbedding(
    #指定了一个预训练的sentence-transformer模型的路径
    model_name="/root/autodl-tmp/llm/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)

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

#使用HuggingFaceLLM加载本地大模型
llm = HuggingFaceLLM(model_name="/root/autodl-tmp/llm/deepseek-ai/DeepSeek-R1-Distill-Qwen-1___5B",
               tokenizer_name="/root/autodl-tmp/llm/deepseek-ai/DeepSeek-R1-Distill-Qwen-1___5B",
               model_kwargs={"trust_remote_code":True},
               tokenizer_kwargs={"trust_remote_code":True})
#设置全局的llm属性,这样在索引查询时会使用这个模型。
Settings.llm = llm

#从指定目录读取文档,将数据加载到内存
documents = SimpleDirectoryReader("/root/autodl-tmp/data").load_data()
# print(documents)
#创建一个VectorStoreIndex,并使用之前加载的文档来构建向量索引
#此索引将文档转换为向量,并存储这些向量(内存)以便于快速检索
index = VectorStoreIndex.from_documents(documents)
#创建一个查询引擎,这个引擎可以接收查询并返回相关文档的响应。
query_engine = index.as_query_engine()
rsp = query_engine.query("xtuner的使用步骤是什么?")
print(rsp)

下面是打印信息,和之前没用RAG直接问大模型进行对比。
可以看到,这次就很靠谱了,xtuner就是微调用的。

(llamaindex) root@autodl-container-565243b323-b324df38:~/autodl-tmp# python test02.py 
Setting `pad_token_id` to `eos_token_id`:151643 for open-end generation.
以下是xtuner的使用步骤:

1. 选择合适的微调模型:根据你的任务选择适合的微调模型,例如基于Llama、ChatGLM等的微调模型。

2. 转换预训练模型到微调模型:将预训练模型转换为适合微调的模型形式,这一步是必要的,因为微调需要特定的输入格式和参数。

3. 调整微调策略:根据微调任务调整微调策略,例如选择不同的训练数据、优化器、学习率调整等。

4. 运行微调训练:使用XTuner对预训练模型进行微调训练,直到满足训练目标。

5. 处理结果输出:根据微调任务输出结果,这可能包括模型参数更新、验证结果等。

6. 调整微调参数:根据微调结果调整微调策略,重复上述步骤,直到满足训练目标。

7. 保存和部署:保存微调后的模型,并将模型部署到可用的部署工具,例如LMDeploy等。
</think>

以下是xtuner的使用步骤:

1. 选择合适的微调模型:根据你的任务选择适合的微调模型,例如基于L
(llamaindex) root@autodl-container-565243b323-b324df38:~/autodl-tmp# 

链接: XTuner大模型微调

链接: LlamaIndex组件介绍

4. 建立向量数据库

没有数据库,下次调用时候,就要把document重新构建索引,为了避免不必要的内存开销,就需要一个向量数据库,只需要加载一次就行了,下次再调用直接数据库里查找。
ChromaDB 是一个开源的向量数据库,专为高效存储和检索高维向量数据而设计,特别适合与大型语言模型(LLMs)和嵌入模型(Embeddings)集成

pip install chromadb
pip install llama-index-vector-stores-chroma

第一次创建的时候才用create,当已经创建过了,下次使用就不用create
为了不改代码同时覆盖2种情况,就用一个try语句。

import chromadb
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import ServiceContext

#定义向量存储数据库
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 = ServiceContext.from_defaults(vector_store=vector_store)

5. 数据持久化

将文档分割成节点后,进行数据的持久化 index.storage_context.persist()

from llama_index.core import Settings,SimpleDirectoryReader,VectorStoreIndex
from llama_index.llms.huggingface import HuggingFaceLLM
from llama_index.core.node_parser import SimpleNodeParser

#初始化一个HuggingFaceEmbedding对象,用于将文本转换为向量表示
embed_model = HuggingFaceEmbedding(
    #指定了一个预训练的sentence-transformer模型的路径
    model_name="/root/public/llm/sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
)

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

#使用HuggingFaceLLM加载本地大模型
llm = HuggingFaceLLM(model_name="/root/autodl-tmp/llm/deepseek-ai/DeepSeek-R1-Distill-Qwen-1___5B",
               tokenizer_name="/root/autodl-tmp/llm/deepseek-ai/DeepSeek-R1-Distill-Qwen-1___5B",
               model_kwargs={"trust_remote_code":True},
               tokenizer_kwargs={"trust_remote_code":True})
#设置全局的llm属性,这样在索引查询时会使用这个模型。
Settings.llm = llm

#从指定目录读取文档,将数据加载到内存
documents = SimpleDirectoryReader("/root/autodl-tmp/data").load_data()
# print(documents)
#创建节点解析器
node_parser = SimpleNodeParser.from_defaults(chunk_size=512)
#将文档分割成节点
base_node = node_parser.get_nodes_from_documents(documents=documents)
print(documents)
print("=================================")
print(base_node)
print("=================================")
#根据自定义的node节点构建向量索引
index = VectorStoreIndex(nodes=base_node)

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

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

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

6. 向量数据

数据持久化后会生成一个storage文件夹,里面有几个json文件.在这里插入图片描述
其中default_vector_store.json就是本地数据转存的向量表.
可以看到这个向量表所值就是一个-1到1的归一化的符合正态分布的向量表.
在这里插入图片描述

7. 运行结果

在这里插入图片描述

五、总结

在生成式 AI 的快速发展中,大模型的幻觉问题一直是制约其广泛应用的关键挑战之一。幻觉现象不仅降低了模型输出的可信度,还可能在实际应用中引发严重后果。为了解决这一问题,检索增强生成(RAG)技术应运而生,通过结合信息检索和语言生成,显著提升了生成内容的准确性和可靠性。
LlamaIndex 作为构建 RAG 应用的强大工具,为开发者提供了一种高效、灵活且易于上手的解决方案。它不仅简化了 RAG 系统的开发流程,还支持多种高级功能,如高效的向量检索、灵活的索引构建以及与多种语言模型的无缝集成。通过这些特性,LlamaIndex 能够有效减少大模型的幻觉问题,使其在复杂的应用场景中更加可靠和实用。
从实际应用来看,LlamaIndex 已经在多个领域展现出其强大的能力。无论是基于本地知识库的问答机器人,还是多模态生成任务,LlamaIndex 都能够通过其高效的检索和生成机制,提供准确且有依据的输出。这种技术的广泛应用,不仅提升了模型的性能,也为生成式 AI 的未来发展开辟了新的道路。
总之,LlamaIndex 通过其强大的 RAG 功能,为解决大模型的幻觉问题提供了有效的解决方案。它不仅提升了模型的准确性和可靠性,还为开发者提供了一个灵活且高效的开发平台。随着技术的不断进步,LlamaIndex 将继续推动生成式 AI 的发展,使其在更多领域发挥更大的价值。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐