langchain框架輕松實現本地RAG

一 什么是RAG?

? ? ? RAG(Retrieval-Augmented Generation)是一種結合了檢索和生成模型的方法,主要用于解決序列到序列的任務,如問答、對話系統、文本摘要等。它的核心思想是通過從大量文檔中檢索相關信息,然后利用這些信息來增強生成模型的輸出。

原理如下圖:

二 RAG實現思路

? RAG實現思路分為準備數據與應用檢索兩階段,如圖:

階段一 數據準備階段

  1. 數據提取:對多種格式(如 PDF、Word、Markdown、數據庫和 API 等)的數據進行處理,包括過濾、壓縮、格式化等,使其成為統一的范式。
  2. 分塊(chunking):將初始文檔分割成合適大小的塊,在不丟失語義的前提下,盡量保持句子或段落的完整性。可以根據換行、句號、問號、感嘆號等進行切分,或以其他合適的原則進行分割。最終將語料分割成 chunk 塊,以便在檢索時獲取相關性最高的 top_n 塊。
  3. 向量化(embedding):使用嵌入模型將文本數據轉化為向量矩陣。常用的 embedding 模型有很多,例如 moka-ai/m3e-base、ganymedenil/text2vec-large-chinese 等,也可以參考 huggingface 推出的嵌入模型排行榜。向量的質量會直接影響到后續檢索的效果。
  4. 數據入庫:將向量化后的數據構建索引,并寫入向量數據庫。適用于 RAG 場景的向量數據庫包括 facebookresearch/faiss(本地)、chroma、elasticsearch、milvus 等。可以根據業務場景、硬件、性能需求等因素綜合考慮,選擇合適的數據庫。

階段二?應用階段

  1. 問題向量化:使用與數據準備階段相同的嵌入模型,將用戶的提問轉化為向量。
  2. 數據檢索:通過計算查詢向量與向量數據庫中存儲向量的相似性得分,采用相似性檢索的方式從數據庫中召回與提問最相關的知識。常見的相似性計算方法包括余弦相似性、歐氏距離、曼哈頓距離等。
  3. 獲取索引數據:獲取檢索到的相關數據。
  4. 注入 prompt:將用戶查詢和檢索到的相關知識整合成一個提示模板。prompt 中通常包括任務描述、背景知識(即檢索得到的相關內容)、任務指令(一般為用戶提問)等。根據任務場景和大模型性能,也可以在 prompt 中適當加入其他指令以優化大模型的輸出。
  5. LLM 生成答案:將增強后的提示輸入到大型語言模型(LLM)中,讓模型生成相應的答案。

三 用Python代碼實現RAG

使用langchain框架用python代碼實現,代碼如下:

import os
import faiss
from langchain.retrievers import ContextualCompressionRetriever
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import PromptTemplate
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.llms.ollama import Ollama
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_text_splitters import RecursiveCharacterTextSplitter
import config as cfg
from log_util import LogUtil
from auto_directory_loader import AutoDirectoryLoader
from BCEmbedding.tools.langchain import BCERerankdoc_path = cfg.load_doc_dir# 在線 embedding model
embedding_model_name = 'maidalun1020/bce-embedding-base_v1'model1_path = r'F:\ai\ai_model\maidalun1020_bce_embedding_base_v1'
model2_path = r'F:\ai\ai_model\maidalun1020_bce_reranker_base_v1'# 本地模型路徑
embedding_model_kwargs = {'device': 'cuda:0'}
embedding_encode_kwargs = {'batch_size': 32, 'normalize_embeddings': True}embeddings = HuggingFaceEmbeddings(model_name=model1_path,model_kwargs=embedding_model_kwargs,encode_kwargs=embedding_encode_kwargs
)reranker_args = {'model': model2_path, 'top_n': 5, 'device': 'cuda:0'}reranker = BCERerank(**reranker_args)# 檢查FAISS向量庫是否存在
if os.path.exists(cfg.faiss_index_path):# 如果存在,從本地加載LogUtil.info("FAISS index exists. Loading from local path...")vectorstore = FAISS.load_local(cfg.faiss_index_path, embeddings, allow_dangerous_deserialization=True)LogUtil.info("FAISS index exists. Loading from local path...")else:# 如果不存在,加載txt文件并創建FAISS向量庫LogUtil.info("FAISS index does not exist. Loading txt file and creating index...")loader = AutoDirectoryLoader(doc_path, glob="**/*.txt")docs = loader.load()LogUtil.info(f"Loaded documents num:{len(docs)}")# 從文檔創建向量庫# 文本分割text_splitter = RecursiveCharacterTextSplitter(chunk_size=cfg.chunk_size, chunk_overlap=cfg.chunk_overlap)documents = text_splitter.split_documents(docs)LogUtil.info(f"Text splits num :{len(documents)}", )# 創建向量存儲vectorstore = FAISS.from_documents(documents, embeddings)LogUtil.info("create db ok.")# 保存向量庫到本地vectorstore.save_local(cfg.faiss_index_path)LogUtil.info("Index saved to local ok.")# 將索引搬到 GPU 上
res = faiss.StandardGpuResources()
gpu_index = faiss.index_cpu_to_gpu(res, 0, vectorstore.index)
vectorstore.index = gpu_indexretriever = vectorstore.as_retriever(search_type="mmr", search_kwargs={"k": 10})
test_ask="宴桃園豪杰三結義有誰參加了?"
# 調試查看結果
retrieved_docs = retriever.invoke(test_ask)
for doc in retrieved_docs:print('++++++單純向量庫提取++++++++')print(doc.page_content)compression_retriever = ContextualCompressionRetriever(base_compressor=reranker, base_retriever=retriever
)response = compression_retriever.get_relevant_documents(test_ask)print("============================================compression_retriever")
print(response)
print("---------------------end")# 定義Prompt模板
prompt_template = """
問題:{question}相關信息:
{retrieved_documents}請根據以上信息回答問題。
"""prompt = PromptTemplate(input_variables=["question", "retrieved_documents"],template=prompt_template,
)# 創建LLM模型
llm = Ollama(model="qwen2:7b")def format_docs(all_docs):txt = "\n\n".join(doc.page_content for doc in all_docs)print('+++++++++使用bce_embedding + bce-reranker 上下文內容++++++')print(txt)return txtrag_chain = ({"retrieved_documents": compression_retriever | format_docs, "question": RunnablePassthrough()}| prompt| llm| StrOutputParser()
)r = rag_chain.invoke(test_ask)
print("++++++加 LLM模型處理最終結果++++++++")
print(r)

?在上面代碼中我準備了一些文檔,上傳到向量庫,其中就有三國演義的,并提出了問題:宴桃園豪杰三結義有誰參加了?運行后回答也與文檔一致,測試結果正確,并在不同的環節輸出相應的結果,如下圖:

第一步,直接向量庫檢索,相近最近的10條內容如下:

經過?bce-embedding與bce_reranker兩在模型的處理,結果也是準確的

?再提交給LLM處理后的效果

?本地環境:win10系統,本地安裝了ollama 并使用的是阿里最新的qwen2:7b,其實qwen:7b測試結果也是準確的。另外還使用了bce-embedding作為嵌入模型,之前測試使用過Lam2+nomic-embed-text做了很多測試發現中文無論怎么調試,都不是很理想,回答的問題總是在胡說八道的感覺。RAG應用個人感覺重點資料輸入這塊也很重要,像圖片里的文字非得要ocr技術,這一點發現有道的qanything做得非常好,以后看來要花點時間查看qanything的源代碼好好惡補一下自己這一塊。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/39885.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/39885.shtml
英文地址,請注明出處:http://en.pswp.cn/web/39885.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vue3-openlayers 圖標閃爍、icon閃爍、marker閃爍

本篇介紹一下使用vue3-openlayers 圖標閃爍、icon閃爍、marker閃爍 1 需求 圖標閃爍、icon閃爍、marker閃爍 2 分析 圖標閃爍、icon閃爍、marker閃爍使用ol-animation-fade組件 3 實現 <template><ol-map:loadTilesWhileAnimating"true":loadTilesWh…

讀人工智能全傳03分治策略

1. 黃金年代 1.1. 圖靈在他發表的論文《計算機器與智能》中介紹了圖靈測試&#xff0c;為人工智能學科邁出第一步做出了重大貢獻 1.2. 美國在第二次世界大戰后幾十年里計算機技術發展的特色&#xff0c;也是美國在未來60年內確立人工智能領域國際領先地位的核心 1.3. 1955年…

lodash中flush的使用(debounce、throttle)

在項目的配置中&#xff0c;看到了一個請求&#xff0c;類似是這樣的 import { throttle } from lodash-es// 請求函數 async function someFetch(){const {data} await xxx.post()return data }// 節流函數 async function throttleFn(someFetch,1000)// 執行拿到數據函數 a…

leetcode--二叉樹中的最長交錯路徑

leetcode地址&#xff1a;二叉樹中的最長交錯路徑 給你一棵以 root 為根的二叉樹&#xff0c;二叉樹中的交錯路徑定義如下&#xff1a; 選擇二叉樹中 任意 節點和一個方向&#xff08;左或者右&#xff09;。 如果前進方向為右&#xff0c;那么移動到當前節點的的右子節點&…

大數據開發中的數據生命周期管理

上班越久&#xff0c;發現有些數據一直放在那里&#xff0c;根本沒有流動&#xff0c;完全沒有發揮價值&#xff0c;數據是有生命周期的&#xff0c;而且生命周期管理得好&#xff0c;工作就會更輕松。 目錄 引言數據創建示例代碼 數據存儲示例代碼 數據使用示例代碼 數據維護示…

JavaScript中閉包的理解

閉包&#xff08;Closure&#xff09;概念&#xff1a;一個函數對周圍狀態的引用捆綁在一起&#xff0c;內層函數中訪問到其外層函數的作用域。簡單來說;閉包內層函數引用外層函數的變量&#xff0c;如下圖&#xff1a; 外層在使用一個函數包裹住閉包是對變量的保護&#xff0c…

學習python常用的英語單詞,有音標,有音節劃分,適合英語基礎差的人來入門

if [?f] 如果 else [els] 否則 while [wa?l] 當...的時候 for [f?:r] “對于”或“遍歷”&#xff0c;適合于 break [brek] 中斷 continue [k?nt?nju:] 繼續 con ti nue [k?n t? nju:] pass [pɑ:s] 通過 height [ha?t] 高度 weight [we?t] 重量 keyword [ki:w…

sping-10

什么是 bean 裝配 在Java中&#xff0c;bean裝配是一種將對象&#xff08;也稱為bean&#xff09;與其他對象之間建立關聯關系的方法。這種裝配可以通過手動編寫代碼來實現&#xff0c;也可以使用依賴注入框架&#xff08;如Spring&#xff09;來自動完成。 在bean裝配中&…

【計算機視覺系列實戰教程 (實戰02)】:基于特征點匹配的圖像配準

這里寫目錄標題 1、特征點提取(1)GFTT算法提取特征點A.What&#xff08;什么是GFTT&#xff09;B.GFTT的優勢C.How&#xff08;如何使用GFTT算法提取圖像特征點&#xff09; (2)FAST算法提取特征點A.What&#xff08;什么是FAST角點&#xff09;B.FAST角點的強度值C.How&#x…

每日Attention學習8——Rectangular self-Calibration Attention

模塊出處 [ECCV 24] [link] [code] Context-Guided Spatial Feature Reconstruction for Efficient Semantic Segmentation 模塊名稱 Rectangular self-Calibration Attention (RCA) 模塊作用 空間注意力 模塊結構 模塊代碼 import torch import torch.nn as nn import tor…

Ubuntu 22.04.1 LTS 離線安裝Docker

確定linux版本 cat /etc/lsb-release DISTRIB_IDUbuntuDISTRIB_RELEASE22.04DISTRIB_CODENAMEjammyDISTRIB_DESCRIPTION"Ubuntu 22.04.1 LTS"確定dpkg版本 sudo dpkg --print-architecture amd64下載地址 https://download.docker.com/linux/ubuntu/dists/jamm…

C++ | Leetcode C++題解之第216題組合總和III

題目&#xff1a; 題解&#xff1a; class Solution { private:vector<vector<int>> res;void backtracking(int k, int n, vector<int> ans){if(k 0 || n < 0){if(k 0 && n 0){res.emplace_back(ans);}return;}int start (ans.size() 0 ?…

深入解析Transformer中的多頭自注意力機制:原理與實現

深入解析Transformer中的多頭自注意力機制&#xff1a;原理與實現 Transformer模型自2017年由Vaswani等人提出以來&#xff0c;已經成為自然語言處理&#xff08;NLP&#xff09;領域的一個里程碑。其核心機制之一——多頭自注意力&#xff08;Multi-Head Attention&#xff0…

字節一年,人間三年

想來字節做研發&#xff0c;可以先看我這三年的體會和建議。 大家好&#xff0c;我是白露啊。 今天和大家分享一個真實的故事&#xff0c;是關于字節網友分享自己三年的工作經歷和感受。 由于白露也曾在字節待過兩年&#xff0c;可以說&#xff0c;說的都對。 你有沒有想過來…

javascript url 傳遞參數中文亂碼問題解決方案

在 JavaScript 中&#xff0c;傳遞 URL 參數時&#xff0c;如果參數包含中文字符&#xff0c;可能會出現亂碼問題。解決這一問題可以使用 encodeURIComponent 和 decodeURIComponent 函數。這些函數會對 URL 參數進行編碼和解碼&#xff0c;確保特殊字符&#xff08;包括中文字…

填報高考志愿,怎樣正確地選擇大學專業?

大學專業的選擇&#xff0c;會關系到未來幾年甚至一輩子的發展方向。這也是為什么很多人結束高考之后就開始愁眉苦臉&#xff0c;因為他們不知道應該如何選擇大學專業&#xff0c;生怕一個錯誤的決定會影響自己一生。 毋庸置疑&#xff0c;在面對這種選擇的時候&#xff0c;我…

全網最簡單的Java設計模式【三】工廠方法模式詳解

Java工廠方法模式詳解 一、概念介紹 1. 什么是工廠方法模式&#xff1f; 工廠方法模式&#xff08;Factory Method Pattern&#xff09;是一種創建型設計模式&#xff0c;它允許定義一個接口或抽象類來創建對象&#xff0c;但將實際對象的實例化延遲到子類中實現。工廠方法模…

mybatis mapper.xml 比較運算符(大于|小于|等于)的寫法: 轉義和<![CDATA[]]>

文章目錄 引言I 使用xml 原生轉義的方式進行轉義II 使用 <![CDATA[ 內容 ]]>引言 應用場景:查詢時間范圍 背景:在 *.xml 中使用常規的 < > = <= >= 會與xml的語法存在沖突 <![CDATA[]]> 比 轉義符 來的繁瑣 <![CDATA[]]> 表示xml解析器忽略…

c++ 聯合(Union)的特性和使用

聯合&#xff08;Union&#xff09;是一種特殊的數據結構&#xff0c;允許在同一內存位置存儲不同的數據類型。一個 union 可以有多個數據成員&#xff0c;但是在任意時刻只有一個數據成員可以有值。當某個成員被賦值后其他成員變為未定義狀態。以下是聯合的主要特點和使用方式…

工程安全監測儀器振弦采集儀提升工程質量和安全水平

工程安全監測儀器振弦采集儀提升工程質量和安全水平 振弦采集儀是一種重要的工程安全監測儀器&#xff0c;可以用來監測建筑物、橋梁、隧道等工程結構的振動情況。它通過測量結構物的振動頻率和振幅&#xff0c;可以提供關鍵的數據用于評估結構的安全性和穩定性。振弦采集儀在…