dede 网站图标,微信公众号如何开通小程序,汽车html静态网站,seo和sem的区别是什么?让我们在LangChain中构建简单代理示例#xff0c;以帮助我们理解代理的基本概念和构建块。通过保持简单#xff0c;我们可以更好地掌握这些代理背后的基本思想#xff0c;使我们能够在未来构建更复杂的代理。 什么是代理
LangChain官方文档有非常好的章节来介绍其代理的高级… 让我们在LangChain中构建简单代理示例以帮助我们理解代理的基本概念和构建块。通过保持简单我们可以更好地掌握这些代理背后的基本思想使我们能够在未来构建更复杂的代理。 什么是代理
LangChain官方文档有非常好的章节来介绍其代理的高级概念。但本文强调简短易懂绝对值得在开始之前浏览一下。
如果你查找人工智能代理的定义你会发现“一个实体能够感知其环境对其环境采取行动并就如何达到给定的目标做出明智的决定以及学习的能力。”
我觉得这很符合LangChain的定义使这一切在软件中成为可能的是大型语言模型LLM的推理能力。LangChain代理的大脑是LLMLLM用于推断执行用户请求的最佳方式。
为了执行任务操作事物和检索信息代理在LangChain中拥有所谓的工具。正是通过这些工具它才能够与环境进行互动。
这些工具基本上就是代理可以访问的方法/类它们可以通过API与Stock Market指数交互、更新办公Calendar事件或对数据库运行查询。我们可以根据需要构建工具这取决于我们试图与代理一起执行的任务的性质。
LangChain中的工具集合称为Toolkit。在实现方面这实际上只是代理可用的工具集合。因此在LangChain中代理的高级概述看起来是这样的 因此在基本层面上代理需要:
一个LLm充当它的大脑并赋予它推理能力工具以便它可以与周围的环境进行交互并实现其目标
构建代理
为了使这些概念更加具体让我们构建一个简单的代理。我们将创建数学代理它可以执行一些简单的数学运算。
环境设置
首先让我们设置环境和脚本
mkdir simple-math-agent amp;amp; cd simple-math-agent
touch math-agent.py
python3 -m venv .venv
. .venv/bin/activatepip install langchain langchain_openai工具
最简单的开始将是首先为我们的数学代理定义工具。
让我们给它“加”、“乘”和“平方”工具这样它就可以对我们传递给它的问题执行这些操作。通过保持我们的工具简单我们可以专注于核心概念并自己构建工具而不是依赖于现有的更复杂的工具如wiki检索它作为维基百科API的包装器需要我们从LangChain库中导入它。
同样我们在这里并没有尝试做任何花哨的事情只是保持简单并将代理的主要构建块放在一起以便我们能够理解它们是如何工作的并使我们的第一个代理启动并运行。
让我们从“加”工具开始。在LangChain中创建工具的自下而上的方法是扩展BaseTool类设置类上的名称和描述字段并实现_run方法。就像这样
from langchain_core.tools import BaseToolclass AddTool(BaseTool):name adddescription Adds two numbers togetherargs_schema: Type[BaseModel] AddInputreturn_direct: bool Truedef _run(self, a: int, b: int, run_manager: Optional[CallbackManagerForToolRun] None) - str:return a b注意我们需要实现_run方法来显示我们的工具如何处理传递给它的参数。还要注意它是如何为args_schema需要一个pydantic模型的。我们在这里定义一下
AddInputa: int Field(descriptionfirst number)b: int Field(descriptionsecond number)现在LangChain确实为我们提供了一种更简单的方法来定义工具然后每次都需要扩展BaseTool类。我们可以在tool装饰器的帮助下做到这一点。使用tool装饰器在LangChain中定义“加”工具代码如下所示:
from langchain.tools import tooltool
def add(a: int, b: int) - int:Adds two numbers together # this docstring gets used as the descriptionreturn a b # the actions our tool performs简单多了对吧在幕后装饰器神奇地使用提供的方法来扩展BaseTool类就像我们前面所做的那样。有些事情需要注意
方法名也成为工具名方法参数定义工具的输入参数文档字符串转换为工具描述
在工具上访问这些属性
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 * btool
def square(a) - int:Calculates the square of a number.a int(a)return a * a就是这样很简单。
因此我们已经定义了我们自己的三个定制工具。更常见的用例可能是使用LangChain中已经提供的和现有的一些工具您可以在这里看到。然而在源代码级别它们都将使用上面描述的类似方法来构建和定义。
这就是我们所关心的工具。现在是时候将我们的工具组合成一个工具包了。
工具包
工具箱听起来很花哨但实际上非常简单。它们实际上只是一个工具列表。我们可以将工具箱定义为如下所示的一系列工具
toolkit [add, multiply, square]就是这样。真的很简单没有什么好混淆的。
通常工具包是一组工具这些工具组合在一起很有用对试图执行某些任务的代理很有帮助。例如SQLToolkit可能包含用于生成SQL查询、验证SQL查询和执行SQL查询的工具。
LangChain文档上的integration Toolkit页面有社区开发的工具箱的大列表这些工具包可能对你有用。
LLM
如上所述LLM是代理的大脑。它根据传递给它的问题决定调用哪个工具根据工具描述采取的最佳下一步是什么。它还决定何时得到最终答案并准备将答案返回给用户。
from langchain_openai import ChatOpenAIllm ChatOpenAI(modelgpt-3.5-turbo-1106, temperature0)提示词
最后我们需要一个提示词传递给我们的代理这样它就有一个关于它是什么类型的代理以及它应该解决什么类型的任务的一般概念。
我们的代理需要一个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.gHuman: What is 1 1?AI: 2),MessagesPlaceholder(chat_history, optionalTrue),(human, {input}),MessagesPlaceholder(agent_scratchpad),]
)就是这样。我们已经设置了我们的Tools和Toolkit我们的代理将需要它们作为其设置的一部分因此它知道它可以处理的操作和功能的类型。我们还设置了LLM和系统提示符。
现在到了有趣的部分建立我们的代理
代理
LangChain可以创建许多不同类型的代理具有不同的推理能力和能力。我们将使用目前可用的最强大的代理OpenAI Tools代理。根据OpenAI工具代理的文档它也使用更新的OpenAI模型 更新的OpenAI模型已经进行了微调可以检测何时应该调用一个或多个函数并使用应该传递给函数的输入进行响应。在API调用中你可以描述函数并让模型智能地选择输出包含参数的JSON对象来调用这些函数。OpenAI工具API的目标是比使用通用文本完成或聊天API更可靠地返回有效和有用的函数调用。这里仅为示例LangChain可以接入主流大模型包括DeepSeek R1. 换句话说这个代理擅长为调用函数生成正确的结构并且能够理解我们的任务是否还需要多个函数工具。这个代理还具有调用具有多个输入参数的函数工具的能力就像我们的一样。有些代理只能处理具有单个输入参数的函数。
如果你熟悉OpenAI的函数调用功能我们可以使用OpenAI LLM生成正确的参数来调用函数我们在这里使用的OpenAI Tools代理正在利用一些功能
agent create_openai_tools_agent(llm, toolkit, prompt)最后为了在LangChain中运行代理我们不能直接对它们调用“run”类型的方法。它们需要通过AgentExecutor运行。
我在最后才提到代理执行者因为我不认为它是理解代理如何工作的关键概念把它和其他东西放在一起只会让整个事情看起来比它需要的更复杂也会分散对其他更基本概念的理解。
因此现在我们正在介绍它AgentExecutor充当LangChain中代理的运行时并允许代理保持运行直到它准备好向用户返回其最终响应。在伪代码中AgentExecutor的操作如下直接引用自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(agentagent, toolstoolkit, verboseTrue)就是这样。现在我们已经准备好向代理传递命令了
result agent_executor.invoke({input: what is 1 1})让我们运行脚本看看代理的输出
python3 math-agent.py因为我们已经在AgentExecutor上设置了verboseTrue所以我们可以看到代理所执行的操作行。它确定了我们应该调用“加”工具调用带有所需参数的“加”工具并返回我们的结果。
下面是完整源代码:
import osfrom langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_openai import ChatOpenAIfrom langchain.tools import BaseTool, StructuredTool, tool
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderos.environ[OPENAI_API_KEY] sk-# setup the tools
tool
def add(a: int, b: int) - int:Add two numbers.return a btool
def multiply(a: int, b: int) - int:Multiply two numbers.return a * btool
def square(a) - int:Calculates the square of a number.a int(a)return a * aprompt ChatPromptTemplate.from_messages([(system, You are a mathematical assistant.Use your tools to answer questions. If you do not have a tool toanswer the question, say so. Return only the answers. e.gHuman: What is 1 1?AI: 2),MessagesPlaceholder(chat_history, optionalTrue),(human, {input}),MessagesPlaceholder(agent_scratchpad),]
)# Choose the LLM that will drive the agent
llm ChatOpenAI(modelgpt-3.5-turbo-1106, temperature0)# 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(agentagent, toolstoolkit, verboseTrue)result agent_executor.invoke({input: what is 1 1?})print(result[output])
测试代码
让我们向代理提出几个问题看看它的表现如何。
5的平方是多少
我们再次得到了正确的结果并看到它确实使用了我们的平方工具。
5的6次方是多少
这需要一个有趣的推理过程。首先使用平方工具然后利用这个结果尝试使用乘法工具来得到最终的答案。无可否认最终的答案3125是错误的需要再乘以5才能得到正确的答案。但是看到代理如何尝试使用不同的工具和多个步骤来尝试获得最终答案是很有趣的。
1 - 3等于多少
我们没有减号工具。但它足够聪明可以使用我们的添加工具但将第二个值设置为-3。有趣的是有时他们是如此的聪明和有创造力。
64的平方根是多少
作为最后的测试如果我们要求它执行一个不属于我们工具集的数学运算会怎么样由于我们没有用于平方根的工具因此它不会尝试调用工具而是直接使用LLM计算值。
我们的系统提示词确实告诉它回答“不知道”如果它没有正确的工具来完成这项工作它有时在测试期间确实会这样做。改进的初始系统提示符可能有助于解决这个问题至少在某种程度上是这样。
观察
基于对代理的使用我注意到以下几点
当直接问它有工具可以回答的问题时它会非常一致地使用正确的工具来完成任务并返回正确的答案。所以从这个意义上说它非常可靠。如果问题有点复杂例如我们的“5的6次方”问题它并不总是返回正确的结果。它有时可以只使用LLM的纯粹力量来回答我们的问题而不调用我们的工具。建议你对照示例测试不同的大模型尤其国内主流大模型如智普、DeepSeek等。
总结
希望本文介绍内容能帮助你开始在LangChain中构建代理。记住代理本质上只是一个大脑LLM和一堆工具它们可以用来帮助我们完成一些特定任务。