十、LangGraph能力详解:LangGraph 的其他特性

目录

[5. LangGraph 的其他特性](#5. LangGraph 的其他特性)

[5.1 使用 Overwrite 绕过 reducer](#5.1 使用 Overwrite 绕过 reducer)

概念解释

[为什么需要 Overwrite?](#为什么需要 Overwrite?)

涉及的核心类和函数

代码实现

[使用 Overwrite 的应用场景](#使用 Overwrite 的应用场景)

[5.2 定义输入输出模式](#5.2 定义输入输出模式)

概念解释

为什么需要独立的内部模式?

涉及的核心类和函数

[StateGraph 初始化参数说明](#StateGraph 初始化参数说明)

代码实现

独立输入和输出的实际应用场景

[5.3 在节点间传递私有状态](#5.3 在节点间传递私有状态)

概念解释

应用场景举例

涉及的核心类和函数

代码实现

运行结果说明

节点间传递私有状态的实际应用场景

总结


5. LangGraph 的其他特性


5.1 使用 Overwrite 绕过 reducer

概念解释

在 LangGraph 中,reducers(归约器) 用于控制状态更新的处理方式。默认情况下,每个状态键都有其独立的 reducer 函数,用于决定如何合并节点返回的更新。但有时我们需要完全覆盖状态值而不是合并 ,这时候就需要使用 Overwrite

为什么需要 Overwrite?

想象一下开发一个聊天应用时:

  • 正常情况下,新消息会追加到消息列表中

  • 但有时需要清空聊天记录并重新开始 ,这时候就需要绕过追加逻辑,直接覆盖整个消息列表

涉及的核心类和函数

名称 来源 作用
StateGraph langgraph.graph 状态图构建器,用于定义工作流
START / END langgraph.graph 特殊节点,表示工作流的开始和结束
Overwrite langgraph.types 类型包装器,用于绕过 reducer 直接覆盖状态
TypedDict typing_extensions 定义状态结构的类型字典
Annotated typing_extensions 类型注解,用于指定 reducer 函数
operator.add operator Python 内置模块,用作列表追加的 reducer

代码实现

python 复制代码
from langgraph.graph import StateGraph, START, END  # 核心图构建组件
from langgraph.types import Overwrite               # 用于绕过 reducer 的特殊类型
from typing_extensions import Annotated, TypedDict   # 类型注解工具
import operator                                      # 用于定义 reducer 函数
​
class State(TypedDict):
    """定义工作流的状态结构
    messages: 消息列表,使用 operator.add 作为 reducer
              - 正常情况下,新消息会追加到列表末尾
              - 使用 Overwrite 可以绕过这个行为,直接替换整个列表
    """
    messages: Annotated[list, operator.add]
    # Annotated[list, operator.add] 的含义:
    # - list: 字段类型为列表
    # - operator.add: reducer 函数,当状态更新时,新值会与旧值相加(列表追加)
​
def add_message(state: State):
    """节点1:添加消息 - 正常返回新消息,会触发 reducer 的追加行为"""
    return {"messages": ["first message"]}
​
def replace_messages(state: State):
    """节点2:替换消息列表 - 使用 Overwrite 包装返回值,绕过 reducer 的追加逻辑"""
    return {"messages": Overwrite(["replacement message"])}
​
# 创建 StateGraph 实例,传入状态类型定义
builder = StateGraph(State)
​
# 添加节点到图中
builder.add_node("add_message", add_message)           # 添加消息节点
builder.add_node("replace_messages", replace_messages) # 替换消息节点
​
# 定义节点之间的连接关系(边)
builder.add_edge(START, "add_message")                  # 开始 → 添加消息
builder.add_edge("add_message", "replace_messages")     # 添加消息 → 替换消息
builder.add_edge("replace_messages", END)               # 替换消息 → 结束
​
# 编译图,生成可执行的工作流
graph = builder.compile()
​
# 调用工作流,传入初始状态
result = graph.invoke({"messages": ["initial"]})
print(result["messages"])
# 输出: ['replacement message']
# 注意:不是 ['initial message', 'first message', 'replacement message']
# 因为 Overwrite 绕过了 reducer,直接替换了整个列表

使用 Overwrite 的应用场景

场景 说明
重置对话 清空聊天历史,开始新对话
状态重置 在错误恢复后重置应用状态
数据清理 替换损坏或过时的数据

5.2 定义输入输出模式

概念解释

默认情况下,LangGraph 使用单一的状态模式 。但我们可以定义独立的输入和输出模式

模式类型 说明
独立的输入模式 验证输入数据的结构
独立的输出模式 过滤输出数据,只返回需要的信息
内部模式 节点间通信使用的完整状态

为什么需要独立的内部模式?

考虑一个问答系统:

  • 输入:用户的问题(字符串)

  • 输出:AI 的答案(字符串)

  • 内部:可能需要存储中间结果、上下文等信息

我们不想把内部状态都暴露给用户

涉及的核心类和函数

名称 来源 作用
StateGraph langgraph.graph 状态图构建器
input_schema StateGraph 参数 定义输入的 State 类
output_schema StateGraph 参数 定义输出的 State 类
state_schema StateGraph 参数 定义完整的 State 类(内部使用)

StateGraph 初始化参数说明

参数名 类型 描述
input_schema type[InputT]None 定义 StateGraph 输入的 State 类
output_schema type[OutputT]None 定义 StateGraph 输出的 State 类
state_schema type[StateT] 定义 StateGraph 的 State 类

代码实现

python 复制代码
from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict
​
# 1. 定义输入模式 - 只包含用户问题
class InputState(TypedDict):
    """输入状态:只暴露给用户的问题字段"""
    question: str
​
# 2. 定义输出模式 - 只包含AI答案
class OutputState(TypedDict):
    """输出状态:只暴露给用户的答案字段"""
    answer: str
​
# 3. 定义完整状态模式(内部使用)
class OverallState(InputState, OutputState):
    """完整状态:继承自 InputState 和 OutputState
    用于节点间通信,包含所有必要的字段
    但在最终输出时,只会返回 OutputState 中定义的字段
    """
    pass
​
def answer_node(state: InputState):
    """处理输入并生成答案
    参数: state - InputState 类型,只包含 question 字段
    返回: dict - 包含 answer 和 question 的字典
    注意:虽然返回了 question,但由于 OutputState 的定义,最终输出中不会包含 question 字段
    """
    return {
        "answer": f"Answer to: {state['question']}",
        "question": state["question"]  # 保留问题用于内部追踪
    }
​
# 构建图时指定输入输出模式
builder = StateGraph(
    OverallState,                  # 完整状态类型(节点间通信使用)
    input_schema=InputState,       # 输入验证:只接受 question 字段
    output_schema=OutputState      # 输出过滤:只返回 answer 字段
)
​
# 添加节点
builder.add_node("answer_node", answer_node)
builder.add_edge(START, "answer_node")
builder.add_edge("answer_node", END)
​
# 编译图
graph = builder.compile()
​
# 调用工作流
result = graph.invoke({"question": "What is LangGraph?"})
print(result)
# 输出: {'answer': 'Answer to: What is LangGraph?'}
# 注意:question 字段被过滤掉了,不在输出中

独立输入和输出的实际应用场景

场景 说明
API 开发 定义清晰的请求/响应格式
微服务 服务间明确的数据契约
数据管道 明确的输入输出规范

5.3 在节点间传递私有状态

概念解释

有时节点间需要传递临时数据 ,这些数据对中间逻辑很重要,但不应该出现在最终输出中 ,只在特定节点间共享,这就是私有状态的概念。

应用场景举例

举个例子,现在我们需要根据数据库中的信息,生成相关数据报告,因此可以设置三个节点:

  • 节点1:从数据库获取原始数据(包含敏感信息)

  • 节点2:处理数据,过滤掉敏感信息

  • 节点3:生成最终报告

此时,节点1 和 节点2 需要共享原始数据 ,但 节点3 不应该看到敏感信息

涉及的核心类和函数

名称 来源 作用
StateGraph langgraph.graph 状态图构建器
TypedDict typing_extensions 定义状态结构
add_sequence builder 方法 添加一系列节点,按顺序执行

代码实现

python 复制代码
from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict
​
# 公共状态(最终输出中可见)
class OverallState(TypedDict):
    """公共状态:包含最终输出需要的字段"""
    final_result: str
​
# 节点1的私有输出
class Node1Output(TypedDict):
    """节点1的私有输出状态 - sensitive_data 字段不会出现在最终状态中"""
    sensitive_data: str
​
# 节点2需要的输入(包含私有数据)
class Node2Input(TypedDict):
    """节点2的输入状态 - 从节点1接收敏感数据"""
    sensitive_data: str
​
def node_1(state: OverallState) -> Node1Output:
    """第一步:获取包含敏感信息的原始数据
    返回 Node1Output 类型,确保 sensitive_data 只在节点间传递,不会泄露到最终输出
    """
    private_data = "这是敏感信息"
    print(f"Node1: 获取到敏感数据,但不会暴露给最终输出")
    return {"sensitive_data": private_data}
​
def node_2(state: Node2Input) -> OverallState:
    """第二步:处理数据,移除敏感信息
    接收 sensitive_data 作为输入,返回时只输出 final_result,敏感数据被过滤掉
    """
    print(f"Node2: 处理敏感数据:{state['sensitive_data']}")
    return {"final_result": "清理后的处理结果"}
​
def node_3(state: OverallState) -> OverallState:
    """第三步:只看到清理后的数据
    无法访问 sensitive_data,只能看到 final_result
    """
    print(f"Node3: 只能看到最终结果:{state['final_result']}")
    return {"final_result": state["final_result"] + " - 完成"}
​
# 构建图
builder = StateGraph(OverallState)
# add_sequence: 支持添加一系列节点,按所给的顺序执行
builder.add_sequence([node_1, node_2, node_3])
builder.add_edge(START, "node_1")
graph = builder.compile()
​
# 调用工作流
response = graph.invoke({"final_result": "initial"})
print(f"\n最终输出:{response}")
# 输出:{'final_result': '清理后的处理结果 - 完成'}
# 注意:sensitive_data 字段没有出现在最终输出中

运行结果说明

python 复制代码
Node1: 获取到敏感数据,但不会暴露给最终输出
Node2: 处理敏感数据:这是敏感信息
Node3: 只能看到最终结果:清理后的处理结果
​
最终输出:{'final_result': '清理后的处理结果 - 完成'}

节点间传递私有状态的实际应用场景

场景 说明
数据处理 中间处理步骤的临时数据
认证流程 令牌等敏感信息的传递
复杂计算 中间计算结果
错误处理 错误详情在内部传递,但对外提供友好消息

总结

以上三个特性让 LangGraph 能够处理复杂的企业级应用场景,同时保持代码的清晰和安全性:

  1. Overwrite:灵活控制状态更新策略

  2. 输入输出模式:清晰的数据边界和接口定义

  3. 私有状态:安全的节点间数据传递

这些特性共同构成了 LangGraph 强大的状态管理能力,使其能够构建生产级的 AI 应用。

相关推荐
xxie12379419 小时前
return与print
开发语言·python
秋919 小时前
从 Python 后端工程师转型 AI Engineer(AI 工程化)的完整补课清单(2026实战版)
开发语言·人工智能·python
周航宇JoeZhou20 小时前
JB3-9-SpringAI(二)
java·ai·agent·多智能体·调度·智能体·观察
慕木沐20 小时前
Google ADK Java 1.0版本 核心机制与实战 Demo
java·开发语言·python
Tbisnic20 小时前
AI大模型学习第十一天:技术选型、安全防护与金融实战
python·学习·ai·大模型·提示词工程
AI工具挖掘机20 小时前
Codex 桌面版上手:从安装到自己开发首个小游戏,0 基础快速入门,手把手教学
经验分享·ai·ai编程
hboot21 小时前
AI工程师第一课 - Python
前端·后端·python
凉菜凉凉21 小时前
AI时代,被抛弃的前端
前端·ai
许彰午21 小时前
30_Java Stream流操作全解
java·windows·python
秋91 天前
3年经验Python后端转AI Engineer:3个月实战转型计划(2026版)
开发语言·人工智能·python