本文整理自 2023 年 9 月 5 日 QCon 全球軟體開發大會 2023 · 北京站 —— 向量資料庫分論壇的同名主題演講《BES 在大規模向量資料庫場景的探索和實踐》。
向量資料庫是一種專門用於儲存和查詢向量資料的資料庫系統。透過 Embedding 技術,可以將影像、聲音、文字等資料的特徵提取出來,用向量的形式表達。而向量之間的距離,表達了原始資料之間特徵的相似程度。因此,可以將原始資料等特徵向量儲存到向量資料庫,然後透過向量檢索的技術,找到相似的原始資料,例如進行以圖搜圖的應用等。
在大模型出現之前,向量檢索這項技術就已經發展成熟。隨著深度學習技術的發展,向量資料庫也廣泛應用於圖片、音訊、影片的搜尋和推薦場景,以及語義檢索、文字問答、人臉識別等場景。
大模型的出現改變了人機互動方式,帶來了人工智慧技術的新革命,並催生了大量的 AI 原生應用。不過目前還處於發展的初期階段,在實際應用上還存在很多問題。首先是知識能力不夠強,大模型雖然能回答通用性問題,但面對垂直領域,由於訓練資料有限,回答的專業性仍有提升空間。而且大模型還有幻覺問題,回答會歪曲事實。另外大模型訓練週期和成本都很高,所以沒辦法頻繁的訓練,這就導致難以獲得實時的資料,只能回答一些時效性不太強的通用問題;除了知識方面,大模型也很難保證隱私資料安全。比如我為大模型提供了一些關於我自己的私人資料,當這個大模型為其他人提供服務的時候,這些隱私資訊很有可能作為答案被說出來。那麼如何增強大模型的知識能力,同時也保護私有資料的安全性呢?如下圖右側內容所示,透過在提問的時候帶上氣象局釋出的天氣預警新聞,可以幫助大模型準確地回答我們的問題。這種透過外接的資料資料和工具來增強大模型能力的技術體系,稱為提示詞工程。從以上討論可以看出,提示詞工程對大模型應用有重要的意義。下面,將為大家詳細介紹如何構建提示詞工程。透過定期將外部的實時新聞、專業知識、行業資料等資料 Embedding 為向量形式,儲存到向量資料庫,可以增量構建一個大模型的外部知識庫。在使用者提問的時候,可以先從知識庫獲取相關性最高的內容,然後拼接提示詞來增強大模型的回答能力。
這樣可以在不重新訓練大模型的情況下,引入外部的實時資料和知識,增強大模型的回答能力,並減少大模型回答偏離事實的情況。透過向量資料庫構建外部知識庫,還可以有效的保障行業資料的隱私安全性。此外,將使用者的會話歷史儲存到向量知識庫,在後續的對話過程中還可以提取出相關性較高的歷史會話,從而解決大語言模型的 token 數量限制導致大模型缺少長期記憶的問題。Elasticsearch 是一個基於 Apache Lucene 的分散式的搜尋與分析引擎,在搜尋引擎資料庫領域排名第一,是全球最受歡迎的開源解決方案,支援多種資料型別,包括結構化和非結構化資料,並且介面簡單易用,文件齊全,在業界有大量的實踐案例。
百度智慧雲 Elasticsearch(BES) 是基於開源 Elasticsearch 構建的成熟的公有云產品,擁有云上的資源保障和運維能力。BES 在 2015 年釋出,是公有云廠商中最先提供的 ES 託管服務。2018 年我們引入了百度 NLP 分詞外掛,並支援基於物件儲存 BOS 進行快照和恢復。2020 年我們支援了基於物件儲存 BOS 的冷熱分離架構等能力,並提供了向量檢索的能力,在百度內部廣泛使用,有著充分的工程積累。2023 年,我們針對向量檢索的場景,從向量引擎、套餐資源等各方面進行了最佳化,以便滿足大模型的場景需求。BES 的架構由管控平臺和 BES 叢集例項兩部分組成。管控平臺是全域性層面來進行統一的叢集管理,監控報警,以及叢集擴縮容、冷熱分離排程的平臺。BES 叢集例項則是一套構件在雲主機和雲磁碟上面的 Elasticsearch 叢集服務,前面透過 BLB 四層代理做節點負載均衡。磁碟上的資料可以透過策略定期下沉儲存到物件儲存 BOS 上,降低儲存成本。BES 的索引架構,整體上採用的是 Shared Nothing + MPP 計算的架構,複用了 ES 的資料流,資料按照索引和分片進行組織,分片可以設定多副本,會透過 ES 的標準方式進行分佈和路由。這樣在執行向量檢索的時候,會在有資料分佈的節點上進行本地計算,透過多節點平行計算提高查詢效率。可以透過增加副本數量配合擴容,提高可以參與查詢的節點數量和資源,從而提高服務整體的查詢 QPS。
向量資料使用 ES 標準的方式進行管理,因此使用上和標量資料的區別不大,向量資料可以和標量資料一起寫入,並複用 ES 對標量資料的檢索和處理能力。使用者可以透過 ES 的 Bulk 介面批次寫入資料,在資料寫入每個分片以後,落盤會形成一些片段檔案,然後即可提供檢索能力。ES 會在後臺定時排程進行分片的合併,來提升檢索的效率。在查詢的時候,查詢請求傳送到任意一個節點上,這個節點即成為協調節點,會下發查詢到每個分片進行平行計算,然後合併得到 TopK 到結果並返回。在 BES 中使用向量也非常簡單,下面我們看一個使用示例。首先需要定義索引的Mapping,指定一些向量相關的引數,這一步相當於建表。然後就可以透過 ES 的 Bulk 介面寫入資料,實際場景中一般是先透過 Embedding 能力將原始資料向量化,然後批次寫入。然後可以透過我們定義的跟 ES 風格接近的語法進行向量檢索。在向量索引的實現方面,我們選擇透過自研外掛來實現向量相關的能力。核心引擎我們透過 C++ 實現,在 ES 中透過 JNI 呼叫。選擇自研外掛,一是希望基於 C++ 實現來獲得更貼近底層的極限效能,並且方便進行 SIMD 等最佳化來加速計算;二是能改寫底層儲存格式的實現,也是方便做到更極致的效能;三是能更靈活地控制檢索邏輯,改寫執行計劃來實現比較複雜的查詢。這裡核心的向量檢索引擎部分,我們選擇基於社群優秀的向量庫實現做二次開發。我們對比了下 nmslib 和 faiss 各自在 ES 上的開箱效能(基於 8cu 虛機進行測試,寫入資料產生的 segments 未合併,資料集 SIFT-1M 128 維),可以看出 HNSW 召回率較高、整體比較耗記憶體,而 nmslib 的實現更勝一籌。透過改造向量檢索引擎的實現,我們在 HNSW 的索引型別上,對 level 0 的向量資料儲存複用了我們自定義的 Lucene 列式儲存資料,並透過 mmap 載入。這樣一方面減少了資料的冗餘度,減少了資源的浪費;另一方面,透過 mmap 方式載入資料,在記憶體不足的時候,會將部分頁換出記憶體,在需要讀取的時候再載入到記憶體中,某種程度上也支援了記憶體 + 磁碟混合的儲存介質。在展開具體最佳化之前,我們先回顧一下當前比較主流的圖演算法原理。圖演算法是一種比較新的近似向量檢索思路,它基於可導航小世界理論,具體是指在一個充分連線的圖裡,透過六跳就可以連通兩個點。按向量間的距離關係構造一個這樣類似於真實世界的「小世界」網路,也就可以透過貪心演算法,按距離建立聯絡一跳一跳逼近目標的向量定點。隨著小世界裡的點不斷插入,根據前面講的挑選近鄰點構建邊的思路,新插入的點會越來越侷限於一個小圈子,這樣的話跟一個很遠的點建立聯絡就需要非常多的跳數了。為了解決這個問題,業界提出了 HNSW 演算法,即採用類似連結串列查詢演算法裡的跳錶的思路。我們建立不同層級的圖,往上指數遞減定點數量來形成稀疏圖,這樣越稀疏的圖自然就越能連線遠方。雖然 HNSW 索引的查詢響應快,召回率也比較高,但是也存在構圖速度慢,CPU、記憶體開銷大等缺點。HNSW 構圖過程,每插入一個點需要檢索計算,插入大量的點也是一筆很大的計算開銷,因此匯入資料會很慢,導致前臺阻塞。因此我們將向量索引構建改造成後臺非同步構建的機制,資料寫入落盤之後就可以直接返回;然後後臺透過 ES 的合併策略或者使用者的定時或主動觸發的方式來觸發在後臺構建 HNSW 索引,透過流式構建的方式,降低構圖過程的記憶體消耗。並且使用獨立執行緒池構建,以免對前臺查詢請求造成影響。同時,我們也對 ES 的片段合併策略進行了最佳化。ES 預設的合併策略,會根據一些條件,例如一次合併參與的片段數量、合併要產生的新片段的大小等,來選擇參與合併的片段的集合,然後計算不同組合的分數,來選擇最優的片段組合進行合併。一般會經過多輪合併的方式,來達到一個資源消耗和查詢效率的平衡狀態。不過因為向量索引的構建成本往往比 ES 的原生資料型別成本更高,所以我們調整了向量索引的合併策略,將多輪合併改為一次合併,減少片段合併的過程開銷。此外,我們也支援在寫入資料之前,將目標索引的自動構建關閉,在批次寫入資料併合並片段之後,再透過 API 一次性完成向量索引構建,比較適合批次灌庫的場景使用。此外,BES 也支援多種向量索引型別和距離計算演算法。對於需要訓練生成的向量索引,我們也提供了流程支援。例如 IVF 系列索引,在此讓我們先回顧下 IVF 演算法的原理。IVF 即倒排索引,倒排索引是一個搜尋引擎的術語,指的從文件網頁裡提取關鍵詞,來建立倒排檢索結構,透過關鍵詞找到原始文件。那麼對向量資料來說,關鍵詞是什麼呢?真實世界的向量在空間分佈上一般會扎堆分佈,具備聚類特徵。請看下圖。透過 k-means 演算法將向量的聚類中心提取出來,那這個向量所處的聚類中心就是這個向量的關鍵詞,用這個來建立倒排索引,就可以像搜尋引擎一樣,先命中聚類中心,再暴力搜尋聚類中心下面的各個向量,這樣相比全域性搜尋能過濾大量的資料。如果覺得找一個聚類中心不夠準確,也可以多找幾個,找的越多,結果越準。對於 IVF 這一類的向量索引,BES 的構建流程是,先寫入訓練資料,然後呼叫 API 訓練模型。這一步會根據訓練資料進行聚類,計算得到每個聚類的中心。在模型訓練好以後,再新建索引寫入實際資料,基於訓練好的模型構建向量索引。具體向量索引的構建和合並機制,還是和前面描述的一樣。有很多場景提出先按標量條件過濾資料再進行向量檢索的需求,例如為向量資料打上標籤,要保證檢索出來的向量能匹配上標籤。支援這樣的需求,可以透過 post-filter 和 pre-filter 兩種方式,post-filter 是指先進行 ANN 的檢索,然後基於檢索結果執行 filter,得到最終的結果,不過可能會導致結果集的大小顯著小於 K。而 pre-filter 是指,先對資料進行過濾,然後基於過濾結果進行最近鄰檢索。這種方式一般可以確保得到 K 個結果。因此我們改造了原有的 HNSW 實現,讓演算法在遍歷圖挑選近鄰的過程中,只考慮符合 filter 條件的向量。具體流程是,先基於 ES 的標量資料索引執行 filter,得到召回文件的 id 列表;然後根據id列表構造點陣圖,並將點陣圖資料透過 JNI 呼叫傳遞到向量引擎,在 HNSW 檢索的過程中,根據點陣圖過濾近鄰頂點,從而得到符合 filter 條件的向量列表。實際測試的時候,發現效能和召回不是很理想。透過測試資料和研究一些資料發現,在過濾比例升高時,因為頂點被過濾導致能連通的路徑變少,直接影響了 HNSW 演算法的收斂速度,以及很容易走進死衚衕導致召回率低。資料表明,過濾比達到 90% 以上是,效能和召回率會急劇下降。因此這裡我們選擇改寫執行計劃,將標量過濾和暴力檢索演算法結合,在過濾比例達到 90% 以上的時候,對於 filter 的結果資料進行暴力檢索,可以取得令人滿意的效果。同時,還透過 SIMD 指令加速暴力檢索效率。首先是易用性,因為向量資料庫主要面向大模型應用開發者,所以希望能夠提供開箱即用的產品體驗,降低使用者理解和使用的門檻。目前 BES 自研的向量引擎在使用上需要使用者對 ES 有一定的熟悉,例如能夠使用 ES 的 DSL 表達查詢邏輯。如果能夠提供更加通用易上手的使用方式,例如支援透過 SQL 進行 knn 檢索,對使用者將更加友好。其次是功能特性,這裡需要支援更多索引演算法和相似度演算法,例如 DiskAnn、百度自研的 Puck&Tinker 演算法等,以應對多種多樣的需求和場景。並考慮支援異構計算能力,提高索引構建和檢索效率。效能成本方面,面向大規模應用的場景,還需要更深入的最佳化,減少系統的 overhead,最佳化資源的使用效率。例如,ES 是基於 JVM 執行的,向量引擎由 C++ 開發,透過 JNI 呼叫執行。那怎麼才能更加靈活的管理全域性的記憶體資源,才能適應不同客戶的 workload,又能將資源的利用率儘可能地提高,這個將是我們後續的一個主要最佳化方向。最後,BES 目前是託管叢集的形態,需要使用者根據自己的業務量級評估叢集資源,選擇合理地套餐,這給使用者帶來了一定的使用成本,如何能夠讓資源更加動態、彈性,幫助使用者降低使用門檻,降低成本,也是我們的最佳化方向。剛剛提到的 Puck&Tinker 演算法,是百度 100% 自研的向量檢索演算法,經過了搜尋業務的大規模實際驗證。在首屆國際向量檢索大賽 BigANN 上,Puck 在參賽的 4 個資料集中均排名第一。在 BIGANN-10M 的資料集上,在召回率相近的情況下,Puck 的效能達到了 HNSW 的 1.7 倍,而記憶體消耗只有 HNSW 的 21% 左右。Puck 已經開源,歡迎大家關注 。首先是向量能力在影片網站多模態檢索場景下的應用。具體場景是對影片切分成幀,對幀進行影像特徵處理和時間建模,透過神經網路將幀序列轉化為向量,寫入 BES,構建物料向量庫。然後在 BES 中透過向量檢索,召回相似度最高的結果輸入上游業務服務,支援影片打標、短帶長、個性化推薦等場景。千帆大模型平臺的知識庫是一款專門面向大語言模型知識問答場景,旨在管理客戶上傳的知識並提供快速查詢檢索功能的產品。
基於百度智慧雲 BES,使用者能夠以高效的方式儲存和檢索大量的知識庫文件,實現快速管理企業私域知識,構建知識問答應用的能力。並且可以保障客戶的資料隱私安全。這裡有兩種應用方式。方式一是獨立部署大模型知識庫,構建本地域內知識檢索應用;方式二是在千帆平臺直接繫結外掛應用,支援問答、生成、任務三類應用。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027828/viewspace-2994650/,如需轉載,請註明出處,否則將追究法律責任。