set_node_defaults 一次性为所有节点配置这些机制,而不是在每个 add_node 调用中重复它们。
:::
:::js
使用 setNodeDefaults 一次性为所有节点配置这些机制,而不是在每个 addNode 调用中重复它们。
:::
这些按固定顺序组合:当节点尝试引发任何异常(包括来自 @[NodeTimeoutError] 的超时异常)时,重试策略决定是否重试。只有在重试尝试耗尽后,错误处理程序才会运行。
要在一个超级步骤边界处干净地停止运行并在稍后恢复,请参阅 优雅停机。
:::python
每个节点的超时和节点级错误处理程序需要
langgraph>=1.2。每个节点的超时和节点级错误处理程序需要
@langchain/langgraph>=1.4.0。重试
重试策略根据异常类型和退避设置自动重新运行失败的节点尝试。 :::python 将retry_policy= 传递给 @[add_node]:
retryPolicy 传递给 @[addNode]:
默认行为
:::python 默认情况下,retry_on 使用 default_retry_on,它在除以下异常及其子类之外的任何异常上重试:
ValueErrorTypeErrorArithmeticErrorImportErrorLookupErrorNameErrorSyntaxErrorRuntimeErrorReferenceErrorStopIterationStopAsyncIterationOSError
requests 和 httpx)的异常,它仅在 5xx 状态码上重试。@[NodeTimeoutError] 默认可重试。
:::
:::js
重试是可选的。节点只有在配置了 retryPolicy 时才会重试,可以直接配置或通过 setNodeDefaults 使用图默认值。一个空策略({})就足够了。如果没有策略,第一次失败将结束尝试,LangGraph 不会调用 retryOn。
如果策略省略了 retryOn,LangGraph 使用内置的处理程序,除了以下异常外会重试抛出的错误:
- 中止和取消错误:
error.name === "AbortError",或error.message以"Cancel"或"AbortError"开头 GraphValueError,匹配error.name- 中止的连接:
error.code === "ECONNABORTED" - HTTP 客户端错误,状态码为 400、401、402、403、404、405、406、407 或 409,从
error.response?.status或error.status读取(针对fetch、Axios 和类似客户端) - OpenAI 风格的配额错误:
error.error?.code === "insufficient_quota"
retryOn,否则都是可重试的。@[NodeTimeoutError] 不在此黑名单中,因此当配置了重试策略时它是可重试的。
某些失败会绕过 retryOn。图控制流错误,如 GraphInterrupt 和 Command 路由,会直接冒泡而不会重试。中止运行信号也会停止重试循环,即使 retryOn 会返回 true。
参数
:::python
:::js
自定义重试逻辑
:::python 将可调用对象或异常类型传递给retry_on。导入 default_retry_on 以扩展默认行为:
retryOn。与 Python 不同,没有导出的 defaultRetryOn 辅助函数——请自行实现自己的谓词:
检查重试状态
使用节点内的执行信息来检查当前尝试次数。这对于在主调用持续失败时切换到备用方案很有用: :::pythonexecution_info 暴露以下字段:
execution_info 即使没有重试策略也可用——node_attempt 默认为 1。
:::
:::js
executionInfo 暴露以下字段:
executionInfo 即使没有重试策略也可用——nodeAttempt 默认为 1。
:::
超时
:::python需要
langgraph>=1.2。add_node] 上的 timeout= 参数限制单个节点尝试的运行时长。传入数字(秒)、timedelta 或 @[TimeoutPolicy] 以设置独立的运行和空闲限制:
需要
@langchain/langgraph>=1.4.0。addNode] 上的 timeout 参数限制单个节点尝试的运行时长。传入数字(毫秒)或 @[TimeoutPolicy] 以设置独立的运行和空闲限制:
运行超时
:::pythonrun_timeout 是单次尝试的硬性时钟限制。无论节点活动如何,它永不刷新:
runTimeout 是单次尝试的硬性时钟限制。无论节点活动如何,它永不刷新:
NodeTimeoutError],清除失败尝试的任何写入,并让重试策略决定是否重试。
空闲超时
:::pythonidle_timeout 是进度重置限制。仅在节点停止在指定时长内产生可观察进度时触发——与 run_timeout 不同,时钟会在节点产生进度信号时重置:
idleTimeout 是进度重置限制。仅在节点停止在指定时长内产生可观察进度时触发——与 runTimeout 不同,时钟会在节点产生进度信号时重置:
run_timeout 和 idle_timeout。先触发的限制将取消尝试。
:::
:::js
可以同时设置 runTimeout 和 idleTimeout。先触发的限制将取消尝试。
:::
进度信号
:::python 在默认refresh_on="auto" 下,空闲时钟会在以下任一情况下重置:
- 通过
CONFIG_KEY_SEND的状态写入 - 流输出(异步流块)
- 子任务调度
- 运行时流写入器调用
- 节点或其子节点的任何 LangChain 回调事件(LLM Token、工具调用、链开始/结束等) :::
refreshOn: "auto" 下,空闲时钟会在以下任一情况下重置:
- 通过图写入路径的状态写入
- 通过
runtime.writer的自定义流输出 - 子任务调度
- 节点或其子节点的任何 LangChain 回调事件(LLM Token、工具调用、链开始/结束等) :::
心跳模式
:::python 将refresh_on="heartbeat" 设置为仅对显式 runtime.heartbeat() 调用进行刷新。这在您希望严格定义空闲且不被健谈的子节点重置时很有用:
refreshOn: "heartbeat" 设置为仅对显式 runtime.heartbeat() 调用进行刷新。这在您希望严格定义空闲且不被健谈的子节点重置时很有用:
手动心跳
对于不自然发出进度信号的长时间运行工作,调用runtime.heartbeat() 手动重置空闲时钟:
:::python
runtime.heartbeat() 在空闲超时尝试外是无操作的,因此您可以无条件调用它。
NodeTimeoutError
当触发超时时,LangGraph 触发 @[NodeTimeoutError],并提供关于哪个限制被触发的结构化上下文:
:::python
:::js
使用
isNodeTimeoutError(error) 可在 TypeScript 中缩小捕获的错误。
:::
NodeTimeoutError 默认可重试。将 timeout 与重试策略结合使用即可无缝工作——超时时钟在每个新尝试中重置,并在下次重试前清除超时尝试的写入:
:::python
使用 Send 的动态超时
在使用 @[Send] 动态分发节点(例如在 map-reduce 模式)时,可以直接在 Send 上传入超时,以覆盖目标节点的静态超时,仅对该特定推送有效:
:::python
Send 上省略超时,则应用目标节点的超时(在 @[add_node] 设置时)。这允许您为节点设置默认超时,并在单个调用中收紧它。
:::
:::js
如果在 Send 上省略超时,则应用目标节点的超时(在 @[addNode] 设置时)。这允许您为节点设置默认超时,并在单个调用中收紧它。
:::
错误处理
:::python需要
langgraph>=1.2。需要
@langchain/langgraph>=1.4.0。Command] 更新状态或路由到不同节点。这对于补偿流(Saga 模式)很有用,您希望优雅地恢复而不是中止整个图。
:::python
将 error_handler= 传递给 @[add_node]:
StateGraph] 上(而非基础 Graph 类)将 errorHandler 传递给 @[addNode]:
NodeError
:::python 错误处理器通过类型注解(与runtime: Runtime 相同的模式)注入的 error: NodeError 参数接收失败上下文:
NodeError] 是一个冻结的数据类,包含两个字段:
error: NodeError 参数是可选的。不需要失败上下文的处理器可以使用更简单的签名如 (state) 或 (state, runtime)。
:::
:::js
错误处理器通过一个类型为 error: NodeError 的参数接收失败上下文:
NodeError] 是一个包含两个字段的类:
error: NodeError 参数是可选的。不需要失败上下文的处理器可以省略第二个参数,只接受 state。
:::
带命令的路由
错误处理器可以返回一个 @[Command] 来更新状态并路由到特定节点,从而启用 Saga / 补偿模式:
:::python
charge_payment 在 ConnectionError 上最多重试 3 次。如果重试次数耗尽(或错误不是 ConnectionError),处理器通过更新状态并路由到 finalize 来补偿,而不是中止图。
:::
:::js
chargePayment 在 ConnectionError 上最多重试 3 次。如果重试次数耗尽(或错误不是 ConnectionError),处理器通过更新状态并路由到 finalize 来补偿,而不是中止图。
:::
可恢复的失败
失败溯源被检查点记录。如果图被中断或在节点失败但处理器完成之前进程崩溃,当图从检查点恢复时,处理器会看到相同的
NodeError 上下文。与 interrupt() 的行为
子图失败
如果一个节点包装了子图并且子图抛出未处理的异常,该异常会传递到父节点。如果父节点有错误处理器,处理器会以子图的异常作为error.error 触发。
:::python
图默认值
需要
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() 时解析,因此你可以在任何顺序中调用 set_node_defaults() 之前或之后 add_node():
默认错误处理器
error_handler 默认值在每次图运行映射到外部进程(例如后台作业行)时特别有价值,并且任何未处理的节点失败都应将该进程标记为失败,而无需在每次 add_node 中重复 error_handler=。当步骤需要自己的逻辑时,每个节点的处理器仍然优先:
fetch_data 重试后失败,mark_process_failed 运行。如果 charge_payment 重试后失败,refund_payment 运行,因为每个节点的处理器覆盖了默认值。
处理器接受 错误处理 中描述的相同 (state, error: NodeError) 签名。它还接受 RunnableConfig 作为可选的第三个参数,如果你需要访问配置值如 thread_id:
适用性矩阵
并非所有默认值都适用于所有节点类型。错误处理器节点(通过add_node(error_handler=...) 注册的)被排除在某些默认值之外以防止不安全行为:
范围
在父图上设置的默认值不会被子图继承。每个图维护自己的默认值。 ::: :::js图默认值
需要
@langchain/langgraph>=1.4.0。addNode 调用中重复相同的 retryPolicy、errorHandler、timeout 或 cachePolicy,不如使用 setNodeDefaults 在一个地方配置全局默认值:
stepA 和 stepB 现在共享相同的重试策略、错误处理器、超时和缓存策略,无需任何重复。
优先级
直接传递给addNode() 的每个节点值始终覆盖 setNodeDefaults() 设置的默认值。默认值在 compile() 时解析,因此你可以在任何顺序中调用 setNodeDefaults() 之前或之后 addNode():
默认错误处理器
errorHandler 默认值在每次图运行映射到外部进程(例如后台作业行)时特别有价值,并且任何未处理的节点失败都应将该进程标记为失败,而无需在每次 addNode 中重复 errorHandler。当步骤需要自己的补偿逻辑时,每个节点的处理器仍然优先:
fetchData 重试后失败,markProcessFailed 运行。如果 chargePayment 重试后失败,refundPayment 运行,因为每个节点的处理器覆盖了默认值。
适用性矩阵
并非所有默认值都适用于所有节点类型。错误处理器节点(通过addNode(..., { errorHandler }) 注册的)被排除在某些默认值之外以防止不安全行为:
范围
在父图上设置的默认值不会被子图继承。每个图维护自己的默认值。 :::函数式 API
:::python 函数式 API 中的timeout= 和 retry_policy= 参数在 @task 和 @entrypoint 中可用:
add_node 相同:NodeTimeoutError 在超时抛出,缓冲写入被清除,重试策略决定是否重试。
:::js
timeout 选项在 task 和 entrypoint 上可用;task 也接受一个 retry 选项(不是 retryPolicy):
addNode 匹配:NodeTimeoutError 在超时时会触发,缓冲写入会被清除,重试策略决定是否重试。JavaScript/TypeScript SDK 中 task / entrypoint 上不可用错误处理器——请使用 StateGraph.addNode(..., { errorHandler }) 替代。
::~
平稳关闭
协作式关闭允许你在当前超级步骤完成后停止正在运行的图运行,并保存可恢复的检查点。这对于处理 SIGTERM 信号或任何需要回收资源而不丢失工作的外部监督者很有用。 :::python需要
langgraph>=1.2。RunControl] 并将其作为 control= 传递给 invoke 或 stream。从任何线程调用 request_drain() 来指示运行应停止:
需要
@langchain/langgraph>=1.4.0。RunControl] 并将其作为 control 传递给 invoke 或 stream。从任何上下文调用 requestDrain() 来指示运行应停止:
语义
Drain 是协作式的,在超级步骤之间操作,从不抢占已运行的工作: :::python
:::js
Drain 后恢复
:::python 使用invoke(None, config) 继续执行耗尽的运行,使用相同的 thread_id:
invoke(null, config) 继续执行耗尽的运行,使用相同的 thread_id:
在节点内读取耗尽状态
通过runtime 参数访问耗尽状态,在超步边界到达前调整节点行为:
:::python
SIGTERM 钩子模式
处理进程退出的推荐模式: :::pythonrequest_drain() 不会取消正在运行的 asyncio 任务或杀死线程。为了设置一个硬性上限,将 drain 与优雅的超时和任务取消结合使用。requestDrain() 不会取消正在进行的异步任务。为了设置一个硬性上限,请将 drain 与一个优雅的定时器以及一个 AbortSignal 配合使用。限制
:::python-
超时仅支持异步:与
timeout的同步节点在编译时会被拒绝。 -
每个节点最多一个处理器:每个节点最多只能有一个
error_handler。 - 处理器错误向上冒泡:如果错误处理器本身抛出异常,该异常会像节点没有处理器一样传播。
-
set_node_defaults不会被子图继承:每个图独立管理自己的默认值。 ::: -
setNodeDefaults不会被子图继承:每个图独立管理自己的默认值。 -
错误处理器是
StateGraph专属:将errorHandler传递给StateGraph.addNode,而不是基础Graph类。错误处理器在task/entrypoint上不可用。 -
每个节点最多一个处理器:每个节点最多只能有一个
errorHandler。 - 处理器失败会冒泡:如果错误处理器本身抛出异常,该异常会像节点没有处理器一样传播。
官方原文:src/oss/langgraph/fault-tolerance.mdx · 非官方翻译,译文由 AI 生成,以英文原文为准。