基于InternLM和LangChain搭建專屬個人的大模型知識庫;
- 大模型開發(fā)范式
- LangChain簡介
- 構(gòu)建
1 大模型開發(fā)范式
大模型具有簡單的廣度回答,但是在垂直領(lǐng)域的知識受限;
- 如何讓LLM及時獲得最新的知識
- 如何打造垂直領(lǐng)域大模型
- 如何打造個人專屬的LLM應(yīng)用
兩種常用開發(fā)范式:RAG VS Finetune
即:檢索增強生成 VS 算法微調(diào);
RAG:
- 成本低
- 可實時更新
- 受基座影響大
- 單次回答知識有限
Finetune:
- 可個性化微調(diào)
- 知識覆蓋面廣
- 成本高昂
- 無法實時更新
1.1 RAG原理
1.2 LangChain框架
LangChain框架:是一個開源工具,為各種LLM提供通用接口來簡化應(yīng)用程序的開發(fā)流程,幫助開發(fā)者自由構(gòu)建LLM應(yīng)用;
LangChain的核心組成模塊:
- 鏈:將組件實現(xiàn)端到端應(yīng)用,通過一個對象封裝實現(xiàn)一系列LLM操作;
- Eg:檢索問答鏈,覆蓋實現(xiàn)了RAG的全部流程;
1.3 構(gòu)建向量數(shù)據(jù)庫
加載源文件–>文檔分塊–>文檔向量化;
1.4 構(gòu)建知識庫助手
- LangChain支持自定義LLM,可以直接接入到框架中;
- 只需將InternLM部署到本地,并封裝一個自定義LLM類,調(diào)用本地的InternLM即可。
RAG方案優(yōu)化建議:
1.5 Web Demo部署
支持簡易Web 部署的框架:Gradio、Streamlit等;
2 動手實踐
2.1 環(huán)境配置
1.安裝環(huán)境,激活環(huán)境,并安裝依賴
2.模型下載
- 直接從服務(wù)器copy;–不可?。?/li>
- modelscope 中的 snapshot_download 函數(shù)下載模型,第一個參數(shù)為模型名稱,參數(shù) cache_dir 為模型的下載路徑。
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm-chat-7b', cache_dir='/root/data/model', revision='v1.0.3')
3.LangChain相關(guān)環(huán)境部署
4.下載NLTK相關(guān)資源
在使用開源詞向量模型構(gòu)建開源詞向量的時候,需要用到第三方庫 nltk 的一些資源。
2.2 知識庫搭建
2.2.1 數(shù)據(jù)收集
- OpenCompass:面向大模型評測的一站式平臺
- IMDeploy:涵蓋了 LLM 任務(wù)的全套輕量化、部署和服務(wù)解決方案的高效推理工具箱)
- XTuner:輕量級微調(diào)大語言模型的工具庫
- InternLM-XComposer:浦語·靈筆,基于書生·浦語大語言模型研發(fā)的視覺-語言大模型
- Lagent:一個輕量級、開源的基于大語言模型的智能體(agent)框架
- InternLM:一個開源的輕量級訓(xùn)練框架,旨在支持大模型訓(xùn)練而無需大量的依賴
開源使用方式
# clone 上述開源倉庫
git clone https://gitee.com/open-compass/opencompass.git
git clone https://gitee.com/InternLM/lmdeploy.git
git clone https://gitee.com/InternLM/xtuner.git
git clone https://gitee.com/InternLM/InternLM-XComposer.git
git clone https://gitee.com/InternLM/lagent.git
git clone https://gitee.com/InternLM/InternLM.git
為語料處理方案,在這里只選用倉庫中的MD、TXT文件作為示例語料庫。
當(dāng)然也可以選用其中的代碼文件放入到知識庫中,但是需要針對代碼文件格式進行專門的額外處理。(代碼文件對邏輯聯(lián)系要求較高,且規(guī)范性較強,在分割時最好基于代碼模塊進行分割再加入向量數(shù)據(jù)庫)。
創(chuàng)建函數(shù):將倉庫里所以滿足條件的.md或.txt文件 的路徑找出來,定義一個函數(shù):將該函數(shù)遞歸指定文件路徑,返回其中所有滿足條件的文件路徑;
import os
def get_files(dir_path):
# args:dir_path,目標文件夾路徑
file_list = []
for filepath, dirnames, filenames in os.walk(dir_path):
# os.walk 函數(shù)將遞歸遍歷指定文件夾
for filename in filenames:
# 通過后綴名判斷文件類型是否滿足要求
if filename.endswith(".md"):
# 如果滿足要求,將其絕對路徑加入到結(jié)果列表
file_list.append(os.path.join(filepath, filename))
elif filename.endswith(".txt"):
file_list.append(os.path.join(filepath, filename))
return file_list
2.2.2 加載數(shù)據(jù)
在上一步將所有目標文件的路徑找出來之后,使用LangChain提供的FileLoader對象來加載目標文件,得到由目標文件解析出的純文本內(nèi)容。
不同類型文件對應(yīng)不同的FileLoader:首先判斷目標文件類型,并針對性調(diào)用對應(yīng)類型的FileLoader,即調(diào)用FileLoader對象的load方法來得到加載之后的純文本對象。
Python 真是好東西,實現(xiàn)簡潔且可讀性超級強
from tqdm import tqdm
from langchain.document_loaders import UnstructuredFileLoader
from langchain.document_loaders import UnstructuredMarkdownLoader
def get_text(dir_path):
# args:dir_path,目標文件夾路徑
# 首先調(diào)用上文定義的函數(shù)得到目標文件路徑列表
file_lst = get_files(dir_path)
# docs 存放加載之后的純文本對象
docs = [] # 得到一個純文本對象對應(yīng)的列表
# 遍歷所有目標文件
for one_file in tqdm(file_lst):
file_type = one_file.split('.')[-1]
if file_type == 'md':
loader = UnstructuredMarkdownLoader(one_file)
elif file_type == 'txt':
loader = UnstructuredFileLoader(one_file)
else:
# 如果是不符合條件的文件,直接跳過
continue
docs.extend(loader.load())
return docs
2.2.3 構(gòu)建向量數(shù)據(jù)庫
在上一步得到純文本對象的列表之后,將它引入到LangChain框架中構(gòu)建向量數(shù)據(jù)庫。由純文本對象構(gòu)建向量數(shù)據(jù)庫,先對文本進行分塊,接著對文本進行向量化。
1.#LangChain有多種文本分塊工具,在這里使用字符串遞歸分割器
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=150)
split_docs = text_splitter.split_documents(docs)
2.選用開源詞向量模型進行文本向量化
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(model_name="/root/data/model/sentence-transformer")
3.將Chroma作為向量數(shù)據(jù)庫,基于上文分塊后的文檔以及加載的開源向量化模型,將語料加載到指定路徑下的向量數(shù)據(jù)庫:
from langchain.vectorstores import Chroma
# 定義持久化路徑
persist_directory = 'data_base/vector_db/chroma'
# 加載數(shù)據(jù)庫
vectordb = Chroma.from_documents(
documents=split_docs,
embedding=embeddings,
persist_directory=persist_directory # 允許我們將persist_directory目錄保存到磁盤上
)
# 將加載的向量數(shù)據(jù)庫持久化到磁盤上
vectordb.persist()
2.3 InternLM接入LangChain
為方便構(gòu)建LLM應(yīng)用,基于本地進行部署InternLM,繼承LangChain的LLM類自定義一個InternLM LLM子類,從而實現(xiàn)將InternLM接入到LangChain框架中。
完成 LangChain 的自定義 LLM 子類之后,可以以完全一致的方式調(diào)用 LangChain 的接口,而無需考慮底層模型調(diào)用的不一致。
from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
class InternLM_LLM(LLM):
# 基于本地 InternLM 自定義 LLM 類
tokenizer : AutoTokenizer = None
model: AutoModelForCausalLM = None
def __init__(self, model_path :str):
# model_path: InternLM 模型路徑
# 從本地初始化模型
super().__init__()
print("正在從本地加載模型...")
self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
self.model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).to(torch.bfloat16).cuda()
self.model = self.model.eval()
print("完成本地模型的加載")
def _call(self, prompt : str, stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any):
# 重寫調(diào)用函數(shù)
system_prompt = """You are an AI assistant whose name is InternLM (書生·浦語).
- InternLM (書生·浦語) is a conversational language model that is developed by Shanghai AI Laboratory (上海人工智能實驗室). It is designed to be helpful, honest, and harmless.
- InternLM (書生·浦語) can understand and communicate fluently in the language chosen by the user such as English and 中文.
"""
messages = [(system_prompt, '')]
response, history = self.model.chat(self.tokenizer, prompt , history=messages)
return response
@property
def _llm_type(self) -> str:
return "InternLM"
在上述類定義中,我們分別重寫了構(gòu)造函數(shù)和 _call 函數(shù):對于構(gòu)造函數(shù),我們在對象實例化的一開始加載本地部署的 InternLM 模型,從而避免每一次調(diào)用都需要重新加載模型帶來的時間過長;_call 函數(shù)是 LLM 類的核心函數(shù),LangChain 會調(diào)用該函數(shù)來調(diào)用 LLM,在該函數(shù)中,我們調(diào)用已實例化模型的 chat 方法,從而實現(xiàn)對模型的調(diào)用并返回調(diào)用結(jié)果。
在Python中看到了類似C++中的用法
2.4 構(gòu)建檢索問答鏈
LangChain 通過提供檢索問答鏈對象來實現(xiàn)對于 RAG 全流程的封裝。所謂檢索問答鏈,即通過一個對象完成檢索增強問答(即RAG)的全流程。
原理:調(diào)用一個 LangChain 提供的 RetrievalQA 對象,通過初始化時填入已構(gòu)建的數(shù)據(jù)庫和自定義 LLM 作為參數(shù),來簡便地完成檢索增強問答的全流程,LangChain 會自動完成基于用戶提問進行檢索、獲取相關(guān)文檔、拼接為合適的 Prompt 并交給 LLM 問答的全部流程。
1 加載向量數(shù)據(jù)庫
將上文構(gòu)建的向量數(shù)據(jù)庫導(dǎo)入進來,直接通過Chroma以及上文定義的詞向量模型來加載已構(gòu)建的數(shù)據(jù)庫:
vedtordb對象即為已經(jīng)構(gòu)建好的向量數(shù)據(jù)庫對象,它可以針對用戶的query進行語義向量檢索,得到與用戶提問相關(guān)的知識;
2 實例化自定義LLM與Prompt Template
實例化一個基于InternLM自定義的LLM對象:
3 構(gòu)建檢索問答鏈
調(diào)用 LangChain 提供的檢索問答鏈構(gòu)造函數(shù),基于我們的自定義 LLM、Prompt Template 和向量知識庫來構(gòu)建一個基于 InternLM 的檢索問答鏈:
2.5 Web Demo
上面兩個小節(jié)分別完成之后,搭建基于Gradio框架部署到網(wǎng)頁,搭建一個小型的Demo,這樣便于測試和調(diào)試;
-
將上面的代碼封裝成一個函數(shù):用于返回 構(gòu)建的檢索問答鏈對象的函數(shù)。在啟動Gradio的initial時調(diào)用函數(shù)得到檢索問答鏈對象,后續(xù)直接使用該對象進行問答對話,避免重復(fù)加載模型;
-
定義一個類:負責(zé)加載并存儲檢索問答鏈,響應(yīng)Web界面里調(diào)用該檢索問答鏈進行回答的動作;
-
按照Gradio框架使用方法,實例化一個Web界面并將點擊動作綁定到上述類的回答方法即可。
-
啟動上面封裝的腳本,默認會在7860端口運行,因此做好服務(wù)器端口與本地端口映射。
ssh -L 7860:127.0.0.1:7860 root@ssh.intern-ai.org.cn -p 34825文章來源:http://www.zghlxwxcb.cn/news/detail-791143.html
3 作業(yè)
文章來源地址http://www.zghlxwxcb.cn/news/detail-791143.html
到了這里,關(guān)于【搭建個人知識庫-3】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!