
目录
1. 案例目标
本案例展示了如何使用LangGraph构建一个集成网络搜索工具的智能代理(Agent),使其能够根据用户输入智能决定何时调用网络搜索工具,从而获取最新信息并提供更准确的回答。
主要目标包括:
- 将网络搜索工具集成到大型语言模型(LLM)中
- 实现条件路由,根据是否调用搜索工具来决定工作流程
- 创建一个能够利用实时网络数据有效响应的聊天机器人
2. 技术栈与核心依赖
- LangGraph: 用于构建有状态、多参与者应用程序的框架
- LangChain: 提供LLM集成和工具调用能力
- LangChain Community: 提供社区维护的工具和集成
- TavilySearchResults: 用于网络搜索的工具
- LangChain OpenTutorial: 教程包,包含设置API密钥的功能
- ChatOpenAI: OpenAI的聊天模型接口
- TypedDict: 用于定义状态结构
3. 环境配置
首先需要安装必要的依赖包:
%pip install langchain-opentutorial
from langchain_opentutorial import package
package.install(
[
"langchain_community",
"langchain_openai",
"langchain_core",
"langgraph",
"langsmith"
],
verbose=False,
upgrade=False,
)
然后设置环境变量:
from langchain_opentutorial import set_env
set_env(
{
"OPENAI_API_KEY": "your-openai-api-key",
"TAVILY_API_KEY": "your-tavily-api-key",
"LANGCHAIN_TRACING_V2": "true",
"LANGCHAIN_ENDPOINT": "https://api.smith.langchain.com",
"LANGCHAIN_PROJECT": "Agent-with-LangGraph",
}
)
这些密钥将用于访问OpenAI的语言模型和Tavily的搜索功能。
4. 案例实现
4.1 创建搜索工具
使用TavilySearchResults创建搜索工具:
from langchain_community.tools import TavilySearchResults
# 创建搜索工具
tool = TavilySearchResults(
max_results=3,
include_answer=True,
include_raw_content=True,
include_images=True,
)
4.2 定义状态
使用TypedDict定义状态结构,并使用add_messages函数管理消息历史:
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph.message import add_messages
# 定义状态模式
class State(TypedDict):
# 对列表类型应用add_messages以启用消息添加
messages: Annotated[list, add_messages]
4.3 初始化LLM并绑定工具
from langchain_openai import ChatOpenAI
# 初始化LLM
llm = ChatOpenAI(model="gpt-4o-mini")
# 将工具绑定到LLM
llm_with_tools = llm.bind_tools(tools)
4.4 定义节点函数
# 定义节点函数
def chatbot(state: State):
# 使用提供的消息调用带工具的LLM
answer = llm_with_tools.invoke(state["messages"])
# 返回更新的消息(自动应用add_messages)
return {"messages": [answer]}
4.5 创建工具节点
import json
from langchain_core.messages import ToolMessage
class BasicToolNode:
"""运行最后AIMessage节点中请求的工具"""
def __init__(self, tools: list) -> None:
# 工具列表
self.tools_list = {tool.name: tool for tool in tools}
def __call__(self, inputs: dict):
# 如果消息存在,提取最新消息
if messages := inputs.get("messages", []):
message = messages[-1]
else:
raise ValueError("输入中未找到消息")
# 工具调用的结果
outputs = []
for tool_call in message.tool_calls:
# 调用工具并存储结果
tool_result = self.tools_list[tool_call["name"]].invoke(tool_call["args"])
outputs.append(
# 将工具调用结果存储为消息
ToolMessage(
content=json.dumps(
tool_result, ensure_ascii=False
), # 将工具调用结果转换为字符串
name=tool_call["name"],
tool_call_id=tool_call["id"],
)
)
return {"messages": outputs}
# 创建工具节点
tool_node = BasicToolNode(tools=[tool])
4.6 创建图并添加节点
from langgraph.graph import StateGraph, START, END
# 使用定义的状态模式初始化状态图
graph_builder = StateGraph(State)
# 将聊天机器人节点添加到图中
graph_builder.add_node("chatbot", chatbot)
# 将工具节点添加到图中
graph_builder.add_node("tools", tool_node)
4.7 定义条件路由
# 定义路由函数
def route_tools(state: State):
if messages := state.get("messages", []):
# 提取最新的AI消息
ai_message = messages[-1]
else:
# 如果没有找到消息,抛出错误
raise ValueError(f"工具边缘的输入状态中未找到消息: {state}")
# 检查AI消息中的工具调用
if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0:
# 如果有工具调用,路由到"tools"
return "tools"
# 如果没有工具调用,路由到"END"
return END
# 向图中添加条件边
graph_builder.add_conditional_edges(
source="chatbot",
path=route_tools,
# 将返回值映射到特定节点
path_map={"tools": "tools", END: END},
)
# 定义额外的边
graph_builder.add_edge("tools", "chatbot") # 工具执行后返回聊天机器人
graph_builder.add_edge(START, "chatbot") # 从聊天机器人节点开始
# 编译图
graph = graph_builder.compile()
4.8 运行代理
inputs = {"messages": "Search for information about the TED YouTube channel"}
for event in graph.stream(inputs, stream_mode="values"):
for key, value in event.items():
print(f"\n==============\nSTEP: {key}\n==============\n")
print(value[-1])
5. 案例效果
这个案例实现了一个能够智能决定何时使用搜索工具的聊天机器人。当用户询问关于TED YouTube频道的信息时,机器人会:
- 接收用户请求
- 分析请求并决定需要使用搜索工具
- 调用Tavily搜索API获取相关信息
- 处理搜索结果并生成回答
- 向用户提供包含最新信息的回答
通过条件路由,机器人能够智能地决定何时需要使用搜索工具,何时可以直接回答问题,从而提高了效率和准确性。
6. 案例实现思路
本案例的核心实现思路是利用LangGraph的工具集成和条件路由功能,构建一个能够根据输入内容智能决策的代理。
6.1 工具集成
通过bind_tools方法将搜索工具绑定到LLM,使LLM能够在需要时调用外部工具。这种绑定使得LLM能够根据输入内容智能决定是否需要调用工具,以及调用哪个工具。
6.2 条件路由
通过add_conditional_edges和自定义的路由函数,系统可以根据LLM的输出决定下一步执行路径。在这个案例中,系统检查LLM的输出是否包含工具调用,如果有则路由到工具节点,否则直接结束对话。
6.3 工具节点
通过自定义的BasicToolNode类,系统能够执行工具调用并将结果格式化为标准消息。这个节点负责解析工具调用、执行相应工具,并将结果返回给LLM进行进一步处理。
6.4 状态管理
通过使用TypedDict和add_messages函数,系统能够有效地管理对话状态。每次工具调用和LLM响应都会被添加到消息列表中,形成完整的对话历史。
7. 扩展建议
- 多工具集成: 可以集成更多类型的工具,如数据库查询、API调用、文件操作等
- 智能路由优化: 实现更复杂的路由逻辑,根据内容类型、用户意图等因素决定使用哪个工具
- 工具链: 支持多个工具的链式调用,使一个工具的输出可以作为另一个工具的输入
- 并行工具调用: 支持同时调用多个工具,提高效率
- 工具缓存: 实现工具结果缓存,避免重复调用相同工具
- 工具权限管理: 根据用户角色和权限限制可用工具
- 工具使用统计: 记录和分析工具使用情况,用于优化代理性能
8. 总结
本案例展示了如何使用LangGraph构建一个集成网络搜索工具的智能代理。通过工具绑定、条件路由和自定义工具节点,我们创建了一个能够根据输入内容智能决策的聊天机器人。
通过这个案例,我们学习了:
- 如何在LangGraph中集成外部工具
- 如何使用条件路由实现智能决策
- 如何创建自定义工具节点
- 如何管理对话状态和消息流
- 如何构建一个能够获取实时信息的智能代理
这种模式特别适用于需要访问实时数据或执行特定操作的应用场景,如信息检索、数据分析、任务执行等。通过结合LLM的推理能力和外部工具的执行能力,我们可以构建更加强大和实用的AI应用。
LangGraph的工具集成和条件路由功能为构建智能代理提供了强大的基础架构。这种架构使得AI应用能够根据输入内容智能地决定何时使用外部工具,从而扩展了AI系统的能力边界,使其能够处理更加复杂和多样化的任务。
645

被折叠的 条评论
为什么被折叠?



