LangGraph Quick Start 1 官方文档
语言模型本身不能执行操作——它们只能输出文本。LangChain的一个大用例是创建代理。代理是使用llm作为推理引擎来确定采取哪些操作以及执行操作所需的输入的系统。在执行操作之后,可以将结果反馈到LLM,以确定是否需要更多操作,或者是否可以完成操作。这通常是通过调用工具实现的。
在本教程中,我们将构建一个可以与搜索引擎交互的代理。你可以问这个代理问题,看着它调用搜索
在本教程中,我们将在LangGraph中构建一个支持聊天机器人,它可以:
✅通过网络搜索回答常见问题
✅维护跨呼叫的对话状态
✅将复杂的查询路由给人工审核
✅使用自定义状态来控制其行为
✅倒带并探索不同的对话路径
我们将从一个基本的聊天机器人开始,逐步添加更复杂的功能,并在此过程中介绍关键的LangGraph概念。让我们开始吧!🌟
LangSmith进行LangGraph开发
注册LangSmith以快速发现问题并提高您的LangGraph项目的性能。LangSmith允许您使用跟踪数据来调试,测试和监控使用LangGraph构建的LLM应用程序-阅读更多关于如何开始的信息。
第1部分:构建基本聊天机器人
我们将首先使用LangGraph创建一个简单的聊天机器人。这个聊天机器人将直接响应用户消息。虽然简单,但它将说明使用LangGraph构建的核心概念。在本节结束时,您将拥有一个构建的基本聊天机器人。
首先创建一个StateGraph。StateGraph对象将聊天机器人的结构定义为“状态机”。我们将添加节点来表示llm和聊天机器人可以调用的函数,并添加边来指定聊天机器人应该如何在这些函数之间转换。
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
class State(TypedDict):
# Messages have the type "list". The `add_messages` function
# in the annotation defines how this state key should be updated
# (in this case, it appends messages to the list, rather than overwriting them)
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
我们的图现在可以处理两个关键任务:
每个节点都可以接收当前状态作为输入,并输出状态更新。
对消息的更新将被附加到现有列表中,而不是覆盖它,这要归功于与Annotated语法一起使用的预构建的add_messages函数。
概念
定义图形时,第一步是定义其状态。状态包括处理状态更新的图的schema和reducer函数。在我们的示例中,State是一个TypedDict,只有一个键:messages。add_messages
reducer函数用于向列表添加新消息,而不是覆盖它。没有reducer注释的键会覆盖之前的值。
接下来,添加一个“聊天机器人”节点。节点表示工作单元。它们是典型的常规python函数。
from langchain_anthropic import ChatAnthropic
# llm = ChatAnthropic(model="claude-3-5-sonnet-20240620")
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")
def chatbot(state: State):
return {"messages": [llm.invoke(state["messages"])]}
# The first argument is the unique node name
# The second argument is the function or object that will be called whenever
# the node is used.
graph_builder.add_node("chatbot", chatbot)
<langgraph.graph.state.StateGraph at 0x24f3f5033e0>
请注意,chatbot节点函数如何将当前状态作为输入,并返回一个字典,其中包含键“messages”下的更新消息列表。
State中的add_messages函数将把llm的响应消息附加到状态中已经存在的任何消息上。
接下来,添加一个入口点。这告诉我们的图在每次运行时从哪里开始工作。
graph_builder.add_edge(START, "chatbot")
<langgraph.graph.state.StateGraph at 0x24f3f5033e0>
同样,设定一个终点。这指示图“任何时候运行这个节点,您都可以退出。”
graph_builder.add_edge("chatbot", END)
<langgraph.graph.state.StateGraph at 0x24f3f5033e0>
最后,我们希望能够运行我们的图。为此,在图形构建器上调用“compile()”。这将创建一个“CompiledGraph”,我们可以在我们的状态上使用invoke。
graph = graph_builder.compile()
您可以使用get_graph方法和“draw”方法之一(如draw_ascii或draw_png)将图形可视化。每个绘制方法都需要额外的依赖项。
from IPython.display import Image, display
try:
display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
# This requires some extra dependencies and is optional
pass
现在让我们运行聊天机器人!
提示:你可以随时通过键入“quit”、“exit”或“q”退出聊天循环。
def stream_graph_updates(user_input: str):
for event in graph.stream({"messages": [("user", user_input)]}):
for value in event.values():
print("Assistant:", value["messages"][-1].content)
while True:
try:
user_input = input("User: ")
if user_input.lower() in ["quit", "exit", "q"]:
print("Goodbye!")
break
stream_graph_updates(user_input)
except:
# fallback if input() is not available
user_input = "What do you know about LangGraph?"
print("User: " + user_input)
stream_graph_updates(user_input)
break
User: What do you know about LangGraph?
Assistant: As of my last knowledge update in October 2023, LangGraph is a framework designed for building applications that utilize large language models (LLMs) through a graph-based approach. It aims to enhance the way developers interact with and utilize LLMs by providing a structured way to manage and manipulate language-related tasks.
Key features of LangGraph may include:
1. **Graph-Based Structure**: LangGraph allows users to represent language tasks as graphs, where nodes can represent different components like prompts, responses, or even data sources, and edges define the relationships and workflows between these components.
2. **Modularity**: The framework promotes modular design, enabling developers to create reusable components that can be easily integrated into various applications.
3. **Interactivity**: LangGraph may facilitate interactive applications, allowing users to engage with LLMs in more dynamic and intuitive ways.
4. **Integration with LLMs**: The framework is designed to work seamlessly with various large language models, providing tools and functionalities to optimize their usage.
5. **Use Cases**: LangGraph can be applied in diverse domains, such as chatbots, content generation, data analysis, and more, leveraging the capabilities of LLMs effectively.
For the most up-to-date and specific information about LangGraph, including any new features or changes, I recommend checking the official documentation or relevant community discussions.
恭喜你!您已经使用LangGraph构建了第一个聊天机器人。这个机器人可以通过接收用户输入并使用LLM生成响应来进行基本对话。您可以在提供的链接中查看上述调用的LangSmith Trace。
然而,您可能已经注意到,机器人的知识仅限于其训练数据中的内容。在下一部分中,我们将添加一个web搜索工具来扩展机器人的知识并使其更有能力。
第2部分:用工具增强聊天机器人
为了处理我们的聊天机器人无法“凭记忆”回答的问题,我们将集成一个网络搜索工具。我们的机器人可以使用这个工具来查找相关信息并提供更好的响应。
环境变量
OPENAI_API_KEY=""
OPENAI_BASE_URL=""
SERPER_API_KEY=""
LANGCHAIN_TRACING_V2="true"
LANGCHAIN_API_KEY=""
TAVILY_API_KEY = "tvly"
from langchain_community.tools.tavily_search import TavilySearchResults
tool = TavilySearchResults(max_results=2)
tools = [tool]
tool.invoke("What's a 'node' in LangGraph?")
[{'url': 'https://langchain-ai.github.io/langgraph/concepts/low_level/',
'content': 'Nodes¶ In LangGraph, nodes are typically python functions (sync or async) where the first positional argument is the state, and (optionally), the second positional argument is a "config", containing optional configurable parameters (such as a thread_id). Similar to NetworkX, you add these nodes to a graph using the add_node method:'},
{'url': 'https://medium/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141',
'content': 'Nodes: Nodes are the building blocks of your LangGraph. Each node represents a function or a computation step. You define nodes to perform specific tasks, such as processing input, making'}]
结果是我们的聊天机器人可以用来回答问题的页面摘要。
接下来,我们开始定义我们的图。下面的代码与第1部分完全相同,只是我们在LLM中添加了bind_tools。如果LLM想要使用我们的搜索引擎,这可以让LLM知道正确的JSON格式。
from typing import Annotated
from langchain_anthropic import ChatAnthropic
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
# llm = ChatAnthropic(model="claude-3-5-sonnet-20240620")
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")
# Modification: tell the LLM which tools it can call
llm_with_tools = llm.bind_tools(tools)
def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
graph_builder.add_node("chatbot", chatbot)
<langgraph.graph.state.StateGraph at 0x24f57777fb0>
接下来,我们需要创建一个函数,以便在调用工具时实际运行这些工具。我们将通过将工具添加到一个新节点来实现这一点。
下面,我们实现了一个BasicToolNode,它检查状态中最近的消息,并在消息包含tool_calls时调用工具。它依赖于LLM的tool_calling支持,该支持在Anthropic、OpenAI、谷歌Gemini和许多其他LLM提供商中可用。稍后我们将用LangGraph的预构建的ToolNode替换它以加快速度,但首先我们自己构建它是有指导意义的。
import json
from langchain_core.messages import ToolMessage
class BasicToolNode:
"""A node that runs the tools requested in the last AIMessage."""
def __init__(self, tools: list) -> None:
self.tools_by_name = {tool.name: tool for tool in tools}
def __call__(self, inputs: dict):
if messages := inputs.get("messages", []):
message = messages[-1]
else:
raise ValueError("No message found in input")
outputs = []
for tool_call in message.tool_calls:
tool_result = self.tools_by_name[tool_call["name"]].invoke(
tool_call["args"]
)
outputs.append(
ToolMessage(
content=json.dumps(tool_result),
name=tool_call["name"],
tool_call_id=tool_call["id"],
)
)
return {"messages": outputs}
tool_node = BasicToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)
<langgraph.graph.state.StateGraph at 0x24f578e00e0>
添加了工具节点后,我们可以定义conditional_edges。
回想一下,边将控制流从一个节点路由到下一个节点。条件边通常包含“if”语句,根据当前的图状态路由到不同的节点。这些函数接收当前的图形状态,并返回一个字符串或字符串列表,指示下一个要调用哪个节点。
下面,调用定义一个名为route_tools的路由器函数,用于检查聊天机器人输出中的tool_calls。
下面,调用定义一个名为route_tools的路由器函数,用于检查聊天机器人输出中的tool_calls。通过调用add_conditional_edges向图提供这个函数,它告诉图,无论何时聊天机器人节点完成,都要检查这个函数,看看下一步要去哪里。
如果工具调用存在,条件将路由到工具,如果不存在则终止。
稍后,为了更简洁,我们将用预构建的tools_condition替换它,但首先我们自己实现它会使事情更清楚。
def route_tools(
state: State,
):
"""
Use in the conditional_edge to route to the ToolNode if the last message
has tool calls. Otherwise, route to the end.
"""
if isinstance(state, list):
ai_message = state[-1]
elif messages := state.get("messages", []):
ai_message = messages[-1]
else:
raise ValueError(f"No messages found in input state to tool_edge: {state}")
if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0:
return "tools"
return END
# The `tools_condition` function returns "tools" if the chatbot asks to use a tool, and "END" if
# it is fine directly responding. This conditional routing defines the main agent loop.
graph_builder.add_conditional_edges(
"chatbot",
route_tools,
# The following dictionary lets you tell the graph to interpret the condition's outputs as a specific node
# It defaults to the identity function, but if you
# want to use a node named something else apart from "tools",
# You can update the value of the dictionary to something else
# e.g., "tools": "my_tools"
{"tools": "tools", END: END},
)
# Any time a tool is called, we return to the chatbot to decide the next step
graph_builder.add_edge("tools", "chatbot")
graph_builder.add_edge(START, "chatbot")
graph = graph_builder.compile()
注意,条件边从单个节点开始。这告诉图“每当‘chatbot’节点运行时,如果它调用工具,就转到‘tools’,如果它直接响应,就结束循环。
与预构建的tools_condition类似,如果没有工具调用,我们的函数返回END字符串。当图转换到END时,它没有更多的任务要完成并停止执行。因为条件可以返回END,所以这次我们不需要显式地设置finish_point。我们的图表已经结束了!
让我们把我们画的图形象化。下面的函数需要运行一些额外的依赖项,这些依赖项对本教程来说并不重要。
from IPython.display import Image, display
try:
display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
# This requires some extra dependencies and is optional
pass
现在我们可以问机器人训练数据之外的问题。
while True:
try:
user_input = input("User: ")
if user_input.lower() in ["quit", "exit", "q"]:
print("Goodbye!")
break
stream_graph_updates(user_input)
except:
# fallback if input() is not available
user_input = "What do you know about LangGraph?"
print("User: " + user_input)
stream_graph_updates(user_input)
break
User: What do you know about LangGraph?
Assistant:
Assistant: [{"url": "https://www.langchain/langgraph", "content": "LangGraph is a framework for building and scaling agentic applications with LangChain Platform. It supports diverse control flows, human-agent collaboration, streaming, and deployment options for complex tasks."}, {"url": "https://www.datacamp/tutorial/langgraph-tutorial", "content": "LangGraph is a library within the LangChain ecosystem that simplifies the development of complex, multi-agent large language model (LLM) applications. Learn how to use LangGraph to create stateful, flexible, and scalable systems with nodes, edges, and state management."}]
Assistant: LangGraph is a framework within the LangChain ecosystem designed for building and scaling agentic applications. It offers support for diverse control flows, human-agent collaboration, streaming, and deployment options for complex tasks.
LangGraph simplifies the development of complex, multi-agent large language model (LLM) applications by enabling the creation of stateful, flexible, and scalable systems utilizing nodes, edges, and state management.
For more information, you can visit the official [LangChain website](https://www.langchain/langgraph) or check out a [tutorial on DataCamp](https://www.datacamp/tutorial/langgraph-tutorial).
恭喜!您已经在langgraph中创建了一个会话代理,它可以在需要时使用搜索引擎检索更新的信息。现在它可以处理更广泛的用户查询。
model_with_tools = model.bind_tools(tools)
现在我们可以调用模型。让我们首先用普通消息调用它,看看它是如何响应的。我们可以同时查看content字段和tool_calls字段。
response = model_with_tools.invoke([HumanMessage(content="Hi!")])
print(f"ContentString: {response.content}")
print(f"ToolCalls: {response.tool_calls}")
ContentString: Hello! How can I assist you today?
ToolCalls: []
现在,让我们尝试用一些期望调用工具的输入来调用它。
我们的聊天机器人仍然不能自己记住过去的互动,这限制了它进行连贯、多回合对话的能力。在下一部分中,我们将添加内存来解决这个问题。
第3部分:向聊天机器人添加内存
我们的聊天机器人现在可以使用工具来回答用户的问题,但它不记得以前交互的上下文。这限制了它进行连贯、多回合对话的能力。
LangGraph通过持久的检查点解决了这个问题。如果在编译图形时提供一个checkpointer,在调用图形时提供thread_id, LangGraph会在每一步之后自动保存状态。当您使用相同的thread_id再次调用图形时,图形将加载其保存的状态,允许聊天机器人从它离开的地方重新开始。
稍后我们将看到,检查点比简单的聊天内存强大得多——它允许您随时保存和恢复复杂的状态,以便进行错误恢复、人在循环工作流、时间旅行交互等等。但在我们过于超前之前,让我们添加检查点以启用多回合对话。
from langgraph.checkpoint.memory import MemorySaver
memory = MemorySaver()
注意,我们使用了一个内存检查指针。这对于我们的教程来说很方便(它将所有内容保存在内存中)。在生产应用程序中,您可能会将其更改为使用SqliteSaver或PostgresSaver并连接到您自己的数据库。
接下来定义图形。现在您已经构建了自己的BasicToolNode,我们将用LangGraph的预构建的ToolNode和tools_condition替换它,因为它们可以做一些很好的事情,比如并行执行API。除此之外,以下内容全部摘自第2部分。
from typing import Annotated
from langchain_anthropic import ChatAnthropic
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import BaseMessage
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
tool = TavilySearchResults(max_results=2)
tools = [tool]
# llm = ChatAnthropic(model="claude-3-5-sonnet-20240620")
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools(tools)
def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
graph_builder.add_node("chatbot", chatbot)
tool_node = ToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)
graph_builder.add_conditional_edges(
"chatbot",
tools_condition,
)
# Any time a tool is called, we return to the chatbot to decide the next step
graph_builder.add_edge("tools", "chatbot")
graph_builder.add_edge(START, "chatbot")
<langgraph.graph.state.StateGraph at 0x24f577a24b0>
最后,用提供的检查指针编译图。
graph = graph_builder.compile(checkpointer=memory)
注意,图的连通性自第2部分以来没有改变。我们所做的就是在图通过每个节点时检查状态。
from IPython.display import Image, display
try:
display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
# This requires some extra dependencies and is optional
pass
现在你可以和你的机器人互动了!首先,选择一个线程作为这个对话的关键。
config = {"configurable": {"thread_id": "1"}}
user_input = "Hi there! My name is Will."
# The config is the **second positional argument** to stream() or invoke()!
events = graph.stream(
{"messages": [("user", user_input)]}, config, stream_mode="values"
)
for event in events:
event["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
Hi there! My name is Will.
==================================[1m Ai Message [0m==================================
Hello Will! How can I assist you today?
注意
:在调用我们的图时,配置作为第二个位置参数提供。重要的是,它没有嵌套在图输入({‘messages’:[]})中。
让我们问一个后续问题:看看它是否记得你的名字。
user_input = "Remember my name?"
# The config is the **second positional argument** to stream() or invoke()!
events = graph.stream(
{"messages": [("user", user_input)]}, config, stream_mode="values"
)
for event in events:
event["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
Remember my name?
==================================[1m Ai Message [0m==================================
Yes, I remember your name is Will! How can I help you today?
请注意,我们没有使用外部列表来存储内存:它都是由检查指针处理的!您可以在这个LangSmith跟踪中检查完整的执行,看看发生了什么。
尝试使用不同的配置。
# The only difference is we change the `thread_id` here to "2" instead of "1"
events = graph.stream(
{"messages": [("user", user_input)]},
{"configurable": {"thread_id": "2"}},
stream_mode="values",
)
for event in events:
event["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
Remember my name?
==================================[1m Ai Message [0m==================================
I'm sorry, but I don't have the ability to remember personal information or past interactions. How can I assist you today?
注意,我们所做的唯一更改是修改配置中的thread_id。请参阅此调用的LangSmith跟踪以进行比较。
到目前为止,我们已经跨两个不同的线程设置了几个检查点。但是什么会进入检查点呢?要在任何时候检查给定配置的图形状态,请调用get_state(config)
snapshot = graph.get_state(config)
snapshot
StateSnapshot(values={'messages': [HumanMessage(content='Hi there! My name is Will.', additional_kwargs={}, response_metadata={}, id='7524bfa6-4aa3-4e57-b51e-6e6e17435f01'), HumanMessage(content='Hi there! My name is Will.', additional_kwargs={}, response_metadata={}, id='3aa17118-97f4-4968-9ba4-e39ef04a067c'), AIMessage(content='Hello Will! How can I assist you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 99, 'total_tokens': 110, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_5154047bf2', 'finish_reason': 'stop', 'logprobs': None}, id='run-960eb178-7908-4aa2-b957-cbca990d32f2-0', usage_metadata={'input_tokens': 99, 'output_tokens': 11, 'total_tokens': 110, 'input_token_details': {}, 'output_token_details': {}}), HumanMessage(content='Remember my name?', additional_kwargs={}, response_metadata={}, id='b3fd3f20-54bf-470c-aeaa-890ad515973f'), AIMessage(content='Yes, I remember your name is Will! How can I help you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 17, 'prompt_tokens': 121, 'total_tokens': 138, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_5154047bf2', 'finish_reason': 'stop', 'logprobs': None}, id='run-e6c6d08e-cb82-4163-b064-65fd6bd6eaad-0', usage_metadata={'input_tokens': 121, 'output_tokens': 17, 'total_tokens': 138, 'input_token_details': {}, 'output_token_details': {}})]}, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efccc0b-932b-66ac-8006-1d62ddbed4ed'}}, metadata={'source': 'loop', 'writes': {'chatbot': {'messages': [AIMessage(content='Yes, I remember your name is Will! How can I help you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 17, 'prompt_tokens': 121, 'total_tokens': 138, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_5154047bf2', 'finish_reason': 'stop', 'logprobs': None}, id='run-e6c6d08e-cb82-4163-b064-65fd6bd6eaad-0', usage_metadata={'input_tokens': 121, 'output_tokens': 17, 'total_tokens': 138, 'input_token_details': {}, 'output_token_details': {}})]}}, 'thread_id': '1', 'step': 6, 'parents': {}}, created_at='2025-01-07T06:29:18.467038+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efccc0b-832f-6300-8005-6dc78f4590a8'}}, tasks=())
snapshot.next # (since the graph ended this turn, `next` is empty. If you fetch a state from within a graph invocation, next tells which node will execute next)
()
上面的快照包含当前状态值、相应的配置和下一个要处理的节点。在我们的示例中,图已达到END状态,因此next为空。
恭喜你!由于LangGraph的检查点系统,您的聊天机器人现在可以跨会话维护会话状态。这为更自然、更有背景的互动开辟了令人兴奋的可能性。LangGraph的检查点甚至可以处理任意复杂的图形状态,这比简单的聊天内存更具表现力和强大得多。
在下一部分中,我们将向我们的机器人引入人工监督,以处理在继续之前可能需要指导或验证的情况。
}}, ‘thread_id’: ‘1’, ‘step’: 6, ‘parents’: {}}, created_at=‘2025-01-07T06:29:18.467038+00:00’, parent_config={‘configurable’: {‘thread_id’: ‘1’, ‘checkpoint_ns’: ‘’, ‘checkpoint_id’: ‘1efccc0b-832f-6300-8005-6dc78f4590a8’}}, tasks=())
snapshot.next # (since the graph ended this turn, `next` is empty. If you fetch a state from within a graph invocation, next tells which node will execute next)
()
上面的快照包含当前状态值、相应的配置和下一个要处理的节点。在我们的示例中,图已达到END状态,因此next为空。
恭喜你!由于LangGraph的检查点系统,您的聊天机器人现在可以跨会话维护会话状态。这为更自然、更有背景的互动开辟了令人兴奋的可能性。LangGraph的检查点甚至可以处理任意复杂的图形状态,这比简单的聊天内存更具表现力和强大得多。
在下一部分中,我们将向我们的机器人引入人工监督,以处理在继续之前可能需要指导或验证的情况。
发布者:admin,转转请注明出处:http://www.yc00.com/web/1754772576a5200247.html
评论列表(0条)