工具集成
将工具集成到 LangGraph 聊天机器人中可以显着增强其功能,使其能够按照您喜欢的方式访问和处理信息。
让我们修改上一节中创建的基本聊天机器人,以包含一个可以在网络上搜索信息的工具。我们将使用langchain_
中community.tools TavilySearchResults
工具,对于此示例,您将需要Tavily API
密钥。
以下代码结合了 LangChain、LangGraph 和 Tavily 搜索工具,创建了一个聊天机器人(chatbot)。代码实现了一个包含多个组件(如模型调用、工具调用、图计算等)的流式聊天框架,涉及到从用户输入到最终响应的完整过程。下面我将详细解释每个部分的作用。
1. 安装依赖:
pip install -U tavily-python langchain_community
- 这行命令安装了两个 Python 库:
tavily-python
:一个用于 Tavily 搜索引擎的工具包,提供搜索功能。langchain_community
:一个开源的 LangChain 扩展库,提供了与多个工具和平台的集成。
2. 导入必要的库:
from typing import Annotated
from langchain_community.tools.tavily_search import TavilySearchResults
from typing_extensions import TypedDict
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
Annotated
和TypedDict
:用于定义类型。TavilySearchResults
:来自langchain_community
,提供 Tavily 搜索工具的接口。StateGraph
、ToolNode
、tools_condition
:来自 LangGraph,用于创建图和添加节点以及条件逻辑。ChatOpenAI
:来自 LangChain,用于调用 OpenAI GPT 模型。MemorySaver
:来自 LangGraph,用于保存和管理聊天过程中的状态。
3. 定义聊天状态 (State
):
class State(TypedDict):
messages: Annotated[list, add_messages]
- State 是一个继承自
TypedDict
的类,定义了聊天状态结构。它包含一个键messages
,存储聊天历史记录。add_messages
装饰器用于确保新的消息会被追加到历史记录中。
4. 初始化工具和模型:
tool = TavilySearchResults(max_results=2)
tools = [tool]
llm = ChatOpenAI(temperature=0)
TavilySearchResults
是一个搜索工具实例,设置了max_results=2
,表示每次搜索返回最多 2 个结果。llm
是一个 ChatOpenAI 模型实例,设置了temperature=0
,使得模型输出更加确定,不太随机。
5. 将工具绑定到模型:
llm_with_tools = llm.bind_tools(tools)
bind_tools
方法将工具绑定到 LLM(语言模型)上。这样,模型就知道可以使用哪些工具。这里的工具是TavilySearchResults
,可以在生成的响应中触发搜索操作。
6. 定义 chatbot
函数:
def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
chatbot
函数接受一个 State 类型的参数,并通过llm_with_tools.invoke()
使用模型生成响应。生成的响应会被返回,并更新messages
字段。
7. 构建 LangGraph:
graph_builder = StateGraph(State)
graph_builder.add_node("chatbot", chatbot)
graph_builder.add_node("tools", tool_node)
StateGraph
创建一个状态图,表示不同的状态(节点)和它们之间的过渡(边)。图的每个节点都是一个函数或工具的调用。add_node
方法将chatbot
和tools
节点添加到图中。
8. 设置条件边:
graph_builder.add_conditional_edges("chatbot", tools_condition)
条件路由:利用 graph_builder.add_conditional_edges() 根据LLM是否决定调用工具来设置路由逻辑。 tools_condition函数检查LLM的响应是否包含工具调用指令。
add_conditional_edges
用于根据某些条件(如工具调用)在节点之间建立边。在这里,tools_condition
函数会检查是否需要调用工具。如果是,它会触发从chatbot
到tools
节点的过渡。
9. 图的入口点和边的设置:
graph_builder.add_edge("tools", "chatbot")
graph_builder.set_entry_point("chatbot")
add_edge
设置从tools
节点到chatbot
节点的边,表示一旦工具被调用,图会回到chatbot
节点,以便模型决定下一步操作。执行该工具后,使用graph_builder.add_edge()将流程引导回chatbot节点,从而允许对话继续。set_entry_point
设置图的入口点为chatbot
,表示聊天的起点。
10. 设置 MemorySaver:
memory = MemorySaver()
graph = graph_builder.compile(checkpointer=memory)
MemorySaver
用作图的检查点,保存和恢复聊天状态。通过将MemorySaver
传递给compile
方法,图的状态将在整个对话过程中保存。
11. 聊天主循环:
config = {"configurable": {"thread_id": "1"}}
while True:
user_input = input("User: ")
if user_input.lower() in ["quit", "exit", "q"]:
print("Goodbye!")
break
for event in graph.stream({"messages": [("user", user_input)]}, config):
for value in event.values():
print("Assistant:", value["messages"][-1].content)
while True
是聊天的主循环,持续接收用户输入直到用户输入quit
、exit
或q
。graph.stream(...)
用于将用户输入流入图中并触发处理。传递给图的状态是{"messages": [("user", user_input)]}
,即用户的输入。event.values()
提取事件的实际数据(如聊天记录),并打印出最后一个消息的内容。
总结:
- 这段代码实现了一个 LangGraph 驱动的聊天机器人,其中整合了 Tavily 搜索工具和 OpenAI 的语言模型(LLM)。
- 使用 LangGraph 定义了图结构,在图中加入了处理聊天逻辑的
chatbot
节点和处理工具调用的tools
节点。 - 工具调用 是由模型的响应控制的,图根据模型的输出判断是否需要调用搜索工具。
- MemorySaver 用于保存对话状态,使得对话可以持续进行并追踪历史。
这种结构提供了一种可扩展的框架,可以在图中添加更多工具或自定义逻辑,灵活应对各种复杂的对话场景。