大模型應用:如何使用Langchain+Qwen部署一套Rag檢索系統

一、TL;DR?

  1. 從0-1使用qwen chat?model+ langchain的鏈式架構搭建一套rag系統
  2. 詳細介紹了Langchain的工具鏈的調用流程
  3. 簡單介紹了可能會出現什么問題

二、方法

參考開源鏈接:https://github.com/Aphasia0515/self_llm/

2.1 硬件和軟件依賴

?類型需求備注
硬件? ? ??
  1. 顯存 >= 24B

實測:

  1. Qwen7B >= 24B
  2. Qwen32B >= 60B 左右
  3. Qwen1B 大概在6B左右(記憶里)
軟件
  1. ubuntu20.04
  2. cuda11.8
  3. py3.8
  1. 其實現在大多數的社區鏡像基本滿足要求,因為Qwen的鏡像都是比較新的依賴
  2. 但是訓練鏡像尤其要注意,我之前就遇到了Qwen和InternVL的訓練鏡像有沖突的問題

2.2 模型下載和準備

注意:模型下載記得從mirror-huggingface上下載,國內打不開huggingface

模型作用?備注
QwenRag系統的生成器、chat模型
  1. 注意根據自己的顯存選擇合適的模型
  2. 注意:1B/4B/7B的差異還是比較明顯的(從天梯圖里可以看到)
?Sentence Transformer?對文本進行向量化

2.3 Rag的文本庫準備

這一節就不仔細講了,將所有你需要的參考文件知識庫放在某個指定目錄下,本文只做txt和markdown的文檔拆分(用于后續的建庫)

三、知識庫提取和向量化

3.1 得到所有文檔的純本文內容

先遍歷2.3節的指定目錄,得到所有的markdown和txt文件,并存成list:

import os 
def get_files(dir_path):# args:dir_path,目標文件夾路徑file_list = []for filepath, dirnames, filenames in os.walk(dir_path):# os.walk 函數將遞歸遍歷指定文件夾for filename in filenames:# 通過后綴名判斷文件類型是否滿足要求if filename.endswith(".md"):# 如果滿足要求,將其絕對路徑加入到結果列表file_list.append(os.path.join(filepath, filename))elif filename.endswith(".txt"):file_list.append(os.path.join(filepath, filename))return file_list

接下來對list里面的內容進行讀取和加載,此處使用LangChain提供的FileLoader進行加載

  1. 注意:此處得到的其實還是純文本loader,而非真正的文本塊
from tqdm import tqdm
from langchain.document_loaders import UnstructuredFileLoader
from langchain.document_loaders import UnstructuredMarkdownLoaderdef get_text(dir_path):# args:dir_path,目標文件夾路徑# 首先調用上文定義的函數得到目標文件路徑列表file_lst = get_files(dir_path)# docs 存放加載之后的純文本對象docs = []# 遍歷所有目標文件for one_file in tqdm(file_lst):file_type = one_file.split('.')[-1]if file_type == 'md':loader = UnstructuredMarkdownLoader(one_file)elif file_type == 'txt':loader = UnstructuredFileLoader(one_file)else:# 如果是不符合條件的文件,直接跳過continuedocs.extend(loader.load())return docs

3.2 對所有的文本進行分塊并向量化

LangChain使用多種文本分塊工具,示例代碼使用的時字符串遞歸分割器,并選擇分塊大小時500,塊重疊長度是150,分塊代碼如下所示:

注意:我上一篇博客所說的,分塊的大小不同的模型有不同的選擇,只有最合適的,沒有固定的

from langchain.text_splitter import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=150)
split_docs = text_splitter.split_documents(docs)

分塊完后,使用2.2節的下載好的模型(sentence Transformer)此時進一步進行向量化,LangChain 提供了直接引入 HuggingFace 開源社區中的模型進行向量化的接口::

注意:這個是直接加載本地路徑

from langchain.embeddings.huggingface import HuggingFaceEmbeddingsembeddings = HuggingFaceEmbeddings(model_name="/root/autodl-tmp/embedding_model")

加載玩模型后,使用?Chroma 作為向量數據庫,基于上文分塊后的文檔以及加載的開源向量化模型,將語料加載到指定路徑下的向量數據庫:

from langchain.vectorstores import Chroma# 定義持久化路徑
persist_directory = 'data_base/vector_db/chroma'
# 加載數據庫
vectordb = Chroma.from_documents(documents=split_docs,embedding=embeddings,persist_directory=persist_directory  # 允許我們將persist_directory目錄保存到磁盤上
)
# 將加載的向量數據庫持久化到磁盤上
vectordb.persist()

運行上述腳本,就得到一個本地構建已持久化的向量數據庫,后續直接導入該數據庫即可,無需重復構建

四、接入LLM-Chat Model

注意:本步驟接入任何llm模型其實都是可以的,主要還是看這個檢索框架的整體實現。

4.1 QwenLM接入LangChain

本地部署Qwen llm模型,然后將QwenLM接入到Langchain框架里面,完成自定義 LLM 類之后,可以以完全一致的方式調用 LangChain 的接口,而無需考慮底層模型調用的不一致。

  1. 從 LangChain.llms.base.LLM 類繼承一個子類,并重寫構造函數與 _call 函數
from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfigclass QwenLM(LLM):# 基于本地 Qwen 自定義 LLM 類tokenizer : AutoTokenizer = Nonemodel: AutoModelForCausalLM = Nonedef __init__(self, model_path :str):# model_path: Qwen 模型路徑# 從本地初始化模型super().__init__()print("正在從本地加載模型...")model_dir = '/root/autodl-tmp/qwen/Qwen-7B-Chat'self.tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True)self.model = AutoModelForCausalLM.from_pretrained(model_dir, device_map="auto", trust_remote_code=True).eval()# Specify hyperparameters for generationself.model.generation_config = GenerationConfig.from_pretrained(model_dir, trust_remote_code=True) # 可指定不同的生成長度、top_p等相關超參print("完成本地模型的加載")def _call(self, prompt : str, stop: Optional[List[str]] = None,run_manager: Optional[CallbackManagerForLLMRun] = None,**kwargs: Any):# 重寫調用函數response, history = self.model.chat(self.tokenizer, prompt , history=[])return response@propertydef _llm_type(self) -> str:return "QwenLM"

上述代碼在構造函數里直接加載了qwen模型,如果有其他的llm model也可以一并加載進去,?_call 函數是 LLM 類的核心函數,LangChain 會調用該函數來調用 LLM來使用qwen的chat能力。

開源倉庫里面將上述代碼封裝為 LLM.py,后續將直接從該文件中引入自定義的 LLM 類,直接使用from LLM import QwenLM。

五、構建檢索問答鏈

LangChain 通過提供檢索問答鏈對象來實現對于 RAG 全流程的封裝

  1. 我們可以調用一個 LangChain 提供的 RetrievalQA 對象,通過初始化時填入已構建的數據庫和自定義 LLM 作為參數,來簡便地完成檢索增強問答的全流程,LangChain 會自動完成基于用戶提問進行檢索、獲取相關文檔、拼接為合適的 Prompt 并交給 LLM 問答的全部流程。

5.1 導入向量數據庫

from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
import os# 定義 Embeddings
embeddings = HuggingFaceEmbeddings(model_name="/root/autodl-tmp/embedding_model")# 向量數據庫持久化路徑
persist_directory = 'data_base/vector_db/chroma'# 加載數據庫
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embeddings
)

注意:向量數據庫里面存儲的是分塊的文檔和對應的向量,是embedding和index的關系

5.2 實例化自定義的QwenLM對象

from LLM import QwenLM
llm = QwenLM(model_path = "/root/autodl-tmp/qwen")
llm.predict("你是誰")

5.3 構建Prompt Template

prompt Template的作用是通過將用戶input、rag檢索得到的知識片段組合成input:

  1. 是一個帶變量的字符串
  2. 在檢索之后,LangChain 會將檢索到的相關文檔片段填入到 Template 的變量中,從而實現帶知識的 Prompt 構建。
from langchain.prompts import PromptTemplate# 我們所構造的 Prompt 模板
template = """使用以下上下文來回答最后的問題。如果你不知道答案,就說你不知道,不要試圖編造答案。盡量使答案簡明扼要。總是在回答的最后說“謝謝你的提問!”。
{context}
問題: {question}
有用的回答:"""# 調用 LangChain 的方法來實例化一個 Template 對象,該對象包含了 context 和 question 兩個變量,在實際調用時,這兩個變量會被檢索到的文檔片段和用戶提問填充
QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],template=template)

5.4 直接檢索問答

最后,可以調用 LangChain 提供的檢索問答鏈構造函數,基于我們的自定義 LLM、Prompt Template 和向量知識庫來構建一個基于 Qwen 的檢索問答鏈:

question = "什么是QwenLM"
result = qa_chain({"query": question})
print("檢索問答鏈回答 question 的結果:")
print(result["result"])# 僅 LLM 回答效果
result_2 = llm(question)
print("大模型回答 question 的結果:")
print(result_2)

可以看到,使用檢索問答鏈生成的答案更接近知識庫里的內容。

六、部署WebDemo

七、可優化的點

上述用的是開源代碼,如果實際工程中可以從哪里優化呢?

  1. 檢索的文本是大文本或者超大文本(>2K文本):
    1. summary,對大文本進行 map-reduce summary
    2. k-means(BRV steps)
  2. 檢索內容太多不準該怎么辦?
  3. 等等 明天再寫把

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

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

相關文章

決策樹:化繁為簡的智能決策利器

本文來自「大千AI助手」技術實戰系列,專注用真話講技術,拒絕過度包裝。 想象一個相親決策過程: 對方收入 > 30萬? → 是 → 見面否 → 顏值高? → 是 → 先聊聊否 → 放棄 這種層層遞進的判斷結構,正是…

html中的盒子標簽div標簽,有序列表,無序列表

div標簽 div標簽對于分析數據很重要&#xff0c;因為數據在頁面中展示是以區域的形式展示的&#xff0c;而查找數據需要先找到盒子名稱在繼續向下找。前端頁面布局中有兩種布局方式&#xff0c;一種是通過表格布局&#xff0c;一種是通過divcss來布局。 <!DOCTYPE html>…

【Redis】解碼Redis中hash類型:理解基礎命令,以及內部編碼方式和使用場景

&#x1f4da;?前言 &#x1f31f;&#x1f31f;&#x1f31f;精彩讀導 本次我們將全面剖析Redis的核心技術要點&#xff0c;包括其豐富的數據類型體系、高效的編碼方式以及秒級響應的性能奧秘。對于渴望深入理解Redis底層機制的技術愛好者&#xff0c;這是一次難得的學習機會…

AI工具在學術寫作中的倫理邊界與誠信規范的平衡

AI寫作助手的興起與爭議 人工智能技術的飛速發展&#xff0c;學境思源&#xff0c;ChatGPT、Grok、Claude 等AI寫作工具逐漸走入高校師生的視野。一鍵生成論文初稿&#xff01;從課程作業到畢業論文&#xff0c;不少學生已經嘗試讓AI參與寫作過程&#xff0c;希望借此提升效率…

課程專注度分析系統項目

前端代碼: <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>課堂專注度分析系統 - 科技…

區塊鏈是什么

區塊鏈的本質與機制 1. 核心定義 區塊鏈 加密的分布式記賬技術&#xff0c;融合密碼學、網絡學、金融學三大學科。 去中心化&#xff1a;數據存儲于全網節點&#xff08;如百萬臺計算機&#xff09;&#xff0c;而非單一數據庫。不可篡改&#xff1a;修改數據需控制全網51%以…

用可觀測工具高效定位和查找設計中深度隱藏的bug

軟件仿真擁有最佳的信號可見性和調試靈活性,被大多數工程師熟練使用,能夠高效捕獲很多顯而易見的常見錯誤。 然而,由軟件實現的數字仿真過程運行速度有限,很難做到100%代碼覆蓋。導致那些深度隱藏的設計問題,將不可避免的逃逸,只能以FPGA在線調試方式解決。 01 為什么全…

華為OD-2024年E卷-字符串化繁為簡[200分] -- python

問題描述&#xff1a; 給定一個輸入字符串&#xff0c;字符串只可能由英文字母(a~z、A~Z) 和左右小括號((、))組成。當字符串里存在小括號時&#xff0c;小括號是成對的&#xff0c;可以有一個或多個小括號對&#xff0c;小括號對不會嵌套&#xff0c;小括號對內可以包含1個或…

使用sealos安裝k8s

一、準備工作&#xff08;所有節點需執行&#xff09;? 1、系統要求 操作系統&#xff1a;本文為Ubuntu 20.0.4 配置&#xff1a;不同主機名、時間同步、SSH 免密互通、關閉防火墻/SELinux/swap。 資源&#xff1a;建議 ≥2核 CPU、2GB 內存&#xff08;生產環境需更高&am…

Pytorch 實戰四 VGG 網絡訓練

系列文章目錄 文章目錄 系列文章目錄前言一、源碼1. 解決線程沖突2.代碼框架 二、代碼詳細介紹1.基礎定義2. epoch 的定義3. 每組圖片的訓練和模型保存 前言 前面我們已經完成了數據集的制作&#xff0c;VGG 網絡的搭建&#xff0c;現在進行網絡模型的訓練。 一、源碼 import t…

課程專注度分析系統文檔

一、項目概述 本項目基于 Flask 框架開發&#xff0c;結合計算機視覺技術&#xff08;利用 YOLOv10 等模型 &#xff09;&#xff0c;實現對課堂視頻的智能分析。可檢測視頻中學生手機使用情況、面部表情&#xff08;專注、分心等 &#xff09;&#xff0c;統計專注度、手機使…

中國設計 全球審美 | 安貝斯新產品發布會:以東方美學開辟控制臺仿生智造新紀元

6月17日&#xff0c;安貝斯&#xff08;武漢&#xff09;控制技術有限公司&#xff08;以下簡稱“安貝斯”&#xff09;在武漢隆重舉行“新產品發布暨協會聯合創新峰會”。近百位來自政府機構、行業協會、行業用戶及戰略合作伙伴的嘉賓齊聚現場&#xff0c;共同見證以“中國設計…

在微信小程序wxml文件調用函數實現時間轉換---使用wxs模塊實現

1. 創建 WXS 模塊文件&#xff08;推薦單獨存放&#xff09; 在項目目錄下新建 utils.wxs 文件&#xff0c;編寫時間轉換邏輯&#xff1a; // utils.wxs module.exports {// 將毫秒轉換為分鐘&#xff08;保留1位小數&#xff09;convertToMinutes: function(ms) {if (typeo…

ByteMD 插件系統詳解

ByteMD 插件系統詳解 ByteMD 的插件系統是其強大擴展性的核心。它允許開發者在 Markdown 解析、AST 轉換、HTML 渲染、以及編輯器 UI 交互的各個階段注入自定義邏輯。這得益于 ByteMD 深度集成了 unified 處理器和其豐富的生態系統&#xff08;remark 用于 Markdown&#xff0c…

每日一練之 Lua 表

Lua 的 table 是什么數據結構&#xff1f;如何創建和訪問&#xff1f; 數據結構:Lua的table是一種哈希表&#xff0c;使用鍵值對存儲數據&#xff0c;支持動態擴容 創建方式: local t1 {} local t2 {10,20,30} local t3 {name"Alice",age25}訪問方式&#xff1a…

實現自動胡批量抓取唯品會商品詳情數據的途徑分享(官方API、網頁爬蟲)

在電商領域&#xff0c;數據就是企業的核心資產。無論是市場分析、競品研究&#xff0c;還是精準營銷&#xff0c;都離不開對大量商品詳情數據的深入挖掘。唯品會作為知名的電商平臺&#xff0c;其豐富的商品信息對于眾多從業者而言極具價值。本文將詳細探討實現自動批量抓取唯…

Zephyr 高階實踐:徹底講透 west 構建系統、模塊管理與跨平臺 CI/CD 配置

本文是 Zephyr 項目管理體系的高階解構與實戰指南&#xff0c;全面覆蓋 west 構建系統原理、模塊解耦與 west.yml 多模塊維護機制&#xff0c;結合企業級多平臺 CI/CD 落地流程&#xff0c;深入講解如何構建可靠、可維護、跨芯片架構的一體化 Zephyr 工程。 一、為什么 Zephyr …

我開源了一套springboot3快速開發模板

我開源了一套springboot3快速開發模板 開箱即用、按需組合、可快速二次開發的后端通用模板。 ? 主要特性 Spring Boot 3.x Java 17&#xff1a;跟隨 Spring 最新生態&#xff0c;利用現代語法特性。多模塊分層&#xff1a;common 抽象通用能力、starter 負責啟動、modules…

OpenCV CUDA模塊設備層-----在GPU上計算兩個uchar1類型像素值的反正切(arctangent)比值函數atan2()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 對輸入的兩個 uchar1 像素值 a 和 b&#xff0c;先分別歸一化到 [0.0, 1.0] 浮點區間&#xff0c;然后計算它們的 四象限反正切函數。 函數原型…

從C++編程入手設計模式——觀察者模式

從C編程入手設計模式——觀察者模式 ? 觀察者模式簡直就是字如其名&#xff0c;觀察觀察&#xff0c;觀察到了告訴別人。觀察手的作用如此&#xff0c;觀察者模式的工作機制也是如此。這個模式的核心思路是&#xff1a;一個對象的狀態發生變化時&#xff0c;自動通知依賴它的…