LangGraph 教程:初学者综合指南(1)
关键概念
图结构
LangGraph 设计的核心是基于图形的应用程序工作流程表示。该图包含两个主要元素:
节点 - 工作的构建块:
LangGraph 中的每个节点代表应用程序中的一个不同的工作或操作单元。这些节点本质上是封装特定任务的 Python 函数。此任务可能涉及多种操作,例如:
- 与LLM直接沟通,进行文本生成、摘要或其他基于语言的任务。
- 与外部工具和 API 交互以获取数据或在现实世界中执行操作。
- 通过格式化、过滤或转换等过程来操作数据。
- 与用户互动以收集输入或显示信息。
边 - 引导信息流和控制:
边充当 LangGraph 内的结缔组织,建立信息流路径并规定操作顺序。 LangGraph支持多种边类型:
- **简单边:**表示从一个节点到另一个节点的直接且无条件的流。第一个节点的输出作为输入馈送到后续节点,从而创建线性级数。
- **条件边:**引入了一层动态,条件边使工作流能够根据特定节点操作的结果进行分支。例如,根据用户的响应,图表可能决定终止交互或继续调用工具。这种决策能力对于创建能够适应不同情况的应用程序至关重要。我们将在本文的后面部分看到一个这样的例子。
状态管理
管理多代理系统的一个重要方面是确保所有代理在对任务当前状态有共同理解的情况下进行操作。 LangGraph 通过自动状态管理解决了这个问题。这意味着当代理执行任务时,库本质上会处理中央状态对象的跟踪和更新。
该状态对象充当需要在工作流中的不同点访问的关键信息的存储库。这可能包括:
- 对话历史记录:在聊天机器人应用程序中,状态可以存储用户和机器人之间正在进行的对话,从而允许上下文感知响应。
- **上下文数据:**与当前任务相关的信息,例如用户偏好、过去的行为或相关的外部数据,可以存储在状态中,供代理在决策时使用。
- **内部变量:**代理可以使用状态来跟踪内部标志、计数器或指导其行为和决策的其他变量。
下面我们从简单的代码开始,在 LangGraph 中创建基本聊天机器人
LangGraph 入门
要开始使用 LangGraph,您需要安装它。要安装 LangGraph,请打开终端或命令提示符并运行以下命令:
pip install -U langgraph
此命令将下载并安装最新版本的 LangGraph。 -U
标志可确保您获得最新版本。
代码主要分为以下几个部分:
1. 导入依赖:
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
- Annotated 和 TypedDict 来自
typing
模块,用于定义类型和数据结构。 - LangGraph 用于创建图模型,其中包含了 StateGraph,START 和 END 标记,用于控制图中节点的开始和结束。
- add_messages 是一个装饰器,用来为消息历史列表添加新消息。
2. 定义 State 类型:
class State(TypedDict):
# 'messages66' will store the chatbot conversation history.
# The 'add_messages' function ensures new messages are appended to the list.
print('什么时候执行呢')
messages66: Annotated[list, add_messages]
- State 类继承自
TypedDict
,用于定义一个字典类型。它有一个键messages66
,用于存储聊天历史。 Annotated[list, add_messages]
说明messages66
是一个列表类型,并且这个列表的操作会通过add_messages
来更新,确保每次调用时新消息被追加到列表中。
3. 初始化 OpenAI 模型:
from langchain_openai import ChatOpenAI
# Set the model as ChatOpenAI
llm = ChatOpenAI(temperature=0)
- ChatOpenAI 是 LangChain 中的一个封装 OpenAI GPT 模型的类。通过
temperature=0
设置模型的温度(0
表示更为确定和一致的回答)。
4. 定义 chatbot 函数:
def chatbot(state: State):
# Use the LLM to generate a response based on the current conversation history.
print('执行顺序1--- state值为:',state)
response = llm.invoke(state["messages66"])
# Return the updated state with the new message appended
return {"messages66": [response]}
- chatbot 函数接收一个 State 类型的参数
state
,该状态包含聊天记录。 state["messages66"]
是传递给模型的聊天历史,它是一个列表,存储用户与助手的对话。- 调用
llm.invoke
来生成基于 当前 聊天记录的回答。 - 函数返回更新后的状态,其中 messages66 包含新生成的消息。
5. 创建 StateGraph:
graph_builder = StateGraph(State)
# Add the 'chatbot' node to the graph,
graph_builder.add_node("chatbot", chatbot)
# For this basic chatbot, the 'chatbot' node is both the entry and finish point
graph_builder.add_edge(START, "chatbot")
graph_builder.add_edge("chatbot", END)
graph = graph_builder.compile()
- StateGraph 是 LangGraph 用于构建图的类。图的每个节点代表一个状态(如聊天机器人处理的对话),而边则表示从一个状态到另一个状态的过渡。
- add_node 方法将 chatbot 函数添加到图中,作为图的一个节点。
- add_edge 方法定义图中各节点之间的边。这里定义了从 START 到 chatbot,再从 chatbot 到 END,形成一个简单的流程。
6. 与用户交互:
while True:
user_input = input("User: ")
if user_input.lower() in ["quit", "exit", "q"]:
print("Goodbye!")
break
# Process user input through the LangGraph
for event in graph.stream({"messages66": [("user", user_input)]}):
for value in event.values():
print('执行顺序2---',value,'/n')
print(value['messages66'],'/n')
print("Assistant:", value["messages66"][-1].content,'/n')
- 这是一个 while True 循环,持续接收用户输入,直到用户输入 quit、exit 或 q。
- graph.stream 方法用于将用户的输入流过图,在图中处理并返回生成的事件。事件包含了聊天历史更新后的状态(
messages66
)。 - 输出结果包括每个事件的 messages66(聊天历史) 和最新生成的助手回复
value["messages66"][-1].content
。
主要流程总结:
- 用户输入一个消息。
- 通过 StateGraph 图流处理该输入,触发 chatbot 节点的执行。
- chatbot 根据聊天历史生成一个新的消息,并返回更新后的状态。
- 程序打印出聊天历史和助手的回答。
此代码的核心是在 LangGraph 中构建一个基于状态机的聊天流程,同时利用 LangChain 的 ChatOpenAI 来生成对话回复。
代码中的event.values()
event.values()
是 LangGraph 中的一个方法,它用于获取图流中某个 事件(event) 的值。这个方法通常用来从图的流中提取与当前状态相关的数据。
从哪里来?
event
是 graph.stream() 返回的对象之一,它代表图中流动的一个事件。在这段代码中,graph.stream 用于在图中执行一个过程,处理用户的输入,并返回相应的事件。在每次循环中,event
包含了一个包含更新状态的数据结构。
详细解释:
-
graph.stream(...)
:
graph.stream()
是一个方法,返回一个生成器对象(或迭代器),通过它你可以按顺序访问每个 event。在每次迭代中,它会返回一个 event,即一个事件对象。 -
事件对象(event):
每个 event 对象都包含了图中流转的状态数据。每个 event 都包含了状态的不同信息,通常是一个字典形式的数据结构。 -
event.values()
:
这个方法用于获取事件中包含的所有值。它会返回事件数据的值部分,通常是图中每个节点更新后的状态。在这段代码中,event.values()
返回的是一个字典列表,其中每个字典包含一个状态,如messages66
等。
举个例子:
for event in graph.stream({"messages66": [("user", user_input)]}):
for value in event.values():
print('执行顺序2---', value) # 这里 value 就是事件的具体值
print(value['messages66']) # 输出更新后的消息历史
print("Assistant:", value["messages66"][-1].content) # 输出助手的最新回复
在这段代码中:
graph.stream
被调用时,它会根据当前的 State(包含用户输入的messages66
)流转图中的状态。- 每次迭代返回一个 event 对象,它包含图中更新后的状态。
event.values()
提取该事件的具体数据(例如,更新后的messages66
)。
总结:
event.values()
是从 graph.stream()
中获得的事件对象的方法,用于提取事件的实际值(即状态数据),在这段代码中,它用于获取包含聊天历史(messages66
)和生成的助手回复的状态。