本文我们将探讨路由器,并专注于创建一个能够流畅地处理工具操作和自然语言响应的智能系统。
路由器
想象一下,我们正在创建一个有用的助手,它知道何时使用工具,何时只需简单回应。这就像一个办公桌前的工作人员——有时他们需要使用工具来帮助你(比如计算器或参考指南),而其他时候他们可以直接回答。
主要组件包括:
基于上述基础,tool_calling_node 决定是选择路线A(工具调用)还是路线B(自然语言响应)。
让我们构建一个简单的代理,它正好能实现这一功能。目前,这个代理将只有一个工具,即一个用于数字相加的加法工具。
安装 python-dotenv
首先,我们来安装 python-dotenv,这是一个包,可以帮助我们从 .env 文件中读取环境变量。我已经为这个教程创建了一个新的 Jupyter 笔记本,并在 VS Code 中打开了它。请在你的笔记本中运行以下命令来安装这个包。
!pip install python-dotenv
导入
让我们导入本项目将使用的包。
LangChain导入
from langchain_core.messages import HumanMessage, AIMessage
from pprint import pprint
from dotenv import load_dotenv
import os
忽略警告
import warnings
warnings.filterwarnings("ignore")
加载环境变量
运行这个单元格时,你可能会看到一个警告:“cannot find .env file”,翻译成中文是“找不到 .env 文件”。
%reload_ext dotenv
%dotenv
这个错误发生是因为我们还没有创建 .env 文件。这个文件对于安全地存储敏感信息(如API密钥和其他应用程序凭据)至关重要。通过将这些密钥保存在 .env 文件中,我们可以防止在将代码推送到像GitHub这样的版本控制系统时意外暴露它们。
为了保护你的敏感文件,请按照以下步骤操作:
目前我们的 .env 文件还不存在——在创建它之前,我们需要先获取一个Anthropic的API密钥。
获取Anthropic API密钥
要获取你的Anthropic API密钥,你需要:
一旦你有了API密钥,在你的项目根目录中创建一个 .env 文件,并按以下方式添加你的密钥:
确保将“your_api_key_here”替换为你从Anthropic收到的实际API密钥。
ANTHROPIC_API_KEY=your_api_key_here
完成后,再次运行加载环境变量的单元格。警告应该会消失。
创建工具
让我们创建一个简单的加法工具,它接受两个整数作为输入,并返回它们的和。这将是一个直接的示例,用于演示工具在我们的系统中的工作方式。
该工具将:
from langgraph.graph import MessagesState
# Tool function
def addition(a: int, b: int) -> int:
"""This tool is to be used to add two numbers together"""
return a + b
创建聊天模型并绑定工具
现在我们将把加法工具连接到聊天模型中,这样当需要时,大型语言模型(LLM)就可以调用并使用这个工具。聊天模型将能够识别何时需要进行加法运算,并自动使用适当的数字调用我们的工具。
这个绑定过程实质上赋予了我们的LLM执行真实计算的能力,而不仅仅是尝试自己计算数字。
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
temperature=0.0,
model="claude-3-opus-20240229",
api_key=os.environ.get("ANTHROPIC_API_KEY")
)
model_with_tools = model.bind_tools([addition])
创建图表
让我们使用上面提到的节点,结合我们之前讨论的路由逻辑,为我们的代理创建一个图表。
首先,让我们从基本的导入开始:
from langgraph.graph import StateGraph, MessagesState, END, START
from langgraph.prebuilt import ToolNode, tools_condition
工具节点:
现在我们可以继续创建工具节点了。
# Tool node
def tool_calling_node(state: MessagesState):
return {"messages": [model_with_tools.invoke(state["messages"])]}
图表本身
# Initialize a state graph that manages conversation messages
builder = StateGraph(MessagesState)
# Add the primary node that determines if tools are needed
builder.add_node("tool_calling_node", tool_calling_node)
# Add the tools node that will execute any requested operations
# The node must be named 'tools' to properly integrate with the StateGraph system
builder.add_node("tools", ToolNode([addition]))
# Set the entry point - start with the tool calling node
builder.add_edge(START, "tool_calling_node")
# Configure the decision-making logic for tool usage
# The tools_condition function evaluates the chat output and routes accordingly:
# 1. If a tool call is detected: Route to the tools node for execution
# 2. If no tool call is needed: Route directly to END to complete the interaction
builder.add_conditional_edges(
"tool_calling_node",
tools_condition
)
# After tool execution, conclude the interaction
builder.add_edge("tools", END)
# Compile the graph into an executable workflow
graph = builder.compile()
可视化图表
from IPython.display import display, Image
display(Image(graph.get_graph().draw_mermaid_png()))
调用图表
现在我们已经构建了图表,可以调用它来查看图表代理的响应。
from langchain_core.messages import HumanMessage
messages = [HumanMessage(content="What is 1 + 1?", name="Human")]
messages = graph.invoke({"messages": messages})
for m in messages["messages"]:
m.pretty_print()
看着这个输出,我们可以看到我们的代理是如何智能地处理这些不同场景的:
在第一个案例中
messages = [HumanMessage(content="Hello there!", name="Human")]
messages = graph.invoke({"messages": messages})
for m in messages["messages"]:
m.pretty_print()
在对比案例中
这展示了我们的路由逻辑是多么有效——它只在必要时使用工具,并且能够在不需要不必要工具调用的情况下处理直接响应。
结论
在这篇文章中,我们学习了AI代理中的路由是如何工作的。有了这些知识,你可以构建相当高级的AI代理来为你完成一些任务。