搜尋結果

×

LangChain RAG實作教學,結合Llama3讓LLM可以讀取PDF和DOC文件,並產生回應

使用Ollama來引入最新的Llama3大語言模型,來實作LangChain RAG教學。

LangChain Retrieval Augmented
本文是使用Ollama來引入最新的Llama3大語言模型,來實作LangChain RAG教學,可以讓LLM讀取PDF和DOC文件,達到客製化聊天機器人的效果。

因為RAG不用重新訓練模型,而且Dataset是你自己準備的,餵食LLM即時又準確的Dataset,可以解決LLM資料有時間限制的問題,因此近期在NLP領域非常受歡迎。

需要文件下載

本文是使用到裡面的langchain_rag_doc.pylangchain_rag_pdf.py檔案。

關於Hugging Face的介紹可以參考這篇 - 使用 Hugging Face 的Pipeline來實現本地端文字轉圖片(Text-to-Image),進行圖片生成

此文章也有發表在Medium上 >>

RAG流程圖

RAG運作圖參考自 https://huggingface.co/learn/cookbook/zh-CN/advanced_rag


圖引用自 Langchain

實作教學

langchain_rag_doc.py >> 這個_doc代表是匯入文件檔案doc

  1. 你會需要import以下套件

     from langchain.chains.combine_documents import create_stuff_documents_chain
     from langchain.chains import create_retrieval_chain
     from langchain_core.prompts import ChatPromptTemplate
     from langchain_community.llms import Ollama
     from langchain_community.embeddings import OllamaEmbeddings
     from langchain_community.vectorstores import FAISS
     from langchain_core.documents import Document
     from langchain_community.document_loaders import PyPDFLoader
    
     from langchain.text_splitter import CharacterTextSplitter
    

本文會匯入Doc文件和PDF來示範,分別為以下兩行

from langchain_core.documents import Document
from langchain_community.document_loaders import PyPDFLoader
  1. 建立模型和文件

     # 初始化Ollama模型
     llm = Ollama(model='llama3')
    
     # 建立文件列表,每個文件包含一段文字內容
     docs = [
         Document(page_content='曼德珍珠奶茶草:這種植物具有強大的魔法屬性,常用於恢復被石化的受害者。'),
         Document(page_content='山羊可愛蓮花石 :是一種從山羊胃中取出的石頭,可以解百毒。在緊急情況下,它被認為是最有效的解毒劑。'),
         Document(page_content='日本小可愛佐籐鱗片:這些鱗片具有強大的治愈能力,常用於製作治療藥水,特別是用於治療深層傷口。'),
     ]
    

文件中的內容建議自創,因為你若寫普世通俗的內容,那麼Llama3本來就已經知道了,因此效果會沒那麼顯著~

  1. 設定文本分割器

     # 設定文本分割器,chunk_size是分割的大小,chunk_overlap是重疊的部分
     text_splitter = CharacterTextSplitter(chunk_size=20, chunk_overlap=5)
     documents = text_splitter.split_documents(docs)  # 將文件分割成更小的部分
    

chunk_size (塊大小)

定義: 每個分割塊的大小,以字符數量為單位。
作用: 決定每個文本塊包含多少字符。

chunk_overlap (塊重疊)

定義: 相鄰文本塊之間重疊的字符數量。
作用: 確保每個分割後的文本塊之間有一些重疊部分,以保證連貫性和上下文不丟失。

為什麼需要 chunk_overlap?

在自然語言處理和其他文本分析任務中,連貫性和上下文信息非常重要。
通過設置塊重疊部分,我們可以確保每個分割後的文本塊仍然包含足夠的上下文信息,避免因切割造成的信息丟失或語義斷裂。

文本分割器的選擇非常多,詳情可以參考官方api文獻官方Text Splitters說明,不過多數情況用 Recursive 即可,關於RecursiveCharacterTextSplitter的使用可以參考Recursively split by character文檔

  1. 建置embeddings和向量資料庫

     # 初始化嵌入模型
     embeddings = OllamaEmbeddings()
    
     # 使用FAISS建立向量資料庫
     vectordb = FAISS.from_documents(docs, embeddings)
     # 將向量資料庫設為檢索器
     retriever = vectordb.as_retriever()
    
  2. 設定提示模板

     # 設定提示模板,將系統和使用者的提示組合
     prompt = ChatPromptTemplate.from_messages([
         ('system', 'Answer the user\'s questions in Chinese, based on the context provided below:\n\n{context}'),
         ('user', 'Question: {input}'),
     ])
    
  3. llm和提示模板結合

     # 創建文件鏈,將llm和提示模板結合
     document_chain = create_stuff_documents_chain(llm, prompt)
    
     # 創建檢索鏈,將檢索器和文件鏈結合
     retrieval_chain = create_retrieval_chain(retriever, document_chain)
    
  4. 從用戶輸入中獲取問題,並用retrieval_chain來回答

     context = []
     input_text = input('>>> ')
     while input_text.lower() != 'bye':
         response = retrieval_chain.invoke({
             'input': input_text,
             'context': context
         })
         print(response['answer'])
         context = response['context']
         input_text = input('>>> ')
    

retrieval_chain.invoke 是執行這條chain的代碼,以前的教學或許會看到.run,但最新版本的LangChain會慢慢用.invoke當主流。

RUN程式,開始問Llama3問題吧:>

root@4be643ba6a94:/app# python3 langchain_rag_doc.py
>>> 請告訴我珍珠奶茶是?
🤔

曼德珍珠奶茶草:這種植物具有強大的魔法屬性,常用於恢復被石化的受害者。

‘context’: context

如果把context註解掉的話,程式也可以RUN,但留著 ‘context’: context看起來會比較直觀。

# context = []
input_text = input('>>> ')
while input_text.lower() != 'bye':
    response = retrieval_chain.invoke({
        'input': input_text,
        # 'context': context
    })
    print(response['answer'])
    # context = response['context']
    input_text = input('>>> ')

若我們把程式碼改成如下,把response給print出來~

while input_text.lower() != 'bye':
    response = retrieval_chain.invoke({
        'input': input_text,
        'context': context
    })
    print(response['answer'])
    context = response['context']
    print("-------------------")
    print(response)
    input_text = input('>>> ')

可以看到結果如下,裡面會分別有response['input']response['context']response['answer']

root@4be643ba6a94:/app# python3 langchain_rag_doc.py
>>> 有哪些工具可以用?
🐐💧️

有以下幾種工具可以使用:

* 山羊可愛蓮花石:可以解百毒,對於急性中毒非常有效。
* 日本小可愛佐籐鱗片:具有強大的治愈能力,可以用於製作治療藥水,特別是深層傷口的治療。
* 曼德珍珠奶茶草:具有強大的魔法屬性,常用於恢復被石化的受害者。

這些工具都可以幫助你解決問題! 💪️
-------------------
{'input': '有哪些工具可以用?', 
'context': [Document(page_content='山羊可愛蓮花石 :是一種從山羊胃中取出的石頭,可以解百毒。在緊急情況下,它被認為是最有效的解毒劑。'), 
Document(page_content='日本小可愛佐籐鱗片:這些鱗片具有強大的治愈能力,常用於製作治療藥水,特別是用於治療深層傷口。'), 
Document(page_content='曼德珍珠奶茶草:這種植物具有強大的魔法屬性,常用於恢復被石化的受害者。')], 
'answer': '🐐💧️\n\n有以下幾種工具可以使用:\n\n* 山羊可愛蓮花石:可以解百毒,對於急性中毒非常有效。\n* 
日本小可愛佐籐鱗片:具有強大的治愈能力,可以用於製作治療藥水,特別是深層傷口的治療。\n* 
曼德珍珠奶茶草:具有強大的魔法屬性,常用於恢復被石化的受害者。\n\n這些工具都可以幫助你解決問題! 💪️'}\n這些工具都可以幫助你解決問題! 💪️'}

實作教學2

langchain_rag_pdf.py >> 這個_pdf代表是匯入pdf檔案

把前面建立模型和文件的程式碼,更改為以下

# 初始化Ollama模型
llm = Ollama(model='llama3')

# 載入並分割PDF文件
loader = PyPDFLoader("文件名稱.pdf")
docs = loader.load_and_split()

本文是使用PyPDFLoader來讀入PDF,LangChain中還有很多其他的API,可以參考官方文獻。官方文獻

Demo

本文有在GitHub放了我寫的PDF測試檔案叫做pdf_test.pdf,大家也可以拿來測試用。

loader = PyPDFLoader("pdf_test.pdf")

root@4be643ba6a94:/app# python3 langchain_rag_pdf.py
>>> 請給我50字的摘要
🇨🇳
Wei tsung chang 的簡介:碩士畢業、AI軟體工程師,熱心工作,喜歡撰寫教學文章。他的技術栈包括Python、JavaScript、C#、Kotlin等程式語言,以及 Git 版本控制、Docker 等知識。
(Translation: Introduction to Wei tsung chang: Master's degree holder, AI software engineer, enthusiastic about work, likes writing tutorial articles. His technical stack includes programming languages such as Python, JavaScript, C#, Kotlin, and version control tools like Git.)🇨🇳

>>> 文件中軟體工程師的名字叫什麼?
🤔
Answer: Wei Tsung Chang 碩士畢業,同樣可以稱呼為 Weiberson。 
(The software engineer's name is Wei Tsung Chang, and can also be called Weiberson.)

print(response) 也就是把retrieval_chain.invoke給print出來,可以讓大家更清楚RAG所生成東西的架構。

{'input': '這篇pdf在說什麼?',
'context': 
[Document(page_content='全部的PDF文字都會顯示在這裡', 
metadata={'source': 'weibert.pdf', 'page': 0})],
'answer': 'LLM給的答案會顯示在這裡.'}

References

https://huggingface.co/learn/cookbook/zh-CN/advanced_rag

https://chatgpt.com/share/e0f169d7-8620-4468-ba0a-581e7d9f5676

https://medium.com/@jackcheang5/%E5%BB%BA%E6%A7%8B%E7%B0%A1%E6%98%93rag%E7%B3%BB%E7%B5%B1-ca4e593f3fed

https://www.linkedin.com/pulse/beginners-guide-retrieval-chain-using-langchain-vijaykumar-kartha-kuinc?trk=article-ssr-frontend-pulse_little-text-block

https://myapollo.com.tw/blog/langchain-tutorial-retrieval/

    喜歡 Weiberson 的文章嗎?在這裡留下你的評論!本留言區支援 Markdown 語法