langchain+qwen1.5-7b-chat搭建本地RAG系统

news2024/11/18 2:47:21

已开源:https://github.com/stay-leave/enhance_llm

概念

检索增强生成(Retrieval Augmented Generation, RAG)是一种结合语言模型和信息检索的技术,用于生成更准确且与上下文相关的输出。

通用模型遇到的问题,也是RAG所擅长的:

  1. 知识的局限性: RAG 通过从知识库、数据库、企业内部数据等外部数据源中检索相关信息,将其注入到模型提示词中,使模型能够利用这些信息进行推理和生成。这弥补了模型仅基于公开训练数据的不足,让其在面对实时性、非公开或离线数据时也能提供相关内容。

  2. 幻觉问题: 由于语言模型的底层运作基于数学概率,其输出本质上是一系列数值运算结果,因此在模型知识匮乏或不擅长的领域,可能会出现幻觉问题,即生成与现实脱节或错误的内容。RAG通过将检索到的准确且相关的信息作为输入的一部分,降低了幻觉问题的发生几率,使模型生成的内容与现实更为一致。

  3. 数据安全性: 对于企业来说,数据安全至关重要,将私有数据上传到第三方平台进行训练存在风险。RAG 可以在企业内部构建知识库或数据库,并从中检索信息,将其注入模型提示词。这一过程可以在本地进行,无需将数据上传到外部,从而确保数据安全。

基本工作流程包括三个主要步骤:

1. 检索(Retrieve)

  • 输入查询: 用户通过输入查询或问题来开始这个流程。
  • 相似性搜索: 系统将用户查询通过嵌入模型转换为向量,并在外部知识源中的向量数据库中进行相似性搜索。
  • 返回相关信息: 搜索会返回与查询最接近的前 k 个数据对象(上下文信息),这些对象来自于知识库、数据库或其他数据源。

2. 增强(Augment):

  • 填入模板: 用户查询与检索到的上下文信息被填入到一个提示模板中。
  • 构建完整提示: 这个模板整合了查询和相关信息,构建出一个完整的提示词,用于指导模型生成。

3. 生成(Generate)

  • 输入到 LLM: 构建好的提示被输入到大型语言模型(LLM),比如 GPT 或 Qwen。
  • 生成内容: 模型根据提示词中的信息生成相关内容,包括回答、文本或其他输出。

RAG 的优势

  • 即时性: 通过检索外部信息源,RAG 能够即时更新模型的知识,让其对实时性、非公开或离线的数据也能提供有效回应。
  • 准确性: 注入的相关信息提升了模型输出的准确性,减少了幻觉问题。
  • 数据安全: 可以在内部构建知识库,从而确保敏感数据不会外泄。

在这里插入图片描述这是有道开源的QAnything,可以拿来直接用,使用MILVUS数据库和langchain。画的这个图很好。

可以根据这个图来分析RAG系统的构建流程:
part1:indexing
1.数据读取:各种类型的数据都可以读取。
2.文档切分:因为一篇文档可能很大,模型的上下文窗口有限;用户query的答案一般只会在文档的某部分。
3.向量嵌入:文本向量化。
4.向量入库:将稠密向量存入向量数据库,如mivlus, Chroma,Faiss。个人觉得第一个最好,但是个人配置太麻烦,选择第二个。
在这里插入图片描述

part2:Retrieval and generation
1.检索:根据query从向量数据库中检索相关文档。
2.prompt增强:将召回的文档填入prompt作为外部知识。
3.生成:LLM基于增强的prompt生成回复。

part1:indexing

索引阶段,包含数据读取,切片,向量化,入库。
langchain提供了开发文档:https://python.langchain.com/docs/modules/data_connection/document_transformers/

数据读取

使用langchain_community.document_loaders,读取PDF,CSV文件。

from langchain_community.document_loaders.csv_loader import CSVLoader
from langchain_community.document_loaders import PyPDFLoader


# 读取csv,返回list
def load_csv(path):
    # 每条记录为一个元素
    loader = CSVLoader(
        file_path="project_1/data/clean.csv",
        encoding='utf-8' # 编码
    )
    data = loader.load()
    return data 


# 读取pdf,返回list
def load_pdf(path):
    # 是以每页为一个元素的
    loader = PyPDFLoader("project_1/data/1.pdf")
    pages = loader.load_and_split()
    return pages

csv的返回,取前两个:
在这里插入图片描述pdf的返回,取第一个:
在这里插入图片描述

文档切块

这里使用RecursiveCharacterTextSplitter,通过特定字符来分割,默认的字符列表是 [“\n\n”, “\n”, " ", “”]
块的大小是指字符的数量。

from langchain_text_splitters import RecursiveCharacterTextSplitter


text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=200, # 指定每个文本块的目标大小,这里设置为200个字符。
    chunk_overlap=50, # 指定文本块之间的重叠字符数,这里设置为50个字符。
    length_function=len, # 用于测量文本长度的函数,这里使用Python内置的`len`函数。
    is_separator_regex=False, # 指定`separators`中的分隔符是否应被视为正则表达式,这里设置为False,表示分隔符是字面字符。
    separators=["\n\n",  "\n",   " ",    ".",    ",",     ",",  "。", ] # 定义用于分割文本的分隔符列表。
)

pages = load_pdf("project_1/data/1.pdf")

texts = text_splitter.split_documents([pages[0].page_content])

返回也是一个list,可以看到两两之间是有重叠部分的。
在这里插入图片描述

向量化

使用BGE模型

from langchain.embeddings import HuggingFaceBgeEmbeddings
model_name = "project_2/bge-large-zh-v1.5"
model_kwargs = {'device': 'cuda'}
# # 当向量都被规范化(归一化)后,它们的范数都是1。
# 余弦相似度的计算只需要向量的点积运算,从而减少了计算的复杂度,加快了处理速度。
hf = HuggingFaceBgeEmbeddings(
    encode_kwargs = {'normalize_embeddings': True} 
    model_name=model_name,
    model_kwargs=model_kwargs,
    encode_kwargs=encode_kwargs,
    query_instruction="为这个句子生成表示以用于检索相关文章:"
)

embedding = hf.embed_query("你好!")
len(embedding)

存储嵌入

这里使用chroma数据库,参考:https://python.langchain.com/docs/integrations/vectorstores/chroma/

# 快速创建数据库
from langchain_chroma import Chroma
db = Chroma.from_documents(
   documents = texts, 
   embedding = hf,
   ids = None,
   collection_name = 'test1',
   collection_metadata = {"hnsw:space": "cosine"},
   persist_directory = 'project_1/chroma_db'
   )

# 相似度方法通过查询文本检索数据
query = "网络首发是什么"
docs = db.similarity_search(query)
print(docs[0].page_content)

检索出4个文本块
在这里插入图片描述

part2:Retrieval and generation

现在真正的RAG了

检索

可以直接将Chroma转换为检索器,会根据相关性分数返回

# 创建一个检索器
retriever = vectorstore.as_retriever(search_kwargs={"k": 10})

query = "萧炎是谁?"

# Get relevant documents ordered by relevance score
docs = retriever.invoke(query)

在这里插入图片描述

生成

将召回转为字符串,输入到prompt中,使用模型推理。

# 实例化自定义模型
llm = Qwen(mode_name_or_path = "/root/autodl-tmp/Qwen1.5-7B-Chat")

prompt = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)

output_parser = StrOutputParser()

# 构建 chain
chain = prompt | llm | output_parser

res = chain.invoke(
                    {
                    "context": format_docs(reordered_docs),
                    "question": "小医仙是谁?"
                    }
                    )

print(res)

直接用query进行召回
在这里插入图片描述Qwen1.5-7B-Chat的回复,看起来重点都抓住了。
在这里插入图片描述sft后的回答,训坏了
在这里插入图片描述dpo后的回答,怎么又拉起来了
在这里插入图片描述更新:
自己手动实现多轮对话
在这里插入图片描述
在这里插入图片描述使用dpo效果就是不错

在这里插入图片描述这个是sft的,训久了,过拟合。

在这里插入图片描述原始的模型结构,也不错。

在这里插入图片描述这个是4b的回答,参数小就是不行。

以上便是基础RAG的全流程,可以理解为两阶段的实现。

参考:
1.https://huggingface.co/docs/transformers/main_classes/text_generation
2.https://zhuanlan.zhihu.com/p/688926320
3.https://api.python.langchain.com/en/latest/vectorstores/langchain_community.vectorstores.chroma.Chroma.html#langchain_community.vectorstores.chroma.Chroma.from_documents
4.https://www.cnblogs.com/AlwaysSui/p/18144181
5.https://github.com/datawhalechina/self-llm/blob/master/Qwen1.5/02-Qwen1.5-7B-Chat%20%E6%8E%A5%E5%85%A5langchain%E6%90%AD%E5%BB%BA%E7%9F%A5%E8%AF%86%E5%BA%93%E5%8A%A9%E6%89%8B.md
6.https://python.langchain.com/docs/expression_language/get_started/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1642701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

头歌实践教学平台:三维图形观察OpenGL1.0

一.任务描述 根据提示,在右侧修改代码,并自己绘制出图形。平台会对你编写的代码进行测试。 1.本关任务 学习了解三维图形几何变换原理。 理解掌握OpenGL三维图形几何变换的方法。 理解掌握OpenGL程序的模型视图变换。 掌握OpenGL三维图形显示与观察的…

怎么用CAPL与Python交互

怎么用CAPL与其他应用程序交互 怎么用CAPL与Python交互 怎么用CAPL与Python交互 怎么用CAPL与其他应用程序交互前言1、CAPL怎么调Python?1.1CAPL调Python的命令1.2CAPL调用Python实例 2、怎么把python运行的结果返回给CAPL2.1通过环境变量 3、CAPL调Python的输入参…

OCC笔记:选择TopoDS_Shape顶点、边、面等等

1、通过AIS_InteractiveContext的函数访问当前选择的图形 hAISContext->InitSelected(); hAISContext->MoreSelected(); hAISContext->NextSelected(); hAISContext->SelectedShape(); 其中hAISContext->SelectedShape()通过StdSelect_…

C语言——rand函数

一、rand函数 这是一个在 C 标准库 <stdlib.h> 中定义的函数&#xff0c;用于生成伪随机数&#xff0c;默认情况下&#xff0c;它生成从 0 到 RAND_MAX 的伪随机数&#xff0c;其中 RAND_MAX 是一个常数&#xff0c;通常是 32767。 1、函数原型&#xff1a; 2、函数返回…

MongoDB的分片集群

MongoDB分片技术 介绍 ​ 分片&#xff08;sharding&#xff09;是MongoDB用来将大型集合分割到不同服务器上采用的方法。分片这种说法起源于关系型数据库。但是实际上非关系型数据库在分片方面相比于传统的关系型数据库更有优势。 ​ 与MySQL分库方案对比&#xff0c;MongoDB…

my-room-in-3d中的电脑,电视,桌面光带发光原理

1. my-room-in-3d中的电脑&#xff0c;电视&#xff0c;桌面光带发光原理 最近在github中&#xff0c;看到了这样的一个项目&#xff1b; 项目地址 我看到的时候&#xff0c;蛮好奇他这个光带时怎么做的。 最后发现&#xff0c;他是通过&#xff0c;加载一个 lightMap.jpg这个…

分布式与一致性协议之一致哈希算法(二)

一致哈希算法 使用哈希算法有什么问题 通过哈希算法&#xff0c;每个key都可以寻址到对应的服务器&#xff0c;比如&#xff0c;查询key是key-01,计算公式为hash(key-01)%3,警告过计算寻址到了编号为1的服务器节点A&#xff0c;如图所示。 但如果服务器数量发生变化&#x…

分享一篇关于AGI的短文:苦涩的教训

学习强化学习之父、加拿大计算机科学家理查德萨顿&#xff08; Richard S. Sutton &#xff09;2019年的经典文章《The Bitter Lesson&#xff08;苦涩的教训&#xff09;》。 文章指出&#xff0c;过去70年来AI研究走过的最大弯路&#xff0c;就是过于重视人类既有经验和知识&…

STM32控制DS1302时钟模块获取实时时间

时间记录&#xff1a;2024/3/30 一、知识点 &#xff08;1&#xff09;读写数据时序&#xff08;伪SPI协议&#xff09; 1.1 读写时序默认电平均为SCLK线低电平&#xff0c;CE线低电平 1.2 写数据&#xff0c;CE线拉高为高电平&#xff0c;开始传输数据&#xff0c;然后准备数…

2024年5月青岛教师编招聘报名详细流程

2024年5月青岛教师编招聘报名详细流程

【开发记录】青龙面板设置飞书机器人

接上篇文章&#xff0c;笔者在写上篇文章时对青龙面板的消息通知功能感兴趣&#xff0c;遂实验之&#xff0c;于是有了这篇文章。 首先参考这篇文章在群聊中引入一个机器人&#xff0c;此时可以获得该机器人的webhook。在青龙面板的通知设置中有larkKey一项&#xff0c;填入web…

[数据结构]————排序总结——插入排序(直接排序和希尔排序)—选择排序(选择排序和堆排序)-交换排序(冒泡排序和快速排序)—归并排序(归并排序)

文章涉及具体代码gitee&#xff1a; 登录 - Gitee.com 目录 1.插入排序 1.直接插入排序 总结 2.希尔排序 总结 2.选择排序 1.选择排序 ​编辑 总结 2.堆排序 总结 3.交换排序 1.冒泡排序 总结 2.快速排序 总结 4.归并排序 总结 5.总的分析总结 1.插入排…

用队列实现栈——leetcode刷题

题目的要求是用两个队列实现栈&#xff0c;首先我们要考虑队列的特点&#xff1a;先入先出&#xff0c;栈的特点&#xff1a;后入先出&#xff0c;所以我们的目标就是如何让先入栈的成员后出栈&#xff0c;后入栈的成员先出栈。 因为有两个队列&#xff0c;于是我们可以这样想&…

[Java EE] 多线程(七): 锁策略

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;Java …

ZOC8 for Mac v8.08.1激活版:卓越性能的SSH客户端

在远程连接和管理的世界中&#xff0c;ZOC8 for Mac以其卓越的性能和丰富的功能&#xff0c;成为了众多专业人士的首选SSH客户端。它支持SSH1、SSH2、Telnet、Rlogin、Serial等多种协议&#xff0c;让您轻松连接到远程服务器。ZOC8拥有简洁直观的界面和强大的功能设置&#xff…

VMware虚拟机中ubuntu使用记录(6)—— 如何标定单目相机的内参(张正友标定法)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、张正友相机标定法1. 工具的准备2. 标定的步骤(1) 启动相机(2) 启动标定程序(3) 标定过程的操作(5)可能的报错 3. 标定文件内容解析 前言 张正友相机标定法…

语义分割——铁路轨道数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 重…

typescript 对象数组和函数

typescript 对象数组和函数 对象 在JavaScript中&#xff0c;对象属于非原始类型。对象也是一种符合数组类型&#xff0c;由若干个对象属性构成。对象属性可以是任意数据类型&#xff0c;比如数组&#xff0c;函数或者对象等。当对象属性为函数的时候&#xff0c;称为方法。 …

vue3--element-plus-抽屉文件上传和富文本编辑器

一、封装组件 article/components/ArticleEdit.vue <script setup> import { ref } from vue const visibleDrawer ref(false)const open (row) > {visibleDrawer.value trueconsole.log(row) }defineExpose({open }) </script><template><!-- 抽…

Java与Go: 生产者消费者模型

什么是生产者消费者模型 生产者-消费者模型&#xff08;也称为生产者-消费者问题&#xff09;是一种常见的并发编程模型&#xff0c;用于处理多线程或多进程之间的协同工作。该模型涉及两个主要角色&#xff1a;生产者和消费者&#xff0c;一个次要角色&#xff1a;缓冲区。 生…