熟悉LangChain中代理的构建块
让我们在LangChain中构建一个简单的代理,以帮助我们了解代理在那里工作的一些基本概念和构建块。
通过保持简单,我们可以更好地掌握这些代理背后的基本思想,从而使我们将来可以构建更复杂的代理。
什么是agent
LangChain文档实际上有一个漂亮的好页面围绕其代理的高级概念。这是一个简短的简单阅读,绝对值得一读。
如果你查找人工智能代理的定义,你会得到类似 “一个能够感知其环境,对其环境采取行动的实体,并就如何实现既定目标以及边学的能力做出明智的决定。”
我想说,这非常符合LangChain Agent的定义。使这一切在软件中成为可能的是大型语言模型 (LLM) 的推理能力。LangChain代理的大脑是LLM。LLM用于推理执行用户请求的询问的最佳方式。
为了执行任务,对事物进行操作并检索信息,代理可以使用LangChain中所谓的工具。通过这些工具,它能够与环境进行交互。
这些工具基本上只是代理可以访问的方法/类,可以通过API与股票市场指数进行交互,更新Google日历事件,或者对数据库运行查询。我们可以根据需要构建工具,这取决于我们试图与代理一起执行的任务的性质。
LangChain中的工具集合称为工具包。在实现方面,这实际上只是代理可用的工具的数组。因此,LangChain中代理的高级概述看起来像这样
作者形象
所以,在基本层面上,代理人需要
- LLMs充当它的大脑,并赋予它推理能力
- 工具,以便它可以与周围的环境互动并实现其目标
构建代理
为了使其中一些概念更加具体,让我们构建一个简单的代理。
我们将创建一个数学代理,它可以执行一些简单的数学运算。
环境设置
首先让我们设置我们的环境和脚本
mkdir simple-math-agent && cd simple-math-agent
touch math-agent.py
python3 -m venv .venv
. .venv/bin/activate
pip安装langchain langchain_openai
或者,您也可以克隆此处使用的代码来自GitHub
git克隆git@github.com:smaameri/simple-math-agent.git
或者看看里面的代码谷歌可乐也。
工具
最简单的开始是为我们的数学代理定义工具。
让我们给它 "添加”,"乘法” 和 "平方” 工具,以便它可以对我们传递给它的问题执行这些操作。通过使我们的工具保持简单,我们可以专注于核心概念,并自己构建工具,而不是依赖现有的和更复杂的工具,如维基儿科,它充当Wikipedia API的包装器,并要求我们从LangChain库导入它。
同样,我们在这里不做任何花哨的事情,只是保持简单并将代理的主要构建块放在一起,以便我们了解它们的工作原理,让我们的第一个特工启动并运行。
让我们从 "添加” 工具开始。在LangChain中创建工具的自下而上的方法是扩展BaseTool类,设置name和description类上的字段,并实现**_run**方法。看起来像这样
from langchain_core.tools import BaseTool
class AddTool(BaseTool):
name = "add"
description = "Adds two numbers together"
args_schema: Type[BaseModel] = AddInput
return_direct: bool = True
def _run(
self, a: int, b: int, run_manager: Optional[CallbackManagerForToolRun] = None
) -> str:
return a + b
请注意,我们需要实施**_run方法来显示我们的工具如何处理传递给它的参数。
还请注意,它如何需要一个pydantic模型args_schema**。我们将在这里定义
AddInput
a: int = Field(description="first number")
b: int = Field(description="second number")
现在,LangChain确实为我们提供了一种更简单的方法来定义工具,然后需要扩展BaseTool Class。我们可以在**@ tool**装饰。使用 @ tool装饰器在LangChain中定义 "添加” 工具将如下所示
from langchain.tools import tool
@tool
def add(a: int, b: int) -> int:
“””Adds two numbers together””” # this docstring gets used as the description
return a + b # the actions our tool performs
简单得多对。在幕后,装饰器神奇地使用提供的方法来扩展BaseTool类,就像我们之前所做的那样。需要注意的是:
- 方法名也变成工具名
- 方法参数定义工具的输入参数
- docstring被转换为工具描述
您还可以在工具上访问这些属性
print(add.name) # add
print(add.description) # Adds two numbers together.
print(add.args) # {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}
请注意,工具的描述非常重要,因为这是LLM用来决定它是否适合这项工作的工具。错误的描述可能会导致该工具在应有的时候使用,或者在错误的时间使用。
与添加工具完成后,让我们继续为我们的定义乘和方形工具。
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
@tool
def square(a) -> int:
"""Calculates the square of a number."""
a = int(a)
return a * a
就这样,就这么简单。
所以我们定义了我们自己的三个自定义工具。一个更常见的用例可能是使用LangChain中已经提供的和现有的一些工具,您可以看到这里。但是,在源代码级别,它们都将使用如上所述的类似方法构建和定义。
就我们所关心的工具而言。现在是时候将我们的工具组合成一个工具包了。
工具包
工具包toolkits听起来很花哨,但实际上非常简单。他们是从字面上看只是一份工具清单。我们可以将我们的工具包定义为一系列工具,比如
toolkit = [加、乘、平方]
就这样。非常简单,没有什么可混淆的。
通常,工具包是一组有用的工具,对于尝试执行某些类型的任务的代理将很有帮助。例如,SQLToolkit可能包含用于生成SQL查询、验证SQL查询和执行SQL查询的工具。
集成工具包LangChain文档上的页面列出了社区开发的大量工具包,这些工具包可能对您有用。LLMs
如上所述,LLM是agent的大脑。它根据传递给它的问题来决定调用哪些工具,以及根据工具描述采取的最佳下一步措施。它还决定何时达到最终答案,并准备将其返回给用户。
让我们在这里设置LLM
提示
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo-1106", temperature=0)
LLm
如上所述,LLM是代理的大脑。它根据传递给它的问题来决定调用哪些工具,以及根据工具描述采取的最佳下一步措施。它还决定何时达到最终答案,并准备将其返回给用户。
让我们在这里设置LLM
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo-1106", temperature=0)
Prompt
最后,我们需要一个提示才能传递给我们的代理,因此它对它是什么样的代理以及应该解决什么样的任务有一个大致的了解。
我们的代理需要一个ChatPromptTemplate 才能工作 (稍后会详细说明)。这就是一个准系统ChatPromptTemplate 的样子。我们关心的主要部分是系统提示,其余的只是我们需要传入的默认设置。
在我们的提示中,我们包含了一个示例答案,向代理显示了我们希望它如何仅返回答案,而不返回任何描述性文本以及答案
prompt = ChatPromptTemplate.from_messages(
[
("system", """
You are a mathematical assistant. Use your tools to answer questions.
If you do not have a tool to answer the question, say so.
Return only the answers. e.g
Human: What is 1 + 1?
AI: 2
"""),
MessagesPlaceholder("chat_history", optional=True),
("human", "{input}"),
MessagesPlaceholder("agent_scratchpad"),
]
)
就是这样。我们已经设置了我们的工具和工具包,我们的代理将需要这些工具和工具包作为其设置的一部分,因此它知道它可以使用的操作和功能的类型。我们还设置了LLM和系统提示。
现在是有趣的部分。建立我们的代理!
Agent
LangChain有一个 不同代理类型的数量 可以用不同的推理能力和能力来创造。我们将使用目前最有能力、最强大的代理, OpenAI工具 代理。根据OpenAI工具代理上的文档,该代理还使用较新的OpenAI模型,
较新的OpenAI模型已经过微调,以检测何时应该调用一个或多个函数并响应应传递给该函数的输入。在API调用中,您可以描述函数,并让模型智能地选择输出一个包含参数的JSON对象来调用这些函数。OpenAI tools API的目标是比使用通用文本完成或聊天API可以完成的更可靠地返回有效和有用的函数调用。
换句话说,该代理擅长为调用函数生成正确的结构,并且能够理解我们的任务是否还需要多个函数 (工具)。该代理还具有调用具有多个输入参数的函数 (工具) 的能力,就像我们的一样。某些代理只能使用具有单个输入参数的函数。
如果你熟悉 OpenAI的功能 调用功能,我们可以使用OpenAI LLM生成正确的参数来调用函数,我们在这里使用的OpenAI工具代理正在利用其中的一些功能,以便能够使用正确的参数调用正确的工具。
为了在LangChain中设置代理,我们需要使用为创建我们选择的代理提供的一种工厂方法。
创建OpenAI工具代理的工厂方法是create_openai_tools_agent()。它需要传入llm,工具和提示我们在上面设置。所以让我们初始化我们的代理。
agent = create_openai_tools_agent(llm, toolkit, prompt)
最后,为了在LangChain中运行代理,我们不能仅仅将其称为”运行“;直接在他们身上键入方法。它们需要通过AgentExecutor运行。
我只在最后提出AgentExecutor,因为我认为这不是理解代理工作方式的关键概念,一开始就把它和其他事情一起提出来,整个事情看起来比它需要的更复杂,以及分散理解其他一些更基本概念的注意力。
因此,现在我们正在介绍它,AgentExecutor充当LangChain中代理的运行时,并允许代理继续运行,直到准备好将其最终响应返回给用户为止。在伪代码中,代理执行器正在按照 (直接从 LangChain文档)
next_action = agent.get_action(...)
while next_action != AgentFinish:
observation = run(next_action)
next_action = agent.get_action(..., next_action, observation)
return next_action
因此,它们基本上是一个while循环,保持在代理上调用下一个操作方法,直到代理返回其最终响应。
因此,让我们在代理执行器内部设置代理。我们通过代理,也必须通过工具包。我们将verbose设置为True,这样我们就可以了解代理在处理我们的请求时正在做什么
agent_executor = AgentExecutor(agent=agent, tools=toolkit, verbose=True)
就这样。我们现在准备将命令传递给我们的代理
result = agent_executor.invoke({"input": "什么是1 + 1"})
让我们运行我们的脚本,并查看代理的输出
python3 math-agent.py
既然我们已经设定了
测试我们的代理
import os
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_openai import ChatOpenAI
from langchain.tools import BaseTool, StructuredTool, tool
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
os.environ["OPENAI_API_KEY"] = "sk-"
# setup the tools
@tool
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
@tool
def square(a) -> int:
"""Calculates the square of a number."""
a = int(a)
return a * a
prompt = ChatPromptTemplate.from_messages(
[
("system", """You are a mathematical assistant.
Use your tools to answer questions. If you do not have a tool to
answer the question, say so.
Return only the answers. e.g
Human: What is 1 + 1?
AI: 2
"""),
MessagesPlaceholder("chat_history", optional=True),
("human", "{input}"),
MessagesPlaceholder("agent_scratchpad"),
]
)
# Choose the LLM that will drive the agent
llm = ChatOpenAI(model="gpt-3.5-turbo-1106", temperature=0)
# setup the toolkit
toolkit = [add, multiply, square]
# Construct the OpenAI Tools agent
agent = create_openai_tools_agent(llm, toolkit, prompt)
# Create an agent executor by passing in the agent and tools
agent_executor = AgentExecutor(agent=agent, tools=toolkit, verbose=True)
result = agent_executor.invoke({"input": "what is 1 + 1?"})
print(result['output'])
让我们向我们的Agent回答几个问题,看看它的表现如何。
5平方是多少?
再次,我们得到了正确的结果,并看到它确实使用了我们的
方形工具作者形象
5对6的幂是多少?
这需要一个有趣的行动方案。它首先使用
方形工具。然后,使用该结果,尝试使用乘**工具几次以获得最终答案。诚然,最终答案3125是错误的,需要再乘以5才能得到正确的答案。但是有趣的是,代理如何尝试使用不同的工具,以及尝试获得最终答案的多个步骤。**作者形象
1减3是多少?
我们没有减号工具。但是它足够聪明,可以使用我们的添加工具,但是将第二个值设置为-3。这很有趣,有时有些令人惊讶,他们是如何聪明和有创造力的。
作者形象
64的平方根是多少
作为最终测试,如果我们要求它进行不属于我们工具集的数学运算,该怎么办?由于我们没有用于方形生根的工具,因此它不会尝试调用工具,而是仅使用LLM直接计算值。
作者形象
我们的系统提示确实告诉它回答,如果它没有正确的工作工具,它 “不知道”,并且有时在测试期间确实这样做。改进的初始系统提示可能有助于解决这一问题,至少在某种程度上
观察
基于稍微使用代理,我注意到以下内容
当询问它有工具可以回答的直接问题时,它在使用正确的工具进行工作并返回正确的答案方面非常一致。所以,在这个意义上相当可靠。
- 如果问题有点复杂,例如我们的 “5到6的幂” 问题,它并不总是返回正确的结果。
- 它有时可以仅使用LLM的纯粹力量来回答我们的问题,而无需调用我们的工具。
- 未来
代理和可以自行推理的程序是编程中的一种新范例,我认为它们将成为构建许多事物的主流。显然,不确定性 (i.非完全可预测的) LLM的性质意味着代理人的结果也会受到影响,质疑我们在需要确定答案的任务上可以依靠他们多少。
也许随着技术的成熟,它们的结果可以越来越可预测,我们可能会为此开发一些解决方案。
我还可以看到代理类型库和包开始成为一个东西。类似于我们如何将第三方库和软件包安装到软件中,例如通过用于python的pip软件包管理器或用于Docker映像的docker Hub,我想知道我们是否可以开始看到代理库和程序包管理器开始开发,随着代理的开发变得非常擅长于他们的特定任务,然后我们也可以将其作为软件包安装到应用程序中。
事实上,朗链的
工具包库在其集成页面上列出的供代理使用的是社区构建的供人们使用的工具集,这可能是社区构建的代理类型库的早期示例。结论
希望这是一个有用的介绍,可以帮助您开始使用LangChain中的Agent进行构建。
记住,代理人基本上只是一个大脑 (LLM) 和一堆工具,他们可以用它们来完成我们周围世界的事情。
快乐黑客!
如果您喜欢这篇文章,并且想了解我发布的有关使用LangChain和AI工具构建事物的最新文章,请执行
在此订阅当他们出来的时候通过电子邮件通知来自:
在LangChain中使用工具和工具包构建简单的代理 | 萨米·马阿梅里 | 2024年4月 | 走向数据科学Building a simple Agent with Tools and Toolkits in LangChain | by Sami Maameri | Apr, 2024 | Towards Data Science