LangGraph中的State管理

本教程将介绍如何使用LangGraph库构建和测试状态图。我们将通过一系列示例代码,逐步解释程序的运行逻辑。

1. 基本状态图构建

首先,我们定义一个状态图的基本结构和节点。

定义状态类

python 复制代码
from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict
from pydantic import BaseModel

# 定义整个图的状态(这是在节点间共享的公共状态)
class OverallState(BaseModel):
    a: str

定义节点函数

python 复制代码
def node(state: OverallState):
    return {"a": "goodbye"}

构建状态图

python 复制代码
# 构建状态图
builder = StateGraph(OverallState)
builder.add_node(node)  # 添加节点
builder.add_edge(START, "node")  # 从起始节点开始
builder.add_edge("node", END)  # 在节点后结束
graph = builder.compile()

测试状态图

python 复制代码
# 使用有效输入测试图
graph.invoke({"a": "hello"})

输出结果:

python 复制代码
{'a': 'goodbye'}

可视化状态图

python 复制代码
from IPython.display import Image, display

try:
    display(Image(graph.get_graph(xray=True).draw_mermaid_png()))
except Exception:
    # 这需要一些额外的依赖项,是可选的
    print("x")
    pass

测试无效输入

python 复制代码
try:
    graph.invoke({"a": 123})  # 应该是字符串
except Exception as e:
    print("An exception was raised because `a` is an integer rather than a string.")
    print(e)

输出结果:

python 复制代码
An exception was raised because `a` is an integer rather than a string.
1 validation error for OverallState
a
  Input should be a valid string [type=string_type, input_value=123, input_type=int]
    For further information visit https://errors.pydantic.dev/2.8/v/string_type

2. 处理无效节点

接下来,我们添加一个返回无效状态的节点,并观察其影响。

定义节点函数

python 复制代码
def bad_node(state: OverallState):
    return {
        "a": 123  # 无效
    }

def ok_node(state: OverallState):
    return {"a": "goodbye"}

构建状态图

python 复制代码
# 构建状态图
builder = StateGraph(OverallState)
builder.add_node(bad_node)
builder.add_node(ok_node)
builder.add_edge(START, "bad_node")
builder.add_edge("bad_node", "ok_node")
builder.add_edge("ok_node", END)
graph = builder.compile()

可视化状态图

python 复制代码
from IPython.display import Image, display

try:
    display(Image(graph.get_graph(xray=True).draw_mermaid_png()))
except Exception:
    # 这需要一些额外的依赖项,是可选的
    pass

测试状态图

python 复制代码
# 使用有效输入测试图
try:
    graph.invoke({"a": "hello"})
except Exception as e:
    print("An exception was raised because bad_node sets `a` to an integer.")
    print(e)

输出结果:

python 复制代码
An exception was raised because bad_node sets `a` to an integer.
1 validation error for OverallState
a
  Input should be a valid string [type=string_type, input_value=123, input_type=int]
    For further information visit https://errors.pydantic.dev/2.8/v/string_type

3. 输入和输出状态的分离

接下来,我们定义输入和输出状态的分离。

定义状态类

python 复制代码
from typing_extensions import TypedDict

# 定义输入状态的架构
class InputState(TypedDict):
    question: str

# 定义输出状态的架构
class OutputState(TypedDict):
    answer: str

# 定义整体架构,结合输入和输出
class OverallState(InputState, OutputState):
    pass

定义节点函数

python 复制代码
def answer_node(state: InputState):
    # 示例答案和一个额外的键
    return {"answer": "bye", "question": state["question"]}

构建状态图

python 复制代码
# 使用指定的输入和输出架构构建图
builder = StateGraph(OverallState, input=InputState, output=OutputState)
builder.add_node(answer_node)  # 添加答案节点
builder.add_edge(START, "answer_node")  # 定义起始边
builder.add_edge("answer_node", END)  # 定义结束边
graph1 = builder.compile()  # 编译图

可视化状态图

python 复制代码
from IPython.display import Image, display

try:
    display(Image(graph1.get_graph(xray=True).draw_mermaid_png()))
except Exception:
    # 这需要一些额外的依赖项,是可选的
    pass

测试状态图

python 复制代码
print(graph1.invoke({"question": "hi"}))

输出结果:

python 复制代码
{'answer': 'bye'}

4. 处理私有数据

最后,我们展示如何在节点间传递私有数据。

定义状态类

python 复制代码
# 整个图的状态(这是在节点间共享的公共状态)
class OverallState(TypedDict):
    a: str

# node_1的输出包含私有数据,不属于整体状态
class Node1Output(TypedDict):
    private_data: str

定义节点函数

python 复制代码
def node_1(state: OverallState) -> Node1Output:
    output = {"private_data": "set by node_1"}
    print(f"Entered node `node_1`:\n\tInput: {state}.\n\tReturned: {output}")
    return output

# node_2的输入仅请求node_1后可用的私有数据
class Node2Input(TypedDict):
    private_data: str

def node_2(state: Node2Input) -> OverallState:
    output = {"a": "set by node_2"}
    print(f"Entered node `node_2`:\n\tInput: {state}.\n\tReturned: {output}")
    return output

# node_3仅能访问整体状态(无法访问node_1的私有数据)
def node_3(state: OverallState) -> OverallState:
    output = {"a": "set by node_3"}
    print(f"Entered node `node_3`:\n\tInput: {state}.\n\tReturned: {output}")
    return output

构建状态图

python 复制代码
# 构建状态图
builder = StateGraph(OverallState)
builder.add_node(node_1)  # node_1是第一个节点
builder.add_node(node_2)  # node_2是第二个节点,接受node_1的私有数据
builder.add_node(node_3)  # node_3是第三个节点,无法看到私有数据
builder.add_edge(START, "node_1")  # 从node_1开始
builder.add_edge("node_1", "node_2")  # 从node_1传递到node_2
builder.add_edge("node_2", "node_3")  # 从node_2传递到node_3(仅共享整体状态)
builder.add_edge("node_3", END)  # 在node_3后结束
graph = builder.compile()

可视化状态图

python 复制代码
from IPython.display import Image, display

try:
    display(Image(graph.get_graph(xray=True).draw_mermaid_png()))
except Exception:
    # 这需要一些额外的依赖项,是可选的
    pass

测试状态图

python 复制代码
# 使用初始状态调用图
response = graph.invoke(
    {
        "a": "set at start",
    }
)

print()
print(f"Output of graph invocation: {response}")

输出结果:

python 复制代码
Entered node `node_1`:
	Input: {'a': 'set at start'}.
	Returned: {'private_data': 'set by node_1'}
Entered node `node_2`:
	Input: {'private_data': 'set by node_1'}.
	Returned: {'a': 'set by node_2'}
Entered node `node_3`:
	Input: {'a': 'set by node_2'}.
	Returned: {'a': 'set by node_3'}

Output of graph invocation: {'a': 'set by node_3'}

通过以上步骤,我们展示了如何使用LangGraphState管理,包括处理私有数据和状态验证。希望这个教程对你有所帮助!

参考链接:https://langchain-ai.github.io/langgraph/how-tos/state-model/
https://langchain-ai.github.io/langgraph/how-tos/input_output_schema/
https://langchain-ai.github.io/langgraph/how-tos/pass_private_state/

如果有任何问题,欢迎在评论区提问。

相关推荐
ASKED_20192 小时前
Langchain学习笔记一 -基础模块以及架构概览
笔记·学习·langchain
zhengfei6117 小时前
【AI平台】- 基于大模型的知识库与知识图谱智能体开发平台
vue.js·语言模型·langchain·知识图谱·多分类
玄同76510 小时前
LangChain 1.0 模型接口:多厂商集成与统一调用
开发语言·人工智能·python·langchain·知识图谱·rag·智能体
Bruk.Liu12 小时前
(LangChain实战12):LangChain中的新型Chain之create_sql_query_chain
数据库·人工智能·sql·langchain
爱吃羊的老虎13 小时前
【大模型开发】学习笔记一:RAG & LangChain 实战核心笔记
人工智能·笔记·语言模型·langchain
玄同76516 小时前
LangChain 1.0 框架全面解析:从架构到实践
人工智能·深度学习·自然语言处理·中间件·架构·langchain·rag
AI Echoes1 天前
LangChain Runnable组件重试与回退机制降低程序错误率
人工智能·python·langchain·prompt·agent
熬夜敲代码的小N2 天前
Agentic AI 实战全指南:从原理到LangChain落地开发
人工智能·langchain
lapiii3582 天前
[AI大模型] DAY 1 :零基础学LangChain
python·langchain·大模型·agent
笨蛋不要掉眼泪2 天前
Spring Boot集成LangChain4j:与大模型对话的极速入门
java·人工智能·后端·spring·langchain