自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

本地化大模型部署:LocalGPT應(yīng)用指南

原創(chuàng) 精選
人工智能
本文探討了大模型在本地部署的實(shí)踐方法,重點(diǎn)介紹了OpenAI的多模態(tài)、Function call 和 AI assistance 功能給 AI開發(fā)者帶來的便利。文中著重討論了使用開源大模型,如Llama2和ChatGLM,來應(yīng)對成本和數(shù)據(jù)安全性挑戰(zhàn)的策略。

作者 | 崔皓

審核 | 重樓

摘要

本文探討了大模型在本地部署的實(shí)踐方法,重點(diǎn)介紹了OpenAI的多模態(tài)、Function call 和 AI assistance 功能AI開發(fā)者帶來的便利。文中著重討論了使用開源大模型,如Llama2和ChatGLM,來應(yīng)對成本和數(shù)據(jù)安全性挑戰(zhàn)的策略。

文章以LocalGPT為例,詳細(xì)闡述了其安裝、使用及代碼實(shí)現(xiàn),為讀者提供了關(guān)于如何將大模型成功集成到自己的應(yīng)用系統(tǒng)中的寶貴經(jīng)驗(yàn)。

開篇

近年來,大模型的發(fā)展可謂日新月異,尤其是OpenAI發(fā)布的多模態(tài)、Function call以及AI assistance功能,為廣大AI開發(fā)者帶來了前所未有的便捷和創(chuàng)新空間。這些功能提升了模型的智能性和多樣性。然而,隨之而來的是一些企業(yè)對數(shù)據(jù)安全性的擔(dān)憂,以及調(diào)用GPT模型所需成本的問題。

面對這些挑戰(zhàn),部分企業(yè)開始轉(zhuǎn)向開源的大模型,如Llama2和ChatGLM,在控制成本的同時(shí),也保障了數(shù)據(jù)的私密性和安全性。然而,采用開源模型同樣面臨著新的問題:如何有效搭建這些模型,并將其順利接入到自己的應(yīng)用系統(tǒng)中呢?這一過程中的技術(shù)挑戰(zhàn)和實(shí)際操作,將是我們接下來探討的重點(diǎn)。

本文將以開源架構(gòu)LocalGPT為例,為您揭開本地部署大模型的神秘面紗,帶您深入了解其背后的具體技術(shù)和實(shí)施步驟。

大模型架構(gòu)與工具

談到大模型本地化部署,市面上有很多流行的工具和架構(gòu),例如:Ollama、Chatchat和LocalGPT。Ollama是一種支持運(yùn)行開源大型語言模型的工具,如Llama 2,它通過一個(gè)Modelfile將模型權(quán)重、配置和數(shù)據(jù)打包成單一程序包。這種方式優(yōu)化了設(shè)置和配置細(xì)節(jié),包括GPU的使用,豐富的模型庫,與langchain代碼實(shí)現(xiàn)無縫對接。本地化運(yùn)行比較流程。

Chatchat則是一種基于本地知識庫的問答應(yīng)用,它利用LangChain的理念,旨在建立一套對中文場景與開源模型支持友好、可離線運(yùn)行的知識庫問答解決方案。它受到了多個(gè)項(xiàng)目的啟發(fā),通過使用FastChat接入多種模型,并依托于LangChain框架提供API調(diào)用服務(wù)。Chatchat的特點(diǎn)在于對中文支持的優(yōu)化,這使得它特別受到中國企業(yè)本地化部署的青睞。

LocalGPT則是一個(gè)開源項(xiàng)目,允許用戶在不妥協(xié)隱私的情況下與文檔進(jìn)行對話。它特別注重?cái)?shù)據(jù)的安全性,確保所有數(shù)據(jù)都在用戶的計(jì)算機(jī)上處理。LocalGPT支持多種開源模型,包括HF、GPTQ、GGML和GGUF等,并提供多種嵌入選項(xiàng)。它的一個(gè)顯著特點(diǎn)是一旦下載了LLM,就可以重復(fù)使用而無需重復(fù)下載。LocalGPT的代碼簡單,非常適合進(jìn)行學(xué)習(xí)和研究。通過對它的學(xué)習(xí),我們可以理解如何創(chuàng)建基于RAG的企業(yè)知識庫。

雖然工具和架構(gòu)各有特色,但是LocalGPT以簡單的代碼與清晰的思路成為程序員學(xué)習(xí)大模型本地部署的首選,后面的內(nèi)容我們將以LocalGPT的源代碼為基礎(chǔ)來介紹它的實(shí)現(xiàn)與使用。

LocalGPT安裝與使用

LocalGPT是一個(gè)開源項(xiàng)目,它允許用戶在保護(hù)隱私的前提下與自己的文檔進(jìn)行對話。這一項(xiàng)目在GitHub上獲得了17.5k的星標(biāo),所有操作均在本地完成,確保了數(shù)據(jù)的完全安全。LocalGPT的特點(diǎn)包括絕對隱私保護(hù)、支持多種開源模型、多樣化的嵌入選擇、一次下載后多次使用的大型語言模型、記錄聊天歷史以及提供用于構(gòu)建RAG應(yīng)用程序的API。此外,LocalGPT還提供了兩種圖形用戶界面,支持多平臺(包括CUDA、CPU和MPS)。

在技術(shù)細(xì)節(jié)實(shí)現(xiàn)方面,LocalGPT通過選擇合適的本地模型和利用LangChain的能力,可以在本地運(yùn)行整個(gè)RAG流程,而且性能合理。ingest.py利用LangChain工具解析文檔并在本地使用InstructorEmbeddings創(chuàng)建嵌入,然后將結(jié)果存儲在本地的Chroma向量數(shù)據(jù)庫中。run_localGPT.py使用本地的大型語言模型來理解問題并創(chuàng)建答案,答案的上下文是通過相似性搜索從本地向量存儲中提取的。用戶可以將此本地大型語言模型替換為HuggingFace中的任何其他模型,只要確保所選模型符合HF格式。

LocalGPT安裝

1.環(huán)境設(shè)置

使用git克隆倉庫:

git clone https://github.com/PromtEngineer/localGPT.git

安裝conda進(jìn)行虛擬環(huán)境管理。創(chuàng)建并激活一個(gè)新的虛擬環(huán)境。

conda create -n localGPT python=3.10.0
conda activate localGPT

2.使用pip安裝依賴項(xiàng)

為了設(shè)置環(huán)境以運(yùn)行代碼,首先安裝所有要求的依賴:

pip install -r requirements.txt

3.安裝LLAMA-CPP

LocalGPT使用LlamaCpp-Python用于GGML(需要llama-cpp-python <=0.1.76)和GGUF(llama-cpp-python >=0.1.83)模型。

如果想在llama-cpp中使用BLAS或Metal,您可以設(shè)置適當(dāng)?shù)臉?biāo)志:

支持NVIDIA GPU,使用cuBLAS

# 示例:cuBLAS

CMAKE_ARGS="-DLLAMA_CUBLAS=on" FORCE_CMAKE=1 pip install llama-cpp-python==0.1.83 --no-cache-dir

支持Apple Metal (M1/M2),使用

# 示例:METAL
CMAKE_ARGS="-DLLAMA_METAL=on" FORCE_CMAKE=1 pip install llama-cpp-python==0.1.83 --no-cache-dir

導(dǎo)入知識庫文檔

將要上傳的文件放在SOURCE_DOCUMENTS文件夾中??梢栽赟OURCE_DOCUMENTS文件夾中放置多個(gè)文件夾,代碼會遞歸地讀取文件。

支持的文件格式方面,LocalGPT目前支持以下文件格式。LocalGPT使用LangChain加載這些文件格式。constants.py中的代碼使用DOCUMENT_MAP字典將文件格式映射到相應(yīng)的加載器。為了添加對另一種文件格式的支持,只需在此字典中添加文件格式和LangChain中的相應(yīng)加載器即可。

DOCUMENT_MAP = {
    ".txt": TextLoader,
    ".md": TextLoader,
    ".py": TextLoader,
    ".pdf": PDFMinerLoader,
    ".csv": CSVLoader,
    ".xls": UnstructuredExcelLoader,
    ".xlsx": UnstructuredExcelLoader,
    ".docx": Docx2txtLoader,
    ".doc": Docx2txtLoader,
}

提取文件信息

如果系統(tǒng)上設(shè)置cuda,運(yùn)行以下命令以攝取所有數(shù)據(jù)。

python ingest.py

輸出如下:

使用device_type參數(shù)來指定特定設(shè)備。在CPU上運(yùn)行

python ingest.py --device_type cpu

在M1/M2上運(yùn)行

python ingest.py --device_type mps

使用help獲取支持設(shè)備的完整列表。

python ingest.py --help

這將創(chuàng)建一個(gè)名為DB的新文件夾,并將其用于新創(chuàng)建的向量存儲。您可以攝取任意多的文檔,所有文檔都將累積在本地嵌入數(shù)據(jù)庫中。如果您想從一個(gè)空數(shù)據(jù)庫開始,刪除DB并重新攝取文檔。

注意:當(dāng)您第一次運(yùn)行時(shí),需要互聯(lián)網(wǎng)連接下載嵌入模型(默認(rèn)為Instructor Embedding)。在隨后的運(yùn)行中,不會有數(shù)據(jù)離開您的本地環(huán)境,您可以在沒有互聯(lián)網(wǎng)連接的情況下攝取數(shù)據(jù)。

對知識庫提問

請運(yùn)行以下命令進(jìn)行聊天(默認(rèn)情況下,它將在cuda上運(yùn)行)。

python run_localGPT.py

可以像ingest.py一樣指定設(shè)備類型

python run_localGPT.py --device_type mps # 在Apple芯片上運(yùn)行

這將加載攝取的向量存儲和嵌入模型。您將看到一個(gè)提示:

> Enter a query

輸入您的問題后,按回車鍵。LocalGPT將根據(jù)系統(tǒng)的硬件花費(fèi)一些時(shí)間。您將得到如下響應(yīng)。

一旦生成了答案,您可以再提出另一個(gè)問題,而無需重新運(yùn)行腳本,只需再次等待提示。

注意:當(dāng)您第一次運(yùn)行時(shí),需要互聯(lián)網(wǎng)連接下載LLM(默認(rèn)為TheBloke/Llama-2-7b-Chat-GGUF)。在此之后,您可以關(guān)閉互聯(lián)網(wǎng)連接,腳本推理仍然會工作。沒有數(shù)據(jù)離開您的本地環(huán)境。

輸入exit以結(jié)束腳本。

GPU和VRAM要求

下表是根據(jù)不同模型的大小(億級參數(shù))的VRAM要求。表中的估計(jì)值不包括嵌入模型使用的VRAM——這將額外使用2GB至7GB的VRAM,具體取決于模型。

我使用了4060筆記本版本的顯卡(8G顯存)進(jìn)行的測試,大模型回應(yīng)的速度在1分鐘左右,如果使用更好的顯卡這個(gè)速度應(yīng)該還會提升。

LocalGPT 程序結(jié)構(gòu)

在了解了LocalGPT的安裝和使用之后,我們來對核心代碼進(jìn)行解析。如下圖所示,在項(xiàng)目代碼中我們將重要代碼部分使用紅色框出,并給大家介紹:

  • SOURCE_DOCUMENTS 目錄下面是用來存放需要上傳的PDF文件,如果要將知識庫所需的文件上傳,必須先將文件放到這個(gè)目錄,然后再執(zhí)行ingest.py 程序進(jìn)行嵌入操作。
  • Constants.py文件用來對程序常量進(jìn)行定義,包括文件目錄,支持的文件類型,大模型的ID和名字等。
  • Ingest.py 是用來嵌入文件到向量庫的代碼文件,也是后面我們要介紹的重點(diǎn)。
  • Requirements.txt 文件用來保存安裝所需要的依賴包。
  • Run_localGPT.py 文件是用來執(zhí)行問答回應(yīng)的代碼文件,在文件嵌入之后就通過它來向知識庫提問。后面會著重介紹。
  • 另外localGPT_UI.py run_localGPT_API.py,前者是提供UI界面的問答程序,后者是提供問答服務(wù)的API。


Ingest.py 代碼解析

它的主要功能是從指定的源目錄加載文檔,將它們切割為適合處理的大小,并為這些文檔片段創(chuàng)建嵌入,最后將它們存儲在一個(gè)本地?cái)?shù)據(jù)庫中。這是一個(gè)文檔處理和嵌入生成的完整流程,主要用于構(gòu)建和管理大型文檔的知識庫。

1. 主要函數(shù)及其功能

load_single_document(file_path: str) -> Document加載單個(gè)文檔。根據(jù)文件路徑和擴(kuò)展名,使用相應(yīng)的加載類來加載文檔。

load_document_batch(filepaths)加載一批文檔。它創(chuàng)建一個(gè)線程池來并行加載多個(gè)文檔。

load_documents(source_dir: str) -> list[Document]從源目錄加載所有文檔。它列出目錄中的所有文件,并根據(jù)文件擴(kuò)展名決定是否加載。

split_documents(documents: list[Document]) -> tuple[list[Document], list[Document]]將文檔分成兩組,一組是普通文本文檔,另一組是Python代碼文檔。

main(device_type)主函數(shù),負(fù)責(zé)初始化日志記錄,加載文檔,分割文檔,創(chuàng)建嵌入,并將結(jié)果持久化。

2. 函數(shù)調(diào)用關(guān)系

main() 是程序的入口點(diǎn)。它首先調(diào)用 load_documents() 來加載源目錄中的所有文檔。

在 load_documents() 內(nèi)部,它通過調(diào)用 load_document_batch() 來加載文檔批次。每個(gè)文檔批次由 load_single_document() 加載。

加載并返回所有文檔后,main() 調(diào)用 split_documents() 將文檔分為文本和Python文檔。

main() 還創(chuàng)建了文檔的嵌入,并將這些嵌入以及原始文檔數(shù)據(jù)存儲在一個(gè)本地的Chroma數(shù)據(jù)庫中。

我們將幾個(gè)重要的函數(shù)展開給大家介紹如下:

def load_single_document(file_path: str) -> Document:
    # Loads a single document from a file path
    file_extension = os.path.splitext(file_path)[1]
    loader_class = DOCUMENT_MAP.get(file_extension)
    if loader_class:
        loader = loader_class(file_path)
    else:
        raise ValueError("Document type is undefined")
    return loader.load()[0]

load_single_document 函數(shù)的目的是加載一個(gè)文件路徑指定的文檔。下面是對關(guān)鍵代碼的解釋:

1. file_extension = os.path.splitext(file_path)[1]:

將文件路徑分割為文件名和擴(kuò)展名。os.path.splitext 是Python的一個(gè)標(biāo)準(zhǔn)庫函數(shù),用于分割文件名和其擴(kuò)展名。這里 [1] 表示提取分割后的第二部分,即文件的擴(kuò)展名。

2. loader_class = DOCUMENT_MAP.get(file_extension):

-在 DOCUMENT_MAP 字典中查找與文件擴(kuò)展名對應(yīng)的加載類。DOCUMENT_MAP 應(yīng)該是一個(gè)預(yù)定義的字典,其鍵為文件擴(kuò)展名,值為相應(yīng)的加載類。

3. if loader_class:

這是一個(gè)條件判斷。它檢查是否找到了與文件擴(kuò)展名對應(yīng)的加載類。如果找到了(即 loader_class 不為空),則執(zhí)行下一步;否則,執(zhí)行 else 部分的代碼。

如果找到了匹配的加載類,這行代碼將創(chuàng)建該類的實(shí)例。它將文件路徑作為參數(shù)傳遞給該類的構(gòu)造函數(shù),從而初始化一個(gè)新的加載器對象。if 條件不滿足時(shí)執(zhí)行的,即如果沒有找到匹配的加載類,會引發(fā)一個(gè) ValueError 異常,表明無法確定文件的文檔類型。

說了文件加載的函數(shù)再來看看Ingest.py的主函數(shù), main 函數(shù)實(shí)現(xiàn)文件加載到嵌入的流程。它從源目錄加載文檔,將它們分割成更小的片段,并為這些片段創(chuàng)建嵌入,最后將這些信息存儲到本地?cái)?shù)據(jù)庫中。下面是對關(guān)鍵代碼的解釋

def main(device_type):
    # Load documents and split in chunks
    logging.info(f"Loading documents from {SOURCE_DIRECTORY}")
    #加載文檔
    documents = load_documents(SOURCE_DIRECTORY)
    #切割文檔
    text_documents, python_documents = split_documents(documents)
    #切割文檔的方式
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
    python_splitter = RecursiveCharacterTextSplitter.from_language(
        language=Language.PYTHON, chunk_size=880, chunk_overlap=200
    )
    texts = text_splitter.split_documents(text_documents)
    texts.extend(python_splitter.split_documents(python_documents))
    logging.info(f"Loaded {len(documents)} documents from {SOURCE_DIRECTORY}")
    logging.info(f"Split into {len(texts)} chunks of text")

    # Create embeddings
    embeddings = HuggingFaceInstructEmbeddings(
        model_name=EMBEDDING_MODEL_NAME,
        model_kwargs={"device": device_type},
    )
    
    db = Chroma.from_documents(
        texts,
        embeddings,
        persist_directory=PERSIST_DIRECTORY,
        client_settings=CHROMA_SETTINGS,
    )
    db.persist()
    db = None

1. documents = load_documents(SOURCE_DIRECTORY):

調(diào)用 load_documents 函數(shù),從 SOURCE_DIRECTORY 指定的目錄中加載所有文檔。這個(gè)函數(shù)返回一個(gè)文檔對象的列表。

2. text_documents, python_documents = split_documents(documents):

調(diào)用 split_documents 函數(shù),將加載的文檔分成兩類:一類是普通文本文檔,另一類是Python代碼文檔。這有助于后續(xù)根據(jù)文檔類型采取不同的處理策略。

3. 創(chuàng)建 RecursiveCharacterTextSplitter 實(shí)例:

text_splitter 和 python_splitter 是用于分割文檔的實(shí)例。text_splitter 用于普通文本,而 python_splitter 專門用于Python代碼。它們通過設(shè)置 chunk_size 和 chunk_overlap 來定義文檔切割的大小和重疊部分。

4. texts = text_splitter.split_documents(text_documents):

使用 text_splitter 對普通文本文檔進(jìn)行分割,結(jié)果存儲在 texts 列表中。

5. texts.extend(python_splitter.split_documents(python_documents)):

使用 python_splitter 對Python代碼文檔進(jìn)行分割,并將這些分割后的文檔追加到 texts 列表中。

6. embeddings = HuggingFaceInstructEmbeddings(...):

創(chuàng)建 HuggingFaceInstructEmbeddings 的實(shí)例,用于生成文檔片段的嵌入。這里使用了模型名稱和設(shè)備類型作為參數(shù)。

7. db = Chroma.from_documents(...):

使用 Chroma 類的 from_documents 方法創(chuàng)建一個(gè)數(shù)據(jù)庫實(shí)例。它接受分割后的文檔片段、嵌入、持久化目錄和客戶端設(shè)置作為參數(shù)。

8. db.persist():

調(diào)用 persist 方法將數(shù)據(jù)庫中的數(shù)據(jù)持久化到本地存儲。

run_localGPT.py代碼解析

這個(gè)代碼實(shí)現(xiàn)文件現(xiàn)了一個(gè)基于大型語言模型的問答系統(tǒng),涵蓋了從模型加載到問答處理的整個(gè)流程。首先,它通過 load_model 函數(shù)根據(jù)設(shè)備類型和模型標(biāo)識符加載和配置適合文本生成的模型。接著,在 main 函數(shù)中,系統(tǒng)初始化嵌入模型和向量存儲,設(shè)置了一個(gè)基于模板的問答鏈,用于處理用戶查詢并生成回答。此外,系統(tǒng)提供了一個(gè)交互式界面,允許用戶輸入問題并接收相應(yīng)的答案,同時(shí)還能展示回答的相關(guān)文檔,這一功能的啟用取決于用戶的選擇。整個(gè)系統(tǒng)通過精心的配置和日志記錄,為用戶提供了一個(gè)高效、可定制的問答體驗(yàn)。接下來,我們圍繞兩個(gè)重要函數(shù)load_model和main 函數(shù)展開說明。

Load_model函數(shù)

def load_model(device_type, model_id, model_basename=None):
        logging.info(f"Loading Model: {model_id}, on: {device_type}")
    logging.info("This action can take a few minutes!")

    if model_basename is not None:
        if ".ggml" in model_basename:
            logging.info("Using Llamacpp for GGML quantized models")
            model_path = hf_hub_download(repo_id=model_id, filename=model_basename)
            max_ctx_size = 4048
            kwargs = {
                "model_path": model_path,
                "n_ctx": max_ctx_size,
                "max_tokens": max_ctx_size,
            }
            if device_type.lower() == "mps":
                kwargs["n_gpu_layers"] = 1000
            if device_type.lower() == "cuda":
                kwargs["n_gpu_layers"] = 1000
                kwargs["n_batch"] = max_ctx_size
            return LlamaCpp(kwargs)

        else:
            # The code supports all huggingface models that ends with GPTQ and have some variation
            # of .no-act.order or .safetensors in their HF repo.
            logging.info("Using AutoGPTQForCausalLM for quantized models")

            if ".safetensors" in model_basename:
                # Remove the ".safetensors" ending if present
                model_basename = model_basename.replace(".safetensors", "")

            tokenizer = AutoTokenizer.from_pretrained(model_id, use_fast=True)
            logging.info("Tokenizer loaded")

            model = AutoGPTQForCausalLM.from_quantized(
                model_id,
                model_basename=model_basename,
                use_safetensors=True,
                trust_remote_code=True,
                device="cuda:0",
                use_triton=False,
                quantize_config=None,
            )
    elif (
        device_type.lower() == "cuda"
    ):  
        logging.info("Using AutoModelForCausalLM for full models")
        tokenizer = AutoTokenizer.from_pretrained(model_id)
        logging.info("Tokenizer loaded")

        model = AutoModelForCausalLM.from_pretrained(
            model_id,
            device_map="auto",
            torch_dtype=torch.float16,
            low_cpu_mem_usage=True,
            trust_remote_code=True,
            
        )
        model.tie_weights()
    else:
        logging.info("Using LlamaTokenizer")
        tokenizer = LlamaTokenizer.from_pretrained(model_id)
        model = LlamaForCausalLM.from_pretrained(model_id)
    generation_config = GenerationConfig.from_pretrained(model_id)
    
    pipe = pipeline(
        "text-generation",
        model=model,
        tokenizer=tokenizer,
        max_length=4048,
        temperature=0,
        top_p=0.95,
        repetition_penalty=1.15,
        generation_config=generation_config,
    )

    local_llm = HuggingFacePipeline(pipeline=pipe)
    logging.info("Local LLM Loaded")

    return local_llm

load_model 的函數(shù),用于加載和配置用于文本生成的大型語言模型(LLM)。這里是對函數(shù)中關(guān)鍵部分的解釋:

1. 函數(shù)參數(shù):

device_type指定運(yùn)行模型的設(shè)備類型(如 "cuda" 或 "cpu")。

model_id指定要從HuggingFace模型庫中加載的模型的標(biāo)識符。

model_basename (可選)如果使用量化模型,則指定模型的基本名稱。

2. 模型加載邏輯:

如果 model_basename 不為 None,則根據(jù)模型文件名的不同,選擇不同的加載方式:

  • 對于文件名包含 ".ggml" 的量化模型,使用 LlamaCpp 加載。
  • 對于文件名包含 ".safetensors" 的量化模型,使用AutoGPTQForCausalLM 加載。

如果 device_type 為 "cuda",則使用 AutoModelForCausalLM 加載完整的模型。

如果不符合上述條件,使用 LlamaTokenizer 和 LlamaForCausalLM 加載模型。

3. 模型配置:

使用 GenerationConfig 來加載模型的配置,以避免警告。

創(chuàng)建 pipeline 對象用于文本生成,配置包括模型、分詞器、最大長度、溫度、top_p 參數(shù)等。

4. 返回值:

函數(shù)返回一個(gè) HuggingFacePipeline 對象,該對象封裝了配置好的文本生成管道。

Load_model函數(shù)顧名思義是用來裝載大模型的,在run_localGPT.py的main函數(shù)中會調(diào)用到Load_mode,接下來我們來看main函數(shù)的主要內(nèi)容。

main 函數(shù)實(shí)現(xiàn)了一個(gè)基于大型語言模型(LLM)的信息檢索和問答任務(wù)。函數(shù)首先根據(jù)設(shè)備類型加載一個(gè)嵌入模型,這可能是 HuggingFaceInstructEmbeddings 或 HuggingFaceEmbeddings。接著,它加載了之前由 inget.py 腳本創(chuàng)建的向量存儲,這是用于文檔檢索的關(guān)鍵部分。使用 load_model 函數(shù),函數(shù)加載了本地的LLM,支持多種不同的LLM。然后,它設(shè)置了一個(gè)問答檢索鏈,使用預(yù)定義的提示模板和對話緩存來處理用戶的查詢。用戶可以通過命令行輸入查詢,函數(shù)將使用LLM和文檔檢索系統(tǒng)來生成答案,并選擇性地顯示回答的源文檔。這個(gè)過程既是交互式的,也是動態(tài)的,允許用戶以自然語言的形式探索信息和知識庫。整個(gè)流程展示了如何將嵌入模型、大型語言模型和文檔檢索相結(jié)合,實(shí)現(xiàn)一個(gè)功能豐富的問答系統(tǒng)。

def main(device_type, show_sources):
    logging.info(f"Running on: {device_type}")
    logging.info(f"Display Source Documents set to: {show_sources}")
    embeddings = HuggingFaceInstructEmbeddings(model_name=EMBEDDING_MODEL_NAME, model_kwargs={"device": device_type})
    # uncomment the following line if you used HuggingFaceEmbeddings in the ingest.py
    # embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL_NAME)
    # load the vectorstore
    db = Chroma(
        persist_directory=PERSIST_DIRECTORY,
        embedding_function=embeddings,
        client_settings=CHROMA_SETTINGS,
    )
    retriever = db.as_retriever()
    template = """Use the following pieces of context to answer the question at the end. If you don't know the answer,\
    just say that you don't know, don't try to make up an answer.
    {context}
    {history}
    Question: {question}
    Helpful Answer:"""
    prompt = PromptTemplate(input_variables=["history", "context", "question"], template=template)
    memory = ConversationBufferMemory(input_key="question", memory_key="history")
    llm = load_model(device_type, model_id=MODEL_ID, model_basename=MODEL_BASENAME)
    qa = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=retriever,
        return_source_documents=True,
        chain_type_kwargs={"prompt": prompt, "memory": memory},
    )
    # Interactive questions and answers
    while True:
        query = input("\nEnter a query: ")
        if query == "exit":
            break
        # Get the answer from the chain
        res = qa(query)
        answer, docs = res["result"], res["source_documents"]

        # Print the result
        print("\n\n> Question:")
        print(query)
        print("\n> Answer:")
        print(answer)

        if show_sources:  # this is a flag that you can set to disable showing answers.
            # # Print the relevant sources used for the answer
            print("----------------------------------SOURCE DOCUMENTS---------------------------")
            for document in docs:
                print("\n> " + document.metadata["source"] + ":")
                print(document.page_content)
            print("----------------------------------SOURCE DOCUMENTS---------------------------")

main 函數(shù)構(gòu)建了一個(gè)基于大型語言模型(LLM)的信息檢索和問答系統(tǒng)。以下是對代碼的關(guān)鍵部分的解釋:

1. 初始化和設(shè)置:

Embeddings加載用于文檔嵌入的模型,這里使用的是 HuggingFaceInstructEmbeddings。

db: 加載由 inget.py 腳本創(chuàng)建的向量存儲 Chroma,它用于后續(xù)的文檔檢索任務(wù)。

2. 問答鏈設(shè)置:

template: 定義一個(gè)提示模板,用于格式化問答的上下文、歷史記錄和問題。

prompt: 創(chuàng)建一個(gè) PromptTemplate 實(shí)例,它將用于生成向語言模型提交的最終提示。

memory: 實(shí)例化 ConversationBufferMemory,用于在問答過程中保持對話歷史的緩存。

3. 加載語言模型:

llm: 使用 load_model 函數(shù)加載本地的大型語言模型,這個(gè)函數(shù)支持不同類型的模型和設(shè)備。

4. 問答邏輯實(shí)現(xiàn):

qa: 實(shí)例化一個(gè) RetrievalQA 對象,它結(jié)合了LLM和文檔檢索器來實(shí)現(xiàn)問答功能。

在一個(gè)循環(huán)中,系統(tǒng)接收用戶輸入的查詢,使用 qa 對象處理這些查詢,并輸出相應(yīng)的答案。

5. 交互和顯示:

用戶可以通過命令行輸入問題,系統(tǒng)根據(jù)用戶輸入的查詢提供答案。

如果設(shè)置了 show_sources 標(biāo)志,系統(tǒng)還會顯示生成答案時(shí)參考的源文檔。

constants.py 代碼解析

說完了Ingest.py和run_localGPT.py,大家對localGPT的主要功能有所了解了,實(shí)際上Ingest.py用來執(zhí)行文檔的嵌入和存儲,run_localGPT.py用來執(zhí)行具體的問答工作,利用事先存儲的向量庫進(jìn)行問題的搜索,然后通過大模型進(jìn)行回應(yīng)。不過這兩塊代碼中始終沒有出現(xiàn)具體的大模型,這個(gè)定義保存在constants.py 文件中,該文件中除了定義了調(diào)用的模型之外,還定了加載文件的類型以及嵌入的方式。代碼如下:

DOCUMENT_MAP = {
    ".txt": TextLoader,
    ".md": TextLoader,
    ".py": TextLoader,
    ".pdf": PDFMinerLoader,
    ".csv": CSVLoader,
    ".xls": UnstructuredExcelLoader,
    ".xlsx": UnstructuredExcelLoader,
    ".docx": Docx2txtLoader,
    ".doc": Docx2txtLoader,
}

#默認(rèn)的嵌入方式
# Default Instructor Model
EMBEDDING_MODEL_NAME = "hkunlp/instructor-large"

#模型的ID 和名字 
MODEL_ID = "TheBloke/Llama-2-7B-Chat-GGML"
MODEL_BASENAME = "llama-2-7b-chat.ggmlv3.q4_0.bin"

一般而言模型的信息包括MODEL_IDMODEL_BASENAME,這塊的信息可以通過Hugging Face 查找獲得。Hugging Face是一家專注于自然語言處理(NLP)的AI研究公司,提供大量預(yù)訓(xùn)練模型和工具,廣泛用于文本理解和生成任務(wù)。最重要的是它提供了一個(gè)大模型的平臺,讓廣大網(wǎng)友可以上傳自己調(diào)優(yōu)的模型。

如下圖所示,可以登陸huggingface.co網(wǎng)站,在首頁的搜索框中輸入想要的模型,它會自動模糊匹配相關(guān)的模型。

選擇模型之后,會進(jìn)入如下頁面,通過模型詳情頁面的“Files and versions”tab頁,可以看到模型的ID,圖中的ID為“TheBloke/Llama-2-7B-Chat-GGML”,同時(shí)可以看到需要下載的模型文件。這里選擇bin 文件,如果模型存在多個(gè)下載文件,選擇第一個(gè),本例中我們選擇“llama-2-7b-chat.ggmlv3.q4_0.bin”,這樣load_model函數(shù)會自動從huggingface 上下載定義好的模型文件。

總結(jié)

本文展示了大模型本地部署的全過程,包括模型選擇、配置、以及與應(yīng)用的集成。通過對LocalGPT的細(xì)致解讀,文章不僅展示了技術(shù)的實(shí)用性,也為有意采用大模型的企業(yè)和開發(fā)者提供了一條清晰的實(shí)施路徑。這些深入的分析和實(shí)例指導(dǎo),對于那些尋求在數(shù)據(jù)安全性和成本效益之間找到平衡點(diǎn)的企業(yè)來說,尤為寶貴。

作者介紹

崔皓,51CTO社區(qū)編輯,資深架構(gòu)師,擁有18年的軟件開發(fā)和架構(gòu)經(jīng)驗(yàn),10年分布式架構(gòu)經(jīng)驗(yàn)。




責(zé)任編輯:華軒 來源: 51CTO
相關(guān)推薦

2023-06-01 08:18:47

GPT大語言模型

2012-05-14 17:10:50

iOS

2012-05-13 13:15:54

IOS

2025-02-18 00:04:00

DeepSeek模型ChatGPT

2022-09-21 11:51:26

模塊化應(yīng)用

2017-11-30 14:44:41

語言代碼文件

2021-01-20 07:37:39

Exceptionle服務(wù)端部署

2022-04-02 14:41:56

云部署云計(jì)算安全

2011-10-10 13:40:22

Distimo移動應(yīng)用本地化

2011-07-04 10:56:42

諾基亞蘋果谷歌

2012-06-08 10:48:31

商務(wù)社交

2013-08-05 10:42:40

SAPRDS快速部署解決方案

2011-05-30 17:11:08

測試策略

2011-05-25 10:13:09

WordPressJavaScript

2023-09-26 18:16:57

2025-02-13 08:30:11

2024-06-06 08:06:19

鴻蒙大語言模型LLM模型

2009-05-11 09:15:20

MozillaPrism瀏覽器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號