上期文章我們實(shí)現(xiàn)了Llama 2-chat-7B模型的云端部署和推理,本期文章我們將用“LangChain+Llama 2”的架構(gòu)打造一個(gè)定制化的心靈療愈機(jī)器人。有相關(guān)知識(shí)背景的讀者可以直接閱讀「實(shí)戰(zhàn)」部分。
01 背景
1.1 微調(diào) vs. 知識(shí)庫
由于大模型在垂直行業(yè)領(lǐng)域的問答效果仍有待提升,因此,領(lǐng)域知識(shí)的注入成為了最直接的解決方案之一。知識(shí)注入方法可以分為領(lǐng)域微調(diào)(Fine-tuning)和外掛知識(shí)庫(Knowledge Base)兩種。
1. 領(lǐng)域微調(diào)
微調(diào)是通過少量特定用例的增量數(shù)據(jù)對(duì)基礎(chǔ)模型進(jìn)行進(jìn)一步訓(xùn)練,改變其神經(jīng)網(wǎng)絡(luò)中的參數(shù)權(quán)重。微調(diào)適用于任務(wù)或域定義明確,且有足夠的標(biāo)記數(shù)據(jù)的場景,比如風(fēng)格微調(diào)。目前常用的微調(diào)方法包括Freeze,P-tuning和LoRA,相關(guān)細(xì)節(jié)會(huì)在下期文章中詳細(xì)介紹。
然而,微調(diào)方法的不足之處在于:
? 高質(zhì)量訓(xùn)練數(shù)據(jù)集的構(gòu)建,微調(diào)訓(xùn)練所需的算力以及微調(diào)模型定期更新等開銷都不容小覷
? 試錯(cuò)成本較高,特定領(lǐng)域數(shù)據(jù)一般難以覆蓋模型已學(xué)到的參數(shù),且可能會(huì)導(dǎo)致模型其他下游任務(wù)的表現(xiàn)下降
2. 外掛知識(shí)庫
外掛知識(shí)庫的本質(zhì)在于不修改基座模型參數(shù),通過提示詞工程(Prompt Engineering)將特定知識(shí)作為prompt中的context,即召回相關(guān)性最高的幾個(gè)文檔,讓模型分析這些蘊(yùn)含知識(shí)后,并返回答案。知識(shí)庫適合要求輸出明確且精度高的任務(wù)。
相對(duì)于微調(diào),知識(shí)庫的優(yōu)勢在于:
? 回答精確度更高,基于相關(guān)文檔中的最相關(guān)特定段落進(jìn)行語義搜索能消除查詢歧義以生成更精確的答案
? 適應(yīng)性更強(qiáng),用戶可以通過輕松更新信息源來調(diào)整和適配新的領(lǐng)域
但大模型上下文窗口長度的限制和Prompt的構(gòu)造等因素帶來的潛在精度下降也需要納入知識(shí)庫構(gòu)建的考量。
為了打造特定領(lǐng)域(Domain-specific Knowledge)的知識(shí)問答系統(tǒng),我們需要借助提供了外掛知識(shí)庫的搜索方案LangChain框架。
1.2 LangChain模塊
LangChain是一個(gè)由語言模型驅(qū)動(dòng)的用于開發(fā)應(yīng)用程序的框架。LangChain主要的兩個(gè)能力是:
? Data-aware:將不同數(shù)據(jù)源接入到語言模型中
? Agentic:允許語言模型和LangChain環(huán)境交互
LangChain的核心模塊包括Models,Prompts,Chains,Indexes,Agents等 [1]。對(duì)于每一個(gè)模塊,LangChain都提供了標(biāo)準(zhǔn)化的可拓展接口。
圖1:LangChain部分模塊 [2]
除了用LLM Wrapper可以接入眾多的大模型(如 OpenAI、Cohere、Hugging Face),LangChain同時(shí)也通過VectorStore Wrapper接口集成了主流的向量數(shù)據(jù)庫(如 Milvus、Pinecone、Chroma等)來優(yōu)化語義搜索。
LangChain能接入的數(shù)據(jù)類型涵蓋了文本、PPT、圖片、HTML、Pdf等非結(jié)構(gòu)化文件。相較于傳統(tǒng)數(shù)據(jù)庫的精確搜索,即完全匹配,向量數(shù)據(jù)庫使用最鄰近(Approximate Nearest Neighbor,ANN)算法和相似度度量(如余弦相似度,內(nèi)積等)來找到和查詢問題最相似的向量。
基于本地知識(shí)庫問答的大致流程如下:
加載文檔 -> 文本拆分 -> 根據(jù)question/query語義檢索匹配文本 -> 構(gòu)建prompt -> LLM生成回答
這里以Milvus數(shù)據(jù)庫和ChatGPT作為示例:
圖2:LangChian + Milvus + ChatGPT pipeline [3]
02 實(shí)戰(zhàn)
目前,我們已經(jīng)拆解完了LangChain+LLM文檔問答的大致鏈路,接下來我們正式進(jìn)入實(shí)戰(zhàn)環(huán)節(jié)。
2.1 環(huán)境搭建
a. 安裝LangChain
確保Python 版本≥ 3.8.1 且 <4.0。
pip install langchain
b. 部署LLama 2
? 關(guān)于Llama 2模型的部署,詳情可參見上期文章《大模型技術(shù)實(shí)踐(二)|關(guān)于Llama 2你需要知道的那些事兒》
? UCloud官方的“LLaMA2 模型快速部署”文檔:https://docs.ucloud.cn/gpu/practice/LLaMA2?id=llama2-模型快速部署
c. 下載Embedding 模型
這里我們選擇text2vec-large-chinese [4]這個(gè)Embedding模型,下載地址為:
https://huggingface.co/GanymedeNil/text2vec-large-chinese
對(duì)于中文的場景,也有其他優(yōu)秀的開源模型可供選擇,如m3e和bge等[5]。
d. 下載數(shù)據(jù)集
心靈雞湯文本數(shù)據(jù)集:https://huggingface.co/datasets/soulteary/warm-chicken-soup/
這個(gè)數(shù)據(jù)集是從Google網(wǎng)頁上爬取的一些心靈雞湯引用短文,共包含631條文本
2.2 文檔解析
a. 加載數(shù)據(jù)集
LangChain對(duì)于不同格式的數(shù)據(jù)源內(nèi)置了不同的解析腳本,最終這些數(shù)據(jù)都將轉(zhuǎn)換為純txt文本格式,以實(shí)現(xiàn)文本標(biāo)準(zhǔn)化。
from langchain.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
loader = UnstructuredFileLoader("數(shù)據(jù)集存放地址")
docs = loader.load()
b. 文本切分
文本切分中的chunk_size指定了切分后的文本塊的字?jǐn)?shù),chunk_overlap指定了切分文本塊之間的重疊字?jǐn)?shù)。由于雞湯引用文本總長度較短,且文本內(nèi)部語義關(guān)聯(lián)度高,所以這里的chunk_size設(shè)置為50,chunk_overlap設(shè)置為20。
text_splitter = RecursiveCharacterTextSplitter(chunk_size=50,chunk_overlap=20)
docs = text_splitter.split_documents(docs)
c. 文本嵌入和向量庫
文本切分后,我們需要將文本進(jìn)行向量化表示,將其映射為低維稠密的向量并存儲(chǔ)到然向量數(shù)據(jù)庫中。向量數(shù)據(jù)庫選用了無需注冊(cè)的FAISS。
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
# 導(dǎo)入向量模型
import os
embeddings = HuggingFaceEmbeddings(
model_name = "{你的地址}/text2vec-large-chinese",
model_kwargs = {'device': 'cuda'})
# 如果沒有本地faiss倉庫,先讀取doc向量庫,再將向量庫保存到本地
if os.path.exists("{你的地址}/my_faiss_store.faiss") == False:
vector_store = FAISS.from_documents(docs,embeddings)
vector_store.save_local("{你的地址}/my_faiss_store.faiss")
# 如果faiss倉庫已存在,則直接讀取
else:
vector_store = FAISS.load_local(
"{你的地址}/my_faiss_store.faiss",
embeddings=embeddings)
2.3 加載模型
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
# 加載tokenizer
tokenizer = AutoTokenizer.from_pretrained(
'/opt/Llama-2-7b-chat-hf',
trust_remote_code=True)
# 加載模型 Llama 2-chat-7B
base_model = AutoModelForCausalLM.from_pretrained(
"/opt/Llama-2-7b-chat-hf",
torch_dtype=torch.float16,
device_map='auto',
trust_remote_code=True
)
llm = base_model.eval()
2.4 語義檢索
接下來,我就能根據(jù)構(gòu)建好的向量數(shù)據(jù)庫召回對(duì)應(yīng)文本片段。
a. 向量化召回
FAISS默認(rèn)使用L2(歐式距離),召回的文檔按照相似度結(jié)果從大到小排序。
query = "面對(duì)求職屢屢碰壁的大學(xué)生,請(qǐng)說一句話來鼓勵(lì)他?"
docs = vector_store.similarity_search(query) # 計(jì)算相似度,并把相似度高的chunk放在前面
context = [doc.page_content for doc in docs] # 提取chunk的文本內(nèi)容
print(context)
b. 設(shè)置提示詞模板
以下是Llama 2默認(rèn)的提示詞模板
#qa_template = """Use the following pieces of information to answer the user's question.
#If you don't know the answer, just say that you don't know, don't try to make up an answer.
#Context: {context}
#Question: {question}
#Only return the helpful answer below and nothing else.
#Helpful answer: """
我們可以參考上面的模板,根據(jù)場景定制化自己的模板來拼接Query和召回結(jié)果
context ="\n".join(context)
prompt = f"基于以上內(nèi)容:\n{context} \n 請(qǐng)回答:{query} \n 字?jǐn)?shù)限制在30字以內(nèi)"
2.5 推理示例
我們對(duì)LLM的參數(shù)進(jìn)行設(shè)置,例如最大令牌(max_new_tokens)、最高k值(top_k)、溫度(temperature)和重復(fù)懲罰(repetition_penalty)等等。最后,將prompt喂給模型。
# 檢查顯存占用
nvidia-smi
inputs = tokenizer([f"Human:{prompt}\nAssistant:"], return_tensors="pt")
input_ids = inputs["input_ids"].to('cuda')
# llm參數(shù)設(shè)置
param_config = {
"input_ids":input_ids,
"max_new_tokens":1024,
"do_sample":True,
"top_k":5,
"top_p":0.95,
"temperature":0.1,
"repetition_penalty":1.3
}
result = llm.generate(**param_config)
answer = tokenizer.decode(result[0], skip_special_tokens=True)
print(answer)
# output example
# Q:面對(duì)求職屢屢碰壁的大學(xué)生,請(qǐng)說一句話來鼓勵(lì)他?
# A:堅(jiān)持不懈,機(jī)會(huì)終將降臨
03 外掛知識(shí)庫的問題和優(yōu)化
3.1 LLM+Embedding-Search的局限
外掛知識(shí)庫將用戶問題和本地知識(shí)向量化,比較兩者的向量相似度(Vector Similarity)進(jìn)行召回。然而,這種全量的Embedding-Search在面對(duì)多知識(shí)點(diǎn)聚合處理的場景下,存在召回精度低的問題。因?yàn)橹R(shí)庫的構(gòu)建是對(duì)單個(gè)知識(shí)點(diǎn)進(jìn)行索引,而非對(duì)不同知識(shí)點(diǎn)的排列組合分別索引。
居里夫人的出生年月 -> 單索引
居里夫人、愛因斯坦、奧本海默的出生年月 -> 組合索引
Q: 居里夫人、愛因斯坦和奧本海默三人中誰最早出生?
為了避免召回遺漏,直觀的處理方法包括降低相似度閾值(similarity score threshold)和增加召回?cái)?shù)量(top_k),但這不免會(huì)引入無關(guān)的知識(shí)點(diǎn)噪聲且增加和LLM交互的token開銷。
3.2 效果優(yōu)化方向
意圖識(shí)別和召回優(yōu)化
提升問答系統(tǒng)的精度可以從意圖識(shí)別和召回優(yōu)化兩個(gè)角度考慮,且兩者都可以用關(guān)鍵詞表示,即從直接將用戶query和知識(shí)點(diǎn)進(jìn)行embedding轉(zhuǎn)變?yōu)閷?duì)兩者提取關(guān)鍵詞后再進(jìn)行匹配。意圖識(shí)別可以通過關(guān)鍵詞提?。↖nformation Extraction, IE)和槽位填充(Slot Filling,SF)實(shí)現(xiàn)。
1. 關(guān)鍵詞提取
a. 面向query——槽位填充
利用LLM思維鏈(Chain-of-Thought,COT)的提示能力來引導(dǎo)用戶多輪對(duì)話并進(jìn)行信息總結(jié)。針對(duì)我們的心靈療愈機(jī)器人的場景,比如用戶查詢心靈雞湯的句子,那么就要求用戶的提供年齡段,情緒問題和情感需求等信息。語義槽格式如下:
"心靈雞湯" : {
"用戶年齡段" : ____, # 青年,中年,老年
"情緒問題" : ____, # 焦慮,失戀
"情感需求" : ____, # 尋求安慰,尋求激勵(lì)
}
b. 面向知識(shí)點(diǎn)——索引入口
對(duì)于知識(shí)點(diǎn)可以從以下兩個(gè)方面考慮:
i. 對(duì)相同知識(shí)點(diǎn)建立多級(jí)索引,有助于實(shí)現(xiàn)對(duì)維度查詢。比如對(duì)一位奧運(yùn)冠軍的姓名,競賽項(xiàng)目,年齡,獲獎(jiǎng)時(shí)間等分別建立索引。
ii. 將知識(shí)庫轉(zhuǎn)化為以關(guān)系三元組為核心的知識(shí)圖譜。三元組的抽取除了傳統(tǒng)的命名實(shí)體識(shí)別(NER)等方法,也可以通過prompt讓大模型來進(jìn)行抽取。
基于關(guān)鍵詞的embedding入庫和搜索流程如下:
2. 多路召回
類似于Bert時(shí)代的垂直領(lǐng)域問答系統(tǒng),我們可以將語義檢索和傳統(tǒng)的Elasticsearch(ES)關(guān)鍵詞搜索并行,對(duì)兩者進(jìn)行加權(quán)打分投票來獲取最終的top_k。
目前類似于以上優(yōu)化思路已經(jīng)落地的有“智海-錄問”法律大模型 [6],其基座模型為Baichuan-7B。智海-錄問知識(shí)增強(qiáng)的完整鏈路如圖3。值得注意的是,智海-錄問在知識(shí)庫中對(duì)每一個(gè)知識(shí)點(diǎn)是以 [key, value] pair 形式存儲(chǔ)的。key是知識(shí)點(diǎn)的內(nèi)容簡介,用于檢索;value是知識(shí)點(diǎn)的具體內(nèi)容,用于模型輸入。實(shí)現(xiàn)細(xì)節(jié)請(qǐng)參照其Hugging Face倉庫。
圖3:“智海-錄問”知識(shí)增強(qiáng)鏈路
其他優(yōu)化方向
除了Embedding部分,“LangChain+LLM”(圖2)鏈路內(nèi)的其他組件也有進(jìn)一步優(yōu)化的空間:
1. 知識(shí)庫細(xì)化
當(dāng)用戶手動(dòng)選擇分區(qū)后,分區(qū)檢索可以明顯提高召回的精度。
圖4:“智海-錄問”的交互界面
2. 文本切分方式
由于文本重疊(overlap)的大小沒有統(tǒng)一標(biāo)準(zhǔn),如何保證語義完整和連貫都需要不斷測試。
3. 提示詞的質(zhì)量
在提示詞模板的設(shè)計(jì)上要增加明確約束條件的指令,減少大模型出現(xiàn)幻覺現(xiàn)象的幾率。
4. 大模型的選型
選擇基座模型還是微調(diào)后的模型,以及對(duì)中文的支持程度的需求都需要結(jié)合下游場景進(jìn)行判別。
本期文章帶你基于“LangChain+LLM”框架快速搭建了知識(shí)增強(qiáng)后的問答機(jī)器人——心靈療愈師,并探討了提升模型的內(nèi)容理解和執(zhí)行能力的潛在優(yōu)化方向。文章來源:http://www.zghlxwxcb.cn/news/detail-741307.html
下期文章我們將深入解讀目前主流的大模型微調(diào)技術(shù),敬請(qǐng)期待~文章來源地址http://www.zghlxwxcb.cn/news/detail-741307.html
到了這里,關(guān)于大模型技術(shù)實(shí)踐(三)|用LangChain和Llama 2打造心靈療愈機(jī)器人的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!