一、大模型開發(fā)整體流程
	1. 何為大模型開發(fā)
	定義
	將開發(fā)以LLM為功能核心,通過LLM的強(qiáng)大理解能力和生成能力,結(jié)合特殊的數(shù)據(jù)或業(yè)務(wù)邏輯來提供獨(dú)特功能的應(yīng)用。
	核心點(diǎn)
	在大模型開發(fā)中,我們一般不會(huì)去大幅度改動(dòng)模型,而是將大模型作為一個(gè)調(diào)用工具。通過 Prompt Engineering、數(shù)據(jù)工程、業(yè)務(wù)邏輯分解等手段來充分發(fā)揮大模型能力,適配應(yīng)用任務(wù),而不會(huì)將精力聚焦在優(yōu)化模型本身上。這因此,作為大模型開發(fā)的初學(xué)者,我們并不需要深研大模型內(nèi)部原理,而更需要掌握使用大模型的實(shí)踐技巧。
	核心能力
	指令理解與文本生成,提供了復(fù)雜業(yè)務(wù)邏輯的簡單平替方案。
	2. 大模型開發(fā)的整體流程
	1. 設(shè)計(jì)
	 
	2. 架構(gòu)搭建
	- 
		
			搭建整體架構(gòu):目前,絕大部分大模型應(yīng)用都是采用的特定數(shù)據(jù)庫+ Prompt + 通用大模型的架構(gòu)。我們需要針對(duì)我們所設(shè)計(jì)的功能,搭建項(xiàng)目的整體架構(gòu),實(shí)現(xiàn)從用戶輸入到應(yīng)用輸出的全流程貫通。一般來說,我們推薦基于 LangChain 框架進(jìn)行開發(fā)。LangChain 提供了 Chain、Tool 等架構(gòu)的實(shí)現(xiàn),我們可以基于 LangChain 進(jìn)行個(gè)性化定制,實(shí)現(xiàn)從用戶輸入到數(shù)據(jù)庫再到大模型最后輸出的整體架構(gòu)連接。
	 
	- 
		
			搭建數(shù)據(jù)庫:個(gè)性化大模型應(yīng)用需要有個(gè)性化數(shù)據(jù)庫進(jìn)行支撐。由于大模型應(yīng)用需要進(jìn)行向量語義檢索,一般使用諸如 chroma 的向量數(shù)據(jù)庫。在該步驟中,我們需要收集數(shù)據(jù)并進(jìn)行預(yù)處理,再向量化存儲(chǔ)到數(shù)據(jù)庫中。數(shù)據(jù)預(yù)處理一般包括從多種格式向純文本的轉(zhuǎn)化,例如 pdf、markdown、html、音視頻等,以及對(duì)錯(cuò)誤數(shù)據(jù)、異常數(shù)據(jù)、臟數(shù)據(jù)進(jìn)行清洗。完成預(yù)處理后,需要進(jìn)行切片、向量化構(gòu)建出個(gè)性化數(shù)據(jù)庫。
	 
	3. Prompt Engineering
	4. 驗(yàn)證迭代
	- 
		
			驗(yàn)證迭代:驗(yàn)證迭代在大模型開發(fā)中是極其重要的一步,一般指通過不斷發(fā)現(xiàn) Bad Case 并針對(duì)性改進(jìn) Prompt Engineering 來提升系統(tǒng)效果、應(yīng)對(duì)邊界情況。在完成上一步的初始化 Prompt 設(shè)計(jì)后,我們應(yīng)該進(jìn)行實(shí)際業(yè)務(wù)測(cè)試,探討邊界情況,找到 Bad Case,并針對(duì)性分析 Prompt 存在的問題,從而不斷迭代優(yōu)化,直到達(dá)到一個(gè)較為穩(wěn)定、可以基本實(shí)現(xiàn)目標(biāo)的 Prompt 版本。
	 
	- 
		
			體驗(yàn)優(yōu)化:在完成前后端搭建之后,應(yīng)用就可以上線體驗(yàn)了。接下來就需要進(jìn)行長期的用戶體驗(yàn)跟蹤,記錄 Bad Case 與用戶負(fù)反饋,再針對(duì)性進(jìn)行優(yōu)化即可。
	 
	5. 前后端搭建
	二、項(xiàng)目流程簡析
	以下我們將結(jié)合本實(shí)踐項(xiàng)目與上文的整體流程介紹,簡要分析本項(xiàng)目開發(fā)流程如下:
	步驟一:項(xiàng)目規(guī)劃與需求分析
	1.項(xiàng)目目標(biāo)
	基于個(gè)人知識(shí)庫的問答助手
	2.核心功能
	- 
		
			上傳文檔、創(chuàng)建知識(shí)庫;
	 
	- 
		
			選擇知識(shí)庫,檢索用戶提問的知識(shí)片段;
	 
	- 
		
			提供知識(shí)片段與提問,獲取大模型回答;
	 
	- 
		
			流式回復(fù);
	 
	- 
		
			歷史對(duì)話記錄
	 
	3.確定技術(shù)架構(gòu)和工具
	- 
		
			LangChain框架
	 
	- 
		
			Chroma知識(shí)庫
	 
	- 
		
			大模型使用準(zhǔn)備
	 
	- 
		
			前后端使用 Gradio 和 Streamlit。
	 
	步驟二:數(shù)據(jù)準(zhǔn)備與向量知識(shí)庫構(gòu)建
	本項(xiàng)目實(shí)現(xiàn)原理如下圖所示(圖片來源),過程包括:
	- 
		
			加載本地文檔
	 
	- 
		
			讀取文本
	 
	- 
		
			文本分割
	 
	- 
		
			文本向量化
	 
	- 
		
			Query 向量化
	 
	- 
		
			向量匹配,最相似的 top k個(gè)
	 
	- 
		
			匹配出的文本作為上下文和問題一起添加到 prompt中
	 
	- 
		
			提交給 LLM做生成回答
	 
	1. 收集和整理用戶提供的文檔。
	用戶常用文檔格式有 pdf、txt、doc 等,首先使用工具讀取文本,通常使用 langchain 的文檔加載器模塊可以方便的將用戶提供的文檔加載進(jìn)來,也可以使用一些 python 比較成熟的包進(jìn)行讀取。
	由于目前大模型使用 token 限制,我們需要對(duì)讀取的文本進(jìn)行切分,將較長的文本切分為較小的文本,這時(shí)一段文本就是一個(gè)單位的知識(shí)。
	2. 將文檔詞向量化
	使用文本嵌入(Embeddings)對(duì)分割后的文檔進(jìn)行向量化,使語義相似的文本片段具有接近的向量表示。然后,存入向量數(shù)據(jù)庫,這個(gè)流程正是創(chuàng)建索引(index)的過程。
	向量數(shù)據(jù)庫對(duì)各文檔片段進(jìn)行索引,支持快速檢索。這樣,當(dāng)用戶提出問題時(shí),可以先將問題轉(zhuǎn)換為向量,在數(shù)據(jù)庫中快速找到語義最相關(guān)的文檔片段。然后將這些文檔片段與問題一起傳遞給語言模型,生成回答。
	3. 將向量化后的文檔導(dǎo)入Chroma知識(shí)庫,建立知識(shí)庫索引。
	Langchain集成了超過30個(gè)不同的向量存儲(chǔ)庫。我們選擇 Chroma 向量庫是因?yàn)樗p量級(jí)且數(shù)據(jù)存儲(chǔ)在內(nèi)存中,這使得它非常容易啟動(dòng)和開始使用。
	將用戶知識(shí)庫內(nèi)容經(jīng)過 embedding 存入向量知識(shí)庫,然后用戶每一次提問也會(huì)經(jīng)過 embedding,利用向量相關(guān)性算法(例如余弦算法)找到最匹配的幾個(gè)知識(shí)庫片段,將這些知識(shí)庫片段作為上下文,與用戶問題一起作為 prompt 提交給 LLM 回答。
	步驟三:大模型集成與API連接
	- 
		
			集成大模型,配置API連接。
	 
	- 
		
			編寫代碼,實(shí)現(xiàn)與大模型API的交互,以便獲取問題答案。
	 
	步驟四:核心功能實(shí)現(xiàn)
	- 
		
			構(gòu)建 Prompt Engineering,實(shí)現(xiàn)大模型回答功能,根據(jù)用戶提問和知識(shí)庫內(nèi)容生成回答。
	 
	- 
		
			實(shí)現(xiàn)流式回復(fù),允許用戶進(jìn)行多輪對(duì)話。
	 
	- 
		
			添加歷史對(duì)話記錄功能,保存用戶與助手的交互歷史。
	 
	步驟五:核心功能迭代優(yōu)化
	- 
		
			進(jìn)行驗(yàn)證評(píng)估,收集 Bad Case。
	 
	- 
		
			根據(jù) Bad Case 迭代優(yōu)化核心功能實(shí)現(xiàn)。
	 
	步驟六:前端與用戶交互界面開發(fā)
	- 
		
			使用 Gradio 和 Streamlit 搭建前端界面。
	 
	- 
		
			實(shí)現(xiàn)用戶上傳文檔、創(chuàng)建知識(shí)庫的功能。
	 
	- 
		
			設(shè)計(jì)用戶界面,包括問題輸入、知識(shí)庫選擇、歷史記錄展示等。
	 
	步驟七:部署測(cè)試與上線
	- 
		
			部署問答助手到服務(wù)器或云平臺(tái),確??稍诨ヂ?lián)網(wǎng)上訪問。
	 
	- 
		
			進(jìn)行生產(chǎn)環(huán)境測(cè)試,確保系統(tǒng)穩(wěn)定。
	 
	- 
		
			上線并向用戶發(fā)布。
	 
	步驟八:維護(hù)與持續(xù)改進(jìn)
	- 
		
			監(jiān)測(cè)系統(tǒng)性能和用戶反饋,及時(shí)處理問題。
	 
	- 
		
			定期更新知識(shí)庫,添加新的文檔和信息。
	 
	- 
		
			收集用戶需求,進(jìn)行系統(tǒng)改進(jìn)和功能擴(kuò)展。
	 
	整個(gè)流程將確保項(xiàng)目從規(guī)劃、開發(fā)、測(cè)試到上線和維護(hù)都能夠順利進(jìn)行,為用戶提供高質(zhì)量的基于個(gè)人知識(shí)庫的問答助手。
	三、項(xiàng)目架構(gòu)簡析
	1. 整體架構(gòu)
	經(jīng)過上文分析,本項(xiàng)目為搭建一個(gè)基于大模型的個(gè)人知識(shí)庫助手,基于 LangChain 框架搭建,核心技術(shù)包括 LLM API 調(diào)用、向量數(shù)據(jù)庫、檢索問答鏈等。項(xiàng)目整體架構(gòu)如下:
	如上,本項(xiàng)目從底向上依次分為 LLM 層、數(shù)據(jù)層、數(shù)據(jù)庫層、應(yīng)用層與服務(wù)層。
	- 
		
			LLM 層:主要基于四種流行 LLM API 進(jìn)行了 LLM 調(diào)用封裝,支持用戶以統(tǒng)一的入口、方式來訪問不同的模型,支持隨時(shí)進(jìn)行模型的切換;
	 
	- 
		
			數(shù)據(jù)層:主要包括個(gè)人知識(shí)庫的源數(shù)據(jù)以及 Embedding API,源數(shù)據(jù)經(jīng)過 Embedding 處理可以被向量數(shù)據(jù)庫使用;
	 
	- 
		
			數(shù)據(jù)庫層:主要為基于個(gè)人知識(shí)庫源數(shù)據(jù)搭建的向量數(shù)據(jù)庫,在本項(xiàng)目中我們選擇了 Chroma;
	 
	- 
		
			應(yīng)用層:為核心功能的最頂層封裝,我們基于 LangChain 提供的檢索問答鏈基類進(jìn)行了進(jìn)一步封裝,從而支持不同模型切換以及便捷實(shí)現(xiàn)基于數(shù)據(jù)庫的檢索問答;
	 
	- 
		
			服務(wù)層:分別實(shí)現(xiàn)了 Gradio 搭建 Demo 與 FastAPI 組建 API 兩種方式來支持本項(xiàng)目的服務(wù)訪問。
	 
	2. 代碼結(jié)構(gòu)
	本項(xiàng)目的完整代碼存放于 project 目錄下,實(shí)現(xiàn)了項(xiàng)目的全部功能及封裝,代碼結(jié)構(gòu)如下:
	
	
		
			-project
		
			? -readme.md 項(xiàng)目說明
		
			? -llm LLM調(diào)用封裝
		
			? -self_llm.py 自定義 LLM 基類
		
			? -wenxin_llm.py 自定義百度文心 LLM
		
			? -spark_llm.py 自定義訊飛星火 LLM
		
			? -zhipu_llm.py 自定義智譜 LLM
		
			? -call_llm.py 將各個(gè) LLM 的原生接口封裝在一起
		
			? -embedding embedding調(diào)用封裝
		
			? -zhipu_embedding.py 自定義智譜embedding
		
			? -data 源數(shù)據(jù)路徑
		
			? -database 數(shù)據(jù)庫層封裝
		
			? -create_db.py 處理源數(shù)據(jù)及初始化數(shù)據(jù)庫封裝
		
			? -chain 應(yīng)用層封裝
		
			? -qa_chain.py 封裝檢索問答鏈,返回一個(gè)檢索問答鏈對(duì)象
		
			? -chat_qa_chian.py:封裝對(duì)話檢索鏈,返回一個(gè)對(duì)話檢索鏈對(duì)象
		
			? -prompt_template.py 存放多個(gè)版本的 Template
		
			? -serve 服務(wù)層封裝
		
			? -run_gradio.py 啟動(dòng) Gradio 界面
		
			? -api.py 封裝 FastAPI
		
			? -run_api.sh 啟動(dòng) API
	 
 
	3. 項(xiàng)目邏輯
	- 
		
			用戶:可以通過run_gradio或者run_api啟動(dòng)整個(gè)服務(wù);
	 
	- 
		
			服務(wù)層調(diào)用qa_chain.py或chat_qa_chain實(shí)例化對(duì)話檢索鏈對(duì)象,實(shí)現(xiàn)全部核心功能;
	 
	- 
		
			服務(wù)層和應(yīng)用層都可以調(diào)用、切換prompt_template.py中的 prompt 模板來實(shí)現(xiàn) prompt 的迭代;
	 
	- 
		
			也可以直接調(diào)用call_llm中的get_completion函數(shù)來實(shí)現(xiàn)不使用數(shù)據(jù)庫的 LLM;
	 
	- 
		
			應(yīng)用層調(diào)用已存在的數(shù)據(jù)庫和 llm 中的自定義 LLM 來構(gòu)建檢索鏈;
	 
	- 
		
			如果數(shù)據(jù)庫不存在,應(yīng)用層調(diào)用create_db.py創(chuàng)建數(shù)據(jù)庫,該腳本可以使用 openai embedding 也可以使用embedding.py中的自定義 embedding。
	 
	4. 各層簡析
	4.1 LLM 層
	LLM 層主要功能為:將國內(nèi)外四種知名 LLM API(OpenAI-ChatGPT、百度文心、訊飛星火、智譜GLM)進(jìn)行封裝,隱藏不同 API 的調(diào)用差異,實(shí)現(xiàn)在同一個(gè)對(duì)象或函數(shù)中通過不同的 model 參數(shù)來使用不同來源的 LLM。
	在 LLM 層,我們首先構(gòu)建了一個(gè) Self_LLM 基類,基類定義了所有 API 的一些共同參數(shù)(如 API_Key,temperature 等);然后我們?cè)谠摶惢A(chǔ)上繼承實(shí)現(xiàn)了上述四種 LLM API 的自定義 LLM。同時(shí),我們也將四種 LLM 的原生 API 封裝在了統(tǒng)一的 get_completion 函數(shù)中。
	在上一章,我們已詳細(xì)介紹了每一種 LLM 的調(diào)用方式、封裝方式,項(xiàng)目代碼中的 LLM 層封裝就是上一章講解的代碼實(shí)踐。
	4.2 數(shù)據(jù)層
	數(shù)據(jù)層主要包括:個(gè)人知識(shí)庫的源數(shù)據(jù)(包括 pdf、txt、md 等)和 Embedding 對(duì)象。源數(shù)據(jù)需要經(jīng)過 Embedding 處理才能進(jìn)入向量數(shù)據(jù)庫,我們?cè)跀?shù)據(jù)層自定義了智譜提供的 Embedding API 的封裝,支持上層以統(tǒng)一方式調(diào)用智譜 Embedding 或 OpenAI Embedding。
	4.3 數(shù)據(jù)庫層
	數(shù)據(jù)庫層主要:存放了向量數(shù)據(jù)庫文件。同時(shí),我們?cè)谠搶訉?shí)現(xiàn)了源數(shù)據(jù)處理、創(chuàng)建向量數(shù)據(jù)庫的方法。
	我們將在第四章詳細(xì)介紹向量數(shù)據(jù)庫、源數(shù)據(jù)處理方法以及構(gòu)建向量數(shù)據(jù)庫的具體實(shí)現(xiàn)。
	4.4 應(yīng)用層
	應(yīng)用層:封裝了整個(gè)項(xiàng)目的全部核心功能。我們基于 LangChain 提供的檢索問答鏈,在 LLM 層、數(shù)據(jù)庫層的基礎(chǔ)上,實(shí)現(xiàn)了本項(xiàng)目檢索問答鏈的封裝。自定義的檢索問答鏈除具備基本的檢索問答功能外,也支持通過 model 參數(shù)來靈活切換使用的 LLM。我們實(shí)現(xiàn)了兩個(gè)檢索問答鏈,分別是有歷史記錄的 Chat_QA_Chain 和沒有歷史記錄的 QA_Chain。
	4.5 服務(wù)層
	服務(wù)層主要是:基于應(yīng)用層的核心功能封裝,實(shí)現(xiàn)了 Demo 的搭建或 API 的封裝。在本項(xiàng)目中,我們分別實(shí)現(xiàn)了通過 Gradio 搭建前端界面與 FastAPI 進(jìn)行封裝,支持多樣化的項(xiàng)目調(diào)用。