LLM - 使用 Langchain 实现本地 Naive RAG

目录

一.引言

二.构建本地 Langchain 库

1.Doc 知识文档

2.Split 文档切分

3.Encode 内容编码

4.Similar 本地库构建

三.缓存本地 Langchain 库

四.读取本地 Langchain 库

1.Load 读取缓存

2.Similar 预测

3.Add 添加文档

五.总结


一.引言

上一篇博客介绍了当下 RAG 的一些发展情况,主要有 Naive RAG、Advanced RAG 以及 Modular RAG,本文通过 Python langchain 库实现一个本地 RAG 的 demo,主要是体会 RAG 搜索增强的流程。本文主要聚焦 Langchain 本地知识库的构建,后续的 LLM 推理因为本机显存的限制,大家可以参考之前推理的博客。

Tips 本文主要从三个方面介绍本地知识库的构建:

- 构建本地 Langchain 知识库

- 缓存本地 Langchain 知识库

- 读取缓存 Langchain 知识库

由于 Langchain 库的更新比较快,有一些 API 的引入方式与用法稍有出入,博主这里的 python 版本为 3.8.6,Langchain 相关 package 版本如下:

二.构建本地 Langchain 库

1.Doc 知识文档

由于是构建本地知识库,所以我们需要获得各个内容的文档,这里我们整理了几篇汽车的新闻作为本地知识库的内容,主要是零跑、理想、小鹏、蔚来汽车的相关新闻。

以 lx.txt 为例,其包含新闻的全部文本:

有消息透露:截至昨晚(3月4日)MEGA大定还没破万,小定转大定的数量有限,不少客户回流到小鹏X9、腾势D9和问界M9。

这样的成绩一定是不符合理想原本的预期的。但自MEGA上市以来经历的网络舆论风向,似乎冥冥之中也指向了这个结果……

经过一年多精心设计的宣传造势,3月1日理想正式推出了它征战纯电市场的首款车型——MEGA。

大约是为了给新车上市增加一波热搜,在发布会之前,李想(理想汽车创始人、董事长)按照惯例再次亲自下场,试图直接蹭一波“苹果放弃造车”的热度。

但李厂长万万没想到,这次的剧情没有按照设计好的发展:热搜还是上了,但话题却非常尴尬——MEGA的设计被不少网友直呼像“棺材”。


汽车的造型设计见仁见智,欣赏不了MEGA的另类造型的确是一些消费者的真实看法。在理想的线下门店,汽车产经记者就遇到多位看车用户直言,对MEGA的配置十分满意,但造型难以接受。

而在这一波黑MEGA的舆论攻势里,“像棺材”虽说是一种更易于理解的具象化表达,但也确实是非常恶劣了。尤其对国人来说,这个“不吉利”的词一旦和一款车深度绑定,必定会对产品的终端销量造成不小的影响。

总之,舆论走向超出了最初的预期,理想彻底怒了,官方直接开始举报、删帖+律师函警告。同时,不少站理想的自媒体KOL纷纷下场,斥责这些行为是“下作、无底线的抹黑”。

其实汽车产品中被送过类似称呼的并非MGEA一个。2015年左右途观事故频发,被消费者调侃为“土棺”。2022年极氪009上市时,也被“赠予”了和MEGA一样的称呼……但这些信息并没有被大肆发酵,尤其是后者,只是新车上市发布时的一个花絮注脚。

这一次理想一心一意想要打造的“公路高铁”MEGA,为什么被黑地愈演愈烈?

很多人认为是,舆论反噬。就像网友说的:理想只是遭遇了“回旋镖”。

今日的车圈营销战不断升级,动辄CEO对线、KOLKOC互踩,李想本人确是“功不可没”的。

创始人亲自下场蹭热度、宣传话术避重就轻,乃至操纵媒体、内涵友商、攻击自家车主……在理想的发展壮大过程中,这些传播手段被用得炉火纯青。客观讲理想L系列是好产品,但销量也大有营销的“功劳”。

理想L9上市后,面对“50万的豪车不用铝缺乏诚意”(使用的铁悬架)的质疑,李想选择了人身攻击:“建议觉得铝比钢和铁好的网友们,把自己家的房子钢筋柱结构都拆掉,全换成铝”。

上周五上市的MEGA被质疑“没有后轮转向”时,理想又在对外宣发中统一口径:后轮转向会让“第三排乘客会感受到更快的横向摆动,会不太舒服”,“后轮转向也不是很厉害的技术,我们的转弯半径也就比L9多一个手掌。”

类似事例不再赘述,看下网友的精辟总结:

社交媒体截图社交媒体截图
对一些有关新车的问题避重就轻,其实不算什么大“黑料”。这原本也是一个车企领袖的基本修养(除了骂人),毕竟人无完人、车无完车。

而除了怼网友怼友商,理想对媒体的控制和拿捏也达到了“极致”。

2月份MEGA上市前在三亚组织了一场媒体试驾,所有参与者都签了保密协议。通过这份协议,理想细致拿捏了媒体宣传节奏——仅一次活动安排,让每家媒体按照理想预定的时间和内容方向陆续推送三四次信息,而消费者每天能刷到什么内容,也完全都在掌控之中。

必须夸一句,当友商们还在思考如何打磨技术,如何做出一场出色的发布会时,理想已经凭借对人性的研究,站在了另一个竞争维度。但那些被操控到如此程度的媒体,恐怕心里总有些不得劲吧。

不得不提的还有,至今无论对网友还是消费者来说都不可原谅的一件事:去年12月底发生在广东的一起理想L7事故中,有人质疑理想的车辆安全时,李想选择在微博曝光驾驶者的行车记录信息和视频,并且误导舆论指向事故车主超速驾驶!

这样的理想,被扣上“鸡贼”厂的名号由来已久,甚至理想自家车主对理想和李想的态度是:车是好车,人不认同。

此次MEGA宣发翻车,一方面因为理想流量太盛,枪打出头鸟,不排除真是竞争对手有意为之玩了一手“以彼之道还施彼身”;但也一定煽动了早就看不惯理想做事风格的网友和媒体,跟风行动。

不管是谁策动,都不由得让人想把李厂长diss友商的经典名句返送给他自己:“这点作战都受不了,难道是巨婴?”

而为了MEGA,这个回旋镖,理想是必须要承受的。

周末,北京最大新势力门店聚集地“蓝色港湾”,理想的门店在中午时段甚至需要排队。大家多为MEGA而来,有的感兴趣,有的出于好奇。

不可否认MEGA是一款足够吸引眼球的产品,但这样的关注度有多少转化为最终销量?还很难说。从增程转战纯电的理想,要重新接受考验。

很多人也都注意到,这次MEGA上市后李想并没有像往常一样回怼各种质疑,也没有迫不及待分享传说中的订单数据。甚至在发布会后理想还经历了股价的下滑。

MEGA的舆论和销量会如何相互裹挟着前行?这一波难堪的舆论风波后,李想又会不会对此有所反思?静观其变。

2.Split 文档切分

对于通用文本,这里建议使用 RecursiveCharacterTextSplitter 分割器进行文本切分。

from langchain_community.document_loaders import TextLoader
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores.chroma import Chroma
from langchain_text_splitters import RecursiveCharacterTextSplitter    


    # 读取原始文档
    raw_documents_lp = TextLoader('/Users/xxx/langchain/LocalDB/lp.txt', encoding='utf-8').load()
    raw_documents_lx = TextLoader('/Users/xxx/langchain/LocalDB/lx.txt', encoding='utf-8').load()

    # 分割文档
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)
    documents_lp = text_splitter.split_documents(raw_documents_lp)
    documents_lx = text_splitter.split_documents(raw_documents_lx)
    documents = documents_lp + documents_lx
    print("documents nums:", documents.__len__())

这里加载零跑与理想的文档,如果文档多的同学直接 os.path 遍历 for 循环添加即可,我们最终得到的是多个通过 text_splitter 分割的 document 文档。其主要包含 page_content 和 metadata 两个属性,前者包含分割后的文本块 Chunk,后者包含一些元信息,主要是文档内容来源。

运行上述代码后会得到分割后文档数量,其中 chunk_size 代表每个块的保留大小,chunk_overlap 代表前后 content 是否有重叠,类似滑动窗口一样。

documents nums: 75

3.Encode 内容编码

由于需要通过向量存储与检索 Top-K,所以需要对应的编码器生成对应 content 的 Embedding,这里我们选择通过 HuggingFaceEmbeddings 方法来生成文本的 Embedding。

    # 生成向量(embedding)
    embedding_model_dict = {
        "mini-lm": "/Users/xxx/model/All-MiniLM-L6-V2"
    }
    EMBEDDING_MODEL = "mini-lm"
    embeddings = HuggingFaceEmbeddings(model_name=embedding_model_dict[EMBEDDING_MODEL])

由于网络连接的问题,这里博主建议把模型下载到本地文件夹中直接加载,登录 HuggignFace 官网 https://huggingface.co/sentence-transformers/ 可以检索到多个文本编码的模型:

这里我们选择轻量级的 all-MiniLM-L6-v2 作为 Embedding 编码的模型,手动一个一个下载或者挂着镜像用 API 下载都可以:

执行完毕后我们获得一个可以编码的 Embedding 模型: 

4.Similar 本地库构建

    db = Chroma.from_documents(documents, embedding=embeddings)

    # 检索
    query = "理想汽车怎么样?"
    docs = db.similarity_search(query, k=5)

    # 打印结果
    for doc in docs:
        print("===")
        print("metadata:", doc.metadata)
        print("page_content:", doc.page_content)

通过本地分割好的文档 documents 与指定的 embedding 模型我们构建本地 Langchain DB,通过 query 与 sim_search API 进行 Top-k 文本的获取,得到的 doc 我们可以获取其 metadata 即来源以及其对应的文本:

可以看到 5 条中有 4 条来自 lx.txt 即理想的文档,而一条来自 lp.txt 即零跑汽车,基于这些 page_content,我们还需要做清洗、合并等处理才能得到最终的增强信息,对用户的原始 Query 进行扩展得到最终的 Prompt 再输入 LLM 得到回复。

三.缓存本地 Langchain 库

如果不想每次都处理加载文档再构建 DB 可以预先处理并把 DB 做本地的 cache,用的时候直接读取 cache 加载即可。

def persist():
    raw_documents_news = TextLoader('/Users/xxx/langchain/lx.txt', encoding='utf-8').load()
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)
    documents_news = text_splitter.split_documents(raw_documents_news)
    embedding_model_dict = {
        "mini-lm": "/Users/xxx/model/All-MiniLM-L6-V2"
    }
    EMBEDDING_MODEL = "mini-lm"
    # 初始化 huggingFace 的 embeddings 对象
    embeddings = HuggingFaceEmbeddings(model_name=embedding_model_dict[EMBEDDING_MODEL])
    db = Chroma.from_documents(documents_news, embeddings, persist_directory="./local_cache")
    db.persist()
    print("Save Success ...")

执行后在 cache 对应文件下生成如下文件即为成功: 

缓存大小为 2mb:

四.读取本地 Langchain 库

1.Load 读取缓存

    embedding_model_dict = {
        "mini-lm": "/Users/xxx/model/All-MiniLM-L6-V2"
    }
    EMBEDDING_MODEL = "mini-lm"
    # 初始化 huggingFace 的 embeddings 对象
    embeddings = HuggingFaceEmbeddings(model_name=embedding_model_dict[EMBEDDING_MODEL])
    db = Chroma(persist_directory="/Users/xxx/langchain/local_cache", embedding_function=embeddings)

同样需要加载 embedding 模型,但是 doc 内容直接从 cache 中获取,通过 persist_directory 方法获取 Chroma Database。

2.Similar 预测

    # 检索
    query = "理想汽车"
    docs = db.similarity_search(query, k=5)

    # 打印结果
    for doc in docs:
        print("===")
        print("metadata:", doc.metadata)
        print("page_content:", doc.page_content)

    exit(0)

3.Add 添加文档

本地库存在更新慢的情况,读取缓存后如果有新的 doc 可以调用 db.add 方法添加,随后再执行查询,下面我们在 cache 的基础上引入小鹏汽车 xp.txt 的信息,并预测新的 query。

    # 添加文档
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=0)
    raw_documents_xp = TextLoader('/Users/xxx/langchain/LocalDB/xp.txt', encoding='utf-8').load()
    documents_news = text_splitter.split_documents(raw_documents_xp)
    db.add_documents(documents_news)

加载本地 Langchain 库后,我们可以继续将新增的本地 doc 添加至 DB 中,下面我们再测试下,这次寻找与新增小鹏汽车相关的信息:

    # 检索
    query = "小鹏汽车"
    docs = db.similarity_search(query, k=5)

    # 打印结果
    for doc in docs:
        print("===")
        print("metadata:", doc.metadata)
        print("page_content:", doc.page_content)

    exit(0)

xp.txt 里小鹏汽车的关键字比较多,所以匹配下来 metadata 都指向 xp.txt,不存在之前 lx 检索到 lp 的情况: 

五.总结

上面简单测试了基于 Doc 构建本地 Langchain 库的一些方法,关于更细粒度的 Langchain 和 RAG,还涉及到很多细节的点,包括对 query 的清洗与处理,对文档的清理与筛选,对 Langchain 结果的取舍与合并以及 LLM Prompt 的构建,这些细致的点大家可以一一扩散提高搜索的效果。

Tips:

Langchain 中文 API 介绍: LangChain中文网 Concepts | 🦜️🔗 Langchain

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

M2TS转MP4怎么转?超快的方法~

M2TS格式的优点主要体现在对高清视频的完美支持,能够提供极致的视觉体验。然而,由于其相对较大的文件大小,有时可能不太适合网络传输。此外,部分不支持M2TS的播放设备可能导致一定的兼容性问题。 想要播放m2ts视频,可…

MySQL实战45讲——30答疑文章(二):用动态的观点看加锁

目录 不等号条件里的等值查询 等值查询的过程 怎么看死锁? 怎么看锁等待? update 的例子 小结 上期问题时间 提示 文章摘自林晓斌老师《MySQL实战45讲》,作为笔记而用,故有加一些自己的理解。在第[20]和[21]篇文章中&…

Python基础二

一、变量 在编程中,变量是用来存储数据值的名称。在 Python 中,变量是动态类型的,这意味着你可以将任何类型的数据分配给一个变量,而不需要提前声明变量的类型。 1、全局变量 在函数外部定义的变量是全局变量,可以在程…

cesium-天际线

主要是两个着色器 let postProccessStage new Cesium.PostProcessStage({//unform着色器对象 textureScalefragmentShader:// 声明一个纹理采样器 colorTexture 用于读取纹理颜色uniform sampler2D colorTexture; // 声明一个纹理采样器 depthTexture 用于读取深度纹理unifor…

Python接口自动化之Token详解及应用

以下介绍Token原理及在自动化中的应用。 一、Token基本概念及原理 1.Token作用 为了验证用户登录情况以及减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。 2.什么是Token Token是服务端生成的一串字符串,以作客户端进行请求的…

《焦点访谈》上的星火大模型:AI生成春天散文,共绘美好春天

发布 | 大力财经 在今年的全国“两会”上,全国人大代表、科大讯飞董事长刘庆峰提出了关于制定国家《通用人工智能发展规划》的建议,推动我国通用人工智能的发展,以应对全球AI领域的激烈竞争。 刘庆峰在3月6日晚间的《焦点访谈》中表示&#…

简单整理vue-router,路由知识

1.项目中引入 1.1 安装注册 1.2 封装抽离 在main.js中 书写,会造成单个js文件过于臃肿的情况,需要将路由配置部分抽离出来,在src下新建router文件夹,新建index.js文件 import Vue from vue import VueRouter from vue-router import HomeView from ../views/HomeView.vue im…

Elasticsearch:dense vector 数据类型及标量量化

密集向量(dense_vector)字段类型存储数值的密集向量。 密集向量场主要用于 k 最近邻 (kNN) 搜索。 dense_vector 类型不支持聚合或排序。 默认情况下,你可以基于 element_type 添加一个 dend_vector 字段作为 float 数值数组: …

【中间件】docker的安装

📝个人主页:五敷有你 🔥系列专栏:中间件 ⛺️稳中求进,晒太阳 .卸载旧版 首先如果系统中已经存在旧的Docker,则先卸载: yum remove docker \docker-client \docker-client-latest \doc…

Web自动化测试学习方向(Selenium)

🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 &#x1…

chrome插件webRequest拦截请求并获取post请求体requestBody数据raw内容,解决中文乱码问题

详细使用说明可以看官方文档:https://developer.chrome.com/docs/extensions/reference/api/webRequest?hlzh-cn 拦截操作 想要通过浏览器插件拦截请求的话,需要在manifest.json里面添加webRequet权限: 拦截请求代码放在background.js里面…

Web服务器

Web服务器 1. 阻塞/非阻塞、同步/异步(网络IO)2. Unix/Linux 上的五种IO模型2.1 阻塞 blocking2.2 非阻塞 non-blocking (NIO)2.3 IO复用(IO multiplexing)2.4 信号驱动(signal-driven)2.5 异步&#xff08…

【项目实践04】【RocketMQ消息收发拦截器】

文章目录 一、前言二、项目背景三、实现方案1. 关键接口2. 消息发送方3. 消息消费方4. 配置引入类5. 使用示例 四、思路扩展1. 消费流程简介 一、前言 本系列用来记录一些在实际项目中的小东西,并记录在过程中想到一些小东西,因为是随笔记录&#xff0c…

【Web】浅聊JDBC的SPI机制是怎么实现的——DriverManager

目录 前言 分析 前言 【Web】浅浅地聊JDBC java.sql.Driver的SPI后门-CSDN博客 上篇文章我们做到了知其然,知道了JDBC有SPI机制,并且可以利用其Driver后门 这篇文章希望可以做到知其所以然,对JDBC的SPI机制的来源做到心里有数 分析 先是…

如何实现数据中心布线变更管理?

前言 随着科技的不断发展,数据中心作为企业的核心基础设施之一,承载着大量重要的业务数据。在数据中心运维过程中,变更管理流程变得尤为重要,它是确保数据中心基础设施稳定运行和保障数据安全的关键环节。变更管理的定义是指在维…

电商效果图云渲染优势是什么?

电商效果图云渲染指的是利用云计算技术,将电商所需的效果图渲染任务转移至云服务器进行处理。这些云服务器凭借其卓越的计算能力与庞大的存储空间,能够迅速完成复杂的渲染任务,从而释放本地电脑资源,提升工作效率。 电商效果图云…

常见四种限流算法详解(附:javaDemo)

限流简介 现代互联网很多业务场景,比如秒杀、下单、查询商品详情,最大特点就是高并发,而往往我们的系统不能承受这么大的流量,继而产生了很多的应对措施:CDN、消息队列、多级缓存、异地多活。 但是无论如何优化&…

今日学习总结2024.3.2

最近的学习状态比较好,感觉非常享受知识进入脑子的过程,有点上头。 实验室一个星期唯一一天的假期周六,也就是今天,也完全不想放假出去玩啊,在实验室泡了一天。 很后悔之前胆小,没有提前投简历找实习&…

基于毕奥-萨伐尔定律的交流电机的4极旋转磁场matlab模拟与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于毕奥-萨伐尔定律的交流电机的4极旋转磁场,对比不同定子半径,对比2级旋转磁场。 2.系统仿真结果 3.核心程序与模型 版本:MATLAB2022a…

UE5数字孪生系列笔记(一)

智慧城市数字孪生系统 虚幻引擎连接数据库 将自己的mysql版本的libmysql.dll替换掉插件里面的libmysql.dll 然后将这个插件目录复制到虚幻项目目录下 然后添加这个插件即可 新建一个UMG,添加一个按钮试试,数据库是否连接 将UI添加到视口 打印是否连接…