隨著大型語言模型(LLM)(如ChatGPT和GPT-4)的興起,現(xiàn)在比以往任何時候都更容易搭建智能聊天機(jī)器人,并且可以堆積如山的文檔,為你的輸入提供更準(zhǔn)確的響應(yīng)。
無論你是想構(gòu)建個人助理、定制聊天機(jī)器人還是自動文檔分析系統(tǒng),本系列都將為你提供構(gòu)建自己的LLM聊天機(jī)器人所需的知識。
創(chuàng)建什么?
使用ChatGPT作為助手來幫助用戶基于多個文檔進(jìn)行問答系統(tǒng)搭建的想法是非???。起初,我們的想法是用特定的數(shù)據(jù)對模型進(jìn)行微調(diào),以實現(xiàn)這一目標(biāo),但這可能成本高昂,并且需要龐大的數(shù)據(jù)集。此外,對模型進(jìn)行微調(diào)只能教會它一項新技能,而不能提供有關(guān)文檔的完整信息。
另一種方法是使用提示工程在(多)文檔QA的提示中提供上下文。然而,GPT模型的注意力范圍有限,將上下文傳遞給API也可能很昂貴,尤其是在處理大量客戶反饋電子郵件和產(chǎn)品文檔時。
那么如何創(chuàng)建呢?
以下是實現(xiàn)這些目標(biāo)的具體步驟:
-
首先加載文檔(PDF、HTML、文本、數(shù)據(jù)庫等);
-
然后將數(shù)據(jù)分割成塊,并對這些塊建立embedding索引,這樣方便使用向量檢索工具進(jìn)行語義搜索;
-
對于每個問題,通過搜索索引和embedding數(shù)據(jù)來獲取與問題相關(guān)的信息;
-
將問題和相關(guān)數(shù)據(jù)輸入到LLM模型中。在這個系列中使用OpenAI的LLM;
實現(xiàn)上述過程主要的兩個框架,分別是:Langchain(https://python.langchain.com/en/latest/)和LLamaIndex(https://gpt-index.readthedocs.io/en/latest/)
通俗易懂講解大模型系列
-
用通俗易懂的方式講解:大模型算法工程師最全面試題匯總
-
用通俗易懂的方式講解:我的大模型崗位面試總結(jié):共24家,9個offer
-
用通俗易懂的方式講解:大模型 RAG 在 LangChain 中的應(yīng)用實戰(zhàn)
-
用通俗易懂的方式講解:一文講清大模型 RAG 技術(shù)全流程
-
用通俗易懂的方式講解:如何提升大模型 Agent 的能力?
-
用通俗易懂的方式講解:ChatGPT 開放的多模態(tài)的DALL-E 3功能,好玩到停不下來!
-
用通俗易懂的方式講解:基于擴(kuò)散模型(Diffusion),文生圖 AnyText 的效果太棒了
-
用通俗易懂的方式講解:在 CPU 服務(wù)器上部署 ChatGLM3-6B 模型
-
用通俗易懂的方式講解:使用 LangChain 和大模型生成海報文案
-
用通俗易懂的方式講解:ChatGLM3-6B 部署指南
-
用通俗易懂的方式講解:使用 LangChain 封裝自定義的 LLM,太棒了
-
用通俗易懂的方式講解:基于 Langchain 和 ChatChat 部署本地知識庫問答系統(tǒng)
-
用通俗易懂的方式講解:在 Ubuntu 22 上安裝 CUDA、Nvidia 顯卡驅(qū)動、PyTorch等大模型基礎(chǔ)環(huán)境
-
用通俗易懂的方式講解:Llama2 部署講解及試用方式
-
用通俗易懂的方式講解:基于 LangChain 和 ChatGLM2 打造自有知識庫問答系統(tǒng)
-
用通俗易懂的方式講解:一份保姆級的 Stable Diffusion 部署教程,開啟你的煉丹之路
-
用通俗易懂的方式講解:對 embedding 模型進(jìn)行微調(diào),我的大模型召回效果提升了太多了
技術(shù)交流
技術(shù)要學(xué)會分享、交流,不建議閉門造車。一個人可以走的很快、一堆人可以走的更遠(yuǎn)。
本文完整代碼、相關(guān)資料、技術(shù)交流&答疑,均可加我們的交流群獲取,群友已超過2000人,添加時最好的備注方式為:來源+興趣方向,方便找到志同道合的朋友。
方式①、微信搜索公眾號:機(jī)器學(xué)習(xí)社區(qū),后臺回復(fù):加群
方式②、添加微信號:mlc2060,備注:來自CSDN + 技術(shù)交流
我們?nèi)绾伍_始
下面是使用Langchain和ChatGPT實現(xiàn)PDF問答系統(tǒng)的大致框架:
在本文,不會詳細(xì)介紹Langchain或LLamaIndex具體原理和實現(xiàn)細(xì)節(jié),后面會專門介紹。本文主要介紹如下內(nèi)容:
-
基于Langchain的生成式問答
-
LLamaIndex生成式問答
-
獎金部分。
準(zhǔn)備工作
首先我們需要在OPenAI官網(wǎng)獲取API秘鑰,具體步驟是:轉(zhuǎn)到https://platform.openai.com,登錄或注冊新帳戶→ 點擊您的個人資料→ 查看API密鑰并創(chuàng)建新的密鑰,如下圖所示:
Note:實際上,我們可以使用其他LLM模型。
下面準(zhǔn)備安裝相關(guān)的python包,需要保證Python>=3.7來進(jìn)行操作,然后創(chuàng)建一個虛擬環(huán)境并安裝以下Python庫:
## to create virtual environment
$ python3 -m venv llm_app_env
## on MacOS or Linux
$ source llm_app_env/bin/activate
## on Window
$ llm_app_env\Scripts\activate.bat
## then install the following libraries.
openai[embeddings]==0.27.6
langchain==0.0.155
pypdf==3.8.1
tiktoken==0.3.3
faiss-cpu==1.7.4
unstructured==0.6.2
chromadb==0.3.21
llama-index==0.6.1
jupyterlab
Langchain 介紹
LangChain 是一個強(qiáng)大的開源工具,可以輕松地與大型語言模型交互并構(gòu)建應(yīng)用程序。將其視為一個中間人,將您的應(yīng)用程序連接到廣泛的LLM提供商,如OpenAI、Cohere、Huggingface、Azure OpenAI等。
然而,LangChain 不僅僅是一個訪問預(yù)訓(xùn)練語言模型的工具,它還提供了許多有用的特性和功能,允許您構(gòu)建自定義應(yīng)用程序和工具。例如:
-
使用自己的文檔進(jìn)行問答和文本摘要
-
處理內(nèi)存和具有有限令牌問題的長文檔。
-
與OpenAI ChatGPT Retriever插件的出色集成
-
多個鏈來處理您定義的問題,或者使用Agent將其提升。
-
還有更多。
Langchain是一個偉大的框架,它使人工智能應(yīng)用程序的創(chuàng)建能力現(xiàn)在掌握在您手中。更令人驚訝的是,它是開源的,所以你知道它掌握在優(yōu)秀社區(qū)的手中。
使用 Langchain 來搭建一個問答系統(tǒng)
設(shè)置OpenAI API密鑰
import logging
import sys
import os
os.environ["OPENAI_API_KEY"] = "<YOUR_OPENAI_API_KEY>"
加載并拆分?jǐn)?shù)據(jù)
## load the PDF using pypdf
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# load the data
loader = PyPDFLoader('../notebooks/documents/Apple-Financial-Report-Q1-2022.pdf')
# the 10k financial report are huge, we will need to split the doc into multiple chunk.
# This text splitter is the recommended one for generic text. It is parameterized by a list of characters.
# It tries to split on them in order until the chunks are small enough.
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
data = loader.load()
texts = text_splitter.split_documents(data)
# view the first chunk
texts[0]
簡單問答
我們將使用OpenAI作為LLM提供者,因此使用OpenAI Embedding,但請注意,OpenAI Embedding API使用的是“text-davinci-003”模型(定價參考:https://openai.com/pricing)
接下來,我們將導(dǎo)入Chroma,Chroma是嵌入數(shù)據(jù)庫,不像傳統(tǒng)的SQL數(shù)據(jù)庫,也不像你通常使用的NoSQL數(shù)據(jù)庫。它嵌入了數(shù)據(jù)庫,使構(gòu)建LLM應(yīng)用程序變得容易。
通過Chroma官方網(wǎng)站
我們的文檔以文本的形式表示,因此很難根據(jù)問題找到相關(guān)信息。假設(shè)你需要在1000頁中找到蘋果上一季度的收入,并將收入與前幾年進(jìn)行比較。這可能需要多大的挑戰(zhàn)性和耗時?因此,為了讓我們的搜索更容易,我們首先需要以數(shù)字格式轉(zhuǎn)換或表示單詞或短語,這些單詞或短語可以用作機(jī)器學(xué)習(xí)模型的輸入。換句話說,幫助機(jī)器理解文本。embeddings將每個單詞或短語映射到實數(shù)向量,通常具有數(shù)百個維度,使得相似的單詞或短語被映射到嵌入空間中的相似向量。
使用embeddings的主要優(yōu)點之一是,它們可以捕捉單詞或短語之間的語義和句法關(guān)系。例如,在嵌入空間中,“國王”和“王后”的向量比“蘋果”的向量更接近,因為它們在語義上與王室頭銜相關(guān)。
因此,嵌入數(shù)據(jù)庫正是這樣做的。它將把所有embeddings數(shù)據(jù)存儲在數(shù)據(jù)庫中,然后給我們提供非常多的索引,使我們能夠執(zhí)行類似數(shù)據(jù)檢索的操作,并以可擴(kuò)展的風(fēng)格進(jìn)行操作。如果你需要得到之前關(guān)于尋找蘋果上季度收入的問題的答案,我們首先需要在嵌入Chroma等數(shù)據(jù)庫的基礎(chǔ)上進(jìn)行相似性搜索或語義搜索,以提取相關(guān)信息,并將這些信息提供給LLM模型來獲得答案。
聽起來太復(fù)雜了!這就是Langchain拯救我們的地方,所有的艱苦工作都將在后臺完成。Just do it!
# import Chroma and OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.embeddings.openai import OpenAIEmbeddings
# initialize OpenAIEmbedding
embeddings = OpenAIEmbeddings(model='text-embedding-ada-002')
# use Chroma to create in-memory embedding database from the doc
docsearch = Chroma.from_documents(texts, embeddings, metadatas=[{"source": str(i)} for i in range(len(texts))])
## perform search based on the question
query = "What is the operating income?"
docs = docsearch.similarity_search(query)
可以看到,我們能夠執(zhí)行相似性搜索,從嵌入數(shù)據(jù)庫中獲取相關(guān)信息。
現(xiàn)在,我們將使用Langchain的主要組件之一Chain將LLM提供程序合并到我們的代碼中。
請記住,本文的目的是建立問答機(jī)器人。因此,只需按照步驟進(jìn)行操作,如果你很好奇,迫不及待地想了解更多細(xì)節(jié),請隨時訪問Langchain的官方網(wǎng)站。
Langchain 提供了四種預(yù)先構(gòu)建的問答Chain,具體如下:
-
問答:load_qa_chain
-
有來源問答:load_qa_with_sources_chain
-
檢索問題答案:RetrievalQA
-
資源檢索問答:RetrievalQAWithSourcesChain
它們非常相似,RetrievalQA和RetrievalQAWithSourcesChain分別使用load_qa_chain和load_qa_with_sources_chain,唯一的區(qū)別是前兩者將把所有嵌入都饋送到LLM中,而后兩者只向LLM提供相關(guān)信息。我們可以使用前兩個來首先提取相關(guān)信息,并僅將該信息提供給LLM。此外,前兩個比后兩個給了我們更多的靈活性。
下面的代碼將演示我們是如何做到這一點的。
## importing necessary framework
from langchain.chains.question_answering import load_qa_chain
from langchain.chains.qa_with_sources import load_qa_with_sources_chain
from langchain.chains import RetrievalQA
from langchain.chains import RetrievalQAWithSourcesChain
from langchain.chat_models import ChatOpenAI
現(xiàn)在我們將嘗試4種不同的問答鏈
1.load_qa_chain
## use LLM to get answering
chain = load_qa_chain(ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'),
chain_type="stuff")
query = "What is the operating income?"
chain.run(input_documents=docs, question=query)
2.load_qa_with_sources_chain
chain = load_qa_with_sources_chain(ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'),
chain_type="stuff")
query = "What is the operating income?"
chain({"input_documents": docs, "question": query}, return_only_outputs=True)
3.RetrievalQA
qa=RetrievalQA.from_chain_type(llm=ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'), chain_type="stuff",
retriever=docsearch.as_retriever())
query = "What is the operating income?"
qa.run(query)
4.RetrievalQAWithSourcesChain
chain=RetrievalQAWithSourcesChain.from_chain_type(ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'), chain_type="stuff",
retriever=docsearch.as_retriever())
chain({"question": "What is the operating income?"}, return_only_outputs=True)
上面的大部分代碼都是非?;镜?。我們只想在深入研究框架能提供什么之前完成這項工作。在此之前,讓我們轉(zhuǎn)到另一個可以與Langchain結(jié)合使用的框架,它將為您提供更多的能力來創(chuàng)建更好的LLM應(yīng)用程序。
LLamaIndex介紹
我首先介紹了 Langchain,如果你花一些時間瀏覽它的官方文件,你可能會想“哇,沒有什么好的東西可以超越這一點”。
我們生活在一個今天好的東西明天可能會過時的世界里。我個人認(rèn)為 Langchain 將有一個非常光明的未來,并將成為用于構(gòu)建LLM應(yīng)用程序的核心技術(shù)。
但 LLamIndex 會讓我們的工作變得更容易,它可以輕松處理一些棘手的問題和現(xiàn)有方法的局限性,引入了自己的優(yōu)勢,這些問題和局限性將花費您的時間和手動操作。
例如:
-
文本塊缺少全局上下文。通常,這個問題需要特定區(qū)塊中索引之外的上下文。
-
仔細(xì)調(diào)整前k/相似性得分閾值。如果值太小,就會錯過上下文。讓價值變得太大,成本/延遲可能會隨著不相關(guān)的上下文而增加。
-
Embeddings 并不總是為問題選擇最相關(guān)的上下文。Embeddings本質(zhì)上是在文本和上下文之間分別確定的。
LLamaIndex(GPT索引)有自己的機(jī)制來處理這些限制。同樣,這個博客的目的是完成這項工作。我不會詳細(xì)介紹LLamaIndex是如何工作的(可以在官方文件上找到)。
那么LLM是什么
一張由Jerry Liu抄寫的羊皮紙,他在羊皮紙上公布了LlamaIndex,這是一個利用GPT的力量,利用詢問者提供的知識,形成對詢問的回復(fù)的門戶網(wǎng)站。
簡而言之,LlamaIndex是通過以下步驟將LLM連接到用戶來響應(yīng)查詢的另一種方式(類似于Langchain的方式):
-
加載文檔(手動或通過數(shù)據(jù)加載程序)
-
將文檔解析為節(jié)點
-
構(gòu)造索引(從節(jié)點或文檔)
-
[可選,高級]在其他指數(shù)之上構(gòu)建指數(shù)
-
查詢索引
簡單來說,LlamaIndex 將數(shù)據(jù)加載到文檔對象中,并將其轉(zhuǎn)換為索引。當(dāng)您輸入查詢時,索引會將其發(fā)送到GPT提示符以生成響應(yīng),默認(rèn)情況下使用OpenAI的text-davinci-003模型。盡管這個過程看起來很復(fù)雜,但只要幾行代碼就可以執(zhí)行,您很快就會了解到這一點。
你很快就會看到LLamaIndex是多么容易使用,因為它已經(jīng)完成了所有的艱苦工作。你的工作只是閱讀它的官方文件,學(xué)習(xí)不同類型的索引,然后分析你的應(yīng)用程序需求,看看什么最適合你。
當(dāng)然,你的應(yīng)用程序中可能需要越來越多復(fù)雜的東西,LLamaIndex 的高級API可能不足以處理此類情況。這就是 LLamaIndex 可以與 Langchain 等其他工具集成以加快開發(fā)過程的便利之處。
讓我們從設(shè)置簡單索引和加載文檔開始。
import logging
import sys
## setup your OpenAI Key
import os
os.environ["OPENAI_API_KEY"] = "<YOUR_OPENAI_API_KEY>"
# enable logs to see what happen underneath
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
LlamaIndex 的核心是指數(shù),有多種類型的指數(shù)。
-
列表索引
-
矢量存儲索引
-
樹索引
-
關(guān)鍵字表索引
-
圖形索引
-
SQL索引。
每個索引都有其獨特的用途,具有不同的用途。好處是,您可以將索引堆疊在其他索引之上,這樣做將使您的應(yīng)用程序更強(qiáng)大,能夠理解您的文檔上下文和應(yīng)用程序需求。
第一步是加載文檔
from llama_index import GPTVectorStoreIndex
from llama_index import download_loader
# we will use this UnstructuredReader to read PDF file
UnstructuredReader = download_loader('UnstructuredReader', refresh_cache=True)
loader = UnstructuredReader()
# load the data
data = loader.load_data(f'../notebooks/documents/_10-Q-Q1-2022-(As-Filed).pdf', split_documents=False)
Document表示數(shù)據(jù)源的輕量級容器??梢赃x擇下面兩步驟之一:
-
將Document對象直接輸入索引
-
首先,將文檔轉(zhuǎn)換為Node對象
同樣,本系列的目的是幫助您盡快構(gòu)建第一個應(yīng)用程序,因此我將直接討論索引構(gòu)建。我將在未來的一篇文章中介紹LLamaIndex的所有方面。
索引構(gòu)建與查詢
我們現(xiàn)在可以在這些Document對象上建立一個索引。最簡單的高級抽象是在索引初始化期間加載Document對象。
index = GPTVectorStoreIndex.from_documents(data)
query_engine = index.as_query_engine()
response = query_engine.query("What is the operating income?")
print(response)
根據(jù)您使用的索引,LlamaIndex可能會進(jìn)行LLM調(diào)用以構(gòu)建索引。GPTVvectorStoreIndex不會調(diào)用LLM,但GPTTreeStoreIndex會調(diào)用。
自定義LLM
默認(rèn)情況下,LlamaIndex使用OpenAI的text-davinci-003模型。在構(gòu)造索引時,您可以選擇使用另一個LLM。
from llama_index import LLMPredictor, PromptHelper, ServiceContext
from langchain.chat_models import ChatOpenAI
# define LLM
llm_predictor = LLMPredictor(llm=ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'))
# define prompt helper
# set maximum input size
max_input_size = 4096
# set number of output tokens
num_output = 256
# set maximum chunk overlap
max_chunk_overlap = 20
prompt_helper = PromptHelper(max_input_size, num_output, max_chunk_overlap)
service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, prompt_helper=prompt_helper)
index = GPTVectorStoreIndex.from_documents(
documents,
service_context=service_context
)
query_engine = index.as_query_engine()
response = query_engine.query("What is the operating income?")
print(response)
在短短幾行代碼中,我們就能夠構(gòu)建一個LLM應(yīng)用程序,可以進(jìn)行基本的問答。
對于具有機(jī)器學(xué)習(xí)工程師或數(shù)據(jù)科學(xué)背景的人來說,這是相當(dāng)簡單明了的,但我相信對于一些新手來說,有時會覺得很困惑。我理解這一點,但很難在一篇帖子中解釋所有內(nèi)容。這篇文章的目的只是讓你體驗一下現(xiàn)在構(gòu)建這樣一個令人驚嘆的LLM應(yīng)用程序是多么容易。你現(xiàn)在可能有很多問題,甚至可能幾行代碼都不懂,但這沒關(guān)系。
您將很快收集組件的所有知識和方面,以構(gòu)建自己的LLM應(yīng)用程序。你可以等到我的下一篇文章,因為我將在下一篇中介紹LlamaIndex,或者如果你足夠好奇,請通過閱讀官方文件來做好準(zhǔn)備。
在此之前,我希望這篇文章能夠幫助您擴(kuò)展編碼知識,并為LLM提供有價值的見解。記得保持好奇心,繼續(xù)探索人工智能的廣闊世界。
祝賀你走到這一步!作為對您努力的獎勵,這里有一段代碼,您可以使用它與文檔聊天
# do imports
from langchain.agents import Tool
from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent
from llama_index.langchain_helpers.agents import LlamaToolkit, create_llama_chat_agent, IndexToolConfig
query_engine = index.as_query_engine()
tool_config = IndexToolConfig(
query_engine=query_engine,
name=f"Financial Report",
description=f"useful for when you want to answer queries about the Apple financial report",
tool_kwargs={"return_direct": True}
)
toolkit = LlamaToolkit(
index_configs=[tool_config]
)
memory = ConversationBufferMemory(memory_key="chat_history")
llm=ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo')
agent_chain = create_llama_chat_agent(
toolkit,
llm,
memory=memory,
verbose=True
)
while True:
text_input = input("User: ")
response = agent_chain.run(input=text_input)
print(f'Agent: {response}')
參考文獻(xiàn):
[1] https://langchain.readthedocs.io/en/latest/index.html(LangChain docs)
[2] https://langchain.readthedocs.io/en/latest/modules/memory.html#memory(LangChain Prompt Memory module)
[3] https://github.com/hwchase17/langchain(LangChain Repo)文章來源:http://www.zghlxwxcb.cn/news/detail-799863.html
[4] https://gpt-index.readthedocs.io/en/latest/index.html(LlamaIndex docs)文章來源地址http://www.zghlxwxcb.cn/news/detail-799863.html
到了這里,關(guān)于用通俗易懂的方式講解:使用 LangChain 和 LlamaIndex 從零構(gòu)建PDF聊天機(jī)器人的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!