Langchain教程 | langchain+OpenAI+PostgreSQL(PGVector) 实现全链路教程,简单易懂入门

前提:

        在阅读本文前,建议要有一定的langchain基础,以及langchain中document loader和text spliter有相关的认知,不然会比较难理解文本内容。

        如果是没有任何基础的同学建议看下这个专栏:人工智能 | 大模型 | 实战与教程

        本文主要展示如何结合langchain使用Postgres矢量数据库,其他相关的基础内容,可以看专栏了解,都已经拆分好了,一步步食用即可,推荐线路:langchain基础、document loader加载器、text spliter文档拆分器等按顺序学习。

PGVector是一个开源向量相似性搜索Postgres

它支持:- 精确和近似最近邻搜索- L2距离,内积和余弦距离 

基础库准备:

# Pip install necessary package
%pip install --upgrade --quiet  pgvector
%pip install --upgrade --quiet  psycopg2-binary
%pip install --upgrade --quiet  tiktoken
%pip install --upgrade --quiet  openai
from langchain.docstore.document import Document
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores.pgvector import PGVector
from langchain_community.embeddings.openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter

我们想使用OpenAIEmbeddings所以我们必须获得OpenAI API密钥。

提示:因为国内政策原因,建议采购代理key,至于哪家好用,这里就不推荐了。

em.py 设置环境变量

import getpass
import osos.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")

 加载环境变量,openai库会自动读取该参数OPEN_API_KEY

## Loading Environment Variables
from dotenv import load_dotenvload_dotenv()

 这里使用的文本内容是: 人民财评:花香阵阵游人醉,“春日经济”热力足

将链接中的文本内容保存到 :state_of_the_union.txt

拆分中文文档需要用到递归型的字符拆分器 RecursiveCharacterTextSplitter,同时要使用中文分隔符:句号。逗号,顿号、感叹号!等。

loader = TextLoader("../../modules/state_of_the_union.txt")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)embeddings = OpenAIEmbeddings()

连接Postgre矢量存储库

# PGVector needs the connection string to the database.
CONNECTION_STRING = "postgresql+psycopg2://harrisonchase@localhost:5432/test3"# # Alternatively, you can create it from environment variables.
# import os

类还内置了一个更直观的方法:connection_string_from_db_params()

CONNECTION_STRING = PGVector.connection_string_from_db_params(driver=os.environ.get("PGVECTOR_DRIVER", "psycopg2"),host=os.environ.get("PGVECTOR_HOST", "localhost"),port=int(os.environ.get("PGVECTOR_PORT", "5432")),database=os.environ.get("PGVECTOR_DATABASE", "postgres"),user=os.environ.get("PGVECTOR_USER", "postgres"),password=os.environ.get("PGVECTOR_PASSWORD", "postgres"),
)

使用欧氏距离进行相似性搜索(默认)

# The PGVector Module will try to create a table with the name of the collection.
# So, make sure that the collection name is unique and the user has the permission to create a table.COLLECTION_NAME = "state_of_the_union_test"db = PGVector.from_documents(embedding=embeddings,documents=docs,collection_name=COLLECTION_NAME,connection_string=CONNECTION_STRING,
)
query = "今年长三角铁路春游运输共历时多少天?"
docs_with_score = db.similarity_search_with_score(query)
for doc, score in docs_with_score:print("-" * 80)print("Score: ", score)print(doc.page_content)print("-" * 80)

输出结果:

最大边际相关性搜索

最大边际相关性优化了查询的相似性和所选文档的多样性。 

docs_with_score = db.max_marginal_relevance_search_with_score(query)
for doc, score in docs_with_score:print("-" * 80)print("Score: ", score)print(doc.page_content)print("-" * 80)

打印结果:

使用vectorstore 

        上面,我们从头开始创建了一个vectorstore。但是,我们经常希望使用现有的vectorstore。为了做到这一点,我们可以直接初始化它。

store = PGVector(collection_name=COLLECTION_NAME,connection_string=CONNECTION_STRING,embedding_function=embeddings,
)

添加文档

我们可以向现有的vectorstore添加文档。

store.add_documents([Document(page_content="今年春游创收客观,实际增长30%。")])
docs_with_score = db.similarity_search_with_score("春游增长多少")
print(docs_with_score[0])
print(docs_with_score[1])

覆盖向量存储

        如果您有一个现有的集合,您可以通过执行以下操作来覆盖它from_documents和设置pre_delete_collection=真

db = PGVector.from_documents(documents=docs,embedding=embeddings,collection_name=COLLECTION_NAME,connection_string=CONNECTION_STRING,pre_delete_collection=True,
)

将VectorStore用作检索器

retriever = store.as_retriever()

与OpenAI结合使用完整代码

里面包含了详细的步骤和注释,直接复制就可运行。

import os
from langchain_community.document_loaders import TextLoader
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores.pgvector import PGVector
from langchain_text_splitters import RecursiveCharacterTextSplitter
from dotenv import load_dotenv# 加载环境变量或者加载.env文件
load_dotenv()
# 导入文本文件
loader = TextLoader("./demo_static/splitters_test.txt")
# 生成文档加载器
documents = loader.load()
# 文档拆分,每块最大限制20,覆盖量10
text_splitter = RecursiveCharacterTextSplitter(separators=["\n\n", "\n", "。", "?", ";"],chunk_size=100,chunk_overlap=20,
)
# 开始拆分文档
docs = text_splitter.split_documents(documents)
# print(len(docs))
# print(docs)# 初始化嵌入式OpenAI大语言模型,手动指定key和代理地址
embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("OEPNAPI_API_KEY"),openai_api_base=os.getenv("OPENAI_API_BASE"))
# 连接矢量存储库,链接换成自己专属的*
CONNECTION_STRING = "postgresql+psycopg2://postgres:password@localhost:5432/postgres"
# 矢量存储名
COLLECTION_NAME = "state_of_the_union_test"
# 建立索引库
vector = PGVector.from_documents(embedding=embeddings,documents=docs,collection_name=COLLECTION_NAME,connection_string=CONNECTION_STRING,use_jsonb=True,pre_delete_collection=True,
)
# 生成检索器
retriever = vector.as_retriever()
# 一个对话模板,内含2个变量context和question
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
# 基于模板生成提示
prompt = ChatPromptTemplate.from_template(template)
# 基于对话openai生成模型
model = ChatOpenAI(openai_api_key=os.getenv("OEPNAPI_API_KEY"),openai_api_base=os.getenv("OPENAI_API_BASE"))
# 生成输出解析器
output_parser = StrOutputParser()
# 将检索索引器和输入内容(问题)生成检索
setup_and_retrieval = RunnableParallel({"context": retriever, "question": RunnablePassthrough()}
)
# 建立增强链
chain = setup_and_retrieval | prompt | model | output_parser
# 问题
question = "今年长三角铁路春游运输共历时多少天?"
# 发起请求
res = chain.invoke(question)
# 打印结果
print(res)

打印结果:

    32天

 创作不易,来个三连(点赞、收藏、关注),同学们的满意是我(H-大叔)的动力。

 代码运行有问题或其他建议,请在留言区评论,看到就会回复,不用私聊。

专栏人工智能 | 大模型 | 实战与教程里面还有其他人工智能|大数据方面的文章,可继续食用,持续更新。

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

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

相关文章

【CicadaPlayer】demuxer_service中DASH的简单理解

DASH协议 dash 是属于demuxer模块的 MPEG-DASH是一种自适应比特率流技术,可根据实时网络状况实现动态自适应下载。和HLS, HDS技术类似, 都是把视频分割成一小段一小段, 通过HTTP协议进行传输,客户端得到之后进行播放;不同的是MPEG-DASH支持MPEG-2 TS、MP4(最新的HLS也支持…

Linux 多线程

目录 初识线程 线程的概念 Linux下的线程 线程优缺点 线程控制 线程创建 线程终止 线程等待 线程分离 线程取消 其它 线程互斥 互斥的概念 互斥锁的使用 锁的本质 线程同步 线程同步的概念 条件变量的概念 条件变量的使用 信号量 信号量的概念 信号量接口…

非机构化解析【包含PDF、word、PPT】

此项目是针对PDF、docx、doc、PPT四种非结构化数据进行解析,识别里面的文本和图片。 代码结构 ├── Dockerfile ├── requirements ├── resluts ├── test_data │ ├── 20151202033304658.pdf │ ├── 2020_World_Energy_Data.pdf │ ├── …

【Web】纯萌新的BUUCTF刷题日记Day1

目录 [RoarCTF 2019]Easy Java [网鼎杯 2018]Fakebook [CISCN2019 华北赛区 Day2 Web1]Hack World [BJDCTF2020]The mystery of ip [网鼎杯 2020 朱雀组]phpweb [BSidesCF 2020]Had a bad day [BJDCTF2020]ZJCTF,不过如此 [BUUCTF 2018]Online Tool [GXYCTF…

虚拟主机VPS和共享服务器有什么区别?VPS和共享服务器怎么选择,VPS和云服务器区别

今天易极赞小编来跟大家科普一个新的知识“虚拟主机和云服务器有什么区别?”看完这篇文章后你应该就能知道虚拟主机和云服务器哪个更适合你了。 如果你不知道服务器的常见类型有哪些,查看下面这篇文章: 服务器7中常见的类型,服务…

【C语言】如何判断一个机器的大小端

如何判断一个机器的大小端 一:什么是机器的大小端二:为什么会有大小端三:设计一个小程序来判断当前机器的大小端方法一:指针类型强转方法二:联合体 一:什么是机器的大小端 机器的大小端是指在内存中存储多…

【移动安全】对webview漏洞的一些分析

这次分析的app如下: 打开发现该app发现需要登录界面: 拖进jadx看一下,先来看一下AndroidManifest.xml文件 发现有两个类是导出,再来分析这两个类 这个RegistrationWebView类利用webview.loadUrl进行加载网页 java public class…

JS——判断节假日(假日包括周末,不包括调休上班的周末)

思路:创建两个数组,数组1为节假日数组,数组2为是周末上班日期数组。如果当前日期(或某日期)同时满足2个条件(1.在节假日数组内或在周末。2.不在周末上班日期数组)即为节假日,否则即为…

SystemC入门学习Demo用例的工程化配置

背景:对不同的用例文件,使用CMakeLists.txt进行工程化管理的演示,这样开发者可以更加关注在代码开发上。 1,首先安装好系统环境的systemC库:ubuntu系统安装systemc-2.3.4流程-CSDN博客 2,准备好一个demo用…

再续前缘——C++【入门】

目录 1. 引用 引用概念 使用场景 1. 做参数 2. 引用做返回值 3.传值、传引用效率比较 4. 引用和指针的不同点 2. 内联函数 3.auto关键字 推导应用场景 auto不能推导的场景 4.基于范围的for循环(C11) 5.指针空值nullptr(C11) 1. 引用 引用概念 引用不是新定义一个…

JUC:手写实现一个简易的线程池(Java)

目录 ​编辑 先上完整代码: 解析: 任务队列: 线程池类: 拒绝策略: 先上完整代码: public class MyThreadPool {public static void main(String[] args) {ThreadPool threadPool new ThreadPool(2, …

Linux进程状态深度解析:探索进程的生命周期

文章目录 一、引言1、进程的概念与重要性2、Linux系统下进程状态的意义3、进程状态与系统性能的关系 二、Linux下进程状态概述1、Linux进程状态的分类2、进程状态信息的获取方法 三、Linux下进程状态详解1、运行状态(Running)2、可中断睡眠状态&#xff…

27.WEB渗透测试-数据传输与加解密(1)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容:26.WEB渗透测试-BurpSuite(五) BP抓包网站网址:http:…

实现Hello Qt 程序

🐌博主主页:🐌​倔强的大蜗牛🐌​ 📚专栏分类:QT❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、使用 "按钮" 实现 1、纯代码方式实现 2、可视化操作实现 (1&#xff09…

Hive3.0.0建库表命令测试

Hive创建表格格式如下: create [external] table [if not exists] table_name [(col_name data_type [comment col_comment],)] [comment table_comment] [partitioned by(col_name data_type [comment col_comment],)] [clustered by (col_name,col_name,...)…

对抗样本攻击

对抗样本是指经过特殊设计或调整的输入数据,旨在欺骗人工智能模型,使其产生错误的预测或输出。对抗样本通常是通过对原始输入进行微小但精心计算的改变,使得模型产生意外的结果。这种模糊化的输入可能难以从人类角度甄别,但对机器…

gma 教程:计算标准化降水指数(SPI)

安装 gma:pip install gma (依赖的 gdal 需自行安装) 本文基于:gma 2.0.8,Python 3.10 本文用到数据请从 gma 网站获取:https://gma.luosgeo.com/UserGuide/climet/Index/SPI.html 。 SPEI 函数简介 gma.c…

比较720组结构数列的收敛过程

在行,列可自由变换的平面上3点结构只有6个 这次计算由这6个结构排列组合,构成的所有720个不重复数列的递推收敛过程。 结果表明,所有的数列都可以在有限步内收敛。 有461个数列在3-4-3的递推过程中是天然稳定的,收敛结果就是本身…

STM32学习和实践笔记(4):分析和理解GPIO_InitTypeDef GPIO_InitStructure (c)

第二个成员变量是GPIOSpeed_TypeDef GPIO_Speed;也与int a一样同理。 GPIOSpeed_TypeDef是一个枚举类型,其定义如下: typedef enum { GPIO_Speed_10MHz 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz }GPIOSpeed_TypeDef; #define IS_GPI…

Leetcode刷题-哈希表详细总结(Java)

哈希表 当我们想使⽤哈希法来解决问题的时候,我们⼀般会选择如下三种数据结构。 数组set (集合)map(映射) 当我们遇到了要快速判断⼀个元素是否出现集合⾥的时候,就要考虑哈希法。如果在做⾯试题⽬的时候…