1、引言
由于目前比較火的chatGPT是預(yù)訓(xùn)練模型,而訓(xùn)練一個大模型是需要較長時間(參數(shù)越多學(xué)習(xí)時間越長,保守估計(jì)一般是幾個月,不差錢的可以多用點(diǎn)GPU縮短這個時間),這就導(dǎo)致了它所學(xué)習(xí)的知識不會是最新的,最新的chatGPT-4o只能基于2023年6月之前的數(shù)據(jù)進(jìn)行回答,距離目前已經(jīng)快一年的時間,如果想讓GPT基于近一年的時間回復(fù)問題,就需要RAG(檢索增強(qiáng)生成)技術(shù)了。
此外,對于公司內(nèi)部的私有數(shù)據(jù),為了數(shù)據(jù)安全、商業(yè)利益考慮,不能放到互聯(lián)網(wǎng)上的數(shù)據(jù),因此GPT也沒有這部分的知識,如果需要GPT基于這部分私有的知識進(jìn)行回答,也需要使用RAG技術(shù)。
本文將通過實(shí)戰(zhàn)代碼示例,意在幫助沒有大模型實(shí)戰(zhàn)經(jīng)驗(yàn)的Java工程師掌握使用LangChain4j框架進(jìn)行大模型開發(fā)。
2、基本概念
2.1 什么是RAG
RAG(Retrieval-Augmented Generation)的核心思想是:將傳統(tǒng)的信息檢索(IR)技術(shù)與現(xiàn)代的生成式大模型(如chatGPT)結(jié)合起來。
具體來說,RAG模型在生成答案之前,會首先從一個大型的文檔庫或知識庫中檢索到若干條相關(guān)的文檔片段。再將這些檢索到的片段作為額外的上下文信息,輸入到生成模型中,從而生成更為準(zhǔn)確和信息豐富的文本。
RAG的工作原理可以分為以下幾個步驟:
1.接收請求:首先,系統(tǒng)接收到用戶的請求(例如提出一個問題)。
2.信息檢索(R):系統(tǒng)從一個大型文檔庫中檢索出與查詢最相關(guān)的文檔片段。這一步的目標(biāo)是找到那些可能包含答案或相關(guān)信息的文檔。
3.生成增強(qiáng)(A):將檢索到的文檔片段與原始查詢一起輸入到大模型(如chatGPT)中,注意使用合適的提示詞,比如原始的問題是XXX,檢索到的信息是YYY,給大模型的輸入應(yīng)該類似于:請基于YYY回答XXXX。
4.輸出生成(G):大模型基于輸入的查詢和檢索到的文檔片段生成最終的文本答案,并返回給用戶。
第2步驟中的信息檢索,不一定必須使用向量數(shù)據(jù)庫,可以是關(guān)系型數(shù)據(jù)庫(如MySQL)或全文搜索引擎(如Elasticsearch, ES),
但大模型應(yīng)用場景廣泛使用向量數(shù)據(jù)庫的原因是:在大模型RAG的應(yīng)用場景中,主要是要查詢相似度高的某幾個文檔,而不是精確的查找某一條(MySQL、ES擅長)。
相似度高的兩個文檔,可能不包含相同的關(guān)鍵詞。 例如,句子1: "他很高興。" 句子2: "他感到非常快樂。" 雖然都是描述【他】很開心快樂的心情,但是不包含相同的關(guān)鍵詞;
包含相同的關(guān)鍵詞的兩個文檔可能完全沒有關(guān)聯(lián),例如:句子1: "他喜歡蘋果。" 句子2: "蘋果是一家大公司。" 雖然都包含相同的關(guān)鍵詞【蘋果】,但兩句話的相似度很低。
2.2 LangChain4j簡介
LangChain4j是LangChiain的java版本,
LangChain的Lang取自Large Language Model,代表大語言模型,
Chain是鏈?zhǔn)綀?zhí)行,即把語言模型應(yīng)用中的各功能模塊化,串聯(lián)起來,形成一個完整的工作流。
它是面向大語言模型的開發(fā)框架,意在封裝與LLM對接的細(xì)節(jié),簡化開發(fā)流程,提升基于LLM開發(fā)的效率。
更多介紹,詳見: https://github.com/langchain4j/langchain4j/blob/main/README.md?
2.3 大模型開發(fā) vs. 傳統(tǒng)JAVA開發(fā)
大模型開發(fā)——大模型實(shí)現(xiàn)業(yè)務(wù)邏輯:
開發(fā)前,開發(fā)人員關(guān)注數(shù)據(jù)準(zhǔn)備(進(jìn)行訓(xùn)練)、選擇和微調(diào)模型(得到更好的效果,更能匹配業(yè)務(wù)預(yù)期),
開發(fā)過程中(大多數(shù)時候),重點(diǎn)在于如何有效的與大模型(LLM)進(jìn)行溝通,利用LLM的專業(yè)知識解決特定的業(yè)務(wù)問題,
開發(fā)中更關(guān)注如何描述問題(提示工程 Propmt Engineering)進(jìn)行有效的推理,關(guān)注如何將大模型的使用集成到現(xiàn)有的業(yè)務(wù)系統(tǒng)中。
傳統(tǒng)的JAVA開發(fā)——開發(fā)者實(shí)現(xiàn)業(yè)務(wù)邏輯:
開發(fā)前,開發(fā)人員關(guān)注系統(tǒng)架構(gòu)的選擇(高并發(fā)、高可用),功能的拆解、模塊化等設(shè)計(jì)。
開發(fā)過程中(大多數(shù)時候)是根據(jù)特定的業(yè)務(wù)問題,設(shè)計(jì)特定的算法、數(shù)據(jù)存儲等以實(shí)現(xiàn)業(yè)務(wù)邏輯,以編碼為主。
3. 實(shí)戰(zhàn)經(jīng)驗(yàn)
3.1 環(huán)境搭建
3.1.1 向量庫(Chroma)
Windows:
先安裝python,參考: https://docs.python.org/zh-cn/3/using/windows.html#the-full-installer
PS:注意需要配置環(huán)境變量
驗(yàn)證-執(zhí)行:
python --version
再安裝chroma,參考:https://docs.trychroma.com/getting-started
驗(yàn)證-執(zhí)行:
chroma run
Mac:
現(xiàn)先安裝python
brew install python
或者下載安裝: https://www.python.org/downloads/macos/
驗(yàn)證-執(zhí)行:
python --version
安裝chroma(同上),參考:https://docs.trychroma.com/getting-started
驗(yàn)證-執(zhí)行:
chroma run
?
3.1.2 集成LangChain4j
0.31.0/langchain4j.version?> /properties?> dev.langchain4j/groupId?> langchain4j-core/artifactId?> ${langchain4j.version}/version?> /dependency?> dev.langchain4j/groupId?> langchain4j/artifactId?> ${langchain4j.version}/version?> /dependency?> dev.langchain4j/groupId?> langchain4j-open-ai/artifactId?> ${langchain4j.version}/version?> /dependency?> dev.langchain4j/groupId?> langchain4j-embeddings/artifactId?> ${langchain4j.version}/version?> /dependency?> dev.langchain4j/groupId?> langchain4j-chroma/artifactId?> ${langchain4j.version}/version?> /dependency?> io.github.amikos-tech/groupId?> chromadb-java-client/artifactId?> ${langchain4j.version}/version?> /dependency?>
3.2 程序編寫
3.2.1 項(xiàng)目結(jié)構(gòu)
LangChain ├── core │ ├── src │ │ ├── main │ │ │ ├── java │ │ │ │ └── cn.jdl.tech_and_data.ka │ │ │ │ ├── ChatWithMemory │ │ │ │ ├── Constants │ │ │ │ ├── Main │ │ │ │ ├── RagChat │ │ │ │ └── Utils │ │ │ ├── resources │ │ │ │ ├── log4j2.xml │ │ │ │ └── 笑話.txt │ │ ├── test │ │ │ └── java │ ├── target ├── pom.xml ├── parent [learn.langchain.parent] ├── pom.xml
?
3.2.2 知識采集
一般是公司內(nèi)網(wǎng)的知識庫中或互聯(lián)網(wǎng)上進(jìn)行數(shù)據(jù)采集,獲取到的文本文件、WORD文檔或PDF文件,本文使用resources目錄下的【笑話.txt】作為知識采集的結(jié)果文件
URL docUrl = Main.class.getClassLoader().getResource("笑話.txt"); if(docUrl==null){ log.error("未獲取到文件"); } Document document = getDocument(docUrl); if(document==null){ log.error("加載文件失敗"); }
private static Document getDocument(URL resource) { Document document = null; try{ Path path = Paths.get(resource.toURI()); document = FileSystemDocumentLoader.loadDocument(path); }catch (URISyntaxException e){ log.error("加載文件發(fā)生異常", e); } return document; }
3.2.3 文檔切分
使用dev.langchain4j.data.document.splitter.DocumentSplitters#recursize
它有三個參數(shù):分段大小(一個分段中最大包含多少個token)、重疊度(段與段之前重疊的token數(shù))、分詞器(將一段文本進(jìn)行分詞,得到token)
其中,重疊度的設(shè)計(jì)是為了減少按大小拆分后切斷原來文本的語義,使其盡量完整。
DocumentSplitter splitter = DocumentSplitters.recursive(150,10,new OpenAiTokenizer()); splitter.split(document);
關(guān)于Token(標(biāo)記):
Token是經(jīng)過分詞后的文本單位,即將一個文本分詞后得到的詞、子詞等的個數(shù),具體取決于分詞器(Tokenizer),
比如:我喜歡吃蘋果,可以拆分成我/喜歡/吃/蘋果,token數(shù)量=4, 也可以拆分成我/喜/歡/吃/蘋果,token數(shù)量=5
chatGPT使用的是BPE(Byte Pair Encoding)算法進(jìn)行分詞,參見: https://en.wikipedia.org/wiki/Byte_pair_encoding
對于上面文本的分詞結(jié)果如下:
18:17:29.371 [main] INFO TokenizerTest - 待分詞的文本:我喜歡吃蘋果 18:17:30.055 [main] INFO cn.jdl.tech_and_data.ka.Utils - 當(dāng)前的模型是:gpt-4o 18:17:31.933 [main] INFO TokenizerTest - 分詞結(jié)果:我 / 喜歡 / 吃 / 蘋果
關(guān)于token與字符的關(guān)系:GPT-4o的回復(fù):
關(guān)于文檔拆分的目的:
由于與LLM交互的時候輸入的文本對應(yīng)的token長度是有限制的,輸入過長的內(nèi)容,LLM會無響應(yīng)或直接該報(bào)錯,
因此不能將所有相關(guān)的知識都作為輸入給到LLM,需要將知識文檔進(jìn)行拆分,存儲到向量庫,
每次調(diào)用LLM時,先找出與提出的問題關(guān)聯(lián)度最高的文檔片段,作為參考的上下文輸入給LLM。
入?yún)⑦^長,LLM報(bào)錯:
雖然根據(jù)響應(yīng),允許輸入1048576個字符=1024K個字符=1M個字符,
但官網(wǎng)文檔給的32K tokens,而一般1個中文字符對應(yīng)1-2個Token,因此字符串建議不大于64K,實(shí)際使用中,為了保障性能,也是要控制輸入不要過長。
如下是常見LLM給定的token輸入上限:
模型名稱 | Token 輸入上限(最大長度) |
---|---|
GPT-3 (davinci) | 4096 tokens |
GPT-3.5 (text-davinci-003) | 4096 tokens |
GPT-4 (8k context) | 8192 tokens |
GPT-4 (32k context) | 32768 tokens |
LLaMA (7B) | 2048 tokens |
LLaMA (13B) | 2048 tokens |
LLaMA (30B) | 2048 tokens |
LLaMA (65B) | 2048 tokens |
訊飛星火(SparkDesk) | 8192 tokens |
文心一言(Ernie 3.0) | 4096 tokens |
智源悟道(WuDao 2.0) | 2048 tokens |
阿里巴巴 M6 | 2048 tokens |
華為盤古(Pangu-Alpha) | 2048 tokens |
言犀大模型(ChatJd) | 2048 tokens |
文檔拆分的方案langchain4j中提供了6種:
1、基于字符的:逐個字符(含空白字符)分割
2、基于行的:按照換行符(n)分割
3、基于段落的:按照連續(xù)的兩個換行符(nn)分割
4、基于正則的:按照自定義正則表達(dá)式分隔
5、基于句子的(使用Apache OpenNLP,只支持英文,所以可以忽略
審核編輯 黃宇
-
JAVA
+關(guān)注
關(guān)注
19文章
2975瀏覽量
105156 -
ChatGPT
+關(guān)注
關(guān)注
29文章
1570瀏覽量
8067 -
LLM
+關(guān)注
關(guān)注
0文章
299瀏覽量
400
發(fā)布評論請先 登錄
相關(guān)推薦
評論