写在前面的话
当我们提到人工智能时也就是AI的时候呢,我们大多数人首先想到的可能就是像chatGPT这样的聊天机器人,这些聊天机器人通过理解,还有生成自然语言可以给我们提供一些信息,这个是AI最终的形态吗或者AI最终的形式吗?
比尔盖茨在他的个人博客中写道,现有的软件形式然而相当的笨拙软件的未来是智能代理,即AI agent。他认为5年之内,每个人都将拥有自己的智能助理,现在所有的软件都值得用智能方式重构一遍,他提到了人工智能代理agent,不仅会改变每个人与计算机交互的方式,它将颠覆软件行业,带来自我们从键入命令到点击图标以来最大的一个计算革命。
比如说你是一家商业咨询公司,每天有大量的数据表格要处理,那不仅要把数据库里面的原始数据
做清洗然后还要抽取成表格还要从这个表格里面去做统计分析,然后最后得到一些商业洞察,那么这个时候,通用的类chatGPT是无法满足的,最理想的方式呢就是使用AI的能力,构建属于自己的业务的一个chatbot或者代理机器人把数据库连接到agent输入你最终想要的洞察问题,不一会儿这个报告就出来了。甚至可以更进一步,比如连接上我们的电子邮箱,直接就发送出去了。包括在银行、电商平台等各个行业,都是可以广泛应用的。它可以有效提高客户互动的质量和效率。同时在类似数据可视化领域agent能够将原始数据转化为交互图表和图形,让数据分析变得更加有效和直观这对于类似市场分析、健康数据追踪等领域尤其重要。为理解大量复杂信息提供了一种新的方式。
我们大家都知道未来是AI的时代,但是呢很多人都会困惑说我如何去迎接AI时代,是学一堆AI工具怎么用吗,是练好提示词怎么写作吗,其实这些都是比较表面的一些东西,如果说打算投身到这个行业,我觉得agent是可以为大家提供一个选择的。个人来说,学习agent之后,可以结合自己的业务和长处去开发各种的agent来实现它业务的一个倍增,我们可以看到现在随着AI的发展,对这个专业人才需求也不断增加。
文章三大部分介绍
首先第一部分会深入了解AIGC行业,会从这个大模型的发展历程聊起介绍主流的大模型,讨论他们现在的不足,然后会引入微调和launching的解决方案,还会去拆解AIGC行业,从论文算法到应用去理解一些行业术语,最后我们会通过虚拟项目进行需求分析和技术选型,揭开后面的内容。
第二部分会深入这个launching的这个框架,通过学习launching的7大板块,系统的理解agent开发基础理论。比如说在本地环境如何运行launching,理解model IO的概念,掌握提示词模板的应用,还会构建大模型外脑这种知识库做增强检索、文本切分、下单数据库等等等等这样的一些内容。
最后第三部分通过一个完整的虚拟项目,把前面学到的知识付诸实践。从项目准备、产品分析、架构设计到开发实现过程。后面还有扩展的部分比如数字人、智能语音等等。
AI2.0时代应用开发者机会
大语言模型(LLM)基础与发展
LLM(Large Language Model)大语言模型是人工智能领域中一种强大的自然语言处理模型,其发展历史可以追溯到词向量、词嵌入技术的出现,逐步演进到对句子和文本的理解,最终实现了对复杂语境的全面理解和生成。
-
词向量与词嵌入:
- 词向量是将单词映射到向量空间的技术,最早由Yoshua Bengio等人提出。这使得单词之间的语义关系能够以向量的形式被表示。
- 词嵌入技术(Word Embeddings)通过训练将单词映射到连续的实值向量空间中,从而捕捉了单词之间的语义关系。Word2Vec、GloVe和FastText等算法为这一技术的发展做出了重要贡献。
-
句向量与全文向量:
- 句向量技术是将整个句子映射到一个向量空间中,捕捉句子的语义信息。Doc2Vec和Skip-Thought Vectors是一些早期的方法,通过训练模型将句子映射到连续向量空间中。
- 全文向量是将整个文档或文本片段表示为一个向量的技术,捕捉了文档的整体语义信息。这为模型理解文本上下文提供了基础。
-
理解上下文:
- 随着深度学习技术的发展,神经网络模型开始在自然语言处理领域展现出强大的性能。特别是循环神经网络(RNN)和长短期记忆网络(LSTM)等模型,使得模型能够更好地理解文本的上下文信息。
- Transformer模型的出现进一步提高了对文本上下文的理解能力,其自注意力机制允许模型在处理长文本时能够更好地捕捉到远距离的依赖关系,而不受长期依赖问题的困扰。
-
大模型介绍:
- 随着硬件计算能力的提升和大规模数据集的可用性增加,研究人员开始尝试构建更大的语言模型。其中最著名的就是OpenAI的GPT系列(Generative Pre-trained Transformer),包括GPT、GPT-2、GPT-3等模型。这些模型利用了Transformer的架构,并通过大规模的预训练数据和参数数量的增加,实现了前所未有的语言理解和生成能力。
- 这些大型语言模型可以通过预训练的方式学习语言的统计规律和语义信息,并在具体任务上进行微调,因此被广泛应用于文本生成、问答系统、机器翻译等领域,取得了令人瞩目的成果。
综上所述,LLM的发展史可以看作是从对单词到句子再到全文的理解能力逐步提升,最终通过大规模预训练的深度神经网络模型实现了对复杂语境的全面理解和生成。
国内外主要LLM及特点介绍
hugging face
提供简单易用的NLP模型和工具库,搞ai界的github。
Hugging Face – The AI community building the future.
大模型的不足以及解决方案
不具备记忆能力,上下文窗口的限制,实时信息更新慢,新旧知识难以区分,无法灵活操控外部系统,无法为领域问题,提供专业靠谱的答案。
AIGC产业拆解以及常见名词
aigc产业拆解
aigc常用名词
应用级开发者应该如何拥抱AIGC
这张这张图上,越往上他的整个难度大,门槛高,然后越往下,机会就会越多。
机会最少的是基座大模型,就是类似chatGPT、国内的百川智能这样的,特点就是消耗算力特别巨大,需要大量的资本来支持。做一次全量的训练的话现在可能在几千万美金,所以只有巨头和大资本是玩得起的。相应的来说的话,他的职业机会是比较少的。
再往下就是我们的行业垂直大模型,就是在所谓的在基座模型基础上去灌入一些行业的数据,在基础大模型上做微调,职业机会稍微多了一点。但是对于我们应用级开发者呢还是机会不是那么多。
再往下看就是所谓的AI原生应用,不管是ToB还是ToC的这块都有大量的机会。我们这些传统做互联网、科技公司、应用开发公司、科技创业公司、应用开发者都有大量的机会存在。它是一个比较重要的一个位置,也是未来一个爆发的赛道。就像苹果一样有自己的APP store。
所以说在这个时候其实是有大量的职业机会或者大量的这种应用开发的机会存在的,我们传统的应用开发者去快速转型去跟上这个赛道的一个绝佳的机会。有点像当年这个苹果刚发布APP store时候那个状态。可以说所有的应用,都值得用AI啊重新做一遍。
比如说AI加文旅,你计划做一次旅行,你的旅游的这个机器人会帮你找到适合你预算的酒店,然后智能体呢还会知道你你在一年中什么时候去旅行,根据他对你总是尝试这个新的目的地的了解或者你喜欢故地重游的行为的了解,他会向你建议旅游目的地,当他被询问的时候他智能就会根据你的兴趣和冒险的倾向为你推荐做可以做的事情,还能帮你预定你喜欢的餐厅。如果没有这样的一个AI场景的话,你现在做这些事情可能需要旅行社帮你去定制。但是呢使用了智能体加这个场景之后我们就可以解决。不远的未来我们每个人都会有自己的私人智能体助理。
agent开发这一个层面上,需要做哪些准备工作呢?或者说我们转型需要掌握一些什么东西。
1、首先就是要学习机器学习和深度学习的一些基础知识,大模型层面和行业模型层面有一个基础的知识准备。
2、需要有Python语言基础,这个方向大量的项目都是用Python来开发的
3、学会使用AI,例如开发工具和框架
4、应用开发是离不开行业场景和业务流程的,所以需要对行业的场景有一个深入的了解,抓到里面最关键的部分,可能成功的几率就会比较高
一、LangChain框架初识
LangChain是什么以及发展过程
LangChain是一个2022年10月25日开源的框架,其主要作用是帮助开发者更加高效、便捷地在实际应用程序中整合和利用大型语言模型(LLMs),例如GPT-3等,并且扩展这些模型的能力使其能够与外部数据源、API和其他服务进行交互。通过LangChain,开发者可以构建上下文感知的应用程序,使得语言模型不仅能基于自身训练内容生成回复,还能结合实时信息和历史上下文进行推理和决策。其特点包括模块化组件设计、支持数据感知的链式调用结构以及增强的语言模型代理功能,从而简化了开发流程并促进了基于LLM的创新型应用的诞生,如聊天机器人、智能问答系统、搜索引擎等高级NLP应用场景。
LangChain是react论文论文的落地实现,那么这个react表示的是什么,react其实是reason加act的一个合并缩写,也就是推理加行动。那么这篇论文啊为什么是launching的基础,它有什么特别。
人类的这个AI的这个方面,我们终极的目标是希望实现AGI,就是所谓的通用AI,那么在通用AI之前我们现在已经走到了大模型这个阶段,大模型要实现像人脑一样的思考首先就是要反过来想人类是怎么解决问题的,人类之所以拥有独一无二的认知能力,重要原因是我们不会采取无意义的行动。人类行动的背后都是有原因的都是有一个逻辑链条。我们人类通过行动,去获取外部世界的信息,这些信息呢又可以让我们形成更加完善的逻辑链条,进而调整后续的行动。
但是一个AI的程序它天然不具备这样的能力,那比如说我们跟open AI交互的时候,很多时候其实是一个直接的输入输出的一个关系,他没有这样的一个思维链,也没有这样的一个逻辑链。模型会给一些推理过程但是答案也是错的,因为它只推理没有获得外部信息,他这种情况下做的最好的只能是把他预训练时候底膜里面的东西知识拿出来去关联,那关联不到他就会瞎编就会出现幻觉。
那么react也就是这个reason加act,这样的一个范式就是想驱动LLM大模型来用类似这样的方法去工作,可以让大模型像人脑一样去思考。
LangChain的github地址:langchain-ai/langchain: 🦜🔗 Build context-aware reasoning applications (github.com)
LangChain能做什么它有什么能力
LangChain的核心思想是将不同的功能组件连接起来形成一个链式结构,每个组件都可以独立运作或与其他组件协作,这些组件包括但不限于:提示模板(Prompt Templates)、大型语言模型(LLMs)、代理(Agents)、短期/长期记忆(Memory)等。
LLMs & Prompt
提供了目前市面上几乎所有 LLM 的通用接口,同时还提供了 提示词 的管理和优化能力,同时也提供了非常多的相关适用工具,以方便开发人员利用 LangChain与 LLMs 进行交互。
Chains
LangChain 把 提示词、大语言模型、结果解析封装成 Chain,并提供标准的接口,以便允许不同的Chain形成交互序列,为 AI原生应用提供了端到端的 Chain
Retrieval Augemented Generation
检索增强生成式 是一种解决预训练语料数据无法及时更新而带来的回答内容陈旧日的方式。LangChain提供了支持 检索增强生成式 的 Chain,在使用时,这些 Chain 会首先与外部数据源进行交互以获得对应数据,然后再利用获得的数据与 LLMs 进行交互。典型的应用场如:基于特定数据源的问答机器人。
Agent
对于一个任务,代理主要涉及让 LLMs 来对任务进行拆分、执行该行动、并观察执行结果,代理 会重复执行这个过程,直到该任务完成为止。LangChain 为 代理 提供了标准接口,可供选择的代理,以及一些端到端的代理的示例。
Memory
指的是 chain 或 agent 调用之间的状态持久化。LangChain 为 内存 提供了标准接口,并提供了一系列的 内存 实现。
Evaluation
LangChain 还提供了非常多的评估能力以允许我们可以更方便的对 LLMs 进行评估。
LangChain的优势和劣势
优势
1、大语言模型调用能力,支持多平台多模型调用,为用户提供灵活选择。
LangChain的核心优势之一是其对多个大型语言模型(LLMs)平台的兼容性,它允许开发人员无缝地集成和切换不同的模型,如OpenAI、Cohere或Hugging Face等。这意味着开发者可以根据项目需求选择最合适的模型,而不是被特定API所限制,极大地增强了应用的灵活性和可扩展性。
2、轻量级SDK(python、javascript)将LLMs与传统编程语言集成在一起。
通过提供Python和JavaScript等编程语言的轻量级软件开发工具包(SDK),LangChain简化了将LLMs整合到传统应用程序中的过程。这种集成方式降低了开发门槛,使得非AI专家也能相对容易地利用强大的语言模型功能,构建复杂的应用程序逻辑。
3、多模态支持,提供多模态数据支持,如图像、音频等。
LangChain不仅限于处理文本数据,还能够支持多模态输入输出,例如处理图像、音频和其他类型的数据。这一特性使得基于LangChain构建的应用可以理解并生成多媒体内容,从而实现更加丰富、智能的交互体验。
劣势
1、学习曲线相对较高。
尽管LangChain旨在简化LLM的应用开发,但由于其架构设计较为先进且具有高度模块化的特点,对于初次接触该框架的开发者来说,理解和掌握如何配置、串联各个组件以达到预期效果可能需要一定的时间投入和学习成本。
2、文档相对不完善,官方文档不是很完善。
刚开始的时候可能是因为赶进度的原因,他的文档质量非常低,基本上得去看他的原代码才能明白是做什么的,但是最新的版本发布以后文档的质量水平有很大的提升了。
3、缺乏大型工业化应用实践。
缺乏大型的工业化应用,也就说没有哪特别大的厂商在用它,但是有很多中小项目在用。
LangChain安装以及测试实例
pip安装LangChain
pip install --upgrade langchain -i https://pypi.org/simple
conda安装LangChain
conda install langchain -c conda-forge
测试示例
我使用的是阿里云的通义千问大模型,使用openai、百度文心都可以,这里只是为了学习测试
调用官方sdk样例
from http import HTTPStatus
import dashscope
#api_key需要自己申请,申请地址阿里云 https://bailian.console.aliyun.com/
dashscope.api_key=""
def sample_sync_call():
prompt_text = '用萝卜、土豆、茄子做饭,给我个菜谱。'
resp = dashscope.Generation.call(
model='qwen-turbo',
prompt=prompt_text
)
# The response status_code is HTTPStatus.OK indicate success,
# otherwise indicate request is failed, you can get error code
# and message from code and message.
if resp.status_code == HTTPStatus.OK:
print(resp.output) # The output text
print(resp.usage) # The usage information
else:
print(resp.code) # The error code.
print(resp.message) # The error message.
sample_sync_call()
使用langchain库调用
#!pip install langchain langchainhub dashscope
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains import LLMChain
from langchain_community.llms import Tongyi
from langchain import hub
import os
prompt1 = ChatPromptTemplate.from_template("""{input}""")
os.environ["DASHSCOPE_API_KEY"] = ""
llm = Tongyi()
chain_one = LLMChain(
llm=llm,
prompt=prompt1,
verbose=False
)
print(chain_one.invoke("用萝卜、土豆、茄子做饭,给我个菜谱。"))
LangChain的核心模块与实操
模型IO大语言模型的交互接口
在langchain
中,“模型IO大语言模型的交互接口”是指一套标准化的方法和结构,用于与各种大型语言模型(Large Language Models, LLMs)进行交互。这些接口旨在提供一种通用的方式来封装不同LLM服务提供商(如OpenAI、Cohere、Hugging Face等)的具体API细节,使开发者能够以一致的方式调用不同模型的功能,而不必关心底层实现的差异。
prompts模板
概念
LangChain 提供了一套用于构建和操作提示(prompts)的模板系统,旨在帮助用户更高效、灵活地与各种大语言模型(LLMs)交互。Prompts 模板旨在标准化、模块化以及自动化提示的设计过程,以优化模型输出的质量和一致性。
PromptTemplate: 这是最基础的提示模板类,用于定义一个可复用的、结构化的文本模板,其中可能包含占位符或变量。模板可以包含静态文本和动态部分,动态部分通过指定的输入变量(如 foo 和 bar)进行填充。
StringPromptTemplate: 特定类型的提示模板,专用于处理字符串形式的模板。它可能提供了额外的方法或特性,便于直接操作文本模板。
PipelinePromptTemplate: 这种模板允许将多个独立的提示按照特定顺序组成一个“流水线”,每个步骤可能使用不同的模型或处理逻辑,使得复杂任务能够通过一系列有序的子任务来完成。
关于提示词
好的提示词能够使语言模型更加有效准确的回答
PromptTemplate字符模板
简单的字符替换
from langchain.prompts import PromptTemplate
prompt = PromptTemplate.from_template("你是一个起名大师,帮我起1个具有{county}特色的男孩名字")
prompt.format(county="法国")
ChatPromptTemplate模板
生成ai对话上下文背景,也就是先做个铺垫,可以使ai更加优化准确的回答
from langchain.prompts import ChatPromptTemplate
chat_template = ChatPromptTemplate.from_messages(
[
("system","你是一个起名大师,你的名字叫{name}"),
("human","你好{name},你感觉如何?"),
("ai","你好!我状态非常好!"),
("human","{user_input}"),
]
)
chat_template.format_messages(name="陈大师",user_input="你叫什么名字呢?")
StoryPromptTemplate自定义模板
from langchain.prompts import PromptTemplate, StringPromptTemplate
from pydantic import BaseModel
from typing import List
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains import LLMChain
from langchain_community.llms import Tongyi
from langchain import hub
import os
# 定义一个用于故事创作的自定义输入模型,包括标题、角色、情节点等信息
class StoryInput(BaseModel):
title: str
characters: List[str]
plot_points: List[str]
# 定义自定义提示模板
class StoryPromptTemplate():
# 基础提示模板字符串
base_prompt: str = "撰写一篇标题为《{title}》的短篇故事,故事中包含以下角色:{characters}。故事应包含以下情节点:{plot_points}。请以一句引人入胜的开场句开始故事。"
def render(self, story_input: StoryInput) -> str:
"""使用提供的故事输入渲染自定义提示。"""
formatted_characters = ", ".join(story_input.characters)
formatted_plot_points = "\n".join(f"- {point}" for point in story_input.plot_points)
return self.base_prompt.format(
title=story_input.title,
characters=formatted_characters,
plot_points=formatted_plot_points,
)
# 创建一个故事输入实例
story_input = StoryInput(
title="神秘森林",
characters=["艾芙琳", "加伦", "智者猫头鹰"],
plot_points=[
"艾芙琳发现一张通往隐藏林地的古老地图。",
"加伦警告森林周围存在一股黑暗诅咒。",
"智者猫头鹰揭示了解除诅咒的秘密。",
],
)
# 创建自定义提示模板实例
story_prompt = StoryPromptTemplate()
# 渲染并打印出最终的提示
final_prompt = story_prompt.render(story_input)
prompt1 = ChatPromptTemplate.from_template("""{input}""")
os.environ["DASHSCOPE_API_KEY"] = "sk-cf5d02e81ea44717a35e22c72e4c0dc1"
llm = Tongyi()
chain_one = LLMChain(
llm=llm,
prompt=prompt1,
verbose=False
)
result = chain_one.invoke(final_prompt)
text_content = result['text']
print(text_content)
RAG检索增强
RAG是一种先进的自然语言处理(NLP)技术,它巧妙地结合了信息检索与神经网络生成模型的特点,提高AI系统在理解和生成文本时的上下文敏感性和准确性。可以弥补LLM语言模型无法实时学习、无法获取外部数据的缺点。
loader文件加载
#使用loader来加载markdown文本
from langchain.document_loaders import TextLoader
loader = TextLoader("loader.md")
loader.load()
#使用loader来加载cvs文件
from langchain.document_loaders.csv_loader import CSVLoader
#loader = CSVLoader(file_path="loader.csv")
loader = CSVLoader(file_path="loader.csv",source_column="Location")
data = loader.load()
print(data)
#某个目录下,有excel文件,我们需要把目录下所有的xlxs文件加载进来
#! pip install "unstructured[xlsx]"
from langchain.document_loaders import DirectoryLoader
#目录下的.html和.rst文件不会被这种loader加载
#loader = DirectoryLoader("目录地址",glob="指定加载说明格式的文件")
loader = DirectoryLoader(path="./example/",glob="*.xlsx")
docs = loader.load()
len(docs)
#使用loader来加载html文件
#from langchain.document_loaders import UnstructuredHTMLLoader
#loader = UnstructuredHTMLLoader("loader.html")
from langchain.document_loaders import BSHTMLLoader
loader = BSHTMLLoader("loader.html")
data = loader.load()
data
#使用loader来加载json文件
#需要先安装 ! pip install jq
from langchain.document_loaders import JSONLoader
loader = JSONLoader(
file_path = "simple_prompt.json",jq_schema=".template",text_content=True
)
data = loader.load()
print(data)
#loader加载pdf文件
from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader("loader.pdf")
pages = loader.load_and_split()
pages[0]
文档切割
文档切割
原理
将文档分成小的、有意义的块(句子).
将小的块组合成为一个更大的块,直到达到一定的大小.
一旦达到一定的大小,接着开始创建与下一个块重叠的部分.
示例
第一个文档分割
按字符切割
代码文档切割
按token来切割
from langchain.text_splitter import RecursiveCharacterTextSplitter
#加载要切割的文档
with open("test.txt") as f:
zuizhonghuanxiang = f.read()
#初始化切割器
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=50,#切分的文本块大小,一般通过长度函数计算
chunk_overlap=20,#切分的文本块重叠大小,一般通过长度函数计算
length_function=len,#长度函数,也可以传递tokenize函数
add_start_index=True,#是否添加起始索引
)
text = text_splitter.create_documents([zuizhonghuanxiang])
text[0]
text[1]
#字符串切割
from langchain.text_splitter import CharacterTextSplitter
#加载要切分的文档
with open("test.txt") as f:
zuizhonghuanxiang = f.read()
#初始化切分器
text_splitter = CharacterTextSplitter(
separator="。",#切割的标志字符,默认是\n\n
chunk_size=50,#切分的文本块大小,一般通过长度函数计算
chunk_overlap=20,#切分的文本块重叠大小,一般通过长度函数计算
length_function=len,#长度函数,也可以传递tokenize函数
add_start_index=True,#是否添加起始索引
is_separator_regex=False,#是否是正则表达式
)
text = text_splitter.create_documents([zuizhonghuanxiang])
print(text[0])
#代码文档切割
from langchain.text_splitter import (
RecursiveCharacterTextSplitter,
Language,
)
#支持解析的编程语言
#[e.value for e in Language]
#要切割的代码文档
PYTHON_CODE = """
def hello_world():
print("Hello, World!")
#调用函数
hello_world()
"""
py_spliter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON,
chunk_size=50,
chunk_overlap=10,
)
python_docs = py_spliter.create_documents([PYTHON_CODE])
python_docs
#按token来切割文档
from langchain.text_splitter import CharacterTextSplitter
#要切割的文档
with open("test.txt") as f:
zuizhonghuanxiang = f.read()
#初始化切分器
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=4000,#切分的文本块大小,一般通过长度函数计算
chunk_overlap=30,#切分的文本块重叠大小,一般通过长度函数计算
)
text = text_splitter.create_documents([zuizhonghuanxiang])
print(text[0])
调用chatGPT-API对文档进行总结、精炼和翻译
#! pip install doctran==0.0.14
#加载文档
with open("letter.txt") as f:
content = f.read()
from dotenv import load_dotenv
import os
load_dotenv("openai.env")
OPENAI_API_KEY = os.environ.get("OPEN_API_KEY")
OPENAI_API_BASE = os.environ.get("OPENAI_API_BASE")
OPENAI_MODEL = "gpt-3.5-turbo-16k"
OPENAI_TOKEN_LIMIT = 8000
from doctran import Doctran
doctrans = Doctran(
openai_api_key=OPENAI_API_KEY,
openai_model=OPENAI_MODEL,
openai_token_limit=OPENAI_TOKEN_LIMIT,
)
documents = doctrans.parse(content=content)
#总结文档
summary = documents.summarize(token_limit=100).execute()
print(summary.transformed_content)
#翻译一下文档
translation = documents.translate(language="chinese").execute()
print(translation.transformed_content)
#精炼文档,删除除了某个主题或关键词之外的内容,仅保留与主题相关的内容
refined = documents.refine(topics=["marketing","Development"]).execute()
print(refined.transformed_content)
Lost in the middle: 长上下文精度问题
#! pip install sentence-transformers
from langchain.chains import LLMChain,StuffDocumentsChain
from langchain.document_transformers import (
LongContextReorder
)
from langchain.embeddings import HuggingFaceBgeEmbeddings
from langchain.vectorstores import Chroma
#使用huggingface托管的开源LLM来做嵌入,MiniLM-L6-v2是一个较小的LLM
embedings = HuggingFaceBgeEmbeddings(model_name="all-MiniLM-L6-v2")
text = [
"篮球是一项伟大的运动。",
"带我飞往月球是我最喜欢的歌曲之一。",
"凯尔特人队是我最喜欢的球队。",
"这是一篇关于波士顿凯尔特人的文件。",
"我非常喜欢去看电影。",
"波士顿凯尔特人队以20分的优势赢得了比赛。",
"这只是一段随机的文字。",
"《艾尔登之环》是过去15年最好的游戏之一。",
"L.科内特是凯尔特人队最好的球员之一。",
"拉里.伯德是一位标志性的NBA球员。"
]
retrieval = Chroma.from_texts(text,embedings).as_retriever(
search_kwargs={"k": 10}
)
query = "关于我的喜好都知道什么?"
#根据相关性返回文本块
docs = retrieval.get_relevant_documents(query)
docs
#对检索结果进行重新排序,根据论文的方案
#问题相关性越低的内容块放在中间
#问题相关性越高的内容块放在头尾
reordering = LongContextReorder()
reo_docs = reordering.transform_documents(docs)
#头尾共有4个高相关性内容块
reo_docs
from dotenv import load_dotenv
load_dotenv("openai.env")
import os
api_key = os.environ.get("OPENAI_API_KEY")
api_base = os.environ.get("OPENAI_API_BASE")
#检测下这种方案的精度效果
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
#设置llm
llm = OpenAI(
api_key=api_key,
api_base=api_base,
model="gpt-3.5-turbo-instruct",
temperature=0
)
document_prompt = PromptTemplate(
input_variables=["page_content"],template="{page_content}"
)
stuff_prompt_override ="""Given this text extracts:
----------------------------------------
{context}
----------------------------------------
Please answer the following questions:
{query}
"""
prompt = PromptTemplate(
template=stuff_prompt_override,
input_variables=["context","query"]
)
llm_chain = LLMChain(
llm=llm,
prompt=prompt
)
WorkChain = StuffDocumentsChain(
llm_chain=llm_chain,
document_prompt=document_prompt,
document_variable_name="context"
)
#调用
WorkChain.run(
input_documents=reo_docs,
query="我最喜欢做什么事情?"
)
文本向量化
embedding嵌入可以让一组文本或者一段话以向量来表示,从而可以让我们在向量空间中进行语义搜索之类的操作,从而大幅提升学习能力。
from langchain_openai import OpenAIEmbeddings
e_model = OpenAIEmbeddings()
ebeddings = e_model.embed_documents(
[
"你好",
"你好啊",
"你叫什么名字?",
"我叫王大锤",
"很高兴认识你大锤",
]
)
ebeddings
embedded_query = e_model.embed_query("这段对话中提到了什么名字?")
embedded_query[:5]
from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import LocalFileStore
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
u_embeddings = OpenAIEmbeddings()
fs = LocalFileStore("./cache/")
cached_embeddings = CacheBackedEmbeddings.from_bytes_store(
u_embeddings,
fs,
namespace=u_embeddings.model,
)
list(fs.yield_keys())
from langchain.vectorstores import FAISS
%timeit -r 1 -n 1 db= FAISS.from_documents(documents,cached_embeddings)
#查看缓存中的键
list(fs.yield_keys())
AI数据持久化向量数据库
向量数据是用空间来描述高维数据,以距离来判断亲疏,是图形处理分类、推荐系统的背后英雄,可以高效的检索,让AI具备记忆能力和知识库更新的能力。
目前用的比较多的向量数据库:
Milvus:开源、Go Python C++、云服务
Faiss:开源、C++ Python、无云服务
Pinecone:闭源
Chroma:开源、Python、无云服务
LanceDB:开源、Rust Python JavaScript、无云服务
chatDoc文档检索对话实现流程
#安装必须的包
! pip install docx2txt
! pip install pypdf
! pip install nltk
#导入必须的包
from langchain.document_loaders import Docx2txtLoader
#定义chatdoc
class ChatDoc():
def getFile():
#读取文件
loader = Docx2txtLoader("example/fake.docx")
text = loader.load()
return text;
ChatDoc.getFile()
#整合优化,动态加载三种文件格式,增加了文本切割
#导入必须的包
from langchain.document_loaders import UnstructuredExcelLoader,Docx2txtLoader,PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
#定义chatdoc
class ChatDoc():
def __init__(self):
self.doc = None
self.splitText = [] #分割后的文本
def getFile(self):
doc = self.doc
loaders = {
"docx":Docx2txtLoader,
"pdf":PyPDFLoader,
"xlsx":UnstructuredExcelLoader,
}
file_extension = doc.split(".")[-1]
loader_class = loaders.get(file_extension)
if loader_class:
try:
loader = loader_class(doc)
text = loader.load()
return text
except Exception as e:
print(f"Error loading {file_extension} files:{e}")
else:
print(f"Unsupported file extension: {file_extension}")
return None
#处理文档的函数
def splitSentences(self):
full_text = self.getFile() #获取文档内容
if full_text != None:
#对文档进行分割
text_split = CharacterTextSplitter(
chunk_size=150,
chunk_overlap=20,
)
texts = text_split.split_documents(full_text)
self.splitText = texts
chat_doc = ChatDoc()
chat_doc.doc = "example/fake.xlsx"
chat_doc.splitSentences()
print(chat_doc.splitText)
#向量化与存储索引
#导入必须的包
from langchain.document_loaders import UnstructuredExcelLoader,Docx2txtLoader,PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
#定义chatdoc
class ChatDoc():
def __init__(self):
self.doc = None
self.splitText = [] #分割后的文本
def getFile(self):
doc = self.doc
loaders = {
"docx":Docx2txtLoader,
"pdf":PyPDFLoader,
"xlsx":UnstructuredExcelLoader,
}
file_extension = doc.split(".")[-1]
loader_class = loaders.get(file_extension)
if loader_class:
try:
loader = loader_class(doc)
text = loader.load()
return text
except Exception as e:
print(f"Error loading {file_extension} files:{e}")
else:
print(f"Unsupported file extension: {file_extension}")
return None
#处理文档的函数
def splitSentences(self):
full_text = self.getFile() #获取文档内容
if full_text != None:
#对文档进行分割
text_split = CharacterTextSplitter(
chunk_size=150,
chunk_overlap=20,
)
texts = text_split.split_documents(full_text)
self.splitText = texts
#向量化与向量存储
def embeddingAndVectorDB(self):
embeddings = OpenAIEmbeddings()
db =Chroma.from_documents(
documents = self.splitText,
embedding = embeddings,
)
return db
chat_doc = ChatDoc()
chat_doc.doc = "example/fake.docx"
chat_doc.splitSentences()
chat_doc.embeddingAndVectorDB()
#索引并使用自然语言找出相关的文本块
#导入必须的包
from langchain.document_loaders import UnstructuredExcelLoader,Docx2txtLoader,PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
#定义chatdoc
class ChatDoc():
def __init__(self):
self.doc = None
self.splitText = [] #分割后的文本
def getFile(self):
doc = self.doc
loaders = {
"docx":Docx2txtLoader,
"pdf":PyPDFLoader,
"xlsx":UnstructuredExcelLoader,
}
file_extension = doc.split(".")[-1]
loader_class = loaders.get(file_extension)
if loader_class:
try:
loader = loader_class(doc)
text = loader.load()
return text
except Exception as e:
print(f"Error loading {file_extension} files:{e}")
else:
print(f"Unsupported file extension: {file_extension}")
return None
#处理文档的函数
def splitSentences(self):
full_text = self.getFile() #获取文档内容
if full_text != None:
#对文档进行分割
text_split = CharacterTextSplitter(
chunk_size=150,
chunk_overlap=20,
)
texts = text_split.split_documents(full_text)
self.splitText = texts
#向量化与向量存储
def embeddingAndVectorDB(self):
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small"
)
db =Chroma.from_documents(
documents = self.splitText,
embedding = embeddings,
)
return db
#提问并找到相关的文本块
def askAndFindFiles(self,question):
db = self.embeddingAndVectorDB()
retriever = db.as_retriever()
results = retriever.invoke(question)
return results
chat_doc = ChatDoc()
chat_doc.doc = "example/fake.docx"
chat_doc.splitSentences()
chat_doc.askAndFindFiles("这家公司叫什么名字?")
#使用多重查询提高文档检索精确度
#导入必须的包
from langchain.document_loaders import UnstructuredExcelLoader,Docx2txtLoader,PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
#引入openai和多重向量检索
from langchain.chat_models import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever
#定义chatdoc
class ChatDoc():
def __init__(self):
self.doc = None
self.splitText = [] #分割后的文本
def getFile(self):
doc = self.doc
loaders = {
"docx":Docx2txtLoader,
"pdf":PyPDFLoader,
"xlsx":UnstructuredExcelLoader,
}
file_extension = doc.split(".")[-1]
loader_class = loaders.get(file_extension)
if loader_class:
try:
loader = loader_class(doc)
text = loader.load()
return text
except Exception as e:
print(f"Error loading {file_extension} files:{e}")
else:
print(f"Unsupported file extension: {file_extension}")
return None
#处理文档的函数
def splitSentences(self):
full_text = self.getFile() #获取文档内容
if full_text != None:
#对文档进行分割
text_split = CharacterTextSplitter(
chunk_size=150,
chunk_overlap=20,
)
texts = text_split.split_documents(full_text)
self.splitText = texts
#向量化与向量存储
def embeddingAndVectorDB(self):
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small"
)
db =Chroma.from_documents(
documents = self.splitText,
embedding = embeddings,
)
return db
#提问并找到相关的文本块
def askAndFindFiles(self,question):
db = self.embeddingAndVectorDB()
#把问题交给LLM进行多角度的扩展
llm = ChatOpenAI(temperature=0)
retriever_from_llm = MultiQueryRetriever.from_llm(
retriever = db.as_retriever(),
llm = llm,
)
return retriever_from_llm.get_relevant_documents(question)
chat_doc = ChatDoc()
chat_doc.doc = "example/fake.docx"
chat_doc.splitSentences()
#设置下logging查看生成查询
import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.DEBUG)
unique_doc = chat_doc.askAndFindFiles("公司名称是什么?")
print(unique_doc)
#使用上下文压缩检索降低冗余信息
#导入必须的包
from langchain.document_loaders import UnstructuredExcelLoader,Docx2txtLoader,PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
#引入openai和多重向量检索
#from langchain.chat_models import ChatOpenAI
#from langchain.retrievers.multi_query import MultiQueryRetriever
#引入上下文压缩相关包
from langchain.llms import OpenAI
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
#定义chatdoc
class ChatDoc():
def __init__(self):
self.doc = None
self.splitText = [] #分割后的文本
def getFile(self):
doc = self.doc
loaders = {
"docx":Docx2txtLoader,
"pdf":PyPDFLoader,
"xlsx":UnstructuredExcelLoader,
}
file_extension = doc.split(".")[-1]
loader_class = loaders.get(file_extension)
if loader_class:
try:
loader = loader_class(doc)
text = loader.load()
return text
except Exception as e:
print(f"Error loading {file_extension} files:{e}")
else:
print(f"Unsupported file extension: {file_extension}")
return None
#处理文档的函数
def splitSentences(self):
full_text = self.getFile() #获取文档内容
if full_text != None:
#对文档进行分割
text_split = CharacterTextSplitter(
chunk_size=150,
chunk_overlap=20,
)
texts = text_split.split_documents(full_text)
self.splitText = texts
#向量化与向量存储
def embeddingAndVectorDB(self):
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small"
)
db =Chroma.from_documents(
documents = self.splitText,
embedding = embeddings,
)
return db
#提问并找到相关的文本块
def askAndFindFiles(self,question):
db = self.embeddingAndVectorDB()
retriever = db.as_retriever()
llm = OpenAI(temperature=0)
compressor = LLMChainExtractor.from_llm(
llm = llm,
)
compressor_retriever = ContextualCompressionRetriever(
base_retriever = retriever,
base_compressor = compressor,
)
return compressor_retriever.get_relevant_documents(query=question)
chat_doc = ChatDoc()
chat_doc.doc = "example/fake.docx"
chat_doc.splitSentences()
#设置下logging查看生成查询
import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.DEBUG)
unique_doc = chat_doc.askAndFindFiles("这间公司的负债有多少?")
print(unique_doc)
#在向量存储里使用最大边际相似性(MMR)和相似性打分
#导入必须的包
from langchain.document_loaders import UnstructuredExcelLoader,Docx2txtLoader,PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
#定义chatdoc
class ChatDoc():
def __init__(self):
self.doc = None
self.splitText = [] #分割后的文本
def getFile(self):
doc = self.doc
loaders = {
"docx":Docx2txtLoader,
"pdf":PyPDFLoader,
"xlsx":UnstructuredExcelLoader,
}
file_extension = doc.split(".")[-1]
loader_class = loaders.get(file_extension)
if loader_class:
try:
loader = loader_class(doc)
text = loader.load()
return text
except Exception as e:
print(f"Error loading {file_extension} files:{e}")
else:
print(f"Unsupported file extension: {file_extension}")
return None
#处理文档的函数
def splitSentences(self):
full_text = self.getFile() #获取文档内容
if full_text != None:
#对文档进行分割
text_split = CharacterTextSplitter(
chunk_size=150,
chunk_overlap=20,
)
texts = text_split.split_documents(full_text)
self.splitText = texts
#向量化与向量存储
def embeddingAndVectorDB(self):
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small"
)
db =Chroma.from_documents(
documents = self.splitText,
embedding = embeddings,
)
return db
#提问并找到相关的文本块
def askAndFindFiles(self,question):
db = self.embeddingAndVectorDB()
#retriever = db.as_retriever(search_type="mmr")
retriever = db.as_retriever(search_type="similarity_score_threshold",search_kwargs={"score_threshold":.1,"k":1})
return retriever.get_relevant_documents(query=question)
chat_doc = ChatDoc()
chat_doc.doc = "example/fake.docx"
chat_doc.splitSentences()
#设置下logging查看生成查询
import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.DEBUG)
unique_doc = chat_doc.askAndFindFiles("这家公司的地址在哪里?")
print(unique_doc)
chatDoc 和文档进行聊天
import os
import os
from dotenv import load_dotenv
# Load environment variables from openai.env file
load_dotenv("openai.env")
# Read the OPENAI_API_KEY from the environment
api_key = os.getenv("OPENAI_API_KEY")
api_base = os.getenv("OPENAI_API_BASE")
os.environ["OPENAI_API_KEY"] = api_key
os.environ["OPENAI_API_BASE"] = api_base
#导入必须的包
from langchain.document_loaders import UnstructuredExcelLoader,Docx2txtLoader,PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
#导入聊天所需的模块
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
#定义chatdoc
class ChatDoc():
def __init__(self):
self.doc = None
self.splitText = [] #分割后的文本
self.template = [
("system","你是一个处理文档的秘书,你从不说自己是一个大模型或者AI助手,你会根据下面提供的上下文内容来继续回答问题.\n 上下文内容\n {context} \n"),
("human","你好!"),
("ai","你好"),
("human","{question}"),
]
self.prompt = ChatPromptTemplate.from_messages(self.template)
def getFile(self):
doc = self.doc
loaders = {
"docx":Docx2txtLoader,
"pdf":PyPDFLoader,
"xlsx":UnstructuredExcelLoader,
}
file_extension = doc.split(".")[-1]
loader_class = loaders.get(file_extension)
if loader_class:
try:
loader = loader_class(doc)
text = loader.load()
return text
except Exception as e:
print(f"Error loading {file_extension} files:{e}")
else:
print(f"Unsupported file extension: {file_extension}")
return None
#处理文档的函数
def splitSentences(self):
full_text = self.getFile() #获取文档内容
if full_text != None:
#对文档进行分割
text_split = CharacterTextSplitter(
chunk_size=150,
chunk_overlap=20,
)
texts = text_split.split_documents(full_text)
self.splitText = texts
#向量化与向量存储
def embeddingAndVectorDB(self):
embeddings = OpenAIEmbeddings()
db =Chroma.from_documents(
documents = self.splitText,
embedding = embeddings,
)
return db
#提问并找到相关的文本块
def askAndFindFiles(self,question):
db = self.embeddingAndVectorDB()
#retriever = db.as_retriever(search_type="mmr")
retriever = db.as_retriever(search_type="similarity_score_threshold",search_kwargs={"score_threshold":.5,"k":1})
return retriever.get_relevant_documents(query=question)
#用自然语言和文档聊天
def chatWithDoc(self,question):
_content = ""
context = self.askAndFindFiles(question)
for i in context:
_content += i.page_content
messages = self.prompt.format_messages(context=_content,question=question)
chat = ChatOpenAI(
model="gpt-4",
temperature=0,
)
return chat.invoke(messages)
chat_doc = ChatDoc()
chat_doc.doc = "example/fake.docx"
chat_doc.splitSentences()
chat_doc.chatWithDoc("公司注册地址是哪里?")
langchain的链与记忆
顺序链 SimpleSequentialChain & SequentialChain
#simpleSequentialChain 只支持固定的链路
from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import SimpleSequentialChain
chat_model = ChatOpenAI(
temperature=0,
model="gpt-3.5-turbo",
)
#chain 1
first_prompt = ChatPromptTemplate.from_template("帮我给{product}的公司起一个响亮容易记忆的名字?")
chain_one = LLMChain(
llm=chat_model,
prompt=first_prompt,
verbose=True,
)
#chain 2
second_prompt = ChatPromptTemplate.from_template("用5个词来描述一下这个公司名字:{company_name}")
chain_two = LLMChain(
llm=chat_model,
prompt=second_prompt,
verbose=True,
)
overall_simple_chain = SimpleSequentialChain(
chains=[chain_one, chain_two],
verbose=True,#打开日志
)
路由链RouterChain
# 导入所需模块
from langchain.prompts import PromptTemplate
from langchain.chains import ConversationChain, LLMChain
from langchain.llms import OpenAI
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE
from langchain.chains.router import MultiPromptChain
# 定义物理链的提示模板
physics_template = """您是一位非常聪明的物理教授.
您擅长以简洁易懂的方式回答物理问题.
当您不知道问题答案的时候,您会坦率承认不知道.
下面是一个问题: {input}"""
# 使用PromptTemplate类创建物理链的提示对象
physics_prompt = PromptTemplate.from_template(physics_template)
# 定义数学链的提示模板
math_template = """您是一位非常优秀的数学教授.
您擅长回答数学问题.
您之所以如此优秀,是因为您能够将困难问题分解成组成的部分,回答这些部分,然后将它们组合起来,回答更广泛的问题.
下面是一个问题: {input}"""
# 使用PromptTemplate类创建数学链的提示对象
math_prompt = PromptTemplate.from_template(math_template)
# 定义物理和数学链的基本信息(名称、描述、提示模板)
prompt_infos = [
{
"name": "physics",
"description": "擅长回答物理问题",
"prompt_template": physics_template,
},
{
"name": "math",
"description": "擅长回答数学问题",
"prompt_template": math_template,
},
]
# 初始化OpenAI大语言模型,设置参数:温度为0(减少随机性),使用"GPT-3.5-turbo-instruct"模型
llm = OpenAI(temperature=0, model="gpt-3.5-turbo-instruct")
# 创建目的地链字典,用于存放物理链和数学链
destination_chains = {}
# 遍历prompt_infos,为每一条信息创建一个LLMChain,并存入destination_chains字典
for p_info in prompt_infos:
name = p_info["name"]
prompt_template = p_info["prompt_template"]
# 创建PromptTemplate对象,指定输入变量为"input"
prompt = PromptTemplate(template=prompt_template, input_variables=["input"])
# 使用LLMChain类创建目的地链,传入llm模型和prompt提示对象
chain = LLMChain(llm=llm, prompt=prompt)
# 将创建的链对象存入destination_chains字典,键为链的名字
destination_chains[name] = chain
# 创建默认链(ConversationChain),用于处理无法匹配到目的地链的问题
default_chain = ConversationChain(llm=llm, output_key="text")
# 构建目的地链的描述字符串,用于路由器模板
destinations = [f"{p['name']}:{p['description']}" for p in prompt_infos]
destinations_str = "\n".join(destinations)
# 根据destinations_str和MULTI_PROMPT_ROUTER_TEMPLATE生成路由器模板
router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(destinations=destinations_str)
# 创建路由器提示对象(PromptTemplate),指定输入变量为"input",并设置输出解析器(RouterOutputParser)
router_prompt = PromptTemplate(
template=router_template, input_variables=["input"], output_parser=RouterOutputParser()
)
# 使用LLMRouterChain.from_llm创建路由器链,传入llm模型和router_prompt提示对象
router_chain = LLMRouterChain.from_llm(llm, router_prompt)
# 创建多提示链(MultiPromptChain),包含路由器链、目的地链字典、默认链,并开启详细日志输出(verbose=True)
multi_prompt_chain = MultiPromptChain(
router_chain=router_chain,
destination_chains=destination_chains,
default_chain=default_chain,
verbose=True,
)
# 使用多提示链运行问题:"什么是牛顿第一定律?"
multi_prompt_chain.run("什么是牛顿第一定律?")
memory工具使用
#内存中的短时记忆
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()
memory.chat_memory.add_user_message("你好,我是人类!")
memory.chat_memory.add_ai_message("你好,我是AI,有什么可以帮助你的吗?")
memory.load_memory_variables({})
#实现一个最近的对话窗口,超过窗口条数的对话将被删除
from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(k=2)
memory.save_context({"input":"你好,我是人类!"},{"output":"你好,我是AI,有什么可以帮助你的吗?"})
memory.save_context({"input":"我想吃鸡肉"},{"output":"好的,我帮你找找鸡肉的做法"})
memory.load_memory_variables({})
# 当对话持续进行且对话内容很多的时候
# 可以使用ConversationSummaryBufferMemory来存储对话摘要
# 这是一种非常有用的方式,它会根据token的数量来自动判断是否需要进行摘要
# 当token数量超过阈值的时候,会自动进行摘要
# 在缓冲区中,会保留最近的k条对话
#比较久的对话会被删除,在删除前会进行摘要
from langchain.memory import ConversationSummaryBufferMemory
from langchain.llms import OpenAI
llm = OpenAI(temperature=0)
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=10,
return_messages=True
)
memory.save_context(
{"input":"帮我找一下tomie"},
{"output":"对不起请问什么是tomie?"}
)
memory.save_context(
{"input":"tomie是一个培训讲师"},
{"output":"好的,我知道了。"}
)
memory.save_context(
{"input":"今天他要讲一门关于RAG的课程"},
{"output":"好的,我知道了。需要RAG的资料吗?"}
)
memory.load_memory_variables({})
## 长时记忆的是实现方式
通过向量数据库来存储之前的对话内容,有的向量数据库服务还提供自动摘要等,每次对话的时候,都会从向量数据库里查询最相关的文档或历史对话
from langchain_openai import OpenAIEmbeddings
from langchain.memory import ConversationBufferMemory
from langchain.vectorstores import FAISS
memory = ConversationBufferMemory()
memory.save_context(
{"input":"帮我找一下tomie"},
{"output":"对不起请问什么是tomie?"}
)
memory.save_context(
{"input":"tomie是一个培训讲师"},
{"output":"好的,我知道了。"}
)
memory.save_context(
{"input":"今天他要讲一门关于RAG的课程"},
{"output":"好的,我知道了。需要RAG的资料吗?"}
)
memory.save_context(
{"input":"不需要资料了,谢谢"},
{"output":"好的,那我就不打扰你了。"}
)
vectorstore = FAISS.from_texts(
memory.buffer.split("\n"),
OpenAIEmbeddings()
)
FAISS.save_local(vectorstore,"test_faiss")
from langchain.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain.memory import VectorStoreRetrieverMemory
r1 = FAISS.load_local("test_faiss",OpenAIEmbeddings(),allow_dangerous_deserialization=True)
r2 = r1.as_retriever(
search_kwargs={"k":1}
)
memory2 = VectorStoreRetrieverMemory(
retriever=r2
)
memory2.load_memory_variables({"prompt":"tomie是什么职业?"})
memory in Chains 链和memory的结合使用
1 如何在LLMChain上增加记忆
2 如何在对话链中加载记忆
3 如何自定义记忆
4 如何在同一个链中合并多个记忆
5 如何向多参数链中添加记忆
#LLMChain
from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.memory import ConversationBufferMemory
from langchain.prompts import PromptTemplate
#自定义模板
template = """你是一个可以和人类对话的机器人.
{chat_history}
人类:{human_input}
机器人:"""
prompt= PromptTemplate(
template=template,
input_variables=["chat_history", "human_input"],
)
memory = ConversationBufferMemory(
memory_key="chat_history",
)
llm = OpenAI(
temperature=0,
)
chain = LLMChain(
llm=llm,
memory=memory,
prompt=prompt,
verbose=True,
)
chain.predict(human_input="我最新喜欢我的世界这个游戏,你还记得我叫什么吗?")
# 同一个链合并使用多个memory
from langchain.chains import ConversationChain
from langchain.llms import OpenAI
from langchain.memory import (
ConversationBufferMemory,
ConversationSummaryMemory,
CombinedMemory
)
from langchain.prompts import PromptTemplate
llm = OpenAI(
temperature=0,
)
#使用CoversationSummaryMemory对对话进行总结
summay = ConversationSummaryMemory(
llm=llm,
input_key="input"
)
#使用ConversationBufferMemory对对话进行缓存
cov_memory = ConversationBufferMemory(
memory_key="history_now",
input_key="input",
)
memory = CombinedMemory(
memories=[summay, cov_memory],
)
TEMPLATE = """下面是一段AI与人类的对话,AI会针对人类问题,提供尽可能详细的回答,如果AI不知道答案,会直接回复'人类老爷,我真的不知道'.
之前的对话摘要:
{history}
当前对话:
{history_now}
Human:{input}
AI:"""
prompt = PromptTemplate(
template=TEMPLATE,
input_variables=["history", "history_now", "input"],
)
chain = ConversationChain(
llm=llm,
memory=memory,
prompt=prompt,
verbose=True,
)
chain.run("那ETH呢?")