简单使用LlamaIndex实现RAG

简单使用LlamaIndex实现RAG

1 介绍

LlamaIndex是一个专门为大语言模型(LLM)设计的开源数据管理工具,旨在简化和优化LLM在外部数据源中的查询过程。适合在数据索引上构建RAG。

参考的地址

# 官网地址
https://docs.llamaindex.ai/en/stable/

# 模块介绍
https://docs.llamaindex.ai/en/stable/module_guides/

# Github地址
https://github.com/run-llama/llama_index

使用的组件

# Openai like
https://docs.llamaindex.ai/en/stable/api_reference/llms/openai_like/
# OpenLLM,我没测试组件,它继承了OpenAILike
https://docs.llamaindex.ai/en/stable/api_reference/llms/openllm/

# 自定义嵌入模型
https://docs.llamaindex.ai/en/stable/module_guides/models/embeddings/#custom-embedding-model

# 自定义LLM模型
https://docs.llamaindex.ai/en/stable/module_guides/models/llms/usage_custom/

# ChromaVectorStore向量存储
https://docs.llamaindex.ai/en/stable/api_reference/storage/vector_store/chroma/#llama_index.vector_stores.chroma.ChromaVectorStore

# Chroma数据库文档
https://docs.trychroma.com/docs/overview/introduction

需要安装的包

⚠️ 我使用的llma-index的版本:0.12.26

pip install llama-index
pip install llama-index-llms-openai-like
pip install llama-index-vector-stores-chroma
pip install chromadb

2 使用官网构建RAG

⚠️ 国内基本无法直接使用,因为需要OpenAI的模型,所以无法直接使用。那就需要根据自己的需求定制。

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader

# 加载数据
documents = SimpleDirectoryReader("E:/data").load_data()
# 转化文档
index = VectorStoreIndex.from_documents(documents)
# 构建查询引擎
query_engine = index.as_query_engine()
# 使用
response = query_engine.query("Some question about the data should go here")
print(response)

3 自定义构建RAG

3.1 RAG构建思路

使用LlamaIndex构建RAG的思路如下图,LlamaIndex需要自定义向量模型和类大模型组件。

graph TD
	A[(1)构建Documet对象列表,读数据文档] --> B
	B[(2)构建Node对象列表,使用分割器分割Document,其中分割器有SentenceSplitter、TextSplitter等] --> C
	C[(3)向量化和存储,自定义嵌入模型和存储到数据库中,可以使用SimpleVectorStore、ChromaVectorStore等] --> D
	D[(4)构建向量索引库,使用VectorStoreIndex构建向量索引] --> E
	E[(5)构建检索器,用于用户检索输入的prompt] --> F
	F[(6)构建响应生成器,自定义大模型生成用户输入的prompt] --> G
	G[(7)构建查询引擎,组合检索器和响应生成器构建查询引擎] --> H
	H[(8)使用prompt查询和生成数据]

在这里插入图片描述

3.2 自定义RAG

(1) my_document_custorm_engine.py

import chromadb
from llama_index.core import Document, VectorStoreIndex, get_response_synthesizer
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.response_synthesizers import ResponseMode
from llama_index.vector_stores.chroma import ChromaVectorStore

from my_custom_rag.custom_like_openai import CustomLikeOpenAI

# 需要安装的组件
"""
pip install llama-index
pip install llama-index-llms-openai-like
pip install llama-index-vector-stores-chroma
"""

from my_custom_rag.custom_embedding import CustomEmbeddings

# 自定嵌入模型
my_embedding = CustomEmbeddings()

# 构建文档列表,可根据自己的需求设置文本文档列表
document_text = [
    "河南大学(Henan University),简称“河大”(HENU),位于中国河南省郑州市、开封市,是河南省人民政府与中华人民共和国教育部共建公办高校 [392]、国家“双一流”建设高校 [69],入选国家“111计划” [2]、中西部高校基础能力建设工程 [313]、中国政府奖学金来华留学生接收院校 [388]。",
    "河南大学创立于1912年,始名河南留学欧美预备学校。后历经中州大学、国立开封中山大学、省立河南大学等阶段,1942年升格为国立河南大学 [153]。1952年院系调整 ,校本部更名为河南师范学院。后经开封师范学院、河南师范大学等阶段,1984年恢复河南大学校名 [153]。2000年6月,原河南大学、开封医学高等专科学校、开封师范高等专科学校合并组建新的河南大学 [154]。2012年,河南大学入选第一批卓越医生教育培养计划项目试点高校 [130];入选国家级卓越法律人才教育培养基地 [390];入选第一批国家卓越医生教育培养计划项目试点高校 [391]。",
    "截至2024年6月,学校设有40个学院、93个本科招生专业 、47个硕士学位授权一级学科 、39种硕士专业学位授权类别 、2种博士专业学位授权类别、24个博士学位授权一级学科 、20个博士后科研流动站、13个学科进入ESI世界排名前1% ;有全日制在校生5万余人、教职工4700余人,教师中有院士、学部委员6人,长江学者、国家杰青、“万人计划”领军人才等国家级领军人才26人,国家级青年人才15人;拥有3个国家重点实验室 ,1个国家野外科学观测研究站 ,3个国家地方联合工程研究中心 ,4个河南省实验室 , 5个教育部和农业部重点实验室 [448]。",
    "河南大学软件学院(Henan University Software College)是全国较早、河南省最早成立的软件学院之一,位于中国河南省开封市。学院是国家示范性软件学院联盟成员单位,信息技术新工科产学研联盟首批会员单位,2020 年度获批河南省特色化示范性软件学院,河南省鲲鹏产业学院建设高校。学院设有软件工程系、网络工程系和公共计算机教学中心,拥有“河南省智能数据处理工程研究中心”、“河南省现代网络技术实验教学示范中心”、“河南省智能网络理论与关键技术国际联合实验室”等省级科研教学平台、“河南省高等学校学科(软件工程)引智基地”、“河南省本科高校大学生校外实践教育基地”和“河南省高校优秀基层教学组织”称号。学院独立承建软件工程和网络工程两个本科专业,软件工程专业为国家一流本科专业, 网络工程专业为河南省一流本科专业。同时,拥有“软件工程技术”二级博士学位授权点,电子信息专业具有硕士学位授予权,建有软件工程博士后科研流动站。"
]

# 构建LlamaIndex的对象列表
documents = list()
for text in document_text:
    documents.append(Document(text=text))
# print(documents)

# 将LlamaIndex的Document拆分Nodes
parser = SentenceSplitter()
nodes = parser.get_nodes_from_documents(documents)

# 使用嵌入模型对node进行嵌入
for node in nodes:
    node.embedding = my_embedding.get_text_embedding(node.get_content())

# 创建Chroma客户端
client = chromadb.Client()

# 创建集合
collection = client.create_collection("my-documents")
chroma_vector_store = ChromaVectorStore(chroma_collection=collection)

# 存入向量库中
chroma_vector_store.add(nodes)

# 使用索引对象
# 注意:VectorStoreIndex必须有向量库支持,否则会报下面的错误
# Cannot initialize from a vector store that does not store text.
vector_index = VectorStoreIndex.from_vector_store(chroma_vector_store, embed_model=my_embedding)


# Llama index中的OpenAILike调用千问和Kimi不能使用,一直报参数错误,所以只能自定义了
llm = CustomLikeOpenAI(
    model="qwen2.5-14b-instruct",
    api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key = "sk-XXX"
)

# 下面的是LlamaIndex中的OpenAILike
# llm = OpenAILike(
#     model="qwen2.5-14b-instruct",
#     base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
#     api_key = "sk-XXX"
# )

"""
# 显示构建查询引擎=检索器+响应生成器

# 创建检索器,similarity_top_k设置返回值的数量
query_retriever = vector_index.as_retriever(similarity_top_k=1)

# 响应生成器有compact(默认模式)、refine、simple_summarize等
response_synthesizer = get_response_synthesizer(
    llm=llm,
    response_mode=ResponseMode.COMPACT,
    # streaming=True
)

query_engine = RetrieverQueryEngine(
    retriever=query_retriever,
    response_synthesizer=response_synthesizer
)

"""
# 隐式构建查询引擎,上面两步可以使用1行构建
query_engine = vector_index.as_query_engine(
    llm=llm,
    # streaming=True
)

# 如果不使用流式输出,直接打印即可
query_data = query_engine.query("用30字介绍一下河南大学")
print(query_data)

# # 使用流式输出
# for text in query_data.response_gen:
#     print(text)
#     pass

(2)custom_embedding.py

自定义嵌入模型

from llama_index.core.base.embeddings.base import Embedding
from llama_index.core.embeddings import BaseEmbedding
from sentence_transformers import SentenceTransformer

# 构建向量模型,可根据自己的需求,自定义调用互联网和本地模型等
embedder = SentenceTransformer("E:/model/sentencetransformers/distiluse-base-multilingual-cased-v1")


class CustomEmbeddings(BaseEmbedding):
    def _get_query_embedding(self, query: str) -> Embedding:
        # 生成嵌入列表
        return embedder.encode(query).tolist()

    async def _aget_query_embedding(self, query: str) -> Embedding:
        # 生成嵌入列表
        return embedder.encode(query).tolist()

    def _get_text_embedding(self, text: str) -> Embedding:
        # 生成嵌入列表
        return embedder.encode(text).tolist()

(3)custom_like_openai.py

自定义大模型

from typing import Any

from llama_index.core.base.llms.types import CompletionResponseGen, LLMMetadata, CompletionResponse
from llama_index.core.llms import CustomLLM
from openai import OpenAI
from pydantic import Field


class CustomLikeOpenAI(CustomLLM):
    model: str = Field(description="自定义模型名称")
    api_key: str = Field(description="自定义API Key")
    api_base: str = Field(description="自定义API地址")
    context_window: int = Field(default=32768, description="上下文窗口大小")
    temperature: float = Field(ge=0, le=1, default=0.3, description="设置温度,值域须为 [0, 1]")
    num_output: int = Field(default=8192, description="设置max_tokens")

    def __init__(self, **data):
        # 必须调用父类初始化
        super().__init__(**data)

        # 创建对象
        self._client = OpenAI(
            api_key=self.api_key,
            base_url=self.api_base
        )

    @property
    def metadata(self) -> LLMMetadata:
        """Get LLM metadata."""
        return LLMMetadata(
            context_window=self.context_window,
            num_output=self.num_output,
            model_name=self.model
        )

    def complete(self, prompt: str, **kwargs: Any) -> CompletionResponse:
        """
        生成文本

        :param prompt: 添加提示词
        :param kwargs: 其他相关参数
        :return: CompletionResponse
        """
        # 构建生成
        completion = self._client.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "user", "content": prompt}
            ],
            temperature=self.temperature,
            max_tokens=self.num_output
        )
        # 返回值
        return CompletionResponse(text=completion.choices[0].message.content)

    def stream_complete(self, prompt: str, **kwargs: Any) -> CompletionResponseGen:
        """
        生成流式文本

        :param prompt: 提示词
        :param kwargs: 其他参数
        :return: CompletionResponseGen迭代器
        """

        # 根据需要可以不实现,如果不想实现使用下面代码即可
        # raise NotImplementedError("Streaming not supported")

        # 构建数据流
        stream = self._client.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "user", "content": prompt}
            ],
            temperature=self.temperature,
            max_tokens=self.num_output,
            stream=True
        )
        # 遍历数据流
        for chunk in stream:
            # 获取新文本
            delta = chunk.choices[0].delta

            # 判断数据是否存在
            if delta.content:
                yield CompletionResponse(text=delta.content, delta=delta.content)

3.3 其他学习

(1)使用SimpleVectorStore存储

from llama_index.core import Document
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.vector_stores import SimpleVectorStore, VectorStoreQuery
from sentence_transformers import SentenceTransformer

# 构建向量模型
embedder = SentenceTransformer("E:/model/sentencetransformers/distiluse-base-multilingual-cased-v1")

# 构建文档列表,可根据自己的需求设置文本文档列表
document_text = [
    "A man is eating food.",
    "A man is eating a piece of bread.",
    "The girl is carrying a baby.",
    "A man is riding a horse.",
    "A woman is playing violin.",
    "Two men pushed carts through the woods.",
    "A man is riding a white horse on an enclosed ground.",
    "A monkey is playing drums.",
    "A cheetah is running behind its prey.",
]

# 构建LlamaIndex的对象列表
documents = list()
for text in document_text:
    documents.append(Document(text=text))
# print(documents)

# 将LlamaIndex的Document拆分Nodes
parser = SentenceSplitter()
nodes = parser.get_nodes_from_documents(documents)

# 使用嵌入模型对node进行嵌入
for node in nodes:
    node.embedding = embedder.encode(node.get_content())
# print(nodes)

# 下面一般不会用于生产环境,生产环境一般用向量库
# 基于内存的方式存储向量
simple_vector_store = SimpleVectorStore()
simple_vector_store.add(nodes)

# 持久化nodes,默认存储在”./storage“
# simple_vector_store.persist()
# 获取持久化数据
# simple_vector_store = SimpleVectorStore.from_persist_path("./storage/vector_store.json")

# # 对查询的文本进行嵌入
query_embed = embedder.encode("A man is eating pasta").tolist()
# 查询到的目标数据
target_data_embed = simple_vector_store.query(VectorStoreQuery(query_embedding=query_embed, similarity_top_k=2))

print(target_data_embed)

(2)使用索引VectorStoreIndex

import chromadb
from llama_index.core import Document, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
from llama_index.vector_stores.chroma import ChromaVectorStore

from my_custom_rag.custom_embedding import CustomEmbeddings

# 自定嵌入模型
my_embedding = CustomEmbeddings()

# 构建文档列表,可根据自己的需求设置文本文档列表
document_text = [
    "A man is eating food.",
    "A man is eating a piece of bread.",
    "The girl is carrying a baby.",
    "A man is riding a horse.",
    "A woman is playing violin.",
    "Two men pushed carts through the woods.",
    "A man is riding a white horse on an enclosed ground.",
    "A monkey is playing drums.",
    "A cheetah is running behind its prey.",
]

# 构建LlamaIndex的对象列表
documents = list()
for text in document_text:
    documents.append(Document(text=text))
# print(documents)

# 将LlamaIndex的Document拆分Nodes
parser = SentenceSplitter()
nodes = parser.get_nodes_from_documents(documents)

# 使用嵌入模型对node进行嵌入
for node in nodes:
    node.embedding = my_embedding.get_text_embedding(node.get_content())

# 创建Chroma客户端
client = chromadb.Client()

# 创建集合
collection = client.create_collection("my-documents")
chroma_vector_store = ChromaVectorStore(chroma_collection=collection)

# 存入向量库中
chroma_vector_store.add(nodes)


# 使用索引对象
# 注意:VectorStoreIndex必须有向量库支持,否则会报下面的错误
# Cannot initialize from a vector store that does not store text.
vector_index = VectorStoreIndex.from_vector_store(chroma_vector_store, embed_model=my_embedding)

# 创建检索器,similarity_top_k设置返回值的数量
query_retriever = vector_index.as_retriever(similarity_top_k=1)

# 查询数据
query_text = "A man is eating pasta"
retrieve_data = query_retriever.retrieve(query_text)

print(retrieve_data)
### 构建和部署大规模语言模型及其RAG工作流 为了满足快速开发、构建并部署像GPT这样的大规模语言模型的需求,尤其是带有检索增强生成(RAG)功能的支持自定义和多种开源模型的应用程序,可以考虑利用现有的工具和技术栈来简化流程。 #### 使用Langchain或LlamaIndex框架加速开发过程 通过采用Langchain或者LlamaIndex这类高级别的抽象层框架,开发者能够更高效地创建复杂的大规模语言处理应用程序。这些框架不仅提供了易于使用的API接口用于集成不同的预训练模型,还内置了许多实用的功能模块,比如向量数据库连接器、索引管理服务等,从而大大减少了从零开始搭建系统的难度[^3]。 对于希望实现基于RAG的工作流来说,上述提到的两个框架都具备良好的支持能力。它们允许用户轻松配置外部数据源作为查询扩展的基础,并且可以通过简单的几行代码完成整个流水线的设计与实施。例如,在Python环境中仅需不到十行的有效编码即可启动一个基础版本的服务实例。 #### 集成多样的开源模型选项 当涉及到具体的技术选型时,除了官方推荐的标准组件外,还可以探索其他社区贡献者维护的各种插件化解决方案。这使得最终产品能够在保持灵活性的同时拥有广泛的适用范围——无论是针对特定领域优化过的微调变体还是完全自主训练的新颖结构都能被纳入考量之中。 值得注意的是,由于不同类型的底层算法可能存在兼容性差异,因此建议优先选用那些已经过充分测试验证并与所选平台具有良好协作记录的产品组合。此外,考虑到性能表现的重要性,务必提前评估候选方案在目标硬件环境下的实际运行效果[^1]。 ```python from langchain import LangChain, models # 初始化链路对象 lang_chain = LangChain() # 加载指定名称/路径处存储的语言模型实例 model_instance = models.load_model('path_to_custom_gpt') # 定义输入输出模式及其他必要参数设置... result = lang_chain.process(query="example query", model=model_instance) print(result) ``` #### 实现离线部署的能力 最后一点但同样重要的是关于能否做到独立于云端资源之外运作的问题。得益于现代软件工程实践的进步,现在有许多途径可以帮助我们达成这一目的。一方面,许多流行的大规模语言模型本身即提供有适用于本地计算机执行的形式;另一方面,则可通过容器镜像打包等方式进一步封装依赖关系以便迁移至任意计算节点上执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值