LangChain大型语言模型(LLM)应用开发(六):Agents

news2025/1/11 19:46:07

LangChain是一个基于大语言模型(如ChatGPT)用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互,将多个组件链接在一起,以便在不同的应用程序中使用。
今天我们来学习DeepLearning.AI的在线课程:LangChain for LLM Application Development的第六门课:Agents, 所谓Agents可以理解为那些可以代替你来完成各种任务的人,即代理人(agent)。agent在执行各种任务的时候可能会用到各种工具,那么今天我们就来讨论agent及其工具的使用。

 

首先我们还是要做一些基础性工作,比如设置openai的api key:

import os

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file

import warnings
warnings.filterwarnings("ignore")

Langchain的内置工具

首先我们解释两个简单的Langchain的内置工具“llm-math”和"wikipedia",这里的llm-math工具具有做数学运算的能力,当我们有时候希望llm完成某些数学计算问题时就可以让llm使用该工具来获得准确的答案,而wikipedia工具则是著名的“维基百科”的查询工具,例如当我们希望llm能够准确回答一些关于历史问题时,我们就可以让llm使用该工具来查询“维基百科”从而获取准确的答案,下面我们来创建一个代理(agent),并让这个代理使用llm-math和wikipedia来完成某些特定任务:

from langchain.agents.agent_toolkits import create_python_agent
from langchain.agents import load_tools, initialize_agent
from langchain.agents import AgentType
from langchain.tools.python.tool import PythonREPLTool
from langchain.python import PythonREPL
from langchain.chat_models import ChatOpenAI

#创建llm
llm = ChatOpenAI(temperature=0)

#定义工具
tools = load_tools(["llm-math","wikipedia"], llm=llm)

#创建代理
agent= initialize_agent(
    tools, 
    llm, 
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    handle_parsing_errors=True,
    verbose = True)

这里对上述代码稍加解释,首先我们创建了一个openai的LLM, 接着我们创建了一个工具集tools,该工具集包含了"llm-math"和"wikipedia"这两个工具,最后我们创建了一个代理(agent), 在创建代理时我们将llm 和tools作为参数传递给了代理,我们还设置了代理的类型为AgentType.ZERO_SHOT_REACT_DESCRIPTION,接下来我们来看一下agent的内置prompt模板:

print(agent.agent.llm_chain.prompt.template)

 

 在该模板中LLM被告知要使用计算器工具和维基百科工具,并说明了这两个工具的使用场景,然后对完成任务的工作流程进行了介绍。

完成了创建代理的工作以后,我们就可以让代理来回答一些数学或者历史问题:

agent("300的25%是多少?")

 我们看到代理在执行这个数学计算问题的时候有一个工作流程,这个流程主要包含下面几个阶段:

  1. Action: 行动要使用的工具
  2. Action Input: 行动的输入条件
  3. Observation:行动完成后的观察到的结果
  4. Thought: 思考观察到的结果是否满足要求
  5. Final Answer: 最终的答案

这里需要说明的,从Action到Thought这四个阶段是可以重复多次执行的,当Thought(思考)观察到的结果不能满足要求,就会开始下一轮的Action到Thought的执行过程,直到最后思考观察到的结果满足要求以后才会结束Action到Thought的执行过程,最后输出最终答案,下面我们来询问一个历史相关的问题:

agent("西游记的作者是谁?请用中文回答我")

 这里我们看到代理认为这是一个“人物的问题”,因此它去搜索了英文版的维基百科,最后找到了西游记的作者是吴承恩。

Python Agent

前面我们在代理中使用了"llm-math","wikipedia"这两个Langchain内置工具,接下来我们来使用langchain的内置python工具PythonREPLTool,在下面这个例子中我们让agent对一组外国人姓名进行排序,排序的顺序是先last name后 first name:

#创建python agent
agent = create_python_agent(
    llm,
    tool=PythonREPLTool(),
    verbose=True
)

#待排序的customer_list 
customer_list = [["Harrison", "Chase"], 
                 ["Lang", "Chain"],
                 ["Dolly", "Too"],
                 ["Elle", "Elem"], 
                 ["Geoff","Fusion"], 
                 ["Trance","Former"],
                 ["Jen","Ayai"]
                ]

#对customer_list安last name,first name次序排序
agent.run(f"""Sort these customers by \
last name and then first name \
and print the output: {customer_list}""") 

 从上面返回的结果中,Action是 Python_REPL,在Action Input中是一段python代码,也就是说代理通过python工具Python_REPL执行了这段python代码,最后得到了按last name排序的结果。

下面我们来手动执行一下Action Input中的这段代码:

sorted([['Harrison', 'Chase'], 
        ['Lang', 'Chain'], 
        ['Dolly', 'Too'], 
        ['Elle', 'Elem'], 
        ['Geoff', 'Fusion'], 
        ['Trance', 'Former'], 
        ['Jen', 'Ayai']], 
       key=lambda x: (x[1], x[0]))

 

 这里我们可以看到Action Input中的这段代码是有效的。

查看输出细节

下面我们来查看一下这个python agent在执行的时候所隐藏的细节,只不过我们需要打开langchain的debug功能:

import langchain
langchain.debug=True

agent.run(f"""Sort these customers by \
last name and then first name \
and print the output: {customer_list}""") 

langchain.debug=False

 上图是我们截取的部分agent在执行过程中返回的部分细节信息,这里我们注意到细节信息中存在两个prompt, 这也就是说agent访问了两次LLM,我们把两个prompt的内容整理如下:

从上面的第一个prompt可知,我们告知LLM,它是一个执行python代码的代理,它可以通过使用python REPL工具来执行python代码,然后我们告诉LLM必须按照一套流程来完成接下来的任务,这个流程是:Question->Thought->Action->Action Input->Oberservation->Thought->Final Answer,其中 Thought/Action/Action Input/Observation 可以重复N次,在prompt的最后,我们抛出了Question, 最后留下空白的Thought等待LLM来回答。

下面是第二个经过整理的prompt内容:

 从上面的prompt中可知第二个prompt比第一个prompt又向前迈了一步,因为第二个prompt中已经有了Thought, Action 和Action Input三个步骤的内容,接下来就需执行Action Input中的代码,来完成Observation和Thought这两个步骤了。

通过上面的分析可知agent通过两次访问LLM后才完成了这个python编程的任务。其中第一次访问LLM时只是告诉LLM任务的内容是什么(也就是question)以及完成这个任务的基本流程,随后LLM返回了完成任务所需要的python 代码,然后调用python工具Python_REPL来执行代码, 第二次访问LLM时我们已经拿到了所需要的代码,还剩下Observation和Thought的步骤需要完成。最后LLM返回了代码的执行结果,并得到了最后的Final Answer。

这里我需要说明的是整个代理的执行过程是有点复杂的,我只是把里面的重点部分说明了一些,如果想仔细研究,那还需要自己亲手跑一下代码。

自定义工具

前面我们演示的都是Langchain的内置工具,其实我们还可以自定义工具,比如下面我们自定义了一个获取当前日期的函数time, 当我们向LLM询问当前日期的时候,代理都会执行这个自定义的函数:

from langchain.agents import tool
from datetime import date

@tool
def time(text: str) -> str:
    """Returns todays date, use this for any \
    questions related to knowing todays date. \
    The input should always be an empty string, \
    and this function will always return todays \
    date - any date mathmatics should occur \
    outside this function."""
    return str(date.today())


agent= initialize_agent(
    tools + [time], 
    llm, 
    agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    handle_parsing_errors=True,
    verbose = True)
try:
    result = agent("whats the date today?") 
    print(result)
except: 
    print("exception on external access")

 整合所有工具

下面我们把内置工具和自定义工具整合在一起开发一个多功能agent的例子,在这个例子中我们将会整合python工具,维基百科工具,duckduckgo搜索工具,自定义工具:

# pip install duckduckgo-search
from langchain.tools import DuckDuckGoSearchRun
from langchain.utilities import WikipediaAPIWrapper
from langchain.python import PythonREPL
from langchain.agents import Tool
from langchain.agents import initialize_agent
from langchain.chat_models import ChatOpenAI
import random

llm = ChatOpenAI(temperature=0)

wikipedia = WikipediaAPIWrapper()
search = DuckDuckGoSearchRun()
python_repl = PythonREPL()


#自定义工具,获取随机数
def random_num(input=""):
    return random.randint(0,5)

#定义维基百科工具
wikipedia_tool = Tool(
    name='wikipedia',
    func= wikipedia.run,
    description="Useful for when you need to look up a topic, country or person on wikipedia"
)

#定义duckduckgo 搜索工具
duckduckgo_tool = Tool(
    name='DuckDuckGo Search',
    func= search.run,
    description="Useful for when you need to do a search on the internet to find information that another tool can't find. \
    be specific with your input."
)

#定义python工具
python_tool = Tool(
    name = "python repl",
    func=python_repl.run,
    description="useful for when you need to use python to answer a question. You should input python code"
)

#定义获取随机数工具
random_tool = Tool(
    name='Random number',
    func= random_num,
    description="Useful for when you need to get a random number. input should be 'random'"
)

#整合所有工具
tools=[python_tool,wikipedia_tool,duckduckgo_tool,random_tool]

#创建代理
zero_shot_agent = initialize_agent(
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    tools=tools,
    llm=llm,
    verbose=True,
    max_iterations=5,
)

下面我们查看一下代理的prompt模板:

print(zero_shot_agent.agent.llm_chain.prompt.template)

 在上面的模板中分别就4个工具的应用场景做了介绍,它告诉LLM在什么情况下应该使用什么工具,工作流程仍然是:Question->Thought->Action->Action Input->Oberservation->Thought->Final Answer,其中 Thought/Action/Action Input/Observation 可以重复N次,下面我们就用这个多工具的agent来做一下测试:

#给我一个随机数
zero_shot_agent.run("Can you give me a random number?")

#乔.拜登是哪一年出生的
zero_shot_agent.run("When was Joe Biden born?")

#17×6等于几?
zero_shot_agent.run("What is 17*6?")

#苹果公司现在的股票价格是多少?
zero_shot_agent.run('what is the current price of AAPL')

 参考资料

DuckDuckGo Search | 🦜️🔗 Langchain

Agent types | 🦜️🔗 Langchain

Agents | 🦜️🔗 Langchain

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

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

相关文章

【Linux指令集】---zip指令(超详细)

个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【Linux专栏】🎈 本专栏旨在分享学习Linux的一点学习心得,欢迎大家在评论区讨论💌 演示环境&#xff1…

DevOps系列文章 之 pipeline 流水线:企业微信群通知消息

部署流程 开发环境Jenkins的job进行编译-打包-build成镜像-推送到镜像私有仓库-部署开发环境-(开发自测)-自测通过-提测。 版本管理: 构建的过程: 开发环境通过验证,则点击“Yes”,没有则Abort。点击Yes后…

在Linux系统中,如何搭建DNS服务

如何搭建DNS服务 要在Linux系统上搭建DNS服务,你可以按照以下步骤进行操作: 1.安装BIND软件包: sudo yum install bind bind-utils2.配置主DNS服务器: 打开/etc/named.conf文件,编辑DNS服务器的配置。根据你的域名和…

122、仿真-基于51单片机的电量监测电压电流和温度报警系统设计(Proteus仿真+程序+流程图+配套资料等)

方案选择 单片机的选择 方案一:STM32系列单片机控制,该型号单片机为LQFP44封装,内部资源足够用于本次设计。STM32F103系列芯片最高工作频率可达72MHZ,在存储器的01等等待周期仿真时可达到1.25Mip/MHZ(Dhrystone2.1)。内部128k字节…

自然语言处理(扩展学习1):Scheduled Sampling(计划采样)与2. Teacher forcing(教师强制)

自然语言处理(扩展学习1):Scheduled Sampling(计划采样)与2. Teacher forcing(教师强制) 作者:安静到无声 个人主页 作者简介:人工智能和硬件设计博士生、CSDN与阿里云开发者博客专家&#xff0…

C/C++动态内存开辟(详解)

目录 一,mallloc 函数参数: 函数原理: 二,calloc 函数参数: 函数原理: 三,realloc 函数参数: 函数原理: 五,小结 2)对开辟空间的越界访问 3&#x…

cnn分类图像cifar10

使用CNN模型来分类图像,数据集采用的cifar10,cifar10共有6万张,这些图像共分为10类。 命名的格式大概是这样的:0_19761.jpg,它的第一个数字表示的就是图像所属的类,分成清楚的就知道了,第0类就是…

Flutter:EasyLoading(loading加载、消息提示)

前言 官方虽然提供了内置的加载指示器和提示信息,但是功能比较简陋,这里推荐:flutter_easyloading CircularProgressIndicator CircularProgressIndicator()加粗样式 ScaffoldMessenger.of(context).showSnackBar(const SnackBar(// 提示…

MySQL(三)SQL优化、Buffer pool、Change buffer

MySQL系列文章 MySQL(一)基本架构、SQL语句操作、试图 MySQL(二)索引原理以及优化 MySQL(三)SQL优化、Buffer pool、Change buffer MySQL(四)事务原理及分析 MySQL(五&a…

泛积木-低代码 搭建 增删改查

文章首发于 增删改查 。 这里我们以增删改查作为示例,演示下从页面创建到各个功能齐全。创建页面的时候,建议接口先写好,当然也可以一边联调一边写接口,当前对增删改查提供以下测试接口: 测试接口 /contactsList 列…

【数据结构】非线性结构之树结构(含堆)

前言 前面的三篇文章已经将线性结构讲述完毕了,下面的文章将会为大家将讲点新东西:非线性结构中的树结构。萌新对这里的知识点相对陌生,建议反复观看!! 关于线性结构的三篇文章放在下面: 线性表之顺序表 线…

数组与指针

博客内容:数组与指针 文章目录 一、 数组?指针?1.区别与联系大小赋值存储位置 二、指针数组、数组指针?二维数组和二级指针&数组名与数组的区别总结 一、 数组?指针? 数组 相同类型数据的集合 指针 指…

谷歌Bard更新:支持中文提问和语音朗读

ChatGPT不断更新功能,从GPT-3到3.5,再到GPT-4,甚至最新的plus版已经支持图像处理和图表生成,而谷歌Bard却自从推出后就一直很安静,没有什么大动作。眼见被ChatGPT、Claude甚至是文心一言抢去了风头,自然心有…

springcache的使用(小白也看得懂)

简介 SpringCache整合Redis可以使用Spring提供的Cacheable注解来实现对Redis的缓存操作。使用这种方式可以轻松地在应用程序中启用缓存,并且不需要手动编写访问Redis的代码。在配置文件中需要配置Redis的连接信息以及缓存管理器。使用这种方式可以做到轻松配置&…

C++报错:二进制“心<“没有找到接受“std:string“类型的右操作数的运算符(或没有可接受的转换)

1、问题&#xff1a;在进行二维数组的相关计算时报错&#xff1a; 二进制"心<"没有找到接受"std:string"类型的右操作数的运算符(或没有可接受的转换) 2、原因&#xff1a;没有加入头文件——String; 3、解决办法&#xff1a;加上头文件——String; 4、…

GNN学习笔记:A Gentle Introduction to Graph Neural Networks

原文地址&#xff1a; https://distill.pub/2021/gnn-intro/ 不同形式来源的图 Images as graphs 论文中提到将图像建模为一张拓扑图的方法是将图像的每一个像素看作图的一个结点&#xff0c;并将单个像素结点与其相邻的所有像素之间建立一条边。 每一个非边缘的像素结点具…

Linux下做性能分析4:怎么开始

战地分析 性能分析常常是一种战地分析&#xff0c;所以&#xff0c;在我们可以端起咖啡慢慢想怎么进行分析之前&#xff0c;我们要先说说我们在战地上的套路。 战地分析是说在实用环境中发现问题&#xff0c;我们真正需要进行性能分析的场合&#xff0c;通常都没有机会让你反…

LeetCode: 18. 四数之和 | 双指针专题

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Java中的几种关键字this、super、static和final介绍

Java中的几种关键字this、super、static和final介绍 在Java编程语言中&#xff0c;关键字是具有特殊含义的预定义标识符。关键字是Java编程语言中具有特殊用途的保留单词&#xff0c;用于表示语法结构和程序行为。关键字在语法上具有特定的用途&#xff0c;不能用作变量名、方…

HTTP1.1、HTTPS、HTTP2.0 、HTTP3.0

HTTP1.1 优点&#xff1a; 整体方面&#xff1a;简单、灵活和易于扩展、应用广泛和跨平台 性能方面&#xff1a;长连接、管道网络传输解决请求队头阻塞&#xff08;没有使用&#xff09; 缺点&#xff1a; 安全方面&#xff1a;无状态、明文窃听、伪装、篡改 性能方面&am…