有時候,我難免不由地感慨,真實的人類世界,本就是一個巨大的娛樂圈,即使是在英雄輩出的 IT 行業。數日前,Google 正式對外發布了 Gemini 1.5 Pro,一個建立在 Transformer 和 MoE 架構上的多模態模型。可惜,這個被 Google 寄予厚望的產品并未激起多少水花,因為就在同一天 OpenAI 發布了 Sora,一個支持從文字生成視頻的模型,可謂是一時風光無二。有人說,OpenAI 站在 Google 的肩膀上,用 Google 的技術瘋狂刷屏。此中曲直,遠非我等外人所能預也。我們唯一能確定的事情是,通用人工智能,即:AGI(Artificial General Intelligence)的實現,正在以肉眼可見的速度被縮短,以前在科幻電影中看到的種種場景,或許會比我們想象中來得更快一些。不過,等待 AGI 來臨前的黑夜注定是漫長而孤寂的。在此期間,我們繼續來探索 AI 應用落地的最佳實踐,即:在成功部署本地 AI 大模型后,如何通過外掛知識庫的方式為其 “注入” 新的知識。
從 RAG & GPTs 開始
在上一期博客中,博主曾經有一個困惑,那就是當前階段 AI 應用的最佳實踐到底是什么?站在 2023 年的時間節點上,博主曾經以為未來屬于提示詞工程(Prompt Engineering),而站在 2024 年的時間節點上,博主認為 RAG & GPTs 在實踐方面或許要略勝一籌。在過去的一年里,我們陸陸續續看到像 Prompt Heroes、PromptBase、AI Short…等等這樣的提示詞網站出現,甚至提示詞可以像商品一樣進行交易。與此同時,隨著 OpenAI GPT Store 的發布,我們仿佛可以看到一種 AI 應用商店的雛形。什么是 GPTs 呢?通常是指可以讓使用者量身定做 AI 助理的工具。譬如,它允許用戶上傳資料來豐富 ChatGPT 的知識庫,允許用戶使用個性化的提示詞來指導 ChatGPT 的行為,允許用戶整合各項技能(搜索引擎、Web API、Function Calling)…等等。我們在上一期博客中提到人工智能的 “安卓時刻”,一個重要的契機是目前產生了類似應用商店的 GPT Store,如下圖所示:
如果你覺得 OpenAI 的 GPT Store 離我們還稍微有點距離的話,不妨了解一下 FastGPT 這個項目,它以更加直觀的方式展示了一個 GPTs 是如何被創造出來的。如圖所示,博主利用我的博客作為知識庫創建了一個博客助手,而這一切只需要選模型、編寫提示詞、上傳資料三個步驟即可。感興趣的朋友可以從 這里 進行體驗:
由此,我們就可以得出一個結論,目前 AI 應用落地主要還是圍繞大模型微調(Fine Tuning)、提示詞工程(Prompt Engineering) 以及知識增強展開,并且 GPTs 里依然有提示詞參與,兩者并不沖突。考慮到,大模型微調這條線存在一定的門檻,我們暫且將其放在一旁。此時,提示詞工程和知識增強就成為了 AI 應用落地的關鍵。知識增強,專業術語為檢索增強生成,即:Retrieval-Augmented Generation,RAG,其基本思路就是將大語言模型和知識庫結合起來,通過外掛知識庫的方式來增強大模型的生成能力。比如微軟的 New Bing 是 GPT-4 + 搜索引擎的方案,而更一般的方案則是 LLM + 向量數據庫的思路,下圖展示了 RAG 運作的基本原理:
從這個角度來看,LangChain 及其衍生項目 AutoChain、Embedchain,甚至 FastGPT 等項目解決的本質都是 RAG 和 Agent 的問題。其中,Agent 不在本文的討論范圍內,這里博主不打算詳細展開。接下來的內容,博主會按照這個思路進行闡述,并且以 LangChain 為例來對其中的細節進行說明。
知識庫構建
如你所見,RAG 由 LLM 和 知識庫兩部分組成。首先,我們來構建知識庫,通常,這個過程可以劃分為下面四個步驟,即:載入文檔(Loader)、拆分文本(Splitter)、文本向量化(Embeddings)、向量存儲(VectorStore)。
Loader
你會注意到,博主在文章中加粗顯示了這四個步驟的英文描述,事實上,這代表了 LangChain 中的一部分概念,以 Loader 為例,它負責從各種文檔中載入內容,下面展示了從文本文件、PDF 文件以及網頁中載入內容:
from langchain_community.document_loaders import DirectoryLoader, TextLoader, PyPDFLoader, WebBaseLoader# TextLoader
# 指定編碼
loader = TextLoader("./input/金庸武俠小說全集/射雕英雄傳.txt", encoding="utf-8")
loader.load()
# 自動推斷
# python -m pip install chardet
loader = TextLoader("./input/金庸武俠小說全集/射雕英雄傳.txt", autodetect_encoding=True)
loader.load()# PyPDFLoader
# python -m pip install pypdf
loader = PyPDFLoader("./input/文學作品/追風箏的人.pdf")
loader.load()# WebBaseLoader
# python -m pip install beautifulsoup4
loader = WebBaseLoader(web_paths=('https://blog.yuanpei.me',), bs_kwargs={})
loader.load()
當然,現實中通常會有很多文檔,此時,我們可以使用 DirectoryLoader 來一次性載入多個文檔:
from langchain_community.document_loaders import DirectoryLoaderloader = DirectoryLoader("./posts/", glob="*.md", loader_kwargs={}, show_progress=True, silent_errors=True)
默認情況下,DirectoryLoad