)
1. 從“相似性搜索”到向量數(shù)據(jù)庫為什么我們需要它如果你用過搜索引擎或者電商平臺的“猜你喜歡”那你已經(jīng)接觸過相似性搜索的雛形了。傳統(tǒng)數(shù)據(jù)庫擅長處理“等于”或“大于小于”這類精確查詢比如“找出所有姓張的用戶”或“價格低于100元的商品”。但面對“找出和這張圖片相似的圖片”或“推薦幾篇和這篇文章主題相近的文章”這類模糊需求時傳統(tǒng)數(shù)據(jù)庫就力不從心了。這背后的核心是文本、圖片、音頻這些非結(jié)構(gòu)化數(shù)據(jù)計算機無法直接理解它們的“含義”。向量數(shù)據(jù)庫的魔法就在于它先將這些數(shù)據(jù)轉(zhuǎn)化為計算機能理解的“數(shù)學語言”——向量。你可以把向量想象成一個高維空間里的點。比如一篇關(guān)于“機器學習”的文章經(jīng)過模型處理后會變成一個由幾百甚至幾千個數(shù)字組成的向量這個向量在空間中的位置就代表了它的“語義”。另一篇關(guān)于“深度學習”的文章其向量位置會和“機器學習”的非常接近因為它們語義相似。而一篇關(guān)于“烘焙蛋糕”的文章其向量就會離得很遠。向量數(shù)據(jù)庫的核心工作就是高效存儲這些向量點并能快速找出與某個查詢向量“距離最近”的鄰居。這個“距離”通常用余弦相似度或歐氏距離來衡量值越小或相似度越高代表兩者越相似。所以當你聽到向量數(shù)據(jù)庫時它本質(zhì)上是一個為“相似性搜索”而優(yōu)化的專用數(shù)據(jù)庫。而 ChromaDB就是這樣一個輕量級、易上手特別適合開發(fā)者快速原型和學習的開源向量數(shù)據(jù)庫。它不像一些工業(yè)級向量數(shù)據(jù)庫如 Milvus那樣需要復雜的部署它可以直接嵌入你的 Python 腳本中讓你在幾分鐘內(nèi)就體驗到從文本到向量再到智能搜索的完整流程。這正是我們接下來要做的。2. 環(huán)境準備不僅僅是安裝 Python 和 ChromaDB在開始寫代碼之前確保你的環(huán)境是正確且隔離的這是一個好習慣能避免未來很多包沖突的麻煩。我們假設(shè)你已經(jīng)在電腦上安裝了 Python3.7 及以上版本。如果你還沒有去 Python 官網(wǎng)下載安裝器是最直接的方式安裝時記得勾選“Add Python to PATH”。2.1 創(chuàng)建并激活虛擬環(huán)境虛擬環(huán)境是你的項目專屬的“沙盒”。在這個沙盒里安裝的包不會影響到系統(tǒng)全局或其他項目。打開你的終端Windows 上是 CMD 或 PowerShellmacOS/Linux 上是 Terminal執(zhí)行以下命令來創(chuàng)建并激活一個虛擬環(huán)境。# 創(chuàng)建名為 chroma_demo 的虛擬環(huán)境 python -m venv chroma_demo # 激活虛擬環(huán)境 # 在 Windows 上 chroma_demo\Scripts\activate # 在 macOS/Linux 上 source chroma_demo/bin/activate激活后你的命令行提示符前面通常會顯示環(huán)境名(chroma_demo)這表示你已經(jīng)進入了這個沙盒。注意很多新手會忽略這一步直接在全系統(tǒng)環(huán)境安裝。當項目多了不同項目依賴不同版本的包時就會陷入“依賴地獄”。養(yǎng)成使用虛擬環(huán)境的習慣是 Python 開發(fā)的基本素養(yǎng)。2.2 安裝核心依賴包在我們的沙盒里安裝本次體驗所需的兩個核心包chromadb和sentence-transformers。后者是一個強大的庫里面封裝了各種用于生成文本向量的預(yù)訓練模型我們用它來把文本變成向量。pip install chromadb sentence-transformers這里有個小坑需要注意sentence-transformers依賴 PyTorch。pip install sentence-transformers會自動嘗試安裝一個兼容的 CPU 版本 PyTorch。如果你的網(wǎng)絡(luò)環(huán)境導致下載慢或失敗可以考慮先使用清華源安裝 PyTorch再安裝sentence-transformers或者耐心重試幾次。安裝過程可能會花費幾分鐘因為它需要下載模型文件。安裝完成后你可以用pip list命令檢查一下是否成功安裝了chromadb和sentence-transformers。3. 第一步將文本轉(zhuǎn)化為向量并存入 ChromaDB理論準備就緒環(huán)境也已搭建現(xiàn)在讓我們開始寫代碼。創(chuàng)建一個新的 Python 文件比如叫做chroma_quickstart.py。3.1 初始化客戶端與創(chuàng)建集合首先我們需要導入必要的庫并初始化 ChromaDB 的客戶端。ChromaDB 可以運行在內(nèi)存中persist_directory參數(shù)為空也可以持久化到磁盤。為了簡單起見我們先用內(nèi)存模式。import chromadb from sentence_transformers import SentenceTransformer # 初始化 ChromaDB 客戶端使用內(nèi)存模式 chroma_client chromadb.Client() # 創(chuàng)建一個集合Collection。集合類似于傳統(tǒng)數(shù)據(jù)庫中的表用于存放一組相關(guān)的向量和元數(shù)據(jù)。 # 如果集合已存在get_or_create_collection 會獲取它否則創(chuàng)建它。 collection chroma_client.get_or_create_collection(namemy_knowledge_base)collection是我們接下來操作的主要對象。3.2 準備數(shù)據(jù)并生成向量我們準備一些簡單的文本數(shù)據(jù)作為我們的“知識庫”。同時我們需要一個模型來把這些文本變成向量。sentence-transformers里的all-MiniLM-L6-v2模型是一個很好的起點它體積小、速度快并且在語義相似度任務(wù)上表現(xiàn)不錯。# 準備一些文檔文本數(shù)據(jù) documents [ 機器學習是人工智能的一個分支它使計算機能夠在沒有明確編程的情況下學習。, 深度學習是機器學習的一個子領(lǐng)域它使用神經(jīng)網(wǎng)絡(luò)模擬人腦的工作方式。, Python 是一種流行的編程語言廣泛用于數(shù)據(jù)科學和機器學習。, 向量數(shù)據(jù)庫是一種專門用于存儲和檢索向量嵌入的數(shù)據(jù)庫。, 今天天氣很好適合去公園散步。 ] # 為每個文檔提供一個唯一的 ID ids [doc1, doc2, doc3, doc4, doc5] # 初始化句子轉(zhuǎn)換模型 model SentenceTransformer(all-MiniLM-L6-v2) # 將文檔列表轉(zhuǎn)換為向量嵌入 # encode 方法會返回一個 numpy 數(shù)組每一行對應(yīng)一個文檔的向量 embeddings model.encode(documents).tolist() # 轉(zhuǎn)換為列表格式因為 ChromaDB 接收列表這里的關(guān)鍵是model.encode(documents)。這行代碼調(diào)用了預(yù)訓練模型將五段文本分別轉(zhuǎn)換成了 384 維的向量all-MiniLM-L6-v2模型輸出維度是 384。你可以把embeddings變量打印出來看看它是一個包含 5 個列表的列表每個子列表有 384 個浮點數(shù)。3.3 將向量和元數(shù)據(jù)存入集合有了向量、原始文本和 ID我們就可以將它們添加到 ChromaDB 的集合中了。# 將文檔、對應(yīng)的向量嵌入以及 ID 添加到集合中 collection.add( embeddingsembeddings, # 向量列表 documentsdocuments, # 原始文本列表 idsids # ID 列表 ) print(數(shù)據(jù)已成功添加到 ChromaDB 集合中)collection.add方法是核心操作。它接收三個主要列表參數(shù)且這三個列表必須一一對應(yīng)。ChromaDB 會將這些向量存儲起來并建立索引以便后續(xù)快速檢索。至此我們已經(jīng)完成了一個微型向量數(shù)據(jù)庫的構(gòu)建。4. 核心體驗執(zhí)行你的第一次語義搜索數(shù)據(jù)庫建好了最激動人心的部分來了——搜索。我們不再使用關(guān)鍵詞匹配而是用自然語言提出問題讓數(shù)據(jù)庫找到語義上最相關(guān)的答案。4.1 進行相似性查詢我們嘗試搜索與“什么是神經(jīng)網(wǎng)絡(luò)”相關(guān)的內(nèi)容。注意我們的知識庫里并沒有完全相同的這句話。# 定義查詢文本 query_text 什么是神經(jīng)網(wǎng)絡(luò) # 將查詢文本同樣轉(zhuǎn)換為向量 query_embedding model.encode([query_text]).tolist() # 注意這里傳入的是列表 # 執(zhí)行查詢尋找最相似的 2 個結(jié)果 results collection.query( query_embeddingsquery_embedding, # 查詢向量 n_results2 # 返回最相似的前 N 個結(jié)果 ) print(\n查詢, query_text) print(最相關(guān)的文檔) for i, doc in enumerate(results[documents][0]): # results[documents] 是一個嵌套列表 print(f{i1}. {doc})運行這段代碼你會看到類似以下的輸出查詢 什么是神經(jīng)網(wǎng)絡(luò) 最相關(guān)的文檔 1. 深度學習是機器學習的一個子領(lǐng)域它使用神經(jīng)網(wǎng)絡(luò)模擬人腦的工作方式。 2. 機器學習是人工智能的一個分支它使計算機能夠在沒有明確編程的情況下學習。太神奇了盡管我們沒有存儲“神經(jīng)網(wǎng)絡(luò)”這個詞但模型理解到“神經(jīng)網(wǎng)絡(luò)”是“深度學習”的核心而“深度學習”又與“機器學習”強相關(guān)。它成功返回了語義上最接近的兩條文檔。這就是向量搜索的魅力它理解含義而不僅僅是字面匹配。4.2 理解查詢結(jié)果的構(gòu)成讓我們更仔細地看看results這個對象。打印一下它的結(jié)構(gòu)print(results)你會看到一個字典通常包含以下幾個關(guān)鍵部分ids: 返回結(jié)果的文檔 ID 列表。embeddings: 返回結(jié)果的向量列表如果你在查詢時要求返回。documents: 返回結(jié)果的原始文本列表。distances: 查詢向量與每個結(jié)果向量之間的距離列表。對于默認的l2歐氏距離來說這個值越小越好。例如你可能看到distances是[0.35, 0.78]這意味著第一個結(jié)果關(guān)于深度學習的與查詢的語義距離是 0.35比第二個結(jié)果0.78要近得多因此相關(guān)性更高。5. 更進一步元數(shù)據(jù)過濾與混合搜索單純的向量搜索已經(jīng)很強大了但在實際應(yīng)用中我們經(jīng)常需要結(jié)合一些結(jié)構(gòu)化條件進行過濾。比如在文檔庫中我們可能只想搜索某個特定作者或某個時間段內(nèi)的文檔。ChromaDB 支持為每個向量條目添加元數(shù)據(jù)metadata并基于元數(shù)據(jù)進行過濾。5.1 添加元數(shù)據(jù)并重新構(gòu)建集合讓我們重構(gòu)一下數(shù)據(jù)為每篇文檔添加類別和作者信息。# 刪除舊的集合重新開始對于內(nèi)存客戶端 chroma_client.delete_collection(namemy_knowledge_base) collection chroma_client.get_or_create_collection(namemy_knowledge_base_with_meta) # 新的文檔、ID 和元數(shù)據(jù) documents [ 機器學習是人工智能的一個分支它使計算機能夠在沒有明確編程的情況下學習。, 深度學習是機器學習的一個子領(lǐng)域它使用神經(jīng)網(wǎng)絡(luò)模擬人腦的工作方式。, Python 是一種流行的編程語言廣泛用于數(shù)據(jù)科學和機器學習。, 向量數(shù)據(jù)庫是一種專門用于存儲和檢索向量嵌入的數(shù)據(jù)庫。, 今天天氣很好適合去公園散步。 ] ids [doc1, doc2, doc3, doc4, doc5] # 為每個文檔定義元數(shù)據(jù) metadatas [ {category: AI, author: Alice}, {category: AI, author: Bob}, {category: Programming, author: Charlie}, {category: Database, author: Alice}, {category: Life, author: David} ] embeddings model.encode(documents).tolist() # 添加數(shù)據(jù)這次包含元數(shù)據(jù) collection.add( embeddingsembeddings, documentsdocuments, metadatasmetadatas, # 新增元數(shù)據(jù)參數(shù) idsids )5.2 執(zhí)行帶過濾條件的查詢現(xiàn)在我們可以在搜索時加入過濾條件。例如我們想搜索與“機器學習”相關(guān)但僅限于“AI”類別的文檔。query_text 機器學習 query_embedding model.encode([query_text]).tolist() results collection.query( query_embeddingsquery_embedding, n_results3, where{category: AI} # 元數(shù)據(jù)過濾條件 ) print(f\n查詢 ‘{query_text}’ (過濾條件: categoryAI)) for doc, meta in zip(results[documents][0], results[metadatas][0]): print(f- {doc} [作者: {meta[author]}])這次結(jié)果將只包含doc1和doc2因為doc3關(guān)于 Python 編程雖然語義上也相關(guān)但其類別是 “Programming”被過濾掉了。這種“向量相似度搜索 元數(shù)據(jù)過濾”的模式被稱為混合搜索它結(jié)合了語義理解和精準過濾是構(gòu)建高級 AI 應(yīng)用如個性化推薦、知識庫問答的基石。6. 實測中的關(guān)鍵細節(jié)與常見“坑點”通過上面的步驟你已經(jīng)跑通了一個完整的流程。但在實際獨立開發(fā)時你可能會遇到下面這些問題。了解它們能讓你走得更穩(wěn)。6.1 嵌入模型的選擇與性能權(quán)衡我們使用了all-MiniLM-L6-v2它是一個權(quán)衡了速度和質(zhì)量的模型。但在實際項目中模型選擇至關(guān)重要更大更強的模型如all-mpnet-base-v2能生成 768 維、質(zhì)量更高的向量搜索結(jié)果更精準但計算更慢、占用內(nèi)存更多。更小更快的模型如all-MiniLM-L6-v2我們用的或paraphrase-albert-small-v2速度極快適合對延遲要求高的場景但精度略有犧牲。領(lǐng)域特定模型如果你處理的是醫(yī)學、法律等專業(yè)文本使用在該領(lǐng)域語料上微調(diào)過的模型如bge系列、gte系列效果會遠好于通用模型。實操心得不要一開始就追求最大最強的模型。先用一個像all-MiniLM-L6-v2這樣的輕量級模型快速驗證想法、搭建管道。當整個應(yīng)用流程跑通并且語義搜索成為性能瓶頸或質(zhì)量瓶頸時再考慮升級模型。升級模型通常意味著要重新生成所有向量的嵌入這是一個成本不低的操作。6.2 ChromaDB 持久化與生產(chǎn)部署我們的示例使用了內(nèi)存客戶端程序關(guān)閉數(shù)據(jù)就丟失了。對于真實項目你需要持久化。初始化客戶端時指定一個目錄即可# 持久化到磁盤 persistent_client chromadb.PersistentClient(path./my_chroma_db) collection persistent_client.get_or_create_collection(namepersistent_collection) # ... 后續(xù)的 add, query 操作不變這樣數(shù)據(jù)會保存在./my_chroma_db目錄下。下次運行程序連接到同一個路徑和集合名數(shù)據(jù)依然存在。關(guān)于生產(chǎn)部署ChromaDB 也提供了 HTTP 服務(wù)器模式可以作為一個獨立服務(wù)運行允許多個客戶端通過網(wǎng)絡(luò)連接。這對于微服務(wù)架構(gòu)是必要的。你可以參考官方文檔使用chroma run --path /db_path來啟動服務(wù)端然后在客戶端代碼中連接http://localhost:8000。6.3 查詢時為什么是results[documents][0]這是一個容易困惑的細節(jié)。collection.query的query_embeddings參數(shù)接受一個列表這意味著你可以一次性提交多個查詢向量進行批量搜索。因此返回的results[‘documents’]也是一個列表其第一維對應(yīng)查詢的數(shù)量。我們只提交了一個查詢所以需要取[0]來獲得這個查詢的結(jié)果列表。同理results[‘distances’][0]對應(yīng)第一個查詢與各個結(jié)果的距離列表。6.4 距離函數(shù)與分數(shù)解釋ChromaDB 默認使用l2歐氏距離。距離越小越相似。你也可以在創(chuàng)建集合時指定cosine余弦相似度或ip內(nèi)積。余弦相似度的值在 -1 到 1 之間1 表示完全相同通常更常用在文本相似度中。需要注意的是ChromaDB 的query接口返回的distances對于余弦相似度實際是1 - cosine_similarity所以它仍然是一個“距離”概念越小越好。理解你使用的距離度量方式對于設(shè)置相似度閾值例如只返回距離小于 0.3 的結(jié)果非常重要。7. 從體驗到實踐接下來可以嘗試什么恭喜你現(xiàn)在你已經(jīng)掌握了 ChromaDB 最基本也是最核心的操作。但這只是一個起點。你可以用這個工具做很多有趣的事情構(gòu)建個人知識庫問答系統(tǒng)將你的筆記、博客、PDF 文檔切片并向量化存入 ChromaDB。然后你可以用自然語言提問讓它幫你找到所有相關(guān)的筆記片段。再結(jié)合像 ChatGPT 這樣的 LLM讓它基于檢索到的片段生成一個連貫的答案這就是一個最簡單的 RAG檢索增強生成應(yīng)用原型。實現(xiàn)推薦系統(tǒng)將商品描述、電影簡介、音樂標簽向量化。根據(jù)用戶的歷史交互點擊、購買向量在向量數(shù)據(jù)庫中尋找相似的商品進行推薦。文本去重與聚類將大量文本向量化后通過計算向量之間的距離可以很容易地發(fā)現(xiàn)內(nèi)容重復或主題相似的文檔進行去重或自動歸類。探索多模態(tài)ChromaDB 不僅能存文本向量也能存圖像、音頻的向量。你可以使用 CLIP 等多模態(tài)模型將圖片和文本映射到同一個向量空間實現(xiàn)“用文字搜圖片”或“用圖片搜相似圖片”。我個人的體會是向量數(shù)據(jù)庫降低了AI應(yīng)用中“記憶”和“聯(lián)想”能力的實現(xiàn)門檻。它把復雜的相似性計算封裝成了簡單的add和query接口。真正的挑戰(zhàn)和樂趣在于如何設(shè)計你的數(shù)據(jù)分塊、清洗、添加元數(shù)據(jù)如何選擇合適的嵌入模型以及如何將檢索結(jié)果巧妙地與下游任務(wù)如LLM生成結(jié)合。這5分鐘的極速入門希望為你打開了一扇門門后是一個正在被向量技術(shù)重塑的、更智能的數(shù)據(jù)處理世界。