矢量數據庫與LLM的集成:實踐指南

矢量數據庫與LLM的集成:實踐指南

本文將瞭解到什麼是矢量數據庫,以及如何與LLMs進行集成。通過LLMs和向量數據庫的結合,可以節省微調帶來的開銷和時間。

通常,LLM會在各種各樣的數據上進行訓練,這使它們具有廣泛的理解能力,但可能會導致在特定的知識領域存在差距。有時,它們甚至可能產生與目標無關或帶有偏見的信息——這是從廣闊但未經篩選的web學習的副產品。爲了解決該問題,我們引入了向量數據庫(Vector Database)的概念。這些數據庫以一種稱爲"向量嵌入"的獨特格式存儲數據,可以讓LLMs掌握和使用的信息更連貫和準確。

本文給出瞭如何使用向量數據庫構建一個LLM,並改進LLM對該流程的使用。我們將會看到二者的結合是如何讓LLMs更加準確可靠(特別針對特定主題)。

下面我們簡單總結了向量數據庫,解釋向量嵌入的概念以及它在增加AI和機器學習應用方面的角色。之後我們會展示這些數據庫和傳統數據庫的不同之處,以及爲什麼他們更適合AI任務,特別是與非結構數據(如文本、圖片和複雜模式)打交道時。

之後,我們會探索使用該技術來構建一個封閉式QA機器人應用,該機器人使用了Falcon-7B模型和ChromaDB向量數據庫,證明了LLMs與正確的工具和技術相結合時的成效。

最後,你將清楚認識到如何使用LLMs和向量數據庫來創建新穎、上下文相關並且可靠的應用。不管你是AI愛好者還是經驗豐富的開發者,本指南將幫助你輕鬆自信地探索這個激動人心的領域。

向量數據庫概述

在深入瞭解向量數據庫之前,需要了解向量嵌入(vector embedding)的概念。向量嵌入是機器學習中用於將原始數據轉換爲AI系統可以理解的數值格式必不可少的一種技術,涉及數據轉換,如將文本或圖片轉換爲一系列數字,這些數字在高維度空間稱之爲向量。高緯度數據指包括很多屬性或特徵的數據,每個數據代表一個不同的維度,這些維度可以幫助捕獲該數據的細微特徵。

創建向量嵌入的過程開始於數據輸入,可以是語句中的任意內容或是圖片的像素等。大語言模型和其他AI算法會分析這些數據並確定其關鍵特徵。例如,在文本數據中,可能涉及理解單詞的意義和它在語句中的上下文。嵌入模型會將這些特徵轉換爲一個數值格式,向量中的每個數值代表數據的一個特徵,通過將這些特徵數值封裝到一起,就可以作爲機器可以處理的輸入。

之所以說這些向量是高緯度的,是因爲它們包含很多數值,每個數值對應數據中的某個(不同)特徵。這種高維度使得向量能夠捕捉複雜、詳細的信息,使之成爲強大的AI模型工具。模型使用這些嵌入向量來識別數據中的模式、關係和潛在結構。

向量數據庫針對向量嵌入的特性提供了優化存儲和查詢的能力。它們擅長提供高效搜索、高性能、可擴展性,並通過比較和識別數據點之間的相似性,實現數據的快速檢索。

這些數值代表了複雜的高緯度信息,使之有別於傳統的主要使用文本和數字存儲數據的系統。向量數據庫的主要能力是管理和查詢如圖片、視頻和文本格式的數據,當這些數據轉換爲向量格式後,特別適用於機器學習和AI應用。

在下面示例中,我們將一段文本轉換爲詞向量,這一步是神經語言處理的基本步驟,可以讓我們量化和分析語言關係。例如,"puppy"的向量表達應該更接近"dog"的向量空間,而不是"house",反映了它們的語義接近性。這種方式還可以拓展到類似的關係中。"man"和"woman"的向量距離和方向類似於"king"和"queen"之間的距離和方向。下面展示了單詞向量不僅僅代表單詞,還可以在多維度向量空間中對它們的語義關係進行有意義的比較。

image

LLMs崛起之前的向量數據庫

向量數據庫用於處理向量嵌入,已經有一些關鍵使用場景,特別是在機器學習和AI領域:

相似搜索:這是向量數據庫的關鍵功能。它們可以在高維度空間內找出與給定請求相似的數據點。特別適用於圖形和音頻檢索(希望找出和特定輸入類似的內容),下面是一些業界使用場景:

  • 電商:通過允許客戶搜索與參考圖像相似的產品來增強產品發現能力。
  • 音樂流服務:找出並給用戶推薦在音頻特徵上和喜歡的曲目類似的歌曲。
  • 醫療成像:通過檢索並對相似病理的醫學圖像(如X光或MRI)進行比較分析來幫助放射科醫生。

推薦系統:向量數據庫通過處理用戶和商品嵌入來支持推薦系統。它可以將用戶和他們感興趣或過去有過互動的物品(如產品、電影或文章)關聯起來。下面是一個業務使用場景:

  • 流平臺:個性化觀看體驗,通過收看的瀏覽歷史來推薦電影和電視。
  • 在線零售:根據購買者的瀏覽和購買歷史來推薦產品,增強交叉銷售和追加銷售機會。
  • 新聞聚合:通過匹配讀者過去的參與模式和偏好來分發個性化新聞。

基於內容的檢索:這裏向量數據庫用於基於實際內容而非傳統元數據來檢索內容。特別對於非結構化數據,如文本和圖像,需要首先對內容本身進行分析。下面是一些業界使用場景:

  • 數字資產管理: 通過方便地根據視覺或音頻內容特徵搜索和檢索圖像或視頻,使公司能夠管理龐大的數字媒體庫。
  • 法律和合規:通常查詢大量文檔來查找與法律案件或合規性調查上下文相關的信息和文檔。
  • 學術研究:幫助研究者查找與他們工作上下文相關的學術文檔和研究論文(即使不指定關鍵字)

關於基於內容的檢索的最後一點越來越重要,並促進了一種新的應用:

使用上下文理解來增強LLMs:通過存儲和處理文本嵌入,向量數據庫可以幫助LLMs實現更精細化以及上下文相關的檢索工作。它們可以幫助理解大量文本的語義內容,在回答複雜搜索、維護對話上下文或生成相關內容等任務中起着關鍵作用。這種應用正迅速成爲向量數據庫的一個重要場景,展示了其在增強高級AI系統(如LLM)能力方面起到的作用。

向量數據庫 vs 傳統數據庫

傳統的SQL數據庫在結構化數據管理方面表現出色,擅長處理精確匹配和明確定義的條件邏輯。它們維護數據的完整性,適合需要精確、結構化數據處理的應用程序。但這種剛性設計模式也使得它們不太適合處理非結構化數據的語義以及上下文之間的細微差別,而這正是LLM和生成式AI應用所需要的。

另一方面,相比傳統的SQL系統,NoSQL數據庫則更加靈活。它們可以處理半結構化和非結構化數據,如JSON文檔,這使得它們更適用於AI和機器學習場景。但即便如此,相比用於LLMs和生成式的向量數據庫來說,NoSQL數據庫依然缺少某些方面的能力,如解析上下文、模式以及簡單數據檢索之外的語義內容。

向量數據庫彌補了這一空白。它們以AI爲中心,使用向量的方式處理數據,可以有效管理複雜的非結構化數據。當與LLMs協作時,向量數據庫支持相似性查找和上下文理解,提供了超出傳統SQL和NoSQL數據庫的能力。它們擅長處理近似值和模式識別,使之特別適用於對數據的微妙理解比精確數據匹配更重要的AI應用。

提升向量數據庫的性能

對於依賴速度和精確檢索高緯數據的應用來說,向量數據庫的性能優化至關重要。這裏面涉及提升查詢速度、保證高準確性以及有效處理不斷增長的數據量和用戶請求。其中最重要的一部分是圍繞索引策略進行優化(一種更有效組織和查詢向量數據的技術)。下面,我們將介紹這些索引策略,以及它們是如何提升向量數據庫性能的。

索引策略

向量數據庫的索引策略用於方便和準確檢索與查詢向量相似的向量。這些策略可以顯著影響到查詢操作的速度和準確性。

  • 量化(Quantization):量化涉及將向量映射到向量空間中的一組有限的參考點,從而有效地壓縮向量數據。這種策略通過將查詢限制到有限點(而非整個數據庫)的方式降低了存儲需求並加快查詢速度。量化的方式有很多種,如標量量化(Scalar Quantization,通過將大空間的向量轉換成相對小空間的向量來減少整體的存儲空間。 通常是將浮點數(比如f32)向量量化成整數(比如int8)向量(存儲的優化比是4X))和向量量化(Vector Quantization,區別於 scalar quantization 是分別從每一個維度進行壓縮,vector quantization 是通過將原始向量當做一個整體去看待,將一個向量映射到指定的參考向量裏),每種量化方式都需要權衡查詢速度和精度。

    量化特別適用於管理大規模數據庫的應用(存儲和內存效率至關重要),這種方法在需要在查詢速度和準確性之間取得平衡的環境中表現出色,這使得它非常適合對速度敏感且可以容忍一定精度損失的應用程序。但它不適合需要高度精確和最小化信息損失的場景,如精確科學研究。

  • HNSW(Hierarchical Navigable Small World,分層可導航小世界)圖:HNSW是一種構建分層圖的索引策略,每層代表數據集中的一個不同粒度。查詢從頂層開始,頂層具有較少、更遠的點,然後向下移動到更詳細的層級。這種方式可以快速遍歷數據集,通過快速縮小相似向量的候選集合,大大減少了搜索時間。

    image

    HNSW圖很好地均衡了查詢速度和準確性,使其非常適於需要立即響應的實時查詢應用和推薦系統。它們在中大型數據集中表現良好,提供可擴展的搜索能力。但對於超大型數據集來說,其內存需求可能會成爲瓶頸,因此這種方式不適用於內存資源受限或數據集大小遠超實際內存容量的場景。

  • 倒排文件索引(Inverted File Index,IVF):IVF使用k-means這樣的算法將向量空間分爲預定義數量的幾個聚類。每個向量分配給最近的聚類,在一個搜索中,只會涉及到最相關聚類中的向量。這種方式降低了搜索空間,提升了查詢速度。通過將IVF和其他技術(如IVFADC-Inverted File Index with Asymmetric Distance Computation, 就結合了IVF和Quantization)相結合,可以通過進一步降低距離計算成本來提升性能。

IVF方法適合處理可擴展查詢環境中的高緯度數據,可以通過對相似項劃分聚類來有效降低搜索空間,特別適用於相對靜態的數據庫,且可以允許偶爾重新聚類的場景。但對於低緯數據(可能存在過分分割)或要求儘可能低延遲的應用(聚類過程和跨多個聚類查詢可能會引入額外的查詢時間)來說,IVF可能不是最佳的選擇。

優化的其他注意事項
  • 降低維度:在應用索引策略之前,可以嘗試降低向量維度。像PCA或自編碼器這樣的技術可以在降低其複雜性的同時保持數據的關鍵特性,以此提升搜索操作的效率和索引速度。
  • 並行處理:很多索引策略都可以通過多CPU核或GPU技術同步執行。這種並行處理能力可以同時處理多個請求,大大提升了吞吐量並降低了大型應用的響應時間。
  • 動態索引:對於需要經常更新數據的數據庫來說,動態索引策略可以在不需要大量重新組織索引的情況下有效插入或刪除向量。這種方式確保數據庫可以隨着時間的推移保持響應並保持最小的性能下降。

通過這些索引策略和注意事項來提升向量數據庫的性能需要深刻理解底層數據以及特定的應用需求。通過仔細選擇並調節這些策略,開發者可以顯著提高基於向量的應用的響應能力和可擴展性,保證其滿足真實使用場景。

用向量數據庫豐富LLM的上下文

像Facebook的 LLama2 或 TIIUAE的 Falcon大語言模型具有先進的人工智能和類人類的文本生成能力,但由於它們是基於廣泛、通用的數據集進行訓練的,因此缺乏對特定上下文的處理能力。

可以使用如下兩種方式解決上下文限制的問題:

  • 針對性訓練:這種方式需要基於特定領域的數據集進行再訓練或微調LLM。雖然這種方式可以顯著增強模型在特定主題或行業的專業知識,但不適合大部分組織和個人。其原因包括與訓練所需的高成本計算資源,以及有效再訓練此類複雜模型所需的專業知識:有效再訓練LLMs需要深刻理解機器學習、自然語言處理以及所討論的模型的具體架構。
  • 通過向量數據庫來整合上下文:或者,LLM可以通過使用向量數據庫來直接擴展上下文。此時,向量數據庫保存了特定的信息,如向量嵌入,LLM可以檢索並使用這些信息來增強其響應能力。通過這種方式可以納入相關的專業知識,而無需進行大量再訓練,特別適用於訓練資源匱乏的組織或個人。它使用已有的模型,同時提供了目標明確的上下文洞察力。

第二種方式稱爲RAG,我們將在下一章中詳細介紹。

image

使用Falcon-7BChromaDB構建一個封閉式問題機器人

本章中,我們將介紹如何使用向量數據庫來構建一個LLM,是使用的模型是一個封閉式問題機器人(Closed Q&A bot),該機器人使用一組集成的技術組件來有效解答與科學相關的問題。

  1. databricks-dolly-15k HuggingFace Dataset:由Databricks員工生成的一個開源指令跟蹤記錄數據集。該數據集專門用於訓練大型語言模型、合成數據生成和數據增強,其中包含各種類型的提示和響應,如頭腦風暴、分類、封閉式QA、生成、信息抽取、開放式QA和總結等。
  2. 使用Chroma作爲向量存儲量:我們使用Chroma作爲主要的向量存儲,作爲機器人的知識庫。
  3. 語義搜索的句子轉換器:我們使用了來自Sentence Transformers的multi-qa-MiniLM-L6-cos-v1模型,該模型特別適用於語義查詢應用,負責生成嵌入向量,並將其存儲在Chroma中。
  4. Falcon 7B Instruct 模型:作爲我們的開源通用模型,Falcon 7B是一個由TII開發的一個僅包含70億參數的解碼器模型,Falcon 7B模型使用了一個龐大的名爲RefinedWeb的1,500B tokens數據集進行訓練,並補充了經過篩選的語料庫。值得注意的是,Falcon 40B作爲Falcon 7B的更大版本,在Hugging Face的Open LLM排行榜中名列前茅,是最頂尖的大型語言模型之一。

實現架構如下。使用multi-qa-MiniLM-L6-cos-v1作爲嵌入模型,負責將數據集的數據導入數據庫。

在用戶提問時,會使用嵌入模型對提問文本進行編碼,生成向量數據庫可以理解的格式,並由向量數據庫返回應答。Falcon 7B模型用於優化向量數據庫的應答結果。

下圖有點問題,看起來請求和應答是異步執行的,但代碼中是串行的。

image

配置環境

爲了實現本文的代碼,需要安裝如下庫:

!pip install -qU \
    transformers==4.30.2 \
    torch==2.0.1+cu118 \
    einops==0.6.1 \
    accelerate==0.20.3 \
    datasets==2.14.5 \
    chromadb \
    sentence-transformers==2.2.2

本代碼運行在Qwak的Workspaces的一臺gpu.a10.2xl 實例上。需要注意的是運行Falcon-7B-Instruct模型的代碼可能會根據硬件配置而變化。

構建"知識庫"

一開始,我們需要拉取Databricks-Dolly數據集,重點關注closed_qa一類的數據集。這些數據條目通常以對精確信息的需求爲特徵,這種轉一性給通用性大語言模型的訓練帶來了一定挑戰。

databricks/databricks-dolly-15kdataset card中可以查看支持的split和過濾字段。

from datasets import load_dataset

# Load only the training split of the dataset
# 加載 train 類型的數據集
train_dataset = load_dataset("databricks/databricks-dolly-15k", split='train')

# 通過過濾拉取 category爲 closed_qa 的一組數據
closed_qa_dataset = train_dataset.filter(lambda example: example['category'] == 'closed_qa')

print(closed_qa_dataset[0])

數據庫通常可以分爲三類:training、validating和evaluating。分別用於訓練、校驗和評估模型。

典型的數據集條目的格式如下:

{
  "instruction": "When was Tomoaki Komorida born?",
  "context": "Komorida was born in Kumamoto Prefecture on July 10, 1981. After graduating from high school, he joined the J1 League club Avispa Fukuoka in 2000. His career involved various positions and clubs, from a midfielder at Avispa Fukuoka to a defensive midfielder and center back at clubs such as Oita Trinita, Montedio Yamagata, Vissel Kobe, and Rosso Kumamoto. He also played for Persela Lamongan in Indonesia before returning to Japan and joining Giravanz Kitakyushu, retiring in 2012.",
  "response": "Tomoaki Komorida was born on July 10, 1981.",
  "category": "closed_qa"
}

下面,我們將重點爲每組指令及其各自的上下文生成詞嵌入,並將它們集成到矢量數據庫ChromaDB中。

Chroma DB是一個開源的向量數據庫系統,擅長管理向量嵌入,專爲語義查詢引擎之類的應用量身定做,這種能力在自然語言處理和機器學習領域至關重要。Chroma DB作爲一個內存型數據庫,支持數據的快速訪問和高速處理。其友好的Python設置增強了對我們項目的吸引力,簡化了與我們工作流程的集成。更多參見Chroma DB 文檔

image

爲了給回答生成嵌入向量,我們使用了multi-qa-MiniLM-L6-cos-v1 模型,該模型專爲語義搜索場景而訓練。給定一個問題/搜索請求,該模型可以找到相關的文本信息,這正是我們所需要的。

在下面例子中,解釋瞭如何將嵌入向量存儲在Chroma的內存集合中。

import chromadb
from sentence_transformers import SentenceTransformer

class VectorStore:

    def __init__(self, collection_name):
       # 初始化嵌入模型和向量數據庫
        self.embedding_model = SentenceTransformer('sentence-transformers/multi-qa-MiniLM-L6-cos-v1')
        self.chroma_client = chromadb.Client()
        self.collection = self.chroma_client.create_collection(name=collection_name)

    # 該方法用於將輸入的數據集轉換爲向量,並保存到向量數據庫中
    def populate_vectors(self, dataset):
        for i, item in enumerate(dataset):
            combined_text = f"{item['instruction']}. {item['context']}"
            embeddings = self.embedding_model.encode(combined_text).tolist()
            self.collection.add(embeddings=[embeddings], documents=[item['context']], ids=[f"id_{i}"])

    # 該方法直接從向量數據庫中與查詢相關的上下文
    def search_context(self, query, n_results=1):
        query_embeddings = self.embedding_model.encode(query).tolist()
        return self.collection.query(query_embeddings=query_embeddings, n_results=n_results)


# Example usage
if __name__ == "__main__":
   # Initialize the handler with collection name
    vector_store = VectorStore("knowledge-base")
    
    # 輸入上一步拉取的 closed_qa 數據集
    vector_store.populate_vectors(closed_qa_dataset)

對於每個數據集條目,我們會生成一個結合了instructioncontext字段的嵌入向量,在我們的LLM提示中,context充當要檢索的文檔。

下面,我們使用Falcon-7b-instruct LLM來生成封閉式信息查詢的應答(無需額外的上下文),並展示知識庫的重要性。

生成基本的回答

爲了實現文本生成任務,我們採用了來自Hugging Face的Falcon-7b-instruct模型。該模型是Falcon的革新系列,由Abu Dhabi的Technology Innovation Institute開發。

Falcon-7B-Instruct引人注目的一點是其有效平衡了高級功能和管理大小,用於理解複雜的文本和生成任務,其性能可以與更大的封閉源代碼模型相媲美,但包更精簡。這也是它成爲我們理想選擇的原因(可以深入語言理解,但不會帶來跟更大模型一樣的開銷)。

如果你打算運行Falcon-7B-Instruct模型(無論是本地機器或遠程服務器),需要注意硬件要求。在HuggingFace的文檔中有提到,該模型最少需要16GB的內存來滿足最佳的性能和更快的響應次數,最好使用GPU。


import transformers
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

class Falcon7BInstructModel:

    def __init__(self):
        # 初始化模型
        model_name = "tiiuae/falcon-7b-instruct"
        self.pipeline, self.tokenizer = self.initialize_model(model_name)

    def initialize_model(self, model_name):
        # 初始化 Tokenizer
        tokenizer = AutoTokenizer.from_pretrained(model_name)

        # Pipeline setup for text generation
        pipeline = transformers.pipeline(
            "text-generation",
            model=model_name,
            tokenizer=tokenizer,
            torch_dtype=torch.bfloat16,
            trust_remote_code=True,
            device_map="auto",
        )

        return pipeline, tokenizer

    def generate_answer(self, question, context=None):
        # Preparing the input prompt
        prompt = question if context is None else f"{context}\n\n{question}"

        # 生成應答
        sequences = self.pipeline(
            prompt,
            max_length=500,
            do_sample=True,
            top_k=10,
            num_return_sequences=1,
            eos_token_id=self.tokenizer.eos_token_id,
        )

        # Extracting and returning the generated text
        return sequences['generated_text']

可以參考Hugging Face的文檔來編寫上述代碼:

  • tokenizer是自然語言處理(NLP)中的一個重要組件,它的主要用於將輸入文本轉換爲一個模型可以理解的格式。本質上講,它將文本切分爲更小的單元,稱爲tokens。根據tokenizer的設計,這些tokens可以是單詞、子單詞(subword)甚至是特徵。在Falcon-7B-Instruct模型的上下文中,AutoTokenizer.from_pretrained(model)調用會加載一個專爲該模型設計的tokenizer,保證能夠遵循該模型訓練的方式來將文本轉化爲token。

  • pipeline是transformers庫中的一個高級工具,它對處理數據和從模型獲取預測所涉及的大部分複雜性進行了抽象。其內部分爲多個步驟,如將輸入文本劃分爲token、將token輸入到模型以及將模型的輸出處理爲人類可讀的格式。在上述腳本中,pipeline被設置爲"text-generation",用於將一個提示(如用戶問題)作爲輸入,然後根據提示生成一個連續的文本。

使用方式如下:

# 初始化 Falcon 模型類
falcon_model = Falcon7BInstructModel()

user_question = "When was Tomoaki Komorida born?"

# LLM使用LLM來爲用戶提問生成回答
answer = falcon_model.generate_answer(user_question)

print(f"Result: {answer}")

你可能已經猜到模型的輸出:

{ answer: “I don't have information about Tomoaki Komorida's birthdate.” }

使用Falcon-7B-Instruct時,如果沒有相關的上下文,就會返回一個否定響應。這說明需要進一步豐富背景知識,爲非一般性問題提供更有針對性和有用的答案。

生成上下文相關的回答

下面我們通過向量存儲來爲模型提供相關上下文,從而提升模型能力。

有趣的是,我們使用相同的VectorStore類來同時生成嵌入向量和從用戶提問中獲取上下文。

# Assuming vector_store and falcon_model have already been initialized

# 從 VectorStore 中獲取上下文(假設數據集已經導入數據庫)
context_response = vector_store.search_context(user_question)

# 從向量數據庫的響應中抽取上下文,上下文應該是 context 關鍵字的第一個元素
context = "".join(context_response['context'][0]) 

# Falcon模型結合提取的上下文生成應答
enriched_answer = falcon_model.generate_answer(user_question, context=context)

print(f"Result: {enriched_answer}")

最後可以得到準確的回答:

Tomoaki Komorida was born on July 10, 1981.

TIPs:

  • 如何從開源查找適合自己的模型和數據集?
    Hugging Face上的ModelsDataset都按照任務類型進行了劃分,在找到感興趣的task之後,還可以依據Trending、Most likes、Most downloads、Recently created和Recently Updated進行排序查找。

  • 如何編寫模型代碼?

    huggingface的各個模塊都提供了對應的Example,參考編寫即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章