langchain 入门中篇:数据封装,Memory 封装

数据的处理流程可以看一张图来帮助理解

数据来源可以是网络,可以是邮件,可以是本地文件

经过 Document Loaders 加载,再在 Transform 阶段对文档进行 split, filter, translate, extract metadata 等操作,之后在 Embed 阶段进行向量化,存储在向量数据库中后期用于检索。

加载文档

准备工作:

安装依赖库:pip install pypdf

加载本地文档

from langchain_community.document_loaders import PyPDFLoaderloader = PyPDFLoader("./data/spyl.pdf") # pdf 是从网上下载的,放在了 ./data 目录下
pages = loader.load_and_split()print(pages[0].page_content)

输出:

加载 web 网页:

from langchain_community.document_loaders import WebBaseLoaderloader = WebBaseLoader("https://docs.smith.langchain.com/user_guide")  # LangSmith 的官方介绍
pages = loader.load_and_split()
print(pages[2].page_content)

输出:

文档处理器

1. TextSplitter

安装依赖库:pip install --upgrade langchain-text-splitters

接下来我们将前面的文档进一步切分处理

from langchain_text_splitters import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter(chunk_size=300,chunk_overlap=50,length_function=len,add_start_index=True
)paragraphs = text_splitter.create_documents([p.page_content for p in pages])
for para in paragraphs:print(para.page_content)print("=====================")

输出:

每个 chunk 300 个 token,重叠最多 50 个 token

注意:L昂Chain 的 PDFLoader 和 TextSplitter 实现都比较粗糙,实际生产不建议使用

向量数据库与向量检索

文档已经加载到内存中,接下来就需要将文档向量化,然后灌入向量数据库

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS# 灌库
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
db = FAISS.from_documents(paragraphs, embeddings)# 检索 top-5 结果
retriever = db.as_retriever(search_kwargs={"k": 5})docs = retriever.invoke("白酒最近的产量")for doc in docs:print(doc.page_content)print("+++++++++++++++++++++")

输出:

根据检索结果,检索成功匹配到了最相关的信息

小结:

  1. 文档处理部分 LangChain 实现较为粗糙,实际生产中不建议使用
  2. 与向量数据库的链接部分本质是接口封装,向量数据库需要自己选型

记忆封装

先来看几个简单的例子:

对话上下文:ConversationBufferMemory

from langchain.memory import ConversationBufferMemory, ConversationBufferWindowMemoryhistory = ConversationBufferMemory()
history.save_context({"input": "你好啊"}, {"output": "你也好啊"})print(history.load_memory_variables({}))history.save_context({"input": "你再好啊"}, {"output": "你又好啊"})print(history.load_memory_variables({}))
{'history': 'Human: 你好啊\nAI: 你也好啊'}
{'history': 'Human: 你好啊\nAI: 你也好啊\nHuman: 你再好啊\nAI: 你又好啊'}

只保留一个窗口的上下文:ConversationBufferWindowMemory

from langchain.memory import ConversationBufferWindowMemorywindow = ConversationBufferWindowMemory(k=2)
window.save_context({"input":"第一轮问"}, {"output":"第一轮答"})
window.save_context({"input":"第二轮问"}, {"output":"第二轮答"})
window.save_context({"input":"第三轮问"}, {"output":"第三轮答"})print(window.load_memory_variables({}))
{'history': 'Human: 第二轮问\nAI: 第二轮答\nHuman: 第三轮问\nAI: 第三轮答'}

限制上下文长度:ConversationTokenBufferMemory

from langchain.memory import ConversationTokenBufferMemory
from langchain_openai import ChatOpenAIllm = ChatOpenAI()
memory = ConversationTokenBufferMemory(max_token_limit=200,llm=llm
)
memory.save_context({"input":"你好"}, {"output":"你好,我是你的AI助手。"})
memory.save_context({"input":"你会干什么?"}, {"output":"我上知天文下知地理,什么都会。"})
print(memory.load_memory_variables({}))
{'history': 'Human: 你会干什么?\nAI: 我上知天文下知地理,什么都会。'}

应用场景:

我们通过一个简单的示例来展示 memory 的作用,这里设置 verbose=True ,这样我们就可以看到 prompt 的生成。

from langchain.chains import ConversationChainconversation_with_summary = ConversationChain(llm=llm,# We set a very low max_token_limit for the purposes of testing.memory=memory,verbose=True,
)
conversation_with_summary.predict(input="今天天气真不错!")
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Current conversation:
Human: 你好
AI: 你好,我是你的AI助手。
Human: 你会干什么?
AI: 我上知天文下知地理,什么都会。
Human: 今天天气真不错!
AI: 是的,今天天气晴朗,气温适宜,适合出门活动。您有什么计划吗?
Human: 今天天气真不错!
AI:> Finished chain.

[13]:

'是的,今天天气确实很好,阳光明媚,适合户外活动。您想去哪里呢?'
conversation_with_summary.predict(input="我喜欢跑步,喜欢放风筝")
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Current conversation:
Human: 你好
AI: 你好,我是你的AI助手。
Human: 你会干什么?
AI: 我上知天文下知地理,什么都会。
Human: 今天天气真不错!
AI: 是的,今天天气晴朗,气温适宜,适合出门活动。您有什么计划吗?
Human: 今天天气真不错!
AI: 是的,今天天气确实很好,阳光明媚,适合户外活动。您想去哪里呢?
Human: 我喜欢跑步,喜欢放风筝
AI:> Finished chain.

[14]:

'那真是个好主意!跑步和放风筝都是很棒的户外活动。您喜欢在什么样的地方跑步呢?有没有特别喜欢去的公园或者跑步道?'
conversation_with_summary.predict(input="获取爬山也不错,不如去爬一次黄山吧")
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Current conversation:
AI: 是的,今天天气晴朗,气温适宜,适合出门活动。您有什么计划吗?
Human: 今天天气真不错!
AI: 是的,今天天气确实很好,阳光明媚,适合户外活动。您想去哪里呢?
Human: 我喜欢跑步,喜欢放风筝
AI: 那真是个好主意!跑步和放风筝都是很棒的户外活动。您喜欢在什么样的地方跑步呢?有没有特别喜欢去的公园或者跑步道?
Human: 获取爬山也不错,不如去爬一次黄山吧
AI:> Finished chain.

[15]:

'黄山是一个非常著名的旅游胜地,有着壮丽的风景和丰富的自然资源。黄山位于安徽省,被誉为中国的五大名山之一。登上黄山,您可以欣赏到奇松怪石、云海日出等壮丽景观。不过需要注意的是,黄山地势险峻,需要一定的体力和意志力来完成登山之旅。希望您在黄山能够享受到美妙的风景和登山的乐趣!您需要我为您提供黄山的相关信息吗?'
conversation_with_summary.predict(input="我喜欢什么运动?")
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Current conversation:
AI: 黄山是一个非常著名的旅游胜地,有着壮丽的风景和丰富的自然资源。黄山位于安徽省,被誉为中国的五大名山之一。登上黄山,您可以欣赏到奇松怪石、云海日出等壮丽景观。不过需要注意的是,黄山地势险峻,需要一定的体力和意志力来完成登山之旅。希望您在黄山能够享受到美妙的风景和登山的乐趣!您需要我为您提供黄山的相关信息吗?
Human: 我喜欢什么运动?
AI:> Finished chain.

[16]:

'很抱歉,我不知道您喜欢什么运动。您可以告诉我您感兴趣的领域,我会尽力为您提供相关信息。比如,如果您喜欢户外活动,我可以为您介绍一些常见的户外运动项目。如果您喜欢健身运动,我也可以为您提供一些健身的建议和指导。请告诉我您的兴趣方向,我会尽力帮助您。'

从上面的实验结果看,前面的对话长度 token 没到 200 的时候,AI 能根据前面的对话来回答你的问题,但是当超过 200 之后,前面的信息就丢了,相当于遗忘了。

ConversationSummaryMemory

如果对话历史如果很长,可以通过摘要记忆对信息进行浓缩

from langchain.memory import ConversationSummaryMemory, ChatMessageHistory
from langchain_openai import OpenAImemory = ConversationSummaryMemory(llm=OpenAI(temperature=0))
memory.save_context({"input": "你好"}, {"output": "你好,有什么需要帮助?"})
memory.load_memory_variables({})
{'history': '\nThe human greets the AI in Chinese. The AI responds in Chinese and asks if there is anything it can help with.'}
通过已经存在的messages或者摘要初始化
history = ChatMessageHistory()
history.add_user_message("hi")
history.add_ai_message("hi there!")memory = ConversationSummaryMemory.from_messages(llm=OpenAI(temperature=0),chat_memory=history,return_messages=True
)memory.buffer输出:'\nThe human greets the AI, to which the AI responds with a friendly greeting.'
通过之前的摘要进行初始化来加快初始化速度
memory = ConversationSummaryMemory(llm=OpenAI(temperature=0),buffer="The human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good because it will help humans reach their full potential.",chat_memory=history,return_messages=True
)

在 chain 使用

from langchain_openai import OpenAI
from langchain.chains import ConversationChain
llm = OpenAI(temperature=0)
conversation_with_summary = ConversationChain(llm=llm,memory=ConversationSummaryMemory(llm=OpenAI()),verbose=True
)
conversation_with_summary.predict(input="Hi, what's up?")

输出:

    > Entering new ConversationChain chain...
    Prompt after formatting:
    The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

    Current conversation:

    Human: Hi, what's up?
    AI:

    > Finished chain.

    " Hi there! I'm doing great. I'm currently helping a customer with a technical issue. How about you?"

向量数据库支持的VectorStoreRetrieverMemory 

当想引用对话中之前提到过的一些信息,这个 memory 会比较有用

初始化向量数据库:

这一步会因使用的向量数据库不同而有所区别,具体细节可以看向量数据库的文档

import faiss
from langchain_openai import OpenAIEmbeddings
from langchain_community.docstore import InMemoryDocstore
from langchain_community.vectorstores import FAISSembedding_size = 1536
index = faiss.IndexFlatL2(embedding_size)
embedding = OpenAIEmbeddings()
vectorstore = FAISS(embedding, index, InMemoryDocstore({}), {})
创建 VectorStoreRetrieverMemory
from langchain.memory import VectorStoreRetrieverMemoryretriever = vectorstore.as_retriever(search_kwargs={"k":2}) # 实际使用时 k 值会设置得比较高
memory = VectorStoreRetrieverMemory(retriever=retriever)# When added to an agent, the memory object can save pertinent information from conversations or used tools
memory.save_context({"input": "我喜欢披萨"}, {"output": "哦,那太好了"})
memory.save_context({"input": "我喜欢足球"}, {"output": "..."})
memory.save_context({"input": "我不喜欢梅西"}, {"output": "ok"}) #
print(memory.load_memory_variables({"prompt": "我该看什么体育节目?"})["history"])

输出:

input: 我喜欢足球
output: ...
input: 我不喜欢梅西
output: ok
在 chain 中使用
from langchain_core.prompts import PromptTemplatellm = OpenAI(temperature=0) # Can be any valid LLM
_DEFAULT_TEMPLATE = """The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Relevant pieces of previous conversation:
{history}(You do not need to use these pieces of information if not relevant)Current conversation:
Human: {input}
AI:"""
PROMPT = PromptTemplate(input_variables=["history", "input"], template=_DEFAULT_TEMPLATE
)
conversation_with_summary = ConversationChain(llm=llm,prompt=PROMPT,memory=memory,verbose=True
)
conversation_with_summary.predict(input="你好,我是 Gem")

输出:

> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Relevant pieces of previous conversation:
input: 我不喜欢梅西
output: ok
input: 我喜欢披萨
output: 哦,那太好了(You do not need to use these pieces of information if not relevant)Current conversation:
Human: 你好,我是 Gem
AI:> Finished chain.

[79]:

' 你好,Gem!我是你的AI助手。我可以回答你关于任何事情的问题。你有什么想知道的吗?'
conversation_with_summary.predict(input="我喜欢什么?")

输出:

> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.Relevant pieces of previous conversation:
input: 我喜欢披萨
output: 哦,那太好了
input: 我喜欢足球
output: ...(You do not need to use these pieces of information if not relevant)Current conversation:
Human: 我喜欢什么?
AI:> Finished chain.

[80]:

' 你喜欢什么?我不太清楚,因为我是一个人工智能,我没有自己的喜好。但是我可以告诉你一些我所知道的事情。比如,我知道你喜欢披萨和足球。你还喜欢什么?'

小结:

  1. LangChain 的 Memory 管理机制属于可用的部分,尤其是简单情况如按轮数或按 Token 数管理;
  2. 对于复杂情况,它不一定是最优的实现,例如检索向量库方式,建议根据实际情况和效果评估;
  3. 但是它对内存的各种维护方法的思路在实际生产中可以借鉴

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

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

相关文章

Keil用ST-LINK下载STM32程序后不自动运行

之后程序可以运行了,但是串口还没有输出,在debug模式下都是ok的。

加权 KNN 算法的原理与详解

加权kNN,k近邻算法的增强改进版本。 加权KNN算法 近邻算法(k-Nearest Neighbors, kNN)是一种用于分类和回归的非参数方法。它的基本思想是“看邻居”,即通过查找离目标点最近的 K 个数据点,来判断目标点的类别或数值。…

学习aurora64/66b.20240703

简介 The AMD LogiCORE™IP Aurora 64B/66B core是一种可扩展的轻量级高数据速率链路层协议,用于高速串行通信。该协议是开放的,可以使用AMD设备技术实现。 Aurora 64B/66B是一种轻量级的串行通信协议,适用于多千兆位链路 (如下图所示)。它…

【MATLAB源码-第139期】基于matlab的OFDM信号识别与相关参数的估计,高阶累量/小波算法调制识别,循环谱估计,带宽估计,载波数目估计等等。

操作环境: MATLAB 2022a 1、算法描述 在现代无线通信系统中,正交频分复用(OFDM)因其高效的频谱利用率、强大的抗多径衰落能力以及灵活的带宽分配等优势,成为了一种非常重要的调制技术。然而,随着无线通信…

采沙船智能监测识别摄像机

对于现代河流管理来说,采沙船智能监测识别摄像机正逐渐成为解决非法采砂和保护河流生态环境的重要工具。这类摄像机通过先进的视觉识别和数据分析技术,有效监控和管理河道上的采沙行为,对保护水域资源和改善生态环境具有显著的意义。 采沙船智…

Linux容器篇-使用kubeadm搭建一个kubernetes集群

kubernetes集群架构和组件 master节点组件 kube-apiserver:Kubernetes API,集群的统一入口,各组件的协调者,以RESTful API提供接口服务,所有对象资源的增删改查和监听操作都交给APIserver处理后再交给Etcd存储。 kube…

学习springAOP

第三章 Spring AOP 第一节 AOP 简介 1. 概念 AOP全称为Aspect Oriented Programming,表示面向切面编程。何为切面呢? 由此可以得出,切面是一种将那些与业务无关,但业务模块都需要使用的功能封装起来的技术。这样便于减少系统的…

昇思25天学习打卡营第4天|应用实践

昇思25天学习打卡营第4天 文章目录 昇思25天学习打卡营第4天基于 MindSpore 实现 BERT 对话情绪识别模型简介环境配置数据集数据加载和数据预处理input_idsattention_mask 模型构建模型验证模型推理自定义推理数据集 打卡记录 基于 MindSpore 实现 BERT 对话情绪识别 模型简介…

奥比中光astra_pro相机使用记录

一、信息获取 1、官网 用于了解产品信息 http://www.orbbec.com.cn/sys/37.html 2、开发者社区 咨询问题下载开发部https://developer.orbbec.com.cn/ 二 、windowvs19 1、相机型号 orbbec_astro_pro 根据对应的型号找到需要的包工具 踩坑1,因为这个相机型号…

第20章 Mac+VSCode配置C++环境

1. 下载VSCode VSCode下载地址在mac终端里输入xcode- select --install命令,根据提示安装xcode工具。 2. 安装插件(4个) 打开VScode,点击应用右侧菜单栏 C/C(必装) Code Runner(必装&#xf…

UCOS-III 任务调度与就绪列表管理

01. 就绪优先级位图 在实时操作系统中,任务调度的效率至关重要。UCOS-III通过就绪优先级位图来快速查找最高优先级的就绪任务,从而实现高效调度。就绪优先级位图是一个按位表示的结构,每个位代表一个优先级,当某个优先级上有任务就…

【FFmpeg】avcodec_open2函数

目录 1. avcodec_open21.1 编解码器的预初始化(ff_encode_preinit & ff_decode_preinit)1.2 编解码器的初始化(init)1.3 释放编解码器(ff_codec_close) FFmpeg相关记录: 示例工程&#xff…

Windows编程之多线程事件对象(Event Object)用法详解

目录 一、前言 二、基础用法 三、API详解 1.创建事件对象 2控制事件状态 3.等待事件对象: 四、实战案例 1.案例描述 2.代码设计 3.总设计代码 4.运行结果 一、前言 事件对象(Event Object)是我们在大型项目中,进行多线…

竞赛选题 医学大数据分析 - 心血管疾病分析

文章目录 1 前言1 课题背景2 数据处理3 数据可视化4 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于大数据的心血管疾病分析 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! &#x1f9…

AI绘画Stable Diffusion 解锁精美壁纸创作:利用SD与LLM定制你的专属壁纸,AI副业变现指南!

大家好,我是画画的小强 今天给大家分享一下用AI绘画Stable Diffusion 制作精美手机壁纸,这也可能是当前最快AIGC变现的一种途径。虽然本文的主题为手机壁纸,当调整不同的比例的分辨率宽高比例,就可以直接复用到手机、电脑和平板、…

机器学习原理之 -- 支持向量机分类:由来及原理详解

支持向量机(Support Vector Machine, SVM)是统计学习理论的一个重要成果,广泛应用于分类和回归问题。SVM以其高效的分类性能和良好的泛化能力在机器学习领域中占据重要地位。本文将详细介绍支持向量机的由来、基本原理、构建过程及其优缺点。…

LVS负载均衡群集部署之——DR模式的介绍及搭建步骤

一、LVS-DR集群介绍1.1 LVS-DR 工作原理1.2 数据包流向分析1.3 LVS-DR 模式的特点1.4 LVS-DR中的ARP问题1.4.1 问题一1.4.2 问题二二、构建LVS-DR集群2.1 构建LVS-DR集群的步骤(理论)1.配置负载调度器(192.168.80.30)(…

5分钟教你用AI把老照片动起来,别再去花49块9的冤枉钱了

文章目录 需要的工具 最近,AI视频在各大平台上,又火了。 只是火的形式,变成了将老照片动起来,打情感牌,或者做很多经典电视剧的再整活。 直接把可灵的生成时间,从以前的4分钟,生生的干成了20分钟…

鸿蒙应用笔记

安装就跳过了,一直点点就可以了 配置跳过,就自动下了点东西。 鸿蒙那个下载要12g个内存,大的有点吓人。 里面跟idea没区别 模拟器或者真机运行 真机要鸿蒙4.0,就可以实机调试 直接在手机里面跑,这个牛逼&#xf…

国标GB/T 28181详解:国标GBT28181-2022 SIP服务器发起广播的命令流程

目录 一、定义 二、作用 1、实现信息的集中管理和分发 (1)信息集中 (2)信息分发 2、提高信息传输的可靠性和效率 (1)可靠性 (2)提高效率 3、支持多种设备和系统的互通 &am…