当前位置: 首页 > news >正文

LangChain大模型应用开发:构建Agent智能体

介绍

大家好,博主又来给大家分享知识了。今天要给大家分享的内容是使用LangChain进行大模型应用开发中的构建Agent智能体。

LangChain中,Agent智能体是一种能够根据输入的任务或问题,动态地决定使用哪些工具(如搜索引擎、数据库查询等)来解决问题的程序。它可以理解自然语言指令,并利用工具获取更多信息,最终生成解决方案。Agent智能体具备推理和决策能力,能够在不同的工具和操作之间进行选择,以达到最佳的问题解决效果。

Agent智能体可以极大地扩展语言模型的能力,使其能够处理更复杂的任务。好了,那么我们直接进入正题。

创建和运行Agent

概念

单独来说,语言模型无法采取行动-它们只能输出文本。LangChain的一个重要用例是创建智能体。智能体是使用LLM作为推理引擎的系统,用于确定应采取哪些行动以及这些行动的输入应该是什么。然后可以将这些行动的结果反馈给智能体,并确定是否需要更多行动,或者是否可以结束。

在本次分享中,我们将构建一个可以与多种不同工具进行交互的智能体:一个是本地数据库,另一个是搜索引擎。我们向该智能体提问,观察它调用工具,并与它进行对话。

接下来,我们会探讨怎样借助LangChain智能体开展搭建工作。对于刚开始接触相关领域的人而言,LangChain智能体是个不错的起点,简单易懂、容易上手。但随着需求变得更复杂,当我们期望对智能体有更灵活的运用,或者需要更强的掌控力时,LangChain智能体就有些力不从心了。要是我们想进一步探索更高级的智能体功能,我建议大家关注一下LangGraph

LangSmith

在使用LangChain开发应用的过程中,随着应用逻辑越来越复杂,对内部运行情况的监控和调试也变得至关重要。这时,LangSmith就派上了用场,它能帮助我们更好地了解应用中各个步骤的执行情况,尤其是大语言模型(LLM)的多次调用过程。

下面,我们就来看看如何安装LangChain以及配置LangSmith,以便开启高效的开发之旅 。

要使用LangSmith,我们必须要要装LangChain库,因为LangSmith主要依赖于LangChain相关的库。我相信大家都已经安装了,但是为了让只看这一篇博文的同事或同学,我还是要把个步骤讲解出来。

安装命令
pip install -U langchain
生成密钥

生成LangSmith密钥的步骤如下:

  1. 注册账号:访问LangSmith官网,使用自己常用的邮箱进行注册或登录。
  2. 进入设置页面:登录成功后,点击页面右上角的菜单,找到并进入Settings页面。
  3. 创建API密钥:在设置页面中,找到API Keys选项,点击Create API Key按钮,系统会为你生成一个新的API密钥。
  4. 保存密钥:生成的API密钥只会显示一次,务必将其复制并妥善保存在安全的地方,比如密码管理工具或本地的加密文件中。

LangSmithAPI密钥在一定条件下是免费的。
Developer(开发者)版本:对于个人开发者或业余爱好者,可免费注册使用。每月有5000条免费跟踪额度,基础跟踪超过部分按$0.50每1000条收费,扩展跟踪(400天保存期)超过部分按$4.50每 1000条收费。

配置环境变量

注册并生成API密钥完成后,设置LANGSMITH_API_KEY环境变量。

配置方式一

我们可以将环境变量在代码中设置。

import osos.environ["LANGSMITH_API_KEY"] = "设置你自己的LangSmith API Key"
# 如果我们想要获取自动化的最佳跟踪,我们还可以启用LangSmith跟踪
os.environ["LANGSMITH_TRACING"] = "true"
配置方式二

我们也可以将环境变量设置在系统环境变量里。博主的电脑为Win11操作系统,步骤为:

桌面“此电脑”图标左键选中->鼠标右键点击弹出菜单中的“属性”->在打开的“系统信息”界面点击“高级系统设置”->在弹出的“系统属性”面板点击“环境变量”。

在弹出的“环境变量”面板中左键点击“系统变量”下的“新建”->在弹出的“新建系统变量”面板中的“变量名”输入LANGSMITH_API_KEY->“变量值”输入自己的LangSmith API Key->点击“确定”。

(可选步骤)当前停留在“环境变量”面板->在“环境变量”面板中左键点击“系统变量”下的“新建”->在弹出的“新建系统变量”面板中的“变量名”输入LANGSMITH_TRACING->“变量值”输入true->点击“确定”。

重启电脑使环境变量生效。

博主笔记:博主推荐“配置方式二”这种方式来配置环境变量。因为这样API Key不会存在代码中,别人也就不会知道你的API Key是多少了,防止自己的敏感信息被泄露。

定义工具

我们首先要创建所需工具,将使用两个工具:Tavily(用于在线搜索),以及将创建的本地索引上的检索器。

Tavily

Tavily是专门为大语言模型和检索增强生成(RAG)场景设计的搜索引擎。TavilySearchResultsLangChain社区工具包中封装的一个类,用于处理从Tavily搜索引擎获取的搜索结果。

安装命令
pip install langchain-community
生成密钥

Tavily生成API密钥步骤如下:

  1. 打开Tavily平台登录页面:访问Log in | Tavily,点击 “sign in”。
  2. 选择登录或注册方式:可选择自己常用的的邮箱注册或登录。
  3. 获取API密钥:登录成功后,页面会跳转到Tavily AI,进入API Keys板块,即可看到且可复制API密钥。

Tavily为用户提供了一定的免费额度免费额度每月提供1000次免费搜索

配置环境变量
配置方式一

我们可以将环境变量在代码中设置。

import osos.environ["TAVILY_API_KEY"] = "设置你自己的Tavily API Key"
配置方式二

我们也可以将环境变量设置在系统环境变量里。博主的电脑为Win11操作系统,步骤为:

桌面“此电脑”图标左键选中->鼠标右键点击弹出菜单中的“属性”->在打开的“系统信息”界面点击“高级系统设置”->在弹出的“系统属性”面板点击“环境变量”。

在弹出的“环境变量”面板中左键点击“系统变量”下的“新建”->在弹出的“新建系统变量”面板中的“变量名”输入TAVILY_API_KEY->“变量值”输入自己的Tavily API Key->点击“确定”。

博主笔记:博主推荐“配置方式二”这种方式来配置环境变量。因为这样API Key不会存在代码中,别人也就不会知道你的API Key是多少了,防止自己的敏感信息被泄露。

重启电脑使环境变量生效

Tavily测试完整代码

我们可以写一段代码来测试Tavily环境变量是否生效。

# 从langchain_community工具包的tavily_search模块中导入TavilySearchResults类
from langchain_community.tools.tavily_search import TavilySearchResults# 创建一个TavilySearchResults类的实例,设置最大返回结果数量为2
search = TavilySearchResults(max_results=2)
# 调用search实例的invoke方法,传入查询语句,并将结果打印输出
print(search.invoke("今天北京天气怎么样"))
 Tavily测试运行结果
[{'url': 'https://tianqi.moji.com/today/china/beijing/beijing', 'content': '首页 天气 下载 资讯 关于墨迹 天气 中国 北京市, 北京市, 中国 热门时景 更多 附近地区 更多 附近景点 更多 1  晴 晴 1°日出 07:14 晴 -9°日落 17:43 周六 晴  多云 02/08 *   周日 晴  晴 02/09 *   周一 晴  多云 02/10 *   周二 多云  多云 02/11 晴 02/12 *   周四 晴  晴 02/13 多云 02/14 *   周六 多云  晴 02/15 *   周日 晴  晴 02/16 *   周一 晴  晴 02/17 *   周二 晴  多云 02/18 *   周三 阴  阴 02/19 *   周四 阴  阴 02/20 *   周五 阴  阴 02/21 *   周六 阴  *   周日 阴  晴 02/23 较适宜 狗狗 不适宜 猫咪 不适宜 运动 不适宜 广场舞 较适宜 钓鱼 不适宜 划船 较不适宜 夜生活 较适宜 旅游 较适宜 洗车 较不适宜 约会 较适宜 逛街 pm2.5 pm2.5省份列表 pm2.5城市列表'}, {'url': 'https://tianqi.fliggy.com/110100/', 'content': '【北京天气预报】最新实时天气,北京旅游指数/交通指数,24小时/未来天气预报查询 - 飞猪天气 搜索 我的订单 注册 登录 飞猪国际 联系我们 机票 酒店 火车票 旅游度假 旅游度假 -10℃最低 -12℃ - 最高 -1℃ 风速:10km/h 北京2月8日 02:02天气预报,今天-12℃--1℃,晴, 风向情况:东南风,总降水量:0.00mm,相对湿度:28%。北京今日生活指数: 交通指数,良好 (天气较好,路面干燥,交通气象条件良好,车辆可以正常行驶。),旅游指数,适宜 (天气较好,温度适宜,是个好天气哦。这样的天气适宜旅游,您可以尽情地享受大自然的风光。)。未来5天,最低温度-12℃,最高温度6℃,查询北京实时、5天天气预报,上飞猪天气预报频道 -10℃最低 -12℃ - 最高 -1℃ 风速:10km/h 北京2月8日 02:02天气预报,今天-12℃--1℃,晴, 风向情况:东南风,总降水量:0.00mm,相对湿度:28%。北京今日生活指数: 交通指数,良好 (天气较好,路面干燥,交通气象条件良好,车辆可以正常行驶。),旅游指数,适宜 (天气较好,温度适宜,是个好天气哦。这样的天气适宜旅游,您可以尽情地享受大自然的风光。)。未来5天,最低温度-12℃,最高温度6℃,查询北京实时、5天天气预报,上飞猪天气预报频道 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 10km/h 体感: -7℃ 最低 -12℃ - 最高 -1℃ 最低 -10℃ - 最高 1℃ 最低 -9℃ - 最高 3℃ 最低 -6℃ - 最高 5℃ 最低 -4℃ - 最高 6℃ 廊坊-12℃ - 0℃ 天津-9℃ - -1℃ 保定-14℃ - 0℃ 唐山-13℃ - 0℃ 张家口-19℃ - -9℃ 承德-17℃ - -3℃ 沧州-12℃ - 0℃ 乔一乔怪味餐厅(东升店)天气 Gucci(成都天府机场店)天气 韩式旋转小火锅(金利来店)天气 罗莎蛋糕(橙子街店)天气 北京2月8日 02:02天气预报,今天-12℃--1℃,晴, 风向情况:东南风,总降水量:0.00mm,相对湿度:28%。北京今日生活指数: 交通指数,良好 (天气较好,路面干燥,交通气象条件良好,车辆可以正常行驶。),旅游指数,适宜 (天气较好,温度适宜,是个好天气哦。这样的天气适宜旅游,您可以尽情地享受大自然的风光。)。未来5天,最低温度-12℃,最高温度6℃,查询北京实时、5天天气预报,上飞猪天气预报频道'}]进程已结束,退出代码为 0

Retriever

在自然语言处理(NLP)和信息检索领域,Retriever(检索器)是一个非常重要的组件,它是一种用于从大量文本数据(如文档集合、知识库等)中快速定位和提取与给定查询相关信息的工具或算法。它的核心任务是在众多文本片段中筛选出最有可能包含问题答案或与查询相关的部分。

RetrieverLangChain库中的一个模块,用于检索工具。检索工具的主要用途是从大型文本集合或知识库中找到相关信息。它们通常用于问答系统、对话智能体和其他需要从大量文本数据中提取信息的应用程序。我们还可以将在自己的一些数据上创建一个Retriever

Retriever测试完整代码

在执行下列代码前,请先使用pip安装faiss-cpufaiss-gpu

pip install faiss-cpu

该命令用于安装仅支持CPU计算的Faiss版本。如果大家使用的计算机没有NVIDIA GPU或者不需要利用GPU的强大计算能力来加速相似性搜索等操作,就可以选择安装这个版本。它可以在各种具备CPU的计算机上运行,包括集成显卡的电脑,因为它不依赖于GPU硬件。 

pip install faiss-gpu

此命令用于安装支持GPU加速的Faiss版本。它依赖于NVIDIA GPU以及相应的CUDA工具包。如果大家的电脑拥有NVIDIA GPU并且希望利用其并行计算能力来显著提高Faiss的搜索速度,尤其是在处理大规模向量数据时,那么应该选择安装这个版本。 

博主笔记:由于博主在这写这篇博文的时候,使用的电脑是没有NVIDIA GPU,所以用的第一个命令。请大家根据自身的电脑情况来选择使用的安装命令。 

FaissFacebook AI Research开发的用于高效相似性搜索和聚类密集向量的库,特点是高性能、索引类型多样且易于使用。在LangChain中,Faiss主要用于:支持向量数据库功能增强检索能力与其他组件集成

# 导入os模块,该模块提供了与操作系统进行交互的功能
import os
# 设置USER_AGENT环境变量,模拟Chrome浏览器在Windows11系统上的请求头信息
os.environ["USER_AGENT"] = ("Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/118.0.0.0 Safari/537.36")
# 从langchain_community.document_loaders模块导入WebBaseLoader类,用于从网页加载文档
from langchain_community.document_loaders import WebBaseLoader
# 从 langchain_community.vectorstores模块导入FAISS类,用于创建基于FAISS的向量存储
from langchain_community.vectorstores import FAISS
# 从langchain_openai模块导入OpenAIEmbeddings类,用于将文本转换为向量表示
from langchain_openai import OpenAIEmbeddings
# 从langchain_text_splitters模块导入RecursiveCharacterTextSplitter类,用于对文档进行文本分割
from langchain_text_splitters import RecursiveCharacterTextSplitter# 创建一个WebBaseLoader实例,指定要加载的网页URL为关于狗的维基百科页面
loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8A%AC")
# 调用loader的load方法,从指定网页加载文档内容
docs = loader.load()
# 创建一个RecursiveCharacterTextSplitter实例,设置每个文本块的大小为1000个字符,重叠部分为200个字符
# 并使用该实例对加载的文档进行分割
documents = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200
).split_documents(docs)
# 使用FAISS类的from_documents方法,将分割后的文档和OpenAIEmbeddings实例传入,创建向量存储
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
# 调用vector的as_retriever方法,将向量存储转换为检索器对象
retriever = vector.as_retriever()
# 调用检索器的invoke方法,传入查询语句,并取第一个检索结果
result = retriever.invoke("狗的特征")[0]
# 打印检索到的结果
print(result)
Retriever测试运行结果
page_content='种族特性
犬类拥有与掠食者相称的身体用于追捕,跳跃和杀死猎物(圖為魏玛伦纳猎狗,Weimaraner)
犬类通过伸舌头喘气以蒸发水汽从而降温,时值夏季高温天
现代狗种在体形,外貌和行为上要比其他驯化动物的差异更大。但即使各个种类差异如此极端,家犬与其野生祖先狼仍然有着共同的属性。所有犬科动物都是掠食动物或食腐动物,拥有便于攻击,抓捕和撕咬它们食物的锋利尖牙和有力的爪。
狗类四肢的结构能够使它们在必要时快速向前出击或是进行跳跃动作,用于追赶或抓捕它们的猎物。因此,它们拥有小而结实的足部,使用前足移动;前腿松软灵活,肌肉只用于与躯干连接;后腿则强健有力。
狗类是二元色视者,所以以人类的标准来说狗类是色盲1,2,基本上在狗的世界中他們可以看見的是藍色與黃色。又由于狗类眼球透镜比人类要平,所以它们不能看见过多的细节事物;另一方面,狗眼比人眼对光和运动更为敏感。有些种类的狗,特别是最好的视力型嗅猎犬(sighthound),拥有270°的视力范围(人类只有100°到120°),而大头狗(broad-headed)向前的视力范围则要小一些,只有180°。1,2
狗类对音频声波的感觉极限为67Hz至45,000Hz(人類為20Hz至20,000Hz;貓为45Hz至64,000Hz )2,另外,狗的耳朵是可以活动的,这可以帮助它们快速准确的定位声音的来源。狗对声音的定位比人类迅速,听见声音的距离也要比人类远四倍,但比貓遜色。' metadata={'source': 'https://zh.wikipedia.org/wiki/%E7%8A%AC', 'title': '犬 - 维基百科,自由的百科全书', 'language': 'zh'}进程已结束,退出代码为 0

博主笔记:

  1. os.environ["USER_AGENT"]的赋值,一定要根据自己电脑的操作系统进行设置。
  2. 设置USER_AGENT代码要放在WebBaseLoader前面,是因为WebBaseLoader在被创建并调用load方法时,就会立即发起HTTP请求去访问指定的网页。在发起请求的过程中,它会读取当前环境中的USER_AGEN信息并将其添加到请求头里。

使用语言模型

我们已经成功创建并配置好了Tavily搜索工具和Retriever检索工具,接下来,我们可以创建一个工具列表,将这两个工具添加进去,以便在后续的Agent或者Chain中方便地调用这些工具来完成特定的任务。

下面我来给大家讲解下如何使用语言模型来调用工具。LangChain支持许多可以互换使用的不同语言模型,请大家选择想要使用的语言模型。

完整代码
# 导入os模块,该模块提供了与操作系统进行交互的功能
import os
# 设置USER_AGENT环境变量,模拟Chrome浏览器在Windows11系统上的请求头信息
os.environ["USER_AGENT"] = ("Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/118.0.0.0 Safari/537.36")
# 从langchain_community工具包的tavily_search模块中导入TavilySearchResults类
from langchain_community.tools.tavily_search import TavilySearchResults
# 从langchain_community.document_loaders模块导入WebBaseLoader类,用于从网页加载文档
from langchain_community.document_loaders import WebBaseLoader
# 从 langchain_community.vectorstores模块导入FAISS类,用于创建基于FAISS的向量存储
from langchain_community.vectorstores import FAISS
# 从langchain_openai模块导入OpenAIEmbeddings类,用于将文本转换为向量表示
from langchain_openai import OpenAIEmbeddings
# 从langchain_text_splitters模块导入RecursiveCharacterTextSplitter类,用于对文档进行文本分割
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 从langchain.tools.retriever模块导入create_retriever_tool函数,用于创建基于检索器的工具
from langchain.tools.retriever import create_retriever_tool
# 从langchain_openai模块导入ChatOpenAI类,用于创建调用OpenAI聊天模型的实例
from langchain_openai import ChatOpenAI
# 从langchain_core.messages模块导入HumanMessage类,用于创建表示人类输入消息的对象
from langchain_core.messages import HumanMessage# 创建一个TavilySearchResults类的实例,设置最大返回结果数量为2
search = TavilySearchResults(max_results=2)# 创建一个WebBaseLoader实例,指定要加载的网页URL为关于狗的维基百科页面
loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8A%AC")
# 调用loader的load方法,从指定网页加载文档内容
docs = loader.load()
# 创建一个RecursiveCharacterTextSplitter实例,设置每个文本块的大小为1000个字符,重叠部分为200个字符
# 并使用该实例对加载的文档进行分割
documents = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200
).split_documents(docs)
# 使用FAISS类的from_documents方法,将分割后的文档和OpenAIEmbeddings实例传入,创建向量存储
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
# 调用vector的as_retriever方法,将向量存储转换为检索器对象
retriever = vector.as_retriever()
# 使用create_retriever_tool函数创建一个检索器工具,该工具基于前面创建的检索器 retriever
retriever_tool = create_retriever_tool(retriever,"wiki_search",  # 为工具命名为"wiki_search",方便后续识别和调用"搜索维基百科",  # 为工具添加描述"搜索维基百科",使得模型在使用工具时能理解其用途
)# 创建一个包含Tavily搜索实例和检索器工具的工具列表
tools = [search, retriever_tool]
# 创建一个ChatOpenAI实例,指定使用的模型为gpt-3.5-turbo
chat_model = ChatOpenAI(model="gpt-3.5-turbo")
# 使用chat_model调用模型,传入一个人类消息"hi!",获取模型的响应
response = chat_model.invoke([HumanMessage(content="hi!")])
# 打印模型响应的内容
print(response.content)
# 将工具列表绑定到chat_model上,创建一个带有工具的模型实例
model_with_tools = chat_model.bind_tools(tools)
# 使用带有工具的模型实例调用模型,传入一个人类消息"你好",获取模型的响应
response = model_with_tools.invoke([HumanMessage(content="你好")])
# 打印模型响应的内容
print(f"ContentString: {response.content}")
# 打印模型响应中涉及的工具调用信息
print(f"ToolCalls: {response.tool_calls}")
# 使用带有工具的模型实例调用模型,传入一个人类消息"今天北京天气怎么样",获取模型的响应
response = model_with_tools.invoke([HumanMessage(content="今天北京天气怎么样")])
# 打印模型响应的内容
print(f"ContentString: {response.content}")
# 打印模型响应中涉及的工具调用信息
print(f"ToolCalls: {response.tool_calls}")
运行结果
Hello! How can I assist you today?
ContentString: 你好!有什么可以帮助你的吗?
ToolCalls: []
ContentString: 
ToolCalls: [{'name': 'tavily_search_results_json', 'args': {'query': '北京今天天气'}, 'id': 'call_9uQYDblcSP5WjKw0W8s7D6u4', 'type': 'tool_call'}]进程已结束,退出代码为 0

运行结果分析

首先,当我们传入消息列表来调用语言模型时,而此时我们没有给语言模型绑定任何工具,最终返回的响应通常确实是一个包含文本内容的对象,从这个对象中提取的主要内容表现为一个字符串content字符串。

# 创建一个包含Tavily搜索实例和检索器工具的工具列表
tools = [search, retriever_tool]
# 创建一个ChatOpenAI实例,指定使用的模型为gpt-3.5-turbo
chat_model = ChatOpenAI(model="gpt-3.5-turbo")
# 使用chat_model调用模型,传入一个人类消息"hi!",获取模型的响应
response = chat_model.invoke([HumanMessage(content="hi!")])
# 打印模型响应的内容
print(response.content)
Hello! How can I assist you today?进程已结束,退出代码为 0

其次,我们给语言模型绑定了工具列表,其中包括我们在上面讲解到的Tavily搜索工具和Retriever检索工具。我们再次调用语言模型,继续用一个基本消息来调用它,看它的回复结果。

我们查看content字段和tool_calls字段,发现content有内容,而tool_calls是空的,说明此时语言模型并没有借助工具集来处理用户需求。

# 将工具列表绑定到chat_model上,创建一个带有工具的模型实例
model_with_tools = chat_model.bind_tools(tools)
# 使用带有工具的模型实例调用模型,传入一个人类消息"你好",获取模型的响应
response = model_with_tools.invoke([HumanMessage(content="你好")])
# 打印模型响应的内容
print(f"ContentString: {response.content}")
# 打印模型响应中涉及的工具调用信息
print(f"ToolCalls: {response.tool_calls}")
ContentString: 你好!有什么可以帮助你的吗?
ToolCalls: []进程已结束,退出代码为 0

然后,在已经正确为语言模型绑定了包含Tavily Search工具等的工具集,且工具配置和初始化均无误的前提下,我们再次向语言模型提问关于天气的问题,这类问题期望语言模型借助工具集来处理。

提问后,我们查看模型响应的content字段和tool_calls字段,发现content字段没有内容,而tool_calls字段中存在工具调用信息,显示语言模型请求调用Tavily Search工具。

# 使用带有工具的模型实例调用模型,传入一个人类消息"今天北京天气怎么样",获取模型的响应
response = model_with_tools.invoke([HumanMessage(content="今天北京天气怎么样")])
# 打印模型响应的内容
print(f"ContentString: {response.content}")
# 打印模型响应中涉及的工具调用信息
print(f"ToolCalls: {response.tool_calls}")
ContentString: 
ToolCalls: [{'name': 'tavily_search_results_json', 'args': {'query': '北京今天天气'}, 'id': 'call_9uQYDblcSP5WjKw0W8s7D6u4', 'type': 'tool_call'}]进程已结束,退出代码为 0

这表明根据模型的判断,需要借助该工具来获取回答问题所需的信息。由于直接通过模型响应中的工具调用指示并不能自动执行工具调用,为了实际调用Tavily Search工具获取天气信息,我们需要创建智能体程序。

智能体程序能够根据模型的工具调用请求,实际调用工具并将工具返回的结果再反馈给语言模型,以帮助生成最终的回答。请大家继续往下看。

创建智能体程序

既然我们已经成功定义好了用于辅助的工具,以及完成了大语言模型(LLM)的配置,接下来就可以着手创建智能体程序了。

我们计划使用的是一个工具调用智能体程序,这种智能体程序能够在处理任务时根据需求调用预先设定好的工具,以获取更准确、更全面的信息来完成任务。

在创建智能体程序的过程中,我们首先需要选择一个合适的提示,这个提示将用于指导智能体程序的行为和决策逻辑。

我们从LangChain中的LangSmith平台中获取一个特定的提示模板,并查看其包含的消息内容,为后续构建基于该提示的智能体或与语言模型的交互做准备。以下链接可访问该模板:LangSmith

获取模板完整代码

# 从langchain导入hub模块,用于从LangChain Hub拉取提示模板
from langchain import hub# 从LangChain Hub拉取名为"hwchase17/openai-functions-agent"的提示模板
prompt = hub.pull("hwchase17/openai-functions-agent")
# 打印拉取到的提示模板中的消息内容
print(prompt.messages)

获取模板运行结果

[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], input_types={}, partial_variables={}, template='You are a helpful assistant'), additional_kwargs={}), MessagesPlaceholder(variable_name='chat_history', optional=True), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'], input_types={}, partial_variables={}, template='{input}'), additional_kwargs={}), MessagesPlaceholder(variable_name='agent_scratchpad')]进程已结束,退出代码为 0

现在,我们可以使用LLM、提示模板和工具初始化智能体。智能体负责接收输入并决定采取什么行动。

初始化智能体演示代码

# 导入os模块,该模块提供了与操作系统进行交互的功能
import os
# 设置USER_AGENT环境变量,模拟Chrome浏览器在Windows11系统上的请求头信息
os.environ["USER_AGENT"] = ("Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/118.0.0.0 Safari/537.36")
# 从langchain_community工具包的tavily_search模块中导入TavilySearchResults类
from langchain_community.tools.tavily_search import TavilySearchResults
# 从langchain_community.document_loaders模块导入WebBaseLoader类,用于从网页加载文档
from langchain_community.document_loaders import WebBaseLoader
# 从 langchain_community.vectorstores模块导入FAISS类,用于创建基于FAISS的向量存储
from langchain_community.vectorstores import FAISS
# 从langchain_openai模块导入OpenAIEmbeddings类,用于将文本转换为向量表示
from langchain_openai import OpenAIEmbeddings
# 从langchain_text_splitters模块导入RecursiveCharacterTextSplitter类,用于对文档进行文本分割
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 从langchain.tools.retriever模块导入create_retriever_tool函数,用于创建基于检索器的工具
from langchain.tools.retriever import create_retriever_tool
# 从langchain_openai模块导入ChatOpenAI类,用于创建调用OpenAI聊天模型的实例
from langchain_openai import ChatOpenAI
# 从langchain导入hub模块,用于从LangChain Hub拉取提示模板
from langchain import hub
# 从langchain.agents模块导入create_tool_calling_agent函数,用于创建工具调用智能体
from langchain.agents import create_tool_calling_agent
# 从langchain.agents模块导入AgentExecutor类,用于执行智能体
from langchain.agents import AgentExecutor# 创建一个TavilySearchResults类的实例,设置最大返回结果数量为2
search = TavilySearchResults(max_results=2)# 创建一个WebBaseLoader实例,指定要加载的网页URL为关于狗的维基百科页面
loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8A%AC")
# 调用loader的load方法,从指定网页加载文档内容
docs = loader.load()
# 创建一个RecursiveCharacterTextSplitter实例,设置每个文本块的大小为1000个字符,重叠部分为200个字符
# 并使用该实例对加载的文档进行分割
documents = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200
).split_documents(docs)
# 使用FAISS类的from_documents方法,将分割后的文档和OpenAIEmbeddings实例传入,创建向量存储
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
# 调用vector的as_retriever方法,将向量存储转换为检索器对象
retriever = vector.as_retriever()
# 使用create_retriever_tool函数创建一个检索器工具,该工具基于前面创建的检索器retriever
retriever_tool = create_retriever_tool(retriever,"wiki_search",  # 为工具命名为"wiki_search",方便后续识别和调用"搜索维基百科",  # 为工具添加描述"搜索维基百科",使得模型在使用工具时能理解其用途
)# 创建一个包含Tavily搜索实例和检索器工具的工具列表
tools = [search, retriever_tool]
# 创建一个ChatOpenAI实例,指定使用的模型为gpt-3.5-turbo
chat_model = ChatOpenAI(model="gpt-3.5-turbo")
# 从LangChain Hub拉取名为"hwchase17/openai-functions-agent"的提示模板
prompt = hub.pull("hwchase17/openai-functions-agent")
# 使用create_tool_calling_agent函数创建一个工具调用智能体,传入聊天模型、工具列表和提示模板
agent = create_tool_calling_agent(chat_model, tools, prompt)

大家注意下,目前智能体不执行任何操作,因为我们还有没有创建AgentExecutor

另外,大家看代码里,我们传递的是chat_model,而不是model_with_tools。这是因为 create_tool_calling_agent会在内部完成工具绑定的操作,即调用.bind_tools

最后,我们将智能体与AgentExecutor中的工具结合起来(AgentExecutor会不断地让智能体对输入进行分析和决策,也就是重复调用智能体)。

创建智能体执行器演示代码

# 导入os模块,该模块提供了与操作系统进行交互的功能
import os
# 设置USER_AGENT环境变量,模拟Chrome浏览器在Windows11系统上的请求头信息
os.environ["USER_AGENT"] = ("Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/118.0.0.0 Safari/537.36")
# 从langchain_community工具包的tavily_search模块中导入TavilySearchResults类
from langchain_community.tools.tavily_search import TavilySearchResults
# 从langchain_community.document_loaders模块导入WebBaseLoader类,用于从网页加载文档
from langchain_community.document_loaders import WebBaseLoader
# 从 langchain_community.vectorstores模块导入FAISS类,用于创建基于FAISS的向量存储
from langchain_community.vectorstores import FAISS
# 从langchain_openai模块导入OpenAIEmbeddings类,用于将文本转换为向量表示
from langchain_openai import OpenAIEmbeddings
# 从langchain_text_splitters模块导入RecursiveCharacterTextSplitter类,用于对文档进行文本分割
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 从langchain.tools.retriever模块导入create_retriever_tool函数,用于创建基于检索器的工具
from langchain.tools.retriever import create_retriever_tool
# 从langchain_openai模块导入ChatOpenAI类,用于创建调用OpenAI聊天模型的实例
from langchain_openai import ChatOpenAI
# 从langchain导入hub模块,用于从LangChain Hub拉取提示模板
from langchain import hub
# 从langchain.agents模块导入create_tool_calling_agent函数,用于创建工具调用智能体
from langchain.agents import create_tool_calling_agent
# 从langchain.agents模块导入AgentExecutor类,用于执行智能体
from langchain.agents import AgentExecutor# 创建一个TavilySearchResults类的实例,设置最大返回结果数量为2
search = TavilySearchResults(max_results=2)# 创建一个WebBaseLoader实例,指定要加载的网页URL为关于狗的维基百科页面
loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8A%AC")
# 调用loader的load方法,从指定网页加载文档内容
docs = loader.load()
# 创建一个RecursiveCharacterTextSplitter实例,设置每个文本块的大小为1000个字符,重叠部分为200个字符
# 并使用该实例对加载的文档进行分割
documents = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200
).split_documents(docs)
# 使用FAISS类的from_documents方法,将分割后的文档和OpenAIEmbeddings实例传入,创建向量存储
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
# 调用vector的as_retriever方法,将向量存储转换为检索器对象
retriever = vector.as_retriever()
# 使用create_retriever_tool函数创建一个检索器工具,该工具基于前面创建的检索器retriever
retriever_tool = create_retriever_tool(retriever,"wiki_search",  # 为工具命名为"wiki_search",方便后续识别和调用"搜索维基百科",  # 为工具添加描述"搜索维基百科",使得模型在使用工具时能理解其用途
)# 创建一个包含Tavily搜索实例和检索器工具的工具列表
tools = [search, retriever_tool]
# 创建一个ChatOpenAI实例,指定使用的模型为gpt-3.5-turbo
chat_model = ChatOpenAI(model="gpt-3.5-turbo")
# 从LangChain Hub拉取名为"hwchase17/openai-functions-agent"的提示模板
prompt = hub.pull("hwchase17/openai-functions-agent")
# 打印拉取到的提示模板中的消息内容
print(prompt.messages)
# 使用create_tool_calling_agent函数创建一个工具调用智能体,传入聊天模型、工具列表和提示模板
agent = create_tool_calling_agent(chat_model, tools, prompt)
# 创建一个AgentExecutor实例,传入智能体和工具列表,用于执行智能体
agent_executor = AgentExecutor(agent=agent, tools=tools)

运行智能体

现在我们开始运行智能体程序。

完整代码
# 导入os模块,该模块提供了与操作系统进行交互的功能
import os
# 设置USER_AGENT环境变量,模拟Chrome浏览器在Windows11系统上的请求头信息
os.environ["USER_AGENT"] = ("Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ""Chrome/118.0.0.0 Safari/537.36")
# 从langchain_community工具包的tavily_search模块中导入TavilySearchResults类
from langchain_community.tools.tavily_search import TavilySearchResults
# 从langchain_community.document_loaders模块导入WebBaseLoader类,用于从网页加载文档
from langchain_community.document_loaders import WebBaseLoader
# 从 langchain_community.vectorstores模块导入FAISS类,用于创建基于FAISS的向量存储
from langchain_community.vectorstores import FAISS
# 从langchain_openai模块导入OpenAIEmbeddings类,用于将文本转换为向量表示
from langchain_openai import OpenAIEmbeddings
# 从langchain_text_splitters模块导入RecursiveCharacterTextSplitter类,用于对文档进行文本分割
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 从langchain.tools.retriever模块导入create_retriever_tool函数,用于创建基于检索器的工具
from langchain.tools.retriever import create_retriever_tool
# 从langchain_openai模块导入ChatOpenAI类,用于创建调用OpenAI聊天模型的实例
from langchain_openai import ChatOpenAI
# 从langchain导入hub模块,用于从LangChain Hub拉取提示模板
from langchain import hub
# 从langchain.agents模块导入create_tool_calling_agent函数,用于创建工具调用智能体
from langchain.agents import create_tool_calling_agent
# 从langchain.agents模块导入AgentExecutor类,用于执行智能体
from langchain.agents import AgentExecutor# 创建一个TavilySearchResults类的实例,设置最大返回结果数量为2
search = TavilySearchResults(max_results=2)# 创建一个WebBaseLoader实例,指定要加载的网页URL为关于狗的维基百科页面
loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8A%AC")
# 调用loader的load方法,从指定网页加载文档内容
docs = loader.load()
# 创建一个RecursiveCharacterTextSplitter实例,设置每个文本块的大小为1000个字符,重叠部分为200个字符
# 并使用该实例对加载的文档进行分割
documents = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200
).split_documents(docs)
# 使用FAISS类的from_documents方法,将分割后的文档和OpenAIEmbeddings实例传入,创建向量存储
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
# 调用vector的as_retriever方法,将向量存储转换为检索器对象
retriever = vector.as_retriever()
# 使用create_retriever_tool函数创建一个检索器工具,该工具基于前面创建的检索器retriever
retriever_tool = create_retriever_tool(retriever,"wiki_search",  # 为工具命名为"wiki_search",方便后续识别和调用"搜索维基百科",  # 为工具添加描述"搜索维基百科",使得模型在使用工具时能理解其用途
)# 创建一个包含Tavily搜索实例和检索器工具的工具列表
tools = [search, retriever_tool]
# 创建一个ChatOpenAI实例,指定使用的模型为gpt-3.5-turbo
chat_model = ChatOpenAI(model="gpt-3.5-turbo")
# 从LangChain Hub拉取名为"hwchase17/openai-functions-agent"的提示模板
prompt = hub.pull("hwchase17/openai-functions-agent")
# 使用create_tool_calling_agent函数创建一个工具调用智能体,传入聊天模型、工具列表和提示模板
agent = create_tool_calling_agent(chat_model, tools, prompt)
# 创建一个AgentExecutor实例,传入智能体和工具列表,用于执行智能体
agent_executor = AgentExecutor(agent=agent, tools=tools)
# 调用智能体执行器,传入包含用户输入“你好”,打印智能体处理后的结果
print(agent_executor.invoke({"input": "你好"}))
# 调用智能体执行器,传入包含用户输入“狗的特征”,打印智能体处理后的结果
print(agent_executor.invoke({"input": "狗的特征"}))
# 调用智能体执行器,传入包含用户输入“今天北京天气怎么样”,打印智能体处理后的结果
print(agent_executor.invoke({"input": "今天北京天气怎么样"}))
运行结果
{'input': '你好', 'output': '你好!有什么可以帮助你的吗?'}
{'input': '狗的特征', 'output': '狗类有许多特征,包括:\n\n1. 犬类是类似掠食者的动物,具有追捕、跳跃和杀死猎物的身体结构。\n2. 狗类通过伸舌头喘气来蒸发水汽降温,适应夏季高温天气。\n3. 狗类拥有锋利的尖牙和有力的爪,适合攻击、抓捕和撕咬食物。\n4. 狗类四肢结构使它们可以快速追逐或跳跃,拥有小而结实的足部和强健有力的后腿。\n5. 狗类是二元色视者,在狗的世界中可以看见蓝色和黄色,但不能看见过多的细节事物。\n6. 狗类对音频声波的感觉范围为67Hz至45,000Hz,比人类更敏感,可以迅速准确地定位声音的来源。\n\n除此之外,狗类与人类有着密切的关系,成为人类的宠物并扮演多重角色,包括导盲、搜救、侦缉等工作。狗类也被证明能传递深度情感,具有认知能力和学习人类社会技能的能力,与人类的情绪产生共鸣。'}
{'input': '今天北京天气怎么样', 'output': '今天北京的天气是晴转多云,最低气温为-11℃,最高气温为-1℃,北风微风。您可以查看更多详细信息和天气预报,请访问以下链接:[北京天气详情](https://tianqi.moji.com/today/china/beijing/beijing)。'}进程已结束,退出代码为 0

运行结果分析

首先,我们可对智能体进行多个查询,这些查询是无状态的(意味着智能体不会记住先前交互。

我们先看一下对智能体进行基础问题提问,智能体如何对查询做出回应。

# 创建一个AgentExecutor实例,传入智能体和工具列表,用于执行智能体
agent_executor = AgentExecutor(agent=agent, tools=tools)
# 调用智能体执行器,传入包含用户输入“你好”,打印智能体处理后的结果
print(agent_executor.invoke({"input": "你好"}))
{'input': '你好', 'output': '你好!有什么可以帮助你的吗?'}进程已结束,退出代码为 0

我们在LangSmith平台查看智能体具体做了什么,并确认它是否调用了工具。

我们发现此时智能体并没有借助工具集来处理用户需求。

接着,我们再去向智能体提问 “狗的特征”,我们期待智能体借助检索器retriever来检索内容,然后再对用户提问做出回答。

# 创建一个AgentExecutor实例,传入智能体和工具列表,用于执行智能体
agent_executor = AgentExecutor(agent=agent, tools=tools)
# 调用智能体执行器,传入包含用户输入“狗的特征”,打印智能体处理后的结果
print(agent_executor.invoke({"input": "狗的特征"}))
{'input': '狗的特征', 'output': '狗类有许多特征,包括:\n\n1. 犬类是类似掠食者的动物,具有追捕、跳跃和杀死猎物的身体结构。\n2. 狗类通过伸舌头喘气来蒸发水汽降温,适应夏季高温天气。\n3. 狗类拥有锋利的尖牙和有力的爪,适合攻击、抓捕和撕咬食物。\n4. 狗类四肢结构使它们可以快速追逐或跳跃,拥有小而结实的足部和强健有力的后腿。\n5. 狗类是二元色视者,在狗的世界中可以看见蓝色和黄色,但不能看见过多的细节事物。\n6. 狗类对音频声波的感觉范围为67Hz至45,000Hz,比人类更敏感,可以迅速准确地定位声音的来源。\n\n除此之外,狗类与人类有着密切的关系,成为人类的宠物并扮演多重角色,包括导盲、搜救、侦缉等工作。狗类也被证明能传递深度情感,具有认知能力和学习人类社会技能的能力,与人类的情绪产生共鸣。'}进程已结束,退出代码为 0

为了确切知晓智能体在处理任务时是否调用了检索器Retriever来检索相关内容, 我们在LangSmith平台上进行细致查看。

我们发现智能体对于“狗的特征”进行了查询,并且使用了检索器Retriever。这符合我们的预期结果。

最后,我们再去向智能体提问 “今天北京天气怎么样”,我们期待智能体借助Tavily搜索工具来搜索内容,然后再对用户提问做出回答。

# 创建一个AgentExecutor实例,传入智能体和工具列表,用于执行智能体
agent_executor = AgentExecutor(agent=agent, tools=tools)
# 调用智能体执行器,传入包含用户输入“今天北京天气怎么样”,打印智能体处理后的结果
print(agent_executor.invoke({"input": "今天北京天气怎么样"}))
{'input': '今天北京天气怎么样', 'output': '今天北京的天气是晴转多云,最低气温为-11℃,最高气温为-1℃,北风微风。您可以查看更多详细信息和天气预报,请访问以下链接:[北京天气详情](https://tianqi.moji.com/today/china/beijing/beijing)。'}进程已结束,退出代码为 0

为了确切知晓智能体在处理任务时是否调用了Tavily搜索工具来搜索相关内容, 我们在LangSmith平台上进行细致查看。 

我们发现智能体对于“今天北京天气怎么样”进行了查询,并且使用了Tavily搜索工具。这符合我们的预期结果。

综上,我们发现我们创建的智能体会根据不同类型的问题有效的调用搜索工具。

添加记忆

如前所述,此智能体是无状态的。这意味着它不会记住先前的交互内容。如果要给它“记忆”,我们需要传递先前的chat_history

完整代码
# 从langchain_openai库导入ChatOpenAI类,用于创建OpenAI聊天模型实例
from langchain_openai import ChatOpenAI
# 从langchain导入hub模块,用于从LangChain Hub拉取提示模板
from langchain import hub
# 从langchain.agents模块导入create_tool_calling_agent函数,用于创建工具调用智能体
from langchain.agents import create_tool_calling_agent
# 从langchain.agents模块导入AgentExecutor类,用于执行智能体
from langchain.agents import AgentExecutor
# 从langchain_core.messages模块导入HumanMessage和AIMessage类,分别表示人类消息和AI消息
from langchain_core.messages import HumanMessage, AIMessage# 创建一个ChatOpenAI实例,指定使用的模型为gpt-3.5-turbo
chat_model = ChatOpenAI(model="gpt-3.5-turbo")
# 从LangChain Hub拉取名为"hwchase17/openai-functions-agent"的提示模板
prompt = hub.pull("hwchase17/openai-functions-agent")
# 调用create_tool_calling_agent函数创建一个工具调用智能体,传入聊天模型、空工具列表和提示模板
agent = create_tool_calling_agent(chat_model, tools=[], prompt=prompt)
# 创建一个AgentExecutor实例,传入智能体和工具列表,用于执行智能体
agent_executor = AgentExecutor(agent=agent, tools=[])
# 定义第一个用户输入内容
first_input = "你好! 我是Ethan"
# 调用智能体执行器处理第一个输入,传入输入内容和空的聊天历史记录,得到响应
response = agent_executor.invoke({"input": first_input, "chat_history": []})
# 定义第二个用户输入内容
second_input = "我的名字是什么?"
# 调用智能体执行器处理第二个输入,传入包含第一次交互信息的聊天历史记录和第二个输入,得到新响应
response = agent_executor.invoke({# 构建聊天历史记录,包含第一次的人类消息和AI的回复"chat_history": [HumanMessage(content=first_input),AIMessage(content=response['output']),],# 第二个用户输入"input": second_input,}
)
# 打印第二次交互的响应结果
print(response)
运行结果
{'chat_history': [HumanMessage(content='你好! 我是Ethan', additional_kwargs={}, response_metadata={}), AIMessage(content='你好,Ethan!有什么我能帮助你的吗?', additional_kwargs={}, response_metadata={})], 'input': '我的名字是什么?', 'output': '你的名字是Ethan。有什么其他问题我可以回答吗?'}进程已结束,退出代码为 0

从运行结果我们看到,在第一次交互中用户告知了自己的名字,并且这些信息被包含在chat_history中传递给了智能体。所以当询问“我的名字是什么?”时,智能体能够利用这些 “记忆”(即聊天历史记录)来给出正确的回答。

这就体现了通过传递聊天历史记录为AgentExecutor赋予了记忆功能,使其能够参考先前的交互信息来处理当前任务。

带消息历史记录的可运行体

RunnableWithMessageHistory。在处理智能体交互消息时,如果希望能自动记录和跟踪这些消息,以便后续使用,可以利用RunnableWithMessageHistory类。将智能体执行相关的操作包装在这个类中,它就能对消息进行自动跟踪管理,方便为智能体赋予记忆等功能,让智能体在后续交互中能参考历史消息。

在使用RunnableWithMessageHistory类时,因为我们有多个输入,我们需要指定两个事项:

  • input_messages_key:用于将输入添加到对话历史记录中的键。
  • history_messages_key:用于将加载的消息添加到其中的键。
完整代码
# 从langchain_openai库导入ChatOpenAI类,用于创建OpenAI聊天模型实例
from langchain_openai import ChatOpenAI
# 从langchain导入hub模块,用于从LangChain Hub拉取提示模板
from langchain import hub
# 从langchain.agents模块导入create_tool_calling_agent函数,用于创建工具调用智能体
from langchain.agents import create_tool_calling_agent
# 从langchain.agents模块导入AgentExecutor类,用于执行智能体
from langchain.agents import AgentExecutor
# 从langchain_community.chat_message_histories模块导入ChatMessageHistory类,用于管理聊天历史记录
from langchain_community.chat_message_histories import ChatMessageHistory
# 从langchain_core.chat_history模块导入BaseChatMessageHistory类,是聊天历史记录类的基类
from langchain_core.chat_history import BaseChatMessageHistory
# 从langchain_core.runnables.history模块导入RunnableWithMessageHistory类,用于创建带有消息历史记录的可运行对象
from langchain_core.runnables.history import RunnableWithMessageHistory# 创建一个ChatOpenAI实例,指定使用的模型为gpt-3.5-turbo
chat_model = ChatOpenAI(model="gpt-3.5-turbo")
# 从LangChain Hub拉取名为"hwchase17/openai-functions-agent"的提示模板
prompt = hub.pull("hwchase17/openai-functions-agent")
# 调用create_tool_calling_agent函数创建一个工具调用智能体,传入聊天模型、空工具列表和提示模板
agent = create_tool_calling_agent(chat_model, tools=[], prompt=prompt)
# 创建一个AgentExecutor实例,传入智能体和工具列表,用于执行智能体
agent_executor = AgentExecutor(agent=agent, tools=[])# 定义一个空字典,用于存储不同会话的聊天历史记录
store = {}# 定义一个函数,根据会话ID获取对应的聊天历史记录,如果不存在则创建一个新的
def get_session_history(session_id: str) -> BaseChatMessageHistory:# 检查会话ID是否已存在于存储中if session_id not in store:# 若不存在,为该会话ID创建一个新的聊天历史记录实例store[session_id] = ChatMessageHistory()# 返回对应会话ID的聊天历史记录return store[session_id]# 创建一个带有消息历史记录的可运行对象,传入智能体执行器、获取会话历史记录的函数以及输入和历史记录的键名
agent_with_chat_history = RunnableWithMessageHistory(agent_executor,get_session_history,input_messages_key="input",history_messages_key="chat_history",
)
# 调用带有消息历史记录的可运行对象处理输入,指定会话ID为123,得到响应
response = agent_with_chat_history.invoke({"input": "你好,我是Ethan"},config={"configurable": {"session_id": "123"}},
)
# 打印此次交互的响应结果
print(response)
# 再次调用带有消息历史记录的可运行对象处理新输入,使用相同的会话ID,得到新响应
new_response = agent_with_chat_history.invoke({"input": "我叫什么名字?"},config={"configurable": {"session_id": "123"}},
)
# 打印新的交互响应结果
print(new_response)
运行结果
{'input': '你好,我是Ethan', 'chat_history': [], 'output': '你好,Ethan!有什么可以帮助你的吗?'}
{'input': '我叫什么名字?', 'chat_history': [HumanMessage(content='你好,我是Ethan', additional_kwargs={}, response_metadata={}), AIMessage(content='你好,Ethan!有什么可以帮助你的吗?', additional_kwargs={}, response_metadata={})], 'output': '您刚刚告诉我您的名字是Ethan。您还有其他问题需要帮助吗?'}进程已结束,退出代码为 0

综上,在开发智能体等对话式应用时,用户与智能体的交互是连续的,需要智能体能够记住之前的对话内容。RunnableWithMessageHistory可以帮助管理对话历史,使得智能体能够理解上下文,提供更准确和连贯的回答。

当处理需要多个步骤完成的任务时,每个步骤的结果和交互信息都可能对后续步骤产生影响。使用 RunnableWithMessageHistory可以记录这些步骤中的消息,确保智能体在整个任务过程中能够参考历史信息,顺利完成任务。

结束

好了,以上就是本次分享的全部内容了。博主希望大家能熟练的掌握创建和运行Agent(智能体),并且可以在实际开发中灵活的去运用它。

LangChain中构建Agent智能体是打造一个能够借助大语言模型,根据用户输入动态规划并执行任务的系统。它具有多方面重要作用,包括提升任务处理能力增强交互体验提高自动化程度拓展应用场景

那么本次分享就到这了。对于上面提到过的NLP,它的全称是Natural Language Processing,翻译过来叫自然语言处理NLP是人工智能和语言学的交叉领域,专注于让计算机理解、处理和生成人类自然语言。

这段时间博主一直在研究这个领域(都快吐了血了🤮,可能是因为博主并不是人工智能专业出身吧)。博主打算把LangChain大模型应用开发完结后,开始讲这部分内容,请大家多关注下博主。(PS:需要大家具备线性代数概率论与数理统计微积分的知识储备哈。🤣🤣🤣)

最后,博主还是那句话:请大家多去大胆的尝试和使用,成功总是在不断的失败中试验出来的,敢于尝试就已经成功了一半。如果大家对博主分享的内容感兴趣或有帮助,请点赞和关注。大家的点赞和关注是博主持续分享的动力🤭,博主也希望让更多的人学习到新的知识。

相关文章:

LangChain大模型应用开发:构建Agent智能体

介绍 大家好,博主又来给大家分享知识了。今天要给大家分享的内容是使用LangChain进行大模型应用开发中的构建Agent智能体。 在LangChain中,Agent智能体是一种能够根据输入的任务或问题,动态地决定使用哪些工具(如搜索引擎、数据库查询等)来…...

巧用GitHub的CICD功能免费打包部署前端项目

近年来,随着前端技术的发展,前端项目的构建和打包过程变得越来越复杂,占用的资源也越来越多。我有一台云服务器,原本打算使用Docker进行部署,以简化操作流程。然而,只要执行sudo docker-compose -f deploy/…...

【2】常用cmd命令大全、使用cmd运行和编译Java程序

文章目录 一、常用cmd命令大全文件和目录操作系统信息查看磁盘管理网络操作其他常用命令 二、使用cmd命令运行和编译Java程序 一、常用cmd命令大全 cmd的常用命令较多,java初学者只需了解这几个即可 dir:查看当前路径下的所有文件夹 cd:进入指…...

UniApp SelectorQuery 讲解

一、SelectorQuery简介 在UniApp中,SelectorQuery是一个非常强大的工具,它允许开发者查询节点信息。通过这个API,我们可以获取到页面元素的尺寸、位置、滚动条位置等信息。这在处理动态布局、动画效果或是用户交互时尤为重要。 二、基本使用…...

【行业解决方案篇十一】【DeepSeek零售分析:客流热力图生成系统】

开篇:当商店开始"思考" 你可能不知道,现在北京三里屯的优衣库旗舰店,每天要处理超过3000个顾客的移动轨迹数据。这些数据不是用来监控,而是让店铺自己"学会"把畅销款T恤摆在哪里最能促进销量。今天要讲的DeepSeek零售分析系统,就是这样一个能把"…...

车载DoIP协议 --- TCP详细解析

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活…...

C++关键字之mutable

1.介绍 在C中,mutable是一个关键字,用于修饰类的成员变量。它的主要作用是允许在常量成员函数或常量对象中修改被标记为mutable的成员变量。通常情况下,常量成员函数不能修改类的成员变量,但有些情况下,某些成员变量的…...

设计模式| 观察者模式 Observer Pattern详解

目录 一、概述1.1 动机1.2 核心思想1.3 别名 二、角色与实现原理2.1 角色2.2 实现原理2.3 类图 三、经典接口实现3.1 示例3.1.1 观察者接口3.1.2 目标接口3.1.3 具体被观察者3.1.4 具体观察者3.1.5 Client3.1.6 UML时序图 3.2 特点 四、其他实现方式4.1 委托与事件(…...

Git-速查

Git 安装 Git 之后,你可以… 配置全局用户信息(推荐) 全局设置,创建本地仓库时默认分支名称为 main(你需要什么名称就该什么名称)【推荐配置为 main 】 git config --global init.defaultBranch main全…...

Spring Boot嵌入式服务器深度解析:从配置到调优的全方位指南

文章目录 引言一、嵌入式服务器核心原理1.1 架构设计特点1.2 主流服务器对比 二、嵌入式服务器配置实战2.1 基础配置模板2.2 HTTPS安全配置 三、高级调优策略3.1 线程池优化(Tomcat示例)3.2 响应压缩配置3.3 访问日志配置 四、服务器切换实战4.1 切换至U…...

深入解析浏览器渲染全流程:从URL输入到页面渲染的底层原理与性能优化(附实战代码)

本文以https://example.com为例,逐层剖析浏览器从输入URL到页面渲染的完整链路,涵盖DNS解析、TCP/TLS握手、HTTP请求、DOM/CSSOM构建等核心阶段,结合代码示例与性能调优技巧,助你掌握浏览器底层运行机制。 一、导航阶段&#xff1…...

【网络安全】常见的web攻击

1、SQL注入攻击 定义: 攻击者在HTTP请求中注入恶意的SQL代码,当服务器利用参数构建SQL语句的时候,恶意的SQL代码被一起构建,并在数据库中执行。 示例: 用户登录: 输入用户名xx, 密码 or 1 …...

MySQL面试学习

MySQL 1.事务 事务的4大特性 事务4大特性:原子性、一致性、隔离性、持久性 原⼦性: 事务是最⼩的执⾏单位,不允许分割。事务的原⼦性确保动作要么全部完成,要么全不执行一致性: 执⾏事务前后,数据保持⼀…...

一文读懂Docker之Docker Compose

目录 一、Docker Compose简介 二、Docker Compose的安装和基本使用 1、Docker Compose的安装 步骤一、下载docker-compose 步骤二、新增可执行权限 步骤三、查看是否安装成功 2、Docker Compose的基本使用 (1)、docker-compose up (2)、docker-compose ps (3)、docke…...

escape SQL中用法

select * from tablename where username like %#%% escape # 这个的意思就是,escape指定字符#,#字符后面的第一个字符被认为是普通字符 查询示例2 查询username字段中包含[的数据也是一样,即: select * from tablename where us…...

Cherno C++ P57 Standard array处理静态数组

这篇文章当中我们讲一下如何使用C自带的standard array来处理静态数组。 首先什么是静态数组,静态数组通常指的是不会增长的数据,长度是已经确定了的。我们在定义数组的时候就必须确定好长度与类型。 其次C当中也确实给我们提供了一些可以用来处理静态…...

linux学习【7】Sourc Insight 4.0设置+操作

目录 1.Source Insight是什么?2.需要哪些配置?3.怎么新建项目4.一些问题的解决1.中文乱码问题 5.常规使用1. 在工程中打开文件2. 在文件中查看函数或变量的定义3. 查找函数或变量的引用4. 快捷键 按照这个设置就可以了,下面的设置会标明设置理…...

JDK、Hadoop下载地址

一、Oracle JDK https://www.oracle.com/java/technologies/downloads/ 刚进去是最新的版本,往下滑可以看到老版本 二、Open JDK的 Azul Zulu https://www.azul.com/downloads/ 直接可以选版本等选项卡 三、Hadoop Apache Download Mirrors...

【小白向超详细】使用 VSCode 远程连接 Linux 服务器详细教程

使用 VSCode 远程连接 Linux 服务器详细教程 前提条件 已安装 VSCode。已在 VSCode 中安装 Remote - SSH 插件。目标 Linux 服务器 开启了 SSH 服务,并可以通过 SSH 访问。本地电脑已安装 SSH 客户端(Linux 和 macOS 自带,Windows 用户可以…...

设计心得——解耦的实现技术

一、说明 在前面的“设计心得——解耦”中,对解耦进行了高层次的抽象说明。本篇则对在实践中常用的解耦技术进行逐一分析说明,以期为开发者能更从理论到实践搭建一个桥梁。至于大家能够如何更好的在自己的项目中进行解耦的实践,就需要不断的…...

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...