RAG:AI大模型聯合向量資料庫和 Llama-index,助力檢索增強生成技術

汀、人工智能發表於2024-05-07

RAG:AI大模型聯合向量資料庫和 Llama-index,助力檢索增強生成技術

在大模型爆發的時代,快速準確地從大量資料中檢索出有價值的資訊變得至關重要。檢索增強生成(RAG)技術,結合了傳統的資訊檢索和最新的大語言模型(LLM),不僅能夠回答複雜的查詢,還能在此基礎上生成資訊豐富的內容。

RAG 技術的核心在於其能夠將大型語言模型的生成能力與特定資料來源的檢索相結合。這意味著,當模型面對使用者提出的問題時,它不僅依賴於自身訓練時的知識,還可以實時地從外部資料來源中檢索相關資訊,以此增強回答的準確性和豐富性。這種方法對於處理最新資訊特別有效,能夠有效彌補傳統模型在時效性方面的不足。

這裡我們將基於大模型、Milvus 向量資料庫、LlamaIndex 大模型應用框架,與大家一起完成 RAG 系統的搭建。本文將以 Yuan2.0 最新發布的 Februa 模型為例進行測試驗證,用更小規模的模型達到更好的效果。

1.RAG 系統架構

RAG(檢索增強生成) 就是透過檢索獲取相關的知識並將其融入 Prompt,讓大模型能夠參考相應的知識從而給出合理回答。因此,可以將 RAG 的核心理解為 “檢索 + 生成”,前者主要是利用向量資料庫的高效儲存和檢索能力,召回目標知識;後者則是利用大模型和 Prompt 工程,將召回的知識合理利用,生成目標答案。

從 RAG 系統的執行流程我們可以看到,整個 RAG 系統可以分解為三個核心部件:

  • 向量資料庫:用來存放向量化之後的知識庫,並提供向量檢索能力,為 RAG 系統實現對知識的初步檢索。這裡我們採用 Milvus 向量資料庫來實現知識的儲存和初篩。它通常被用來儲存、索引和管理由深度神經網路和其他機器學習(ML)模型生成的大規模嵌入向量。作為一個專門設計用於處理輸入向量查詢的資料庫,Milvus 能夠處理萬億級別的向量索引。與現有的關係型資料庫主要處理遵循預定義模式的結構化資料不同,Milvus 從底層設計用於處理從非結構化資料轉換而來的嵌入向量。

  • 語言大模型(LLM):用來實現基於檢索到的知識的推理和答案生成。這裡我們將採用浪潮最新發布的 Yuan2.0 大模型來實現答案生成。從官方公佈的資料來看,Yuan2.0 是在 Yuan1.0 的基礎上,利用更多樣的高質量預訓練資料和指令微調資料集,令模型在語義、數學、推理、程式碼、知識等不同方面具備更強的理解能力。Yuan2.0 包含了 2B、51B、102B 不同引數量的系列模型。根據官方公佈的資料顯示,今年 3 月最新發布的 Yuan2-2B-Februa 在數學推理、程式碼生成等任務上的精度均取得了明顯提升。為了部署方便,我們將採用 Yuan2-2B-Februa 來構建 RAG 系統的 LLM 模組。關於 Yuan2.0 模型的詳細介紹請參考:Yuan2.0 Github

  • 問答推理框架:問答推理框架主要用來實現 RAG 系統的問答邏輯。它接收使用者的提問輸入,並根據輸入向向量資料庫發起索引請求,將得到的索引結果與問題結合,形成新的提示詞(prompt),並將提示詞提交給 LLM,最後將 LLM 生成的結果返回給使用者。這裡我們將採用 LlamaIndex 工具來實現這個框架。其主要由 3 部分組成:

    • 資料連線。首先將資料能讀取進來,這樣才能挖掘。
    • 索引構建。要查詢外部資料,就必須先構建可以查詢的索引,LlamdaIndex 將資料儲存在 Node 中,並基於 Node 構建索引。索引型別包括向量索引、列表索引、樹形索引等;
    • 查詢介面。透過這些介面使用者可以先基於索引進行檢索,再將檢索結果和之前的輸入 Prompt 進行組合形成新的擴充 Prompt,對話大模型並拿到結果進行解析。

2.部署教程

2.1 流程圖

以 Yuan2-2B-Februa 大模型為例,RAG 實踐流程圖如下所示:

  • Yuan2.0-2B 大模型 RAG 實踐包括以下步驟:
    • Step 1: 向量資料庫的安裝,以及知識的填充;詳細安裝過程參見後續章節;
    • Step 2:Llama_index 的安裝;詳細安裝過程參見後續章節;
    • Step 3:Llama_index 中設定 data_loader 模組,可以直接從向量資料庫中查詢;
    • Step 4:根據使用者輸入進行向量檢索,將檢索結果與 Input 合併,形成新的 prompt;
    • Step 5:載入 Yuan2.0-2B 大模型;合併後的 prompt 作為輸入,傳遞給大模型,大模型將結果輸出返回;

2.2 向量資料庫安裝以及知識填充

向量資料庫安裝步驟如下:

#Create Milvus file
mkdir -p /home/$USER/milvus/conf
cd /home/$USER/milvus/conf
wget https://raw.githubusercontent.com/milvus-io/milvus/v0.8.0/core/conf/demo/server_config.yaml
wget https://raw.githubusercontent.com/milvus-io/milvus/v0.8.0/core/conf/demo/log_config.conf
#Start Milvus
docker run -d --name milvus_cpu \
-p 19530:19530 \
-p 19121:19121 \
-p 9091:9091 \
-v /home/$USER/milvus/db:/var/lib/milvus/db \
-v /home/$USER/milvus/conf:/var/lib/milvus/conf \
-v /home/$USER/milvus/logs:/var/lib/milvus/logs \
-v /home/$USER/milvus/wal:/var/lib/milvus/wal \
milvusdb/milvus:0.8.0-cpu-d041520-464400
  • 這裡我們以 txt 文字為例,演示如何將知識庫匯入到資料庫中。在任意目錄下新建一個 python 指令碼 milvus.py,輸入以下程式碼:
from pymilvus import (
    connections,
    utility,
    FieldSchema, CollectionSchema, DataType,
    Collection,
)
from llama_index.embeddings import HuggingFaceEmbedding
fmt = "\n=== {:30} ===\n"
#1. connect to Milvus
print(fmt.format("start connecting to Milvus"))
connections.connect("default", host="localhost", port="19530")
#2. define collection
fields = [
   FieldSchema("pk", DataType.INT64, is_primary=True, auto_id=True),
   FieldSchema("vector", DataType.FLOAT_VECTOR, dim=768),]
schema = CollectionSchema(fields, "hello_milvus is the simplest demo to introduce the APIs")
print(fmt.format("Create collection `hello_milvus`"))
hello_milvus = Collection("hello_milvus", schema, consistency_level="Strong")
#3. insert data
chunk_list = []
print("Creat embedding model...")
embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-zh-v1.5",trust_remote_code=True)
with open('knowledge.txt', 'r') as file:
    line = file.readline()
    while line:
        # Generate embeddings using encoder from HuggingFace.
        embeddings = embed_model.get_text_embedding(line)
        chunk_list.append(embeddings)
        line = file.readline()
insert_result = hello_milvus.insert(chunk_list)
hello_milvus.flush()
#create index
index = {
    "index_type": "AUTOINDEX",
    "metric_type": "COSINE",
}
hello_milvus.create_index("vector", index)

上述程式碼首先匯入 python 連線 milvus 所需的庫,然後透過 connections.connect("default", host="localhost", port="19530") 指定使用本地的 19530 埠建立資料庫連線。其中 knowledge.txt 就是我們的知識庫內容,這個檔案放在與 milvus.py 指令碼相同的目錄下。如果使用者的知識庫在其他路徑存放,修改 with open('knowledge.txt', 'r') 中的路徑即可。

knowledge.txt 的初始樣例中每行代表一條知識。其中一條資料樣例如下,稍後將基於這條知識進行實驗驗證。

廣州大學(Guangzhou University),簡稱廣大(GU),是由廣東省廣州市人民政府舉辦的全日制普通高等學校,實行省市共建、以市為主的辦學體制,是國家“111計劃”建設高校、廣東省和廣州市高水平大學重點建設高校。廣州大學的辦學歷史可以追溯到1927年創辦的私立廣州大學;1951年併入華南聯合大學;1983年籌備復辦,1984年定名為廣州大學;2000年7月,經教育部批准,與廣州教育學院(1953年創辦)、廣州師範學院(1958年創辦)、華南建設學院西院(1984年創辦)、廣州高等師範專科學校(1985年創辦)合併組建成立新的廣州大學。

2.3 Llama_index 安裝以及設定安裝 Llama-index1

##線上安裝
pip install llama-index

設定 data_loader 載入,從 Milvus 中獲取知識, 具體原始碼可參考 yuan.py 檔案。

from llama_index import download_loader
import os
MilvusReader = download_loader("MilvusReader")
reader = MilvusReader(
   host="localhost", port=19530, user="<user>", password="<password>", use_secure=False
)
#the query_vector is an embedding representation of your query_vector
#Example query vector:
#query_vector=[0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3]
query_vector=[n1, n2, n3, ...]
documents = reader.load_data(
   query_vector=query_vector,
   collection_name="demo",
   limit=5
)

2.4 Prompt 合併

text_qa_template=PromptTemplate(
    ("背景:{context_str}"
    "問題: {query_str}\n")
)

說明:

  1. context_str 是知識庫中查詢到的結果;
  2. query_str 為使用者輸入的問題;

具體情況如下:1

在本例項中,
query_str具體內容是:介紹一下廣州大學

context_str具體內容是:file_path: data\***.txt

廣州大學(Guangzhou University),簡稱廣大(GU),是由廣東省廣州市人民政府舉辦的全日制普通高等學校,實行省市共建、以市為主的辦學體制,是國家“111計劃”建設高校、廣東省和廣州市高水平大學重點建設高校。廣州大學的辦學歷史可以追溯到1927年創辦的私立廣州大學;1951年併入華南聯合大學;1983年籌備復辦,1984年定名為廣州大學;2000年7月,經教育部批准,與廣州教育學院(1953年創辦)、廣州師範學院(1958年創辦)、華南建設學院西院(1984年創辦)、廣州高等師範專科學校(1985年創辦)合併組建成立新的廣州大學。

3.5 Yuan 大模型下載以及推理試用安裝

Yuan2.0 模型是浪潮資訊釋出的新一代基礎語言大模型。我們開源了全部的 3 個模型:Yuan2.0-102B、Yuan2.0-51B、Yuan2.0-2B。提供預訓練、微調、推理服務的相關指令碼,以供研發人員做進一步開發。Yuan2.0 是在 Yuan1.0 的基礎上,利用更多樣的高質量預訓練資料和指令微調資料集,令模型在語義、數學、推理、程式碼、知識等不同方面具備更強的理解能力。

提供了 Yuan2.0 的模型檔案,可以透過以下連結進行下載:

  • Yuan2.0-102B-hf | 序列長度:4K

    • ModelScope:https://modelscope.cn/models/YuanLLM/Yuan2.0-102B-hf/summary
    • HuggingFace:https://huggingface.co/IEITYuan/Yuan2-102B-hf
    • OpenXlab:https://openxlab.org.cn/models/detail/YuanLLM/Yuan2-102B-hf
    • 百度網盤:https://pan.baidu.com/s/1O4GkPSTPu5nwHk4v9byt7A?pwd=pq74
    • WiseModel:https://www.wisemodel.cn/models/IEIT-Yuan/Yuan2-102B-hf
  • Yuan 2.0-51B-hf | 序列長度:4K

    • ModelScopehttps://modelscope.cn/models/YuanLLM/Yuan2.0-51B-hf/summary* HuggingFacehttps://huggingface.co/IEITYuan/Yuan2.0-51B-hf
    • OpenXlabhttps://openxlab.org.cn/models/detail/YuanLLM/Yuan2-51B-hf
    • 百度網盤https://pan.baidu.com/s/1-qw30ZuyrMfraFtkLgDg0A?pwd=v2nd
    • WiseModelhttps://www.wisemodel.cn/models/IEIT-Yuan/Yuan2-51B-hf

更多內容見:https://modelscope.cn/headlines/article/373

執行以下程式碼可以進行簡單的推理效果試用:

import torch, transformers
import sys, os
sys.path.append(
    os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
from transformers import AutoModelForCausalLM,AutoTokenizer,LlamaTokenizer
print("Creat tokenizer...")
tokenizer = LlamaTokenizer.from_pretrained('IEITYuan/Yuan2-2B-Februa-hf', add_eos_token=False, add_bos_token=False, eos_token='<eod>')
tokenizer.add_tokens(['<sep>', '<pad>', '<mask>', '<predict>', '<FIM_SUFFIX>', '<FIM_PREFIX>', '<FIM_MIDDLE>','<commit_before>','<commit_msg>','<commit_after>','<jupyter_start>','<jupyter_text>','<jupyter_code>','<jupyter_output>','<empty_output>'], special_tokens=True)
print("Creat model...")
model = AutoModelForCausalLM.from_pretrained('IEITYuan/Yuan2-2B-Februa-hf', device_map='auto', torch_dtype=torch.bfloat16, trust_remote_code=True)
inputs = tokenizer("請問目前最先進的機器學習演算法有哪些?", return_tensors="pt")["input_ids"].to("cuda:0")
outputs = model.generate(inputs,do_sample=False,max_length=100)
print(tokenizer.decode(outputs[0]))

3.案例測試

利用 Yuan2.0 大模型,聯合向量資料和 Llama_index,對比使用者同一個問題的輸出結果,驗證方案的可行性。

使用者輸入問題:"介紹一下廣州大學",使用檢索增強生成技術之前的模型回答效果,該結果可以直接使用 Yuan2-2B-Februa 模型進行推理復現:

廣州大學是一所位於中國廣東省廣州市的本科高校,建立於1980年。學校以“南國情懷、卓越創新”為校訓,是一所以工科為主,工學、理學、管理學、法學、文學、教育學等學科門類齊全的綜合性大學。目前設有14個學院和26個研究院所,擁有全日制本科生近3.5萬名,碩士、博士研究生超過7萬人。校園環境優美,設施完善,是全國文明單位和國家綠化先進集體。

使用檢索增強生成技術之後的模型回答效果,執行完整程式碼,可以復現該結果:

廣州大學是一所位於中國廣東省廣州市的綜合性大學,是廣東省重點建設高校之一,也是國家“111計劃”建設的高校之一。它於1927年由原國立廣東法商學院在廣州創立,是中國第一所獨立設立的現代高等教育機構之一。學校的前身是成立於1927年的廣州大學公學,發展至今已成為一所具有悠久歷史的研究型大學。學校佔地約1880畝,擁有現代化的教學樓、實驗樓和圖書館等設施,同時注重學生的全面發展和社會實踐能力培養。

對比發現:新增知識庫之後,大模型的回答學到了 “國家“111 計劃” 建設的高校“的新知識。

4.總結

利用 Yuan 大模型、向量資料庫和 LlamaIndex 助力大模型檢索增強生成技術,為 NLP 領域開闢了一個可能性領域。這個管道不僅可以理解和生成文字,而且還利用龐大的資訊資料庫來增強其響應,使其在聊天機器人、推薦系統等各種應用程式中具有難以置信的強大功能。

然而,旅程並沒有就此結束。NLP 的世界正在迅速發展,保持最新趨勢和技術的更新至關重要。這裡討論的實現是進入更廣泛、更復雜的語言理解和生成世界的墊腳石。不斷試驗,不斷學習,最重要的是不斷創新。

5. 附完整程式碼

完整程式碼檔案 yuan.py 內容如下:

from llama_index import download_loader
import logging
import sys
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from llama_index.embeddings import HuggingFaceEmbedding
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
from llama_index import VectorStoreIndex, SimpleDirectoryReader, ServiceContext
from llama_index.llms import HuggingFaceLLM
from llama_index.prompts import PromptTemplate
query = "介紹一下廣州大學"
yuan_path = "/workspace/yuan_2/Yuan2-2B-Februa-hf"
print("Yuan2-2B-Februa Creat tokenizer...")
tokenizer = AutoTokenizer.from_pretrained(yuan_path, add_eos_token=False, add_bos_token=False, eos_token='<eod>')
tokenizer.add_tokens(['<sep>', '<pad>', '<mask>', '<predict>', '<FIM_SUFFIX>', '<FIM_PREFIX>', '<FIM_MIDDLE>','<commit_before>','<commit_msg>','<commit_after>','<jupyter_start>','<jupyter_text>','<jupyter_code>','<jupyter_output>','<empty_output>'], special_tokens=True)
print("Yuan2-2B-Februa Creat model...")
model = AutoModelForCausalLM.from_pretrained(yuan_path, torch_dtype=torch.bfloat16, trust_remote_code=True)
device_map = torch.cuda.current_device() if torch.cuda.is_available() else torch.device('cpu')
model = model.to(device_map)
# model = model.to("cpu")
llm = HuggingFaceLLM(
    # context_window=2048,
    max_new_tokens=1024,
    generate_kwargs={"temperature": 0.25, "do_sample": False, "repetition_penalty": 1.2, "max_length": 2048},
    # query_wrapper_prompt=query_wrapper_prompt,
    tokenizer=tokenizer,
    model=model,
    # tokenizer_name=yuan_path,
    # model_name=yuan_path,
    device_map="auto",
    # tokenizer_kwargs={"max_length": 2048},
    # uncomment this if using CUDA to reduce memory usage
    model_kwargs={"torch_dtype": torch.float16, "trust_remote_code":True}
)
print("Creat embedding model...")
embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-zh-v1.5",trust_remote_code=True)
# load documents
MilvusReader = download_loader("MilvusReader")
reader = MilvusReader(
    host="localhost", port=19530, user="<user>", password="<password>", use_secure=False
)
# Example query vector:
documents = reader.load_data(
    query_vector=embed_model.get_text_embedding(query),
    collection_name="demo",
    limit=5
)
service_context = ServiceContext.from_defaults(llm=llm, embed_model=embed_model)
index = VectorStoreIndex.from_documents(
    documents, service_context=service_context, show_progress=True
)
# define prompts that are used in llama-index, {query_str} is user's question,{context_str} is content queried by milvus
query_engine = index.as_query_engine(**{"text_qa_template":PromptTemplate(
    ("背景:{context_str}"
    "問題: {query_str}\n")
)})
response = query_engine.query(query)
print(response)

更多優質內容請關注公號:汀丶人工智慧;會提供一些相關的資源和優質文章,免費獲取閱讀。

相關文章