LangGraph实战教程:defer延迟节点——让收尾工作自动排到最后

  1. LangGraph 入门基础全解析
  2. LangGraph中的Reducer是什么
  3. LangGraph 核心概念详解:从编译到可视化
  4. LangGraph实战教程:一文搞懂图的状态(State)管理
  5. LangGraph实战教程:状态管理与graph.invoke入参深度解析
  6. LangGraph高级教程:Multi Schema多状态管理详解
  7. LangGraph实战教程:预定义状态MessagesState与AgentState
  8. LangGraph实战教程:控制流详解

一、场景引入

想象这样一个场景:你的图里有好几个节点并行执行任务,比如一个写诗、一个写笑话。等它们都完成后,你想做个审计------检查一下诗和笑话是不是都生成了。

通常的做法是:给每个任务节点都连一条线到审计节点。

但如果任务节点很多,或者图结构很复杂,这种做法就很麻烦。

有没有更简单的办法?有!用 defer=True。

二、defer到底是什么?

defer的意思是"推迟"。在LangGraph中,给节点加上 defer=True,就相当于告诉框架:

"这个节点先别急着执行,等其他所有常规节点都跑完了,再让它上场。"

ini 复制代码
builder.add_node("audit_node", audit_node, defer=True)

就这么简单的一行,审计节点就会自动排到最后执行。

三、一个完整的例子

下面这个图有三个节点:一个写诗、一个写笑话、一个做审计。

python 复制代码
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langchain.messages import HumanMessage
from langchain_deepseek import ChatDeepSeek
from loguru import logger

from dotenv import load_dotenv
load_dotenv(override=True)

model = ChatDeepSeek(
    model="deepseek-v4-flash",
    extra_body={"thinking": {"type": "disabled"}}
)

class OverAllState(TypedDict):
    topic: str
    poem: str
    joke: str

def node_a(state: OverAllState) -> OverAllState:
    """生成诗歌"""
    poem = model.invoke([HumanMessage(f"写一首关于 {state['topic']} 的七言绝句")]).content
    return {"poem": poem}

def node_b(state: OverAllState) -> OverAllState:
    """生成笑话"""
    joke = model.invoke([HumanMessage(f"写一个关于 {state['topic']} 的笑话")]).content
    return {"joke": joke}

def audit_node(state: OverAllState) -> OverAllState:
    """审计节点:在所有任务完成后执行"""
    logger.info(
        f"任务全部完成,"
        f"诗 {'✅ 已生成' if state.get('poem') else '❌ 未生成'},"
        f"笑话 {'✅ 已生成' if state.get('joke') else '❌ 未生成'}"
    )
    return {}

# 构建图
builder = StateGraph(state_schema=OverAllState)
builder.add_node("node_a", node_a)
builder.add_node("node_b", node_b)
builder.add_node("audit_node", audit_node, defer=True)  # 👈 关键:defer=True

# 所有节点都从START出发
builder.add_edge(START, "node_a")
builder.add_edge(START, "node_b")
builder.add_edge(START, "audit_node")  # 虽然也从START出发,但不会立即执行

builder.add_edge("node_a", END)
builder.add_edge("node_b", END)
builder.add_edge("audit_node", END)

graph = builder.compile()
res = graph.invoke({"topic": "布偶狗"})
print(res)

输出结果:

css 复制代码
2026-05-28 17:07:09.618 | INFO | 任务全部完成,诗 ✅ 已生成,笑话 ✅ 已生成

{
    'topic': '布偶狗',
    'poem': '《咏布偶狗》\n绸身棉腑自憨娇...',
    'joke': '这是一个关于布偶狗的笑话:\n有一只布偶狗...'
}

四、执行流程

这个图的执行过程分为三步:

第一步:常规节点先跑

sql 复制代码
START → node_a(写诗)→ 完成 ✅
START → node_b(写笑话)→ 完成 ✅
START → audit_node(⚠️ 被延迟,先不动)

node_a和 node_b正常执行,audit_node虽然也被触发了,但因为 defer=True,它先"睡一会儿"。

第二步:常规节点全部完成

node_a和 node_b都跑完了,状态中也写入了诗和笑话。

此时常规流程结束。

第三步:延迟节点被唤醒

复制代码
audit_node(审计)→ 执行 ✅

audit_node醒来,读取状态------这时候诗和笑话都已经有了,所以它能正确地做审计。

五、defer到底解决了什么问题?

没有 defer 的时候:

如果你想在所有任务完成后做审计,需要这样画图:

sql 复制代码
START → node_a → audit_node → END
START → node_b → audit_node → END

每个任务节点都要单独连到审计节点。如果任务有10个,就要连10条线。

有 defer 的时候:

sql 复制代码
START → node_a → END
START → node_b → END
START → audit_node → END  (defer=True,自动最后执行)

代码更简洁,结构更清晰,而且不管加多少任务节点,审计节点都会自动排到最后。

六、defer适合做什么?

场景 是否适合 说明
日志记录 ✅ 非常适合 记录哪些节点执行了,耗时多久
审计检查 ✅ 非常适合 检查所有任务是否按要求完成
结果汇总 ✅ 适合 把各个节点的输出汇总到一起
收尾清理 ✅ 适合 关闭文件、释放资源等
核心业务逻辑 ❌ 不适合 defer节点出错不会回滚前面的结果

七、一句话总结

defer=True就像给节点贴了个"压轴出场"的标签------所有常规节目演完了,它才登台谢幕。


八、相关面试题

面试题1:defer=True和把审计节点放在最后位置有什么区别?

打个比方:

  • 放在最后位置:就像排队,你必须站在最后一个人的后面
  • defer=True:就像买了"免排队"票,不管前面有多少人,你都最后上场

放在最后位置需要给每个前驱节点都连线,而 defer=True只需要设置一个参数。

面试题2:如果我有两个 defer=True的节点,谁先执行?

答案: ​ 不确定。它们会在同一个时刻被唤醒,谁先执行取决于调度顺序。

如果两个延迟节点之间有依赖关系(比如B需要A的结果),就不要都用 defer=True,而是用普通边建立先后关系。

面试题3:defer节点里出错了怎么办?

答案: ​ 常规节点的结果已经保存了,不会回滚。所以不要把关键的业务逻辑放在 defer节点里。

举个例子:如果 defer节点是做日志记录的,日志写失败了没关系,诗和笑话还在。但如果 defer节点是做数据校验的,校验失败了但数据已经生成,你就需要额外处理这个异常。

面试题4:defer节点能不能更新状态?

答案: ​ 可以。defer节点也可以返回状态更新。只不过它更新完之后,通常不会有其他节点再被触发了(除非还有其他 defer节点)。


希望这个通俗版的教程能帮你轻松掌握 defer的用法!

相关推荐
AIGS0012 小时前
什么是本体语义平台?和知识图谱、传统数据中台的区别在哪
人工智能·知识图谱·数据中台·ai问数·本体语义平台·智能数据中台
YOLO数据集集合2 小时前
烟叶病虫害检测数据集 | 烟叶病害 无人机航拍 智慧农业 病害检测 9125期
人工智能·目标检测·目标跟踪·无人机·烟草病虫·烟草虫害
Experience-摆渡3 小时前
一个开源免费的本地AI抠图工具 unbagrnd:断网也能用的背景移除
人工智能·开源
只是甲3 小时前
Text2SQL 系列博客 07:4 步选型法(上)- 场景与标准的定义
人工智能·text2sql·nl2sql·ai agent·智能问数
Csvn3 小时前
并发模式:让渲染学会排队、插队和让路
前端
Csvn3 小时前
AI 应用日志别再 print 了:结构化日志 + request_id 贯穿(O01)
人工智能
可乐鸡翅yeah_3 小时前
新手梳理:M3U8 线上问题,哪些是前端锅,哪些是后端锅
前端·ios·音视频·实时音视频·m3u8·音视频在线播放
Flynt3 小时前
Linear 用 1000 个 PR 换掉 styled-components,我写了 200 个按钮,把这笔账复现了一遍
前端·css·preact
波力海苔夹心脆6753 小时前
C# 序列化与反序列化详解:System.Text.Json、Newtonsoft.Json、XmlSerializer 用法、特性选项与安全实践
经验分享·后端·c#·json·.net
空 白II3 小时前
9.26 大语言模型研究简报:把 Agent 开发做成“数据—训练—Harness”闭环
人工智能·语言模型·自然语言处理