山東大學專案實訓-基於LLM的中文法律文書生成系統(十九)- RAG(5)

H1S96發表於2024-06-24

專案程式碼解讀

# 官方庫
import os
import shutil
import time
from datetime import datetime
import logging
import pickle
from glob import glob
from typing import List

# 第三方庫
# langchain庫
from langchain.document_loaders import UnstructuredPowerPointLoader, UnstructuredWordDocumentLoader, \
    UnstructuredPDFLoader, UnstructuredFileLoader
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter

import faiss
import numpy as np
from tqdm import tqdm
 
# 內部庫
from client import get_client
from conversation import postprocess_text, preprocess_text, Conversation, Role
 
client = get_client()
  1. from langchain.embeddings import HuggingFaceEmbeddings:這行程式碼匯入了langchain庫中的HuggingFaceEmbeddings類。
  2. from langchain.text_splitter import RecursiveCharacterTextSplitter:這行程式碼匯入了langchain庫中的RecursiveCharacterTextSplitter類。

Embedding模型

我們在做RGA開發時又會涉及到向量資料庫,在建立向量資料庫時又需要使用Embedding模型對文字進行向量化處理,目前市面上的大模型如OpenAI,Gemini的模型都提供可供呼叫的Embedding模型,但這些大公司的Embedding模型都存在著種種限制條件比如OpenAI的Embedding模型不是免費的,它是根據token數量來收費的,這顯而易見會增加我們的使用成本,而Gemini的Embedding模型目前可以免費使用,但是它又有每分鐘不得超過60次呼叫的限制,這些種種的限制會給我們在建立向量資料庫時帶來很大的麻煩,為此我們需要找到一種免費的高效能的Embedding模型,經過我在網上不予餘力的搜尋,

終於找到了一個比較適合我們中國人使用的Embedding模型:BAAI的Embedding模型,而且它是我們中國人自己開發的,同時支援中文和英文。大家可以在github或者Huggingface上面檢視他們模型的相關資訊。

img

對於本專案,基於中文文件的需要,最終我們選擇了這個模型:

shibing624/text2vec: text2vec, text to vector. 文字向量表徵工具,把文字轉化為向量矩陣,實現了Word2Vec、RankBM25、Sentence-BERT、CoSENT等文字表徵、文字相似度計算模型,開箱即用。 (github.com)

image-20240624005542326

langchain.text_splitter

RecursiveCharacterTextSplitter可以處理通用文字。它以一個字元列表作為引數,按照順序嘗試基於這些字元進行分割,直到塊足夠小。預設的字元列表是["\n\n", "\n", " ", ""]. 這樣做的效果是儘可能保持段落(然後是句子,最後是單詞)在一起,因為從通用的角度來看,這些通常是語義上最相關的文字片段。

class ChatDoc:
	# 實現單例模式
    _instance = None
    # 向量資料庫的基路徑
    db_base_path = "data/db"
 
    def __init__(self) -> None:
        self.llm = client
        # 向量資料庫的引用
        self.vector_db = None
        # 字串資料庫的引用
        self.string_db = None
        # 檔案列表
        self.files = None
        
        self.embeddings_size = 768
        self.embeddings = HuggingFaceEmbeddings(model_name="./embedding")
        # 初始化完成後列印一條訊息,表示聊天機器人初始化成功。
        print("chatbot init success!")

_instance = None:這行程式碼定義了一個私有靜態變數_instance,其初始值為None。這用於實現單例模式。

模型引數:

db_base_path = "data/db":向量資料庫的基路徑。

self.llm = client:模型ChatGLM3入口地址。

self.vector_db = None:向量資料庫的引用。

self.string_db = None:字串資料庫的引用。

self.files = None:檔案列表的引用。

self.embeddings_size = 768:這行程式碼初始化了一個名為self.embeddings_size的例項變數,其值為768。這可能是嵌入的大小。

self.embeddings = HuggingFaceEmbeddings(model_name="./embedding"):初始化embeddings例項變數,引數是模型路徑。

單例模式

python __instance

簡單而言,單例模式就是保證某個例項在專案的整個生命週期中只存在一個,在專案的任意位置使用,都是同一個例項。

@classmethod
def get_instance(cls):
    if cls._instance is None:
        cls._instance = ChatDoc()
    return cls._instance

如果cls._instance尚未初始化,則執行。

cls._instance = ChatDoc():這行程式碼建立一個新的ChatDoc例項,並將其儲存在cls._instance變數中。這是單例例項的初始化。

return cls._instance:這行程式碼返回cls._instance變數,即單例例項。

透過使用get_instance方法,您可以確保在整個程式中只有一個ChatDoc例項被建立和訪問。這有助於節省資源,因為您不需要為每個請求建立新的例項,並且可以保證所有操作都使用相同的例項。

邊界情況

class Singleton(object):
    
    _instance = None
    def __new__(cls, *args, **kw):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance

這種寫法有兩個問題。

1.單例模式對應類例項化時無法傳入引數,將上面的程式碼擴充套件成下面形式。

python __instance_單例模式

此時會丟擲TypeError: object.__new__() takes exactly one argument (the type to instantiate)錯誤

2.多個執行緒例項化Singleton類時,可能會出現建立多個例項的情況,因為很有可能多個執行緒同時判斷cls._instance is None,從而進入初始化例項的程式碼中。

相關文章