1. 前置知识

正式介绍检索增强生成(Retrieval Augmented Generation,RAG)技术以前。 给模型注入新知识的方式,可以简单分为两种方式,一种是内部的,即更新模型的权重,另一个就是外部的方式,给模型注入格外的上下文或者说外部信息,不改变它的的权重。 第一种方式,改变了模型的权重即进行模型训练,这是一件代价比较大的事情,大语言模型具体的训练过程,可以参考InternLM2技术报告。 第二种方式,并不改变模型的权重,只是给模型引入格外的信息。类比人类编程的过程,第一种方式相当于你记住了某个函数的用法,第二种方式相当于你阅读函数文档然后短暂的记住了某个函数的用法。

 

对比两种注入知识方式,第二种更容易实现。RAG 正是这种方式。它能够让基础模型实现非参数知识更新,无需训练就可以掌握新领域的知识。本次课程选用了 LlamaIndex 框架。LlamaIndex 是一个上下文增强的 LLM 框架,旨在通过将其与特定上下文数据集集成,增强大型语言模型(LLMs)的能力。它允许您构建应用程序,既利用 LLMs 的优势,又融入您的私有或领域特定信息。

2. 浦语 API+LlamaIndex 实践

 2.1安装LlamaIndex

进入开发机后,创建新的conda环境,命名为 llamaindex

conda create -n llamaindex python=3.10

激活环境,安装python 依赖包

pip install einops==0.7.0 protobuf==5.26.1

安装 Llamaindex和相关的包

pip install llama-index==0.11.20

pip install llama-index-llms-replicate==0.3.0

pip install llama-index-llms-openai-like==0.2.0

pip install llama-index-embeddings-huggingface==0.3.1

pip install llama-index-embeddings-instructor==0.2.1

pip install torch==2.5.0 torchvision==0.20.0 torchaudio==2.5.0 --index-url https://download.pytorch.org/whl/cu121

 2.2 下载 Sentence Transformer 模型

源词向量模型 Sentence Transformer:(我们也可以选用别的开源词向量模型来进行 Embedding,目前选用这个模型是相对轻量、支持中文且效果较好的,可以自由尝试别的开源词向量模型) 运行以下指令,新建一个python文件

cd ~

mkdir llamaindex_demo

mkdir model

cd ~/llamaindex_demo

touch download_hf.py

打开download_hf.py 贴入以下代码

import os

# 设置环境变量

os.environ['HF_ENDPOINT'] = 'HF-Mirror'

# 下载模型

os.system('huggingface-cli download --resume-download sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/model/sentence-transformer')

然后,在 /root/llamaindex_demo 目录下执行该脚本即可自动开始下载:

cd/root/llamaindex_demo
conda activate llamaindex
python download_hf.py

推荐从modelscope下载

git lfs install

cd /root/model/

git clone 魔搭社区

mv paraphrase-multilingual-MiniLM-L12-v2 sentence-transformer

2.3 下载 NLTK 相关资源

我们在使用开源词向量模型构建开源词向量的时候,需要用到第三方库 nltk 的一些资源。正常情况下,其会自动从互联网上下载,但可能由于网络原因会导致下载中断,此处我们可以从国内仓库镜像地址下载相关资源,保存到服务器上。 我们用以下命令下载 nltk 资源并解压到服务器上:

cd/root
git clone
yzy0612/nltk_data  --branch gh-pages
cdnltk_data
mv packages/*./
cdtokenizers
unzip punkt.zip
cd../taggers
unzip averaged_perceptron_tagger.zip

之后使用时服务器即会自动使用已有资源,无需再次下载

2.4使用 LlamaIndex 前后对比

2.4.1 不使用 LlamaIndex RAG(仅API

获取API

浦语官方 API: 书生·浦语

硅基流动: 硅基流动统一登录

运行以下指令,新建一个python文件

cd ~/llamaindex_demo

touch test_internlm.py

打开test_internlm.py 贴入以下代码

from openai import OpenAI

base_url = "https://internlm-chat.intern-ai.org.cn/puyu/api/v1/"

api_key = "sk-请填写准确的 token!"

model="internlm2.5-latest"

# base_url = "https://api.siliconflow.cn/v1"

# api_key = "sk-请填写准确的 token!"

# model="internlm/internlm2_5-7b-chat"

client = OpenAI(

    api_key=api_key ,

    base_url=base_url,

)

chat_rsp = client.chat.completions.create(

    model=model,

    messages=[{"role": "user", "content": "xtuner是什么?"}],

)

for choice in chat_rsp.choices:

    print(choice.message.content)

运行结果为

并不是我们想要的xtuner,因为internlm2.5-latest并没有学习到xtuner相关的知识。

2.4.2 使用 API+LlamaIndex

激活环境,在llamaindex_demo目录下新建我们的知识检索目录。可以查看(README_zh-CN.md)中的相关知识内容

mkdir data

cd data

git clone https://github.com/InternLM/xtuner.git

mv xtuner/README_zh-CN.md ./         

运行以下指令,新建一个python文件

cd ..

touch llamaindex_RAG.py

贴入以下代码

import os

os.environ['NLTK_DATA'] = '/root/nltk_data'

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader

from llama_index.core.settings import Settings

from llama_index.embeddings.huggingface import HuggingFaceEmbedding

from llama_index.legacy.callbacks import CallbackManager

from llama_index.llms.openai_like import OpenAILike

# Create an instance of CallbackManager

callback_manager = CallbackManager()

api_base_url =  "https://internlm-chat.intern-ai.org.cn/puyu/api/v1/"

model = "internlm2.5-latest"

api_key = "请填写 API Key"

# api_base_url =  "https://api.siliconflow.cn/v1"

# model = "internlm/internlm2_5-7b-chat"

# api_key = "请填写 API Key"

llm =OpenAILike(model=model, api_base=api_base_url, api_key=api_key, is_chat_model=True,callback_manager=callback_manager)

#初始化一个HuggingFaceEmbedding对象,用于将文本转换为向量表示

embed_model = HuggingFaceEmbedding(

#指定了一个预训练的sentence-transformer模型的路径

    model_name="/root/model/sentence-transformer"

)

#将创建的嵌入模型赋值给全局设置的embed_model属性,

#这样在后续的索引构建过程中就会使用这个模型。

Settings.embed_model = embed_model

#初始化llm

Settings.llm = llm

#从指定目录读取所有文档,并加载数据到内存中

documents = SimpleDirectoryReader("/root/llamaindex_demo/data").load_data()

#创建一个VectorStoreIndex,并使用之前加载的文档来构建索引。

# 此索引将文档转换为向量,并存储这些向量以便于快速检索。

index = VectorStoreIndex.from_documents(documents)

# 创建一个查询引擎,这个引擎可以接收查询并返回相关文档的响应。

query_engine = index.as_query_engine()

response = query_engine.query("xtuner是什么?")

print(response)

运行结果为:       

可以看到已经可以检索到我们所需要的知识了。

 

注意:第一次运行会下载相关数据需要一段时间,请耐心等待,如中断可能导致第二次运行因为文件损坏报错!!!所有下载如果出现中断情况,最好进入相关目录(rm - r)删除后再重新下载.

2.4.3LlamaIndex web

安装依赖

pip install streamlit==1.39.0

llamaindex_demo目录下新建一个python文件

touch app.py

贴入代码

import streamlit as st

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings

from llama_index.embeddings.huggingface import HuggingFaceEmbedding

from llama_index.legacy.callbacks import CallbackManager

from llama_index.llms.openai_like import OpenAILike

# Create an instance of CallbackManager

callback_manager = CallbackManager()

api_base_url =  "https://internlm-chat.intern-ai.org.cn/puyu/api/v1/"

model = "internlm2.5-latest"

api_key = "请填写 API Key"

# api_base_url =  "https://api.siliconflow.cn/v1"

# model = "internlm/internlm2_5-7b-chat"

# api_key = "请填写 API Key"

llm =OpenAILike(model=model, api_base=api_base_url, api_key=api_key, is_chat_model=True,callback_manager=callback_manager)

st.set_page_config(page_title="llama_index_demo", page_icon="🦜🔗")

st.title("llama_index_demo")

# 初始化模型

@st.cache_resource

def init_models():

    embed_model = HuggingFaceEmbedding(

        model_name="/root/model/sentence-transformer"

    )

    Settings.embed_model = embed_model

    #用初始化llm

    Settings.llm = llm

    documents = SimpleDirectoryReader("/root/llamaindex_demo/data").load_data()

    index = VectorStoreIndex.from_documents(documents)

    query_engine = index.as_query_engine()

    return query_engine

# 检查是否需要初始化模型

if 'query_engine' not in st.session_state:

    st.session_state['query_engine'] = init_models()

def greet2(question):

    response = st.session_state['query_engine'].query(question)

    return response

     

# Store LLM generated responses

if "messages" not in st.session_state.keys():

    st.session_state.messages = [{"role": "assistant", "content": "你好,我是你的助手,有什么我可以帮助你的吗?"}]   

    # Display or clear chat messages

for message in st.session_state.messages:

    with st.chat_message(message["role"]):

        st.write(message["content"])

def clear_chat_history():

    st.session_state.messages = [{"role": "assistant", "content": "你好,我是你的助手,有什么我可以帮助你的吗?"}]

st.sidebar.button('Clear Chat History', on_click=clear_chat_history)

# Function for generating LLaMA2 response

def generate_llama_index_response(prompt_input):

    return greet2(prompt_input)

# User-provided prompt

if prompt := st.chat_input():

    st.session_state.messages.append({"role": "user", "content": prompt})

    with st.chat_message("user"):

        st.write(prompt)

# Gegenerate_llama_index_response last message is not from assistant

if st.session_state.messages[-1]["role"] != "assistant":

    with st.chat_message("assistant"):

        with st.spinner("Thinking..."):

            response = generate_llama_index_response(prompt)

            placeholder = st.empty()

            placeholder.markdown(response)

    message = {"role": "assistant", "content": response}

    st.session_state.messages.append(message)

运行 streamlit run app.py

结果为:

Ctrl+左键本地进入相关网址即可正常使用:

自建RAG知识库。

       首先询问大模型(你知道良品铺子酸辣粉事件吗?)

运行代码test_internlm.py回答如下

    

data目录下新建文档

touch readlp.md

写入百度百科中相关内容

运行app.py

streamlit run app.py(也可以修改llamaindex_RAG.py相关代码,python运行)

 

 

可以看到大模型已经可以对相关内容进行检索,但是在最后的语言方面还有需要改进的地方,主要原因与我那粗枝烂叶般的知识库有关(只为验证)。

 

 

3本地部署InternLM+LlamaIndex实践

  其步骤与第二部分大同小异,但因某些依赖版本不同,选择另建环境

conda create -n llamaindex_bd python=3.10

激活环境后安装相关依赖

pip install einops==0.7.0 protobuf==5.26.1

pip install llama-index==0.10.38 llama-index-llms-huggingface==0.2.0 "transformers[torch]==4.41.1" "huggingface_hub[inference]==0.23.1" huggingface_hub==0.23.1 sentence-transformers==2.7.0 sentencepiece==0.2.0

pip install llama-index-embeddings-huggingface==0.2.0 llama-index-embeddings-instructor==0.1.3

在这一步请确定llama-index-embeddings-huggingface安装成功 --------pip show llama-index-embeddings-huggingface

如果存在not found错误,请重新安装

# pip install llama-index-embeddings-huggingface==0.2.0

确保 huggingface_hub==0.23.1

最后再安装 Pytorch:

conda install pytorch==2.0.1 torchvision==0.15.2 torchaudio==2.0.2 pytorch-cuda=11.7 -c pytorch -c nvidia

安装完成后,验证 Pytorch 是否正确安装并使用了指定的 CUDA 版本:(可以使用pip show 查看

import torch

print(torch.__version__)        # 应输出类似 '2.0.1'

print(torch.version.cuda)       # 应输出 '11.7'

print(torch.cuda.is_available())# 应输出 True

3.1 下载 Sentence Transformer 模型(在第二部分已安装)

3.2 下载 NLTK 相关资源(在第二部分已安装)

3.3LlamaIndex HuggingFaceLLM

运行以下指令,把 InternLM2 1.8B 软连接出来

cd ~/model

ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b/ ./

运行以下指令,新建一个 python 文件

mkdir llamaindex_bd

cd ~/llamaindex_bd

touch llamaindex_internlm.py

贴入以下代码

from llama_index.llms.huggingface import HuggingFaceLLM

from llama_index.core.llms import ChatMessage

llm = HuggingFaceLLM(

    model_name="/root/model/internlm2-chat-1_8b",

    tokenizer_name="/root/model/internlm2-chat-1_8b",

    model_kwargs={"trust_remote_code":True},

    tokenizer_kwargs={"trust_remote_code":True}

)

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

print(rsp)

python运行即可(第一次总是需要较长时间才能成功的,你需要耐心的等待)

显然这不是我们需要的结果

 3.4LlamaIndex RAG

运行以下命令,获取知识库

cd ~/llamaindex_demo

mkdir data

cd data

git clone https://github.com/InternLM/xtuner.git

mv xtuner/README_zh-CN.md ./

新建一个 python 文件

cd ~/llamaindex_demo

touch llamaindex_RAG.py

贴入以下代码

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings

from llama_index.embeddings.huggingface import HuggingFaceEmbedding

from llama_index.llms.huggingface import HuggingFaceLLM

#初始化一个HuggingFaceEmbedding对象,用于将文本转换为向量表示

embed_model = HuggingFaceEmbedding(

#指定了一个预训练的sentence-transformer模型的路径

    model_name="/root/model/sentence-transformer"

)

#将创建的嵌入模型赋值给全局设置的embed_model属性,

#这样在后续的索引构建过程中就会使用这个模型。

Settings.embed_model = embed_model

llm = HuggingFaceLLM(

    model_name="/root/model/internlm2-chat-1_8b",

    tokenizer_name="/root/model/internlm2-chat-1_8b",

    model_kwargs={"trust_remote_code":True},

    tokenizer_kwargs={"trust_remote_code":True}

)

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

Settings.llm = llm

#从指定目录读取所有文档,并加载数据到内存中

documents = SimpleDirectoryReader("/root/llamaindex_bd/data").load_data()

#创建一个VectorStoreIndex,并使用之前加载的文档来构建索引。

# 此索引将文档转换为向量,并存储这些向量以便于快速检索。

index = VectorStoreIndex.from_documents(documents)

# 创建一个查询引擎,这个引擎可以接收查询并返回相关文档的响应。

query_engine = index.as_query_engine()

response = query_engine.query("xtuner是什么?")

print(response)

注意修改部分路径!!!同时注意这里如果是10%算力(8G)的话可能会报错显存不足

python 运行即可

3.5LlamaIndex web

首先安装依赖

pip install streamlit==1.36.0   

新建一个 python 文件

cd ~/llamaindex_bd

touch app.py

贴入以下代码

import streamlit as st

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings

from llama_index.embeddings.huggingface import HuggingFaceEmbedding

from llama_index.llms.huggingface import HuggingFaceLLM

st.set_page_config(page_title="llama_index_demo", page_icon="🦜🔗")

st.title("llama_index_demo")

# 初始化模型

@st.cache_resource

def init_models():

    embed_model = HuggingFaceEmbedding(

        model_name="/root/model/sentence-transformer"

    )

    Settings.embed_model = embed_model

    llm = HuggingFaceLLM(

        model_name="/root/model/internlm2-chat-1_8b",

        tokenizer_name="/root/model/internlm2-chat-1_8b",

        model_kwargs={"trust_remote_code": True},

        tokenizer_kwargs={"trust_remote_code": True}

    )

    Settings.llm = llm

    documents = SimpleDirectoryReader("/root/llamaindex_demo/data").load_data()

    index = VectorStoreIndex.from_documents(documents)

    query_engine = index.as_query_engine()

    return query_engine

# 检查是否需要初始化模型

if 'query_engine' not in st.session_state:

    st.session_state['query_engine'] = init_models()

def greet2(question):

    response = st.session_state['query_engine'].query(question)

    return response

# Store LLM generated responses

if "messages" not in st.session_state.keys():

    st.session_state.messages = [{"role": "assistant", "content": "你好,我是你的助手,有什么我可以帮助你的吗?"}]

    # Display or clear chat messages

for message in st.session_state.messages:

    with st.chat_message(message["role"]):

        st.write(message["content"])

def clear_chat_history():

    st.session_state.messages = [{"role": "assistant", "content": "你好,我是你的助手,有什么我可以帮助你的吗?"}]

st.sidebar.button('Clear Chat History', on_click=clear_chat_history)

# Function for generating LLaMA2 response

def generate_llama_index_response(prompt_input):

    return greet2(prompt_input)

# User-provided prompt

if prompt := st.chat_input():

    st.session_state.messages.append({"role": "user", "content": prompt})

    with st.chat_message("user"):

        st.write(prompt)

# Gegenerate_llama_index_response last message is not from assistant

if st.session_state.messages[-1]["role"] != "assistant":

    with st.chat_message("assistant"):

        with st.spinner("Thinking..."):

            response = generate_llama_index_response(prompt)

            placeholder = st.empty()

            placeholder.markdown(response)

    message = {"role": "assistant", "content": response}

    st.session_state.messages.append(message)

streamlit run app.py运行即可

参考: https://github.com/InternLM/Tutorial/tree/camp4/docs/L1/LlamaIndex

Logo

ModelScope旨在打造下一代开源的模型即服务共享平台,为泛AI开发者提供灵活、易用、低成本的一站式模型服务产品,让模型应用更简单!

更多推荐