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.mzph.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…

每日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…

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 ?…

字节一年,人间三年

想来字节做研发&#xff0c;可以先看我这三年的体会和建议。 大家好&#xff0c;我是白露啊。 今天和大家分享一个真实的故事&#xff0c;是关于字节网友分享自己三年的工作经历和感受。 由于白露也曾在字节待过两年&#xff0c;可以说&#xff0c;说的都对。 你有没有想过来…

填报高考志愿,怎样正确地选择大学专业?

大学专业的选择&#xff0c;会关系到未来几年甚至一辈子的发展方向。这也是为什么很多人结束高考之后就开始愁眉苦脸&#xff0c;因为他们不知道应该如何选择大学专业&#xff0c;生怕一个错误的决定会影响自己一生。 毋庸置疑&#xff0c;在面对这种选择的时候&#xff0c;我…

mybatis mapper.xml 比较运算符(大于|小于|等于)的写法: 转义和<![CDATA[]]>

文章目录 引言I 使用xml 原生转义的方式进行转义II 使用 <![CDATA[ 内容 ]]>引言 应用场景:查询时间范围 背景:在 *.xml 中使用常规的 < > = <= >= 会与xml的语法存在冲突 <![CDATA[]]> 比 转义符 来的繁琐 <![CDATA[]]> 表示xml解析器忽略…

工程安全监测仪器振弦采集仪提升工程质量和安全水平

工程安全监测仪器振弦采集仪提升工程质量和安全水平 振弦采集仪是一种重要的工程安全监测仪器&#xff0c;可以用来监测建筑物、桥梁、隧道等工程结构的振动情况。它通过测量结构物的振动频率和振幅&#xff0c;可以提供关键的数据用于评估结构的安全性和稳定性。振弦采集仪在…

【项目实践】贪吃蛇

一、游戏效果展示二、博客目标三、使用到的知识四、Win32 API 介绍 4.1 WIn32 API4.2 控制台程序4.3 控制屏幕上的坐标COORD4.4 GetStdHandle4.5 GetConsoleCursorInfo 4.5.1 CONSOLE_CURSOR_INFO 4.6 SetConsoleCursorInfo4.7 SetConsoleCursorPosition4.8 GetAsyncKeyState 五…

秋招突击——7/4——复习{}——新作{最长公共子序列、编辑距离}

文章目录 引言复习新作1143-最长公共子序列个人实现 参考实现编辑距离个人实现参考实现 贪心——买股票的最佳时机个人实现参考实现 贪心——55-跳跃游戏个人实现参考做法 总结 引言 昨天主要是面试&#xff0c;然后剩下的时间都是用来对面试中不会的东西进行查漏补缺&#xff…

项目管理实用表格与应用【项目文件资料分享】

项目管理基础知识 项目管理可分为五大过程组&#xff08;启动、规划、执行、监控、收尾&#xff09;十大知识领域&#xff0c;其中包含49个子过程 项目十大知识领域分为&#xff1a;项目整合管理、项目范围管理、项目进度管理、项目成本管理、项目质量管理、项目资源管理、项目…

标量场与向量场

标量场与向量场 flyfish 场 是一个函数&#xff0c;它把空间中的每一点关联到一个数值或一个数学对象&#xff08;如向量、张量等&#xff09;。在物理学中&#xff0c;场可以描述许多物理现象&#xff0c;例如温度分布、电场、磁场、压力场等。 标量场 标量场 是一个函数&…

【BUUCTF-PWN】9-ciscn_2019_n_8

不属于栈溢出&#xff0c;应该是比较简单的pwn&#xff0c;看懂代码逻辑使用pwntools 32位&#xff0c;开启了Stack、NX、PIE保护 执行效果&#xff1a; main函数 使用通义千问询问的代码解读&#xff1a; 即当var数组的第十四个元素是17就可以 这里可以用两种payload…

天环公益原创开发进度网站源码带后台免费分享

天环公益计划首发原创开发进度网站源码带后台免费分享 后台地址是&#xff1a;admin.php 后台没有账号密码 这个没有数据库 有能力的可以自己改 天环公益原创开发进度网站 带后台

微软中国全面撤店!我们到现场看了看

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 7月1日&#xff0c;微软官方发言人向媒体表示&#xff1a; “微软不断评估其零售策略以满足我们的客户不断变化的需求&#xff0c;微软已决定对中国大陆市场的渠道进行整合。客户仍可通过零售合作伙伴…

校园失物招领系统带万字文档java项目失物招领管理系统java课程设计java毕业设计springboot vue

文章目录 校园失物招领系统一、项目演示二、项目介绍三、万字字项目文档四、部分功能截图五、部分代码展示六、底部获取项目源码带万字文档&#xff08;9.9&#xffe5;带走&#xff09; 校园失物招领系统 一、项目演示 校园失物招领系统 二、项目介绍 语言: Java 数据库&…