set_node_defaults 一次性为所有节点配置这些机制,而不是在每个 add_node 调用中重复配置。
这些机制按固定顺序组合:当一个节点尝试引发任何异常(包括来自超时的 NodeTimeoutError)时,重试策略决定是否重试。只有在重试耗尽后,错误处理器才会运行。
有关在超步(superstep)边界处干净地停止运行并在稍后恢复,请参阅优雅关停。
每个节点的超时和节点级错误处理器需要
langgraph>=1.2。重试
重试策略根据异常类型和退避设置自动重新运行失败的节点尝试。 向add_node 传递 retry_policy=:
默认行为
默认情况下,retry_on 使用 default_retry_on,它会对除以下及其子类之外的任何异常进行重试:
ValueErrorTypeErrorArithmeticErrorImportErrorLookupErrorNameErrorSyntaxErrorRuntimeErrorReferenceErrorStopIterationStopAsyncIterationOSError
requests 和 httpx 等流行 HTTP 库的异常,它只对 5xx 状态码进行重试。NodeTimeoutError 默认是可重试的。
参数
自定义重试逻辑
向retry_on 传递一个可调用对象或异常类型。导入 default_retry_on 以扩展默认行为:
检查重试状态
在节点内部使用执行信息来检查当前尝试次数。当主调用持续失败时,这对于切换到备用方案非常有用:execution_info 暴露了以下字段:
即使没有重试策略,
execution_info 也可用——node_attempt 默认为 1。
超时
需要
langgraph>=1.2。add_node 上的 timeout= 参数限制单个节点尝试可以运行的时长。传递一个数字(秒)、一个 timedelta,或一个 TimeoutPolicy 以设置单独的运行和空闲限制:
运行超时
run_timeout 是对单次尝试的硬性挂钟时间限制。无论节点活动如何,它永远不会被刷新:
NodeTimeoutError,清除失败尝试的任何写入,并让重试策略决定是否重试。
空闲超时
idle_timeout 是一个进度重置限制。它只在节点在指定持续时间内停止产生可观察的进度时才会触发——与 run_timeout 不同,当时钟重置时,节点会产生一个进度信号:
run_timeout 和 idle_timeout。先触发的那个将取消尝试。
进度信号
在默认的refresh_on="auto" 下,空闲时钟在以下任何情况下重置:
- 通过
CONFIG_KEY_SEND进行状态写入 - 流输出(产出的异步流块)
- 子任务调度
- 运行时流写入器调用
- 来自节点或其后代的任何 LangChain 回调事件(LLM token、工具调用、链开始/结束等)
心跳模式
设置refresh_on="heartbeat" 以将刷新源限制为仅限显式的 runtime.heartbeat() 调用。当您想要一个严格的空闲定义,不被话多的下属重置时,这非常有用:
手动心跳
对于不自然发出进度信号的长时间运行的工作,调用runtime.heartbeat() 来手动重置空闲时钟:
runtime.heartbeat() 在空闲计时尝试之外是无操作的,因此您可以无条件地调用它。
NodeTimeoutError
当超时触发时,LangGraph 会抛出NodeTimeoutError,并附带关于触发了哪个限制的结构化上下文:
NodeTimeoutError 默认是可重试的。将 timeout 与重试策略结合使用开箱即用——超时时钟在每次新尝试时重置,并且超时尝试的写入在下次重试前被清除:
使用 Send 的动态超时
当使用Send 动态分派节点时(例如,在 map-reduce 模式中),您可以直接在 Send 上传递一个超时,以覆盖该特定推送的静态超时:
Send 上省略了超时,则应用目标节点的超时(在 add_node 时设置)。这允许您在节点上设置默认超时,并为单个调用收紧它。
错误处理
需要
langgraph>=1.2。Command 路由到不同的节点。这对于补偿流程(Saga 模式)非常有用,您可以在其中优雅地恢复,而不是中止整个图。
向 add_node 传递 error_handler=:
NodeError
错误处理器通过类型化的error: NodeError 参数接收失败上下文,该参数通过类型注解注入(与 runtime: Runtime 的模式相同):
NodeError 是一个具有两个字段的冻结数据类:
error: NodeError 参数是选择加入的。不需要失败上下文的处理器可以使用更简单的签名,如 (state) 或 (state, runtime)。
使用 Command 进行路由
错误处理器可以返回一个Command 来更新状态并路由到特定节点,从而实现 Saga / 补偿模式:
charge_payment 会针对 ConnectionError 最多重试 3 次。如果重试耗尽(或错误不是 ConnectionError),处理器将通过更新状态并路由到 finalize 来补偿,而不是中止图。
恢复安全的失败
失败来源被检查点化。如果图在节点失败后但在处理器完成前被中断或进程崩溃,当图从其检查点恢复时,处理器将看到相同的
NodeError 上下文。与 interrupt() 的行为
子图失败
如果一个节点包装了一个子图,并且子图引发了未处理的异常,该异常将浮出到父节点。如果父节点有一个错误处理器,处理器将在error.error 中包含子图的异常并被触发。
图默认值
需要
langgraph>=1.2。add_node 调用中重复相同的 retry_policy=、error_handler=、timeout= 或 cache_policy=,不如使用 set_node_defaults 在一个地方配置图形范围的默认值:
step_a 和 step_b 现在共享相同的重试策略、错误处理器和超时,没有任何重复。
优先级
直接传递给add_node() 的每个节点值始终覆盖由 set_node_defaults() 设置的默认值。默认值在 compile() 时解析,因此您可以按任意顺序在 add_node() 之前或之后调用 set_node_defaults():
默认错误处理器
error_handler 默认值在每次图形运行都映射到外部过程(例如后台作业行)时特别有价值,并且任何未处理的节点失败都应该将该过程标记为失败,而无需在每个 add_node 上重复 error_handler=。当某个步骤需要自己的逻辑时,每个节点的处理器仍然优先:
fetch_data 在重试后失败,mark_process_failed 会运行。如果 charge_payment 在重试后失败,则 refund_payment 会运行,因为每个节点的处理器覆盖了默认值。
处理器接受错误处理中描述的相同 (state, error: NodeError) 签名。如果需要访问配置值,如 thread_id,它还接受 RunnableConfig 作为可选的第三个参数:
适用性矩阵
并非所有默认值都适用于所有节点类型。错误处理器节点(通过add_node(error_handler=...) 注册的那些)被排除在某些默认值之外,以防止不安全的行为:
范围
父图上设置的默认值不会被子图继承。每个图维护自己的默认值。函数式 API
函数式 API 中的@task 和 @entrypoint 上提供了相同的 timeout= 和 retry_policy= 参数:
add_node 相同:超时时引发 NodeTimeoutError,缓冲的写入被清除,重试策略决定是否重试。
优雅关停
协作关停允许您在当前超步完成后停止正在运行的图形运行,并保存一个可恢复的检查点。这对于处理 SIGTERM 信号或任何需要回收资源而不丢失工作的外部监督器非常有用。需要
langgraph>=1.2。RunControl 并将其作为 control= 传递给 invoke 或 stream。从任何线程调用 request_drain() 以表示运行应停止:
语义
排空是协作的,并在超步之间进行,不会抢占已经运行的工作:排空后恢复
使用相同的thread_id 通过 invoke(None, config) 恢复已排空的运行:
在节点内读取排空状态
通过runtime 参数访问排空状态,以在达到超步边界之前调整节点行为:
SIGTERM 钩子模式
处理进程关闭的推荐模式:request_drain() 不会取消运行中的 asyncio 任务或终止线程。要设置硬上限,请将排空与优雅超时和任务取消结合使用。限制
- 超时仅适用于异步:具有
timeout的同步节点在编译时会被拒绝。 - 每个节点一个处理器:每个节点最多可以有一个
error_handler。 - 处理器失败会向上冒泡:如果错误处理器本身引发异常,该异常会像节点没有处理器一样传播。
set_node_defaults不会被子图继承:每个图独立管理自己的默认值。
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

