快速入门指南: 创建自己的LLM Agent:让语言模型动起来

创建自己的LLM Agent:让语言模型动起来

语言模型本身不能采取行动——它们只能输出文本。LangChain的一个重要应用就是创建智能代理。代理是一种系统,使用LLM作为推理引擎来确定应该采取哪些行动以及传递什么输入。在执行操作后,可以将结果反馈给LLM,以确定是否需要更多操作,或者是否可以结束。

在本教程中,我们将构建一个可以与搜索引擎互动的智能代理。你将能够向这个代理提问,观看它调用搜索工具,并与它进行对话。

端到端代理

下面的代码片段展示了一个完全功能的代理,使用LLM来决定使用哪些工具。它配备了一个通用的搜索工具,并具有对话记忆功能——意味着它可以作为多轮对话的聊天机器人使用。

在本指南的其余部分,我们将逐步讲解各个组件及其作用——但如果你想直接拿代码上手,请随意使用以下代码!

# 导入相关功能
from langchain_anthropic import ChatAnthropic
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import HumanMessage
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.prebuilt import create_react_agent

# 创建代理
memory = SqliteSaver.from_conn_string(":memory:")
model = ChatAnthropic(model_name="claude-3-sonnet-20240229")
search = TavilySearchResults(max_results=2)
tools = [search]
agent_executor = create_react_agent(model, tools, checkpointer=memory)

# 使用代理
config = {"configurable": {"thread_id": "abc123"}}
for chunk in agent_executor.stream(
    {"messages": [HumanMessage(content="你好,我是小明!我住在旧金山。")]}, config
):
    print(chunk)
    print("----")

for chunk in agent_executor.stream(
    {"messages": [HumanMessage(content="我住的地方天气怎么样?")]}, config
):
    print(chunk)
    print("----")

API参考:ChatAnthropic | TavilySearchResults | HumanMessage

设置环境

Jupyter Notebook

本指南(以及文档中的大多数指南)使用Jupyter notebook,并假设读者也在使用它。Jupyter notebook是学习如何使用LLM系统的完美互动环境,因为很多时候事情会出错(例如输出不符合预期、API挂掉等),观察这些情况是更好地理解LLM构建的好方法。

这个和其他教程最好在Jupyter notebook中运行。查看此处了解安装方法。

安装

要安装LangChain,请运行:

%pip install -U langchain-community langgraph langchain-anthropic tavily-python

详情请参见安装指南

LangSmith

你用LangChain构建的许多应用程序将包含多步操作和多次LLM调用。随着这些应用程序变得越来越复杂,能够检查链或代理内部发生的具体情况变得至关重要。最好的方法是使用LangSmith。

注册后,确保设置环境变量以开始记录跟踪:

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="..."

或者,如果在notebook中,可以这样设置:

import getpass
import os

os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = getpass.getpass()
Tavily

我们将使用Tavily(一个搜索引擎)作为工具。要使用它,你需要获取并设置API密钥:

export TAVILY_API_KEY="..."

或者,如果在notebook中,可以这样设置:

import getpass
import os

os.environ["TAVILY_API_KEY"] = getpass.getpass()

定义工具

我们首先需要创建我们要使用的工具。我们的主要工具将是Tavily——一个搜索引擎。LangChain内置了一个工具,可以轻松使用Tavily搜索引擎作为工具。

from langchain_community.tools.tavily_search import TavilySearchResults

search = TavilySearchResults(max_results=2)
search_results = search.invoke("旧金山的天气怎么样?")
print(search_results)

# 如果我们愿意,可以创建其他工具。
# 一旦我们有了所有想要的工具,我们可以将它们放在一个列表中,稍后会引用它们。
tools = [search]

API参考:TavilySearchResults

使用语言模型

接下来,让我们学习如何使用语言模型调用工具。LangChain支持许多不同的语言模型,可以互换使用——选择你想使用的一个!

pip install -qU langchain-openai
import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass()

from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4")

你可以通过传入消息列表来调用语言模型。默认情况下,响应是一个内容字符串。

from langchain_core.messages import HumanMessage

response = model.invoke([HumanMessage(content="你好!")])
response.content

API参考:HumanMessage

‘你好!’

现在我们可以看看启用这个模型调用工具是什么样子的。为了启用这个功能,我们使用.bind_tools来让语言模型知道这些工具。

model_with_tools = model.bind_tools(tools)

我们现在可以调用模型。首先用一个普通消息调用,看看它如何响应。我们可以查看内容字段以及工具调用字段。

response = model_with_tools.invoke([HumanMessage(content="你好!")])

print(f"内容字符串:{response.content}")
print(f"工具调用:{response.tool_calls}")

内容字符串:‘你好!’

工具调用:[]

现在,让我们试着用一些需要调用工具的输入来调用它。

response = model_with_tools.invoke([HumanMessage(content="旧金山的天气怎么样?")])

print(f"内容字符串:{response.content}")
print(f"工具调用:{response.tool_calls}")

内容字符串:

工具调用:[{‘name’: ‘tavily_search_results_json’, ‘args’: {‘query’: ‘旧金山的天气’}, ‘id’: ‘toolu_01VTP7DUvSfgtYxsq9x4EwMp’}]

我们可以看到,现在没有文本内容,但有一个工具调用!它希望我们调用Tavily搜索工具。

这还没有调用工具——它只是告诉我们要这么做。为了实际调用它,我们需要创建我们的代理。

创建代理

现在我们已经定义了工具和LLM,我们可以创建代理。我们将使用LangGraph来构建代理。目前我们使用高级接口来构建代理,但LangGraph的好处在于这个高级接口由低级、高度可控的API支持,以防你想修改代理逻辑。

现在,我们可以用LLM和工具初始化代理。

注意,我们传入的是model,而不是model_with_tools。这是因为create_react_agent会在底层为我们调用.bind_tools

from langgraph.prebuilt import create_react_agent

agent_executor = create_react_agent(model, tools)

运行代理

我们现在可以对一些查询运行代理了!注意,目前这些都是无状态查询(它不会记住先前的交互)。注意,代理将在交互结束时返回最终状态(包括所有输入,稍后我们将看到如何仅获取输出)。

首先,让我们看看当不需要调用工具时它如何响应:

response = agent_executor.invoke({"messages": [HumanMessage(content="你好!")]})

response["messages"]
[HumanMessage(content='你好!', id='a820fcc5-9b87-457a-9af0-f21768143ee3'),
 AIMessage(content='你好!', response_metadata={'id': 'msg_01VbC493X1VEDyusgttiEr1z', 'model': 'claude-3-sonnet-20240229', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 264, 'output_tokens': 5}}, id='run-0e0ddae8-a85b-4bd6-947c-c36c857a4698-0', usage_metadata={'input_tokens': 264, 'output_tokens': 5, 'total_tokens': 269})]

为了确切了解底层发生了什么(并确保它没有调用工具),我们可以查看LangSmith跟踪。

现在让我们试试一个应该调用工具的示例:

response = agent_executor.invoke(
    {"messages": [HumanMessage(content="旧金山的天气怎么样?")]}
)
response["messages"]
[HumanMessage(content='旧金山的天气怎么样?', id='1d6c96bb-4ddb-415c-a579-a07d5264de0d'),
 AIMessage(content=[{'id': 'toolu_01Y5EK4bw2LqsQXeaUv8iueF', 'input': {'query': 'weather in san francisco'}, '

name': 'tavily_search_results_json'}], tool_name='tavily_search_results_json', id='run-0e0ddae8-a85b-4bd6-947c-c36c857a4698-1'),
 AIMessage(content='根据搜索结果,旧金山目前的天气是...', response_metadata={'id': 'msg_01Y5EK5kPZa6ykHJVuIghgdR', 'model': 'claude-3-sonnet-20240229', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 14, 'output_tokens': 23}}, id='run-0e0ddae8-a85b-4bd6-947c-c36c857a4698-2', usage_metadata={'input_tokens': 14, 'output_tokens': 23, 'total_tokens': 37})]

我们可以看到代理输出了一个工具调用。为了实际执行该工具调用,我们需要启用代理的工具调用功能。我们将通过执行代码来实现这一点。

将其作为流式数据

为了以流的方式接收数据并观察所有步骤,我们可以使用.stream方法。这将生成工具调用,允许我们与最终结果交互。

config = {"configurable": {"thread_id": "abc123"}}
for chunk in agent_executor.stream(
    {"messages": [HumanMessage(content="你好,我是小明!我住在旧金山。")]}, config
):
    print(chunk)
    print("----")

for chunk in agent_executor.stream(
    {"messages": [HumanMessage(content="我住的地方天气怎么样?")]}, config
):
    print(chunk)
    print("----")

添加对话记忆

为了让我们的代理记住对话内容,我们将添加一个记忆模块。我们将使用SqliteSaver来保存会话数据。

from langgraph.checkpoint.sqlite import SqliteSaver

memory = SqliteSaver.from_conn_string(":memory:")
agent_executor = create_react_agent(model, tools, checkpointer=memory)

现在,我们的代理可以在对话过程中记住先前的内容。请注意,在使用记忆时,我们需要为每个对话设置一个唯一的线程ID(例如thread_id),以便代理知道哪些信息属于哪个对话。

config = {"configurable": {"thread_id": "abc123"}}
for chunk in agent_executor.stream(
    {"messages": [HumanMessage(content="你好,我是小明!我住在旧金山。")]}, config
):
    print(chunk)
    print("----")

for chunk in agent_executor.stream(
    {"messages": [HumanMessage(content="我住的地方天气怎么样?")]}, config
):
    print(chunk)
    print("----")

总结

通过本教程,你学会了如何使用LangChain和LLM构建一个可以调用工具的智能代理。你还学会了如何将对话记忆功能集成到代理中。现在,你可以根据自己的需求扩展和定制这个代理,创建一个更复杂、更强大的系统。

让你的语言模型动起来,开始构建智能代理吧!

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值