首页 > 其他分享 >在langchain中的rag学习使用之旅-从半知半解到实现效果

在langchain中的rag学习使用之旅-从半知半解到实现效果

时间:2024-05-16 21:44:53浏览次数:21  
标签:rag name 从半知 city text langchain vector post id

rag我简单理解来看就是我先有一段文本,先把它转成向量,保存到向量数据库中,下次我调用llm时将向量数据库中查询的结果给llm作参考并回答。

对rag了解不多,所以开启学习之旅,学完了要应用到实际的需求中,因为最近手里有一个订单就是需要用到这个技术,但是又一知半解。

现在新知识太多了,学不过来,完全学不过来。

看了一个B站关于langchain的rag相关的知识,介绍了langchain官方文档该怎么看,感觉有用,贴一下链接:

https://www.bilibili.com/video/BV1Cp421R7Y7/?spm_id_from=333.337.search-card.all.click&vd_source=dfb9822d48ce5215cb969f1d686c38c5

因为我是在pgsql中存储和搜索向量,所以推荐这篇文章如何安装pgsql支持向量的操作:
https://blog.csdn.net/FrenzyTechAI/article/details/131552053

原生的pgsql不支持或者没有很好的支持向量的操作,所以需要用到扩展的pgsql。

又问了一下同事,大致知道流程了,就是:我需要提供一个接口将文本转成向量存到pgsql数据库。再提供一个查询的接口,这个接口先把传入的文本转成向量,再去pgsql向量数据库查询,最后得出结果,表结构就是文本对应向量,然后查询的时候根据向量文本相似度查询相似度最高的几条记录,这样就可以拿到文本了,再将这个文本丢给AI作参考,然后AI就可以先基于本地内容回答了。

所以本地知识库其实和rag差不多的。

OK!大致思路整理清楚了开始动工:
我这边使用的数据库也是pgsql,但是我本地是windows系统,所以还得看看怎么在windows上安装pgsql的pgvector扩展:

根据:

https://www.cnblogs.com/xiaonanmu/p/17979626

https://blog.csdn.net/qq_57963867/article/details/131720092

这两篇文章的参考,我需要在本地安装C++然后手动make,先安装C++

https://visualstudio.microsoft.com/zh-hans/downloads/

 

我们下载社区版就行

然后我们只装这一个:

 

等下载完成:

 

安装好后打开:C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build

就能看到有这个文件

 

我们命令行执行:

call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"

 

再去官网下载pgsql的pgvector扩展:

https://pgxn.org/dist/vector/0.5.1/

 

这个官网下面还有使用教程:

 

我们这里下载0.5.1版本的:

 

下载之后解压:

 

然后打开命令行输入nmake看看有没有效:

 

输出内容了,说明nmake安装成功!

接下来开始编译pgvector扩展,我们的目标文件:

 

我们先设置一下pgsql的安装目录,这里要改成自己真实的安装目录,再以管理员身份运行命令行输入,不然可能会失败:
set "PGROOT=D:\soft_install\pgsql-16"

不设置的话会报错:

 

我们设置一下:

 

再输入nmake /F Makefile.win,执行结果时这样的:

 

 

再输入nmake /F Makefile.win install:

 

 

应该是安装完成了。

安装完成后还得启用,我们是windows的话,打开pgadmin4:

 

运行此命令以启用扩展:CREATE EXTENSION vector;;

 

验证是否安装成功:

 

说明我们成功安装了vector0.5.1版本的了。

在这里也能看到:

 

我再创建一个符合我的项目需求的表,用来存储文本和向量结构:

CREATE TABLE IF NOT EXISTS public.job_info_vector
(
  id character varying(36) COLLATE pg_catalog."default" NOT NULL,
  city_id character varying(36) COLLATE pg_catalog."default" NOT NULL,
  city_name character varying(36) COLLATE pg_catalog."default" NOT NULL,
  post_id character varying(36) COLLATE pg_catalog."default" NOT NULL,
  post_name character varying(36) COLLATE pg_catalog."default" NOT NULL,
  description character varying(1024) COLLATE pg_catalog."default" NOT NULL,
  created_on character varying(35) COLLATE pg_catalog."default" NOT NULL,
  description_vector vector NOT NULL,
  CONSTRAINT job_info_vector_pkey PRIMARY KEY (id)
)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.job_info_vector
OWNER to postgres;
COMMENT ON COLUMN public.job_info_vector.city_id
IS '城市id';
COMMENT ON COLUMN public.job_info_vector.city_name
IS '城市名';
COMMENT ON COLUMN public.job_info_vector.post_id
IS '岗位id';
COMMENT ON COLUMN public.job_info_vector.post_name
IS '岗位名称';
COMMENT ON COLUMN public.job_info_vector.description
IS '岗位对应的招聘信息';
COMMENT ON COLUMN public.job_info_vector.created_on
IS '创建时间';
COMMENT ON COLUMN public.job_info_vector.description_vector
IS '向量的表示';

大致的流程:

1、我需要提供一个接口供将传入的内容分块并向量化存储

2、提供查询接口(将查询的内容向量化再查询)

一个一个来实现。

网上找了下,暂时没找到加载一段文本的,而是只有加载文件的,就那几行代码。

 

所以我这里封装一个方法,可以把一段文本封装为一个文本流:

import io
def read_from_text(text):
  with io.StringIO(text) as f:
  return f.read()

拆分的代码:

from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=200,
chunk_overlap=30,
length_function=len,
)
texts = text_splitter.create_documents([read_from_text(r.text)])

效果:

 

下一段的开头会有一段内容和上一段结尾的内容重合的:

 

ok,拆分这一步完成了,接下来就是有多少段就向量化几次并入库:

texts = text_splitter.create_documents([read_from_text(r.description)])
job_dao = JobInfoVectorDao()
  for text in texts:
  vector = self.text_to_vector(app, text.page_content)
  if not vector:
  continue
  # 数据入库
  job_dao.add(JobInfoVectorModel(
    id=str(uuid.uuid4()),
    city_id=r.city_id,
    city_name=r.city_name,
    post_id=r.post_id,
    post_name=r.post_name,
    description=text.page_content,
    description_vector=json.dumps(vector),
  ))

数据库效果如下:

 

 

OK!向量的拆分和入库完成。

这里文本转向量的方法用的是智谱的。

接下来就是搜索了:

pgvector官网就有搜索的sql,直接拿过来再结合自己的项目就行,我这里也直接用原生sql了。

 

调一下智谱的embedding接口看看效果,首先我们得先有向量数据:

 

text_embedding接口文档:
https://open.bigmodel.cn/dev/api#text_embedding

拿到结果后就需要入库了,我这边的代码:

# 先拆分
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=Config.ZHIPUAI_EMBEDDING_CHUNK_SIZE,
chunk_overlap=Config.ZHIPUAI_EMBEDDING_CHUNK_OVERLAP,
length_function=len,
)
texts = text_splitter.create_documents([read_from_text(r.description)])
job_dao = JobInfoVectorDao()
for text in texts:
  vector = self.text_to_vector(app, text.page_content)
  if not vector:
  	continue
  # 数据入库
  job_dao.add(JobInfoVectorModel(
    id=str(uuid.uuid4()),
    city_id=r.city_id,
    city_name=r.city_name,
    post_id=r.post_id,
    post_name=r.post_name,
    description=text.page_content,
    description_vector=json.dumps(vector),
  ))
  return self.return_dataclass(EmbeddingsTextToVectorResponse(
    success=True,
    chunk_count=len(texts),
    chunk_size=Config.ZHIPUAI_EMBEDDING_CHUNK_SIZE,
    chunk_overlap=Config.ZHIPUAI_EMBEDDING_CHUNK_OVERLAP,
  ))

我让ChatGPT给了我们一批内容用来训练:

 

然后我逐个调用智谱的embedding入库,结果如下:

 

然后我的查找的代码:
from sqlalchemy import text
def get_list(self, model: JobInfoVectorModel, r: EmbeddingsTextToVectorSearchRequest):
  where_sql = "where 1 = 1"
  if not is_empty(r.city_id):
  where_sql += " and city_id = :city_id "
  if not is_empty(r.city_name):
  where_sql += " and city_name = :city_name "
  if not is_empty(r.post_id):
  where_sql += " and post_id = :post_id "
  if not is_empty(r.post_name):
  where_sql += " and post_name = :post_name "
  order_sql = f"ORDER BY description_vector <-> '{json.dumps(r.description_vector)}' ASC"
  limit_sql = f" LIMIT 5 "
  query_sql = text(f"select id, city_id, city_name, post_id, post_name, description, "
  f"created_on from {model.__tablename__} {where_sql} {order_sql} {limit_sql}")
  result = db.session.execute(query_sql, {
    'city_id': r.city_id,
    'city_name': r.city_name,
    'post_id': r.post_id,
    'post_name': r.post_name
  }).fetchall()

结果还是很不错的,见下图:

 

 

 

又学到一个新知识!满足。

这篇文章就到这里啦!如果你对文章内容有疑问或想要深入讨论,欢迎在评论区留言,我会尽力回答。同时,如果你觉得这篇文章对你有帮助,不妨点个赞并分享给其他同学,让更多人受益。

想要了解更多相关知识,可以查看我以往的文章,其中有许多精彩内容。记得关注我,获取及时更新,我们可以一起学习、讨论技术,共同进步。

感谢你的阅读与支持,期待在未来的文章中与你再次相遇!

我的微信公众号:【xdub】,欢迎大家订阅,我会同步文章到公众号上。

标签:rag,name,从半知,city,text,langchain,vector,post,id
From: https://www.cnblogs.com/shuinanxun/p/18196788

相关文章

  • 精通RAG架构:从0到1,基于LLM+RAG构建生产级企业知识库
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • LangChain 进阶历史对话管理
    自动历史管理前面的示例将消息显式地传递给链。这是一种完全可接受的方法,但确实需要外部管理新消息。LangChain还包括一个名为RunnableWithMessageHistory的包裹器,能够自动处理这个过程。为了展示其工作原理,我们稍微修改上面的提示,增加一个最终输入变量,该变量在聊天历史记录之后......
  • RAG学习--pdf读取
    RAG流程:线下:1、文档加载2、文档切分3、向量化4、向向量数据库灌数据线上:1、获取用户问题2、用户问题向量化3、检索向量数据库4、将检索结果和问题填充到pomp模板5、用最终获得的pomp调用LLM6、最终由LLM生成回复本篇完成文档加载与切割(pdf加载与切割)1、文档加载......
  • SystemVerilog -- 10.0 SystemVerilog Functional Coverage
    SystemVerilogFunctionalCoverageWhatisfunctionalcoverage?functionalcoverage是测试对设计的哪些功能/特性的衡量。这在约束随机验证(CRV)中非常有用,可以了解回归中的一组测试涵盖了哪些特征。Whatareitslimitations?这仅与为它编写的代码一样好。假设您在设计文档......
  • 困扰了一天的flask结合智谱ai langchain流式输出json问题终于解决了
    本次对接的大模型是智谱,首先想到去智谱开放平台找找有没有和langchain结合的文档: 结果还真有,就省去了谷歌的时间,但是智谱的文档只提供了非流式的示例代码,想着先拷过来跑一下再说,结果就是非流式是正常输出的,流式就遇到问题了,不管我咋配置,好像只能在控制台输出流失内容,遂去谷歌......
  • langchain教程
    参考网址:https://python.langchain.com/docs/get_started/introduction/https://python.langchain.com/docs/modules/1、简介LangChain是一个用于开发由大型语言模型(LLM)驱动的应用程序的框架。LangChain简化了LLM申请生命周期的每个阶段:开发:使用LangChain的LCLE和......
  • 利用LangChain构建的智能数据库操作系统
    在Retrieval或者ReACT的一些场景中,常常需要数据库与人工智能结合。而LangChain本身就封装了许多相关的内容,在其官方文档-SQL能力中,也有非常好的示例。而其实现原理主要是通过LLM将自然语言转换为SQL语句,然后再通过LLM获取执行的操作,最终生成一个答案和结论。应用......
  • Outrageously Large Neural Networks The Sparsely-Gated Mixture-of-Experts Layer
    目录概MoE训练ShazeerN.,MirhoseiniA.,MaziarzK.,DavisA.,LeQ.,HintonG.andDeanJ.Outrageouslylargeneuralnetworks:Thesparsely-gatedmixture-of-expertslayer.ICLR,2017.概Mixture-of-Experts(MoE).MoE通过一gatingnetwork选择不同的exp......
  • UEC++做拖拽时的UDragDropOperation 的PayLoad是什么
    在UnrealEngine中,使用C++进行拖拽操作时,UDragDropOperation类的Payload成员变量允许你传递与拖拽操作相关的任何类型的数据。它通常被用来存储一些关于被拖拽元素的信息,这些信息在拖拽开始时被设置,然后可以在拖拽结束时被检索和使用。Payload是一个UObject*类型的指针,这意......
  • AI 数据观 | TapData Cloud + MongoDB Atlas:大模型与 RAG 技术有机结合,落地实时工单处
    本篇为「AI数据观」系列文章第二弹,在这里,我们将进一步探讨AI行业的数据价值。以RAG的智能工单应用场景为例,共同探索如何使用TapdataCloud+MongoDBAtlas实现具备实时更新能力的向量数据库,为企业工单处理的智能化和自动化需求,提供准实时的新鲜数据。完整分布教程指引,详见......