interrupt() 函数来工作。该函数接受任何可 JSON 序列化的值,该值会暴露给调用者。当你准备好继续时,通过使用 Command 重新调用图来恢复执行,该 Command 会成为节点内部 interrupt() 调用的返回值。
与静态断点(在特定节点前后暂停)不同,中断是动态的:它们可以放在代码的任何位置,并且可以根据你的应用逻辑设置条件。
- 检查点会保留你的位置: 检查点记录器会写入精确的图状态,以便你稍后恢复,即使处于错误状态也是如此。
thread_id是你的指针: 在invoke方法的选项中设置{ configurable: { thread_id: ... } }来告诉检查点记录器加载哪个状态。- 中断的有效负载通过
__interrupt__暴露: 你传递给interrupt()的值会在__interrupt__字段中返回给调用者,这样你就知道图在等待什么。
thread_id 实际上就是你持久化的游标。重用该 ID 会恢复同一个检查点;使用新值则会启动一个全新的线程,状态为空。
使用 interrupt 暂停
interrupt 函数会暂停图的执行并将一个值返回给调用者。当你在节点内调用 interrupt 时,LangGraph 会保存当前的图状态并等待你使用输入来恢复执行。
要使用 interrupt,你需要:
- 一个检查点记录器来持久化图状态(生产环境中应使用持久化的检查点记录器)
- 在配置中提供一个线程 ID,以便运行时知道从哪个状态恢复
- 在你希望暂停的位置调用
interrupt()(有效负载必须是 JSON 可序列化的)
interrupt 时,会发生以下情况:
-
图的执行在调用
interrupt的准确位置被挂起 - 使用检查点记录器保存状态,以便稍后恢复执行。在生产环境中,这应当是一个持久化的检查点记录器(例如由数据库支持)
-
值被返回给调用者,出现在
__interrupt__下;它可以是任何 JSON 可序列化的值(字符串、对象、数组等) - 图无限期等待,直到你使用响应恢复执行
-
当你恢复时,响应会传回节点,成为
interrupt()调用的返回值
恢复中断
中断暂停执行后,你可以通过使用包含恢复值的Command 再次调用图来恢复它。这个恢复值会被传递回 interrupt 调用,使得节点能够使用外部输入继续执行。
- 恢复时,你必须使用与触发中断时相同的线程 ID
- 传递给
new Command({ resume: ... })的值会成为interrupt调用的返回值 - 恢复时,节点会从调用
interrupt的节点开头重新开始执行,因此interrupt之前的任何代码都会再次运行 - 你可以将任何 JSON 可序列化的值作为恢复值传递
常见模式
中断所解锁的核心能力是能够暂停执行并等待外部输入。这对于多种用例都很有用,包括:- 审批工作流:在执行关键操作(API 调用、数据库更改、金融交易)前暂停
- 处理多个中断:在单次调用中恢复多个中断时,将中断 ID 与恢复值配对
- 审查与编辑:在继续之前,让人类审查并修改 LLM 输出或工具调用
- 在工具中中断:在执行工具调用前暂停,以便在执行前审查并编辑工具调用
- 验证人类输入:在进入下一步前暂停,以验证人类输入
使用人工介入(HITL)中断进行流式处理
在构建具有人工介入工作流的交互式智能体时,你可以使用事件流在循环中并发消费消息块和状态快照,同时处理中断。 在循环中使用graph.stream_events(..., version="v3") 返回的类型化投影,直到运行完成:
- 通过
stream.messages逐令牌地流式传输 AI 响应 - 通过
stream.values观察每一步的状态快照 - 通过
stream.interrupted检测中断,并从stream.interrupts读取其有效负载 - 通过再次调用
stream_events并传入Command(resume=...)来恢复执行,并重复此过程直到stream.interrupted为 false
stream.messages: 以内容块形式输出的聊天模型输出;迭代message.text以获取令牌差异。对于嵌套子图,从stream.subgraphs[*].messages读取消息块。stream.values: 每一步之后完整的状态快照stream.interrupted/stream.interrupts: 每次运行后,检查图是否暂停;从stream.interrupts读取有效负载Command(resume=...): 作为下一个streamEvents输入传递以恢复执行;循环直到运行完成且不再中断
处理多个中断
当并行分支同时中断时(例如,扇出到多个节点,每个节点都调用interrupt()),你可能需要在一次调用中恢复多个中断。
在单次调用中恢复多个中断时,将每个中断 ID 映射到其恢复值。
这可以确保每个响应在运行时与正确的中断配对。
批准或拒绝
中断最常见的用途之一是在关键操作前暂停并请求批准。例如,你可能希望让人类批准 API 调用、数据库更改或任何其他重要决策。true 表示批准,传递 false 表示拒绝:
完整示例
完整示例
审查和编辑状态
有时,你希望让人类在继续之前审查并编辑图状态的某一部分。这对于纠正 LLM 输出、添加缺失信息或进行调整非常有用。完整示例
完整示例
工具中的中断
你也可以直接在工具函数内部放置中断。这使得工具在被调用时自身会暂停以等待批准,并允许在工具调用执行之前进行人工审查和编辑。 首先,定义一个使用interrupt 的工具:
完整示例
完整示例
验证人类输入
有时你需要验证人类的输入,如果无效则再次询问。你可以通过在一个循环中使用多个interrupt 调用来实现这一点。
完整示例
完整示例
中断的规则
当你在节点内调用interrupt 时,LangGraph 会通过抛出一个特殊异常来挂起执行,该异常通知运行时暂停。该异常会沿着调用堆栈向上传播,并被运行时捕获,运行时通知图保存当前状态并等待外部输入。
当执行恢复时(在你提供所需的输入之后),运行时从头重新开始整个节点——它不会从调用 interrupt 的确切行恢复。这意味着在 interrupt 之前运行的任何代码都将再次执行。因此,在使用中断时,需要遵循一些重要的规则,以确保它们按预期工作。
不要将 interrupt 调用包裹在 try/catch 中
interrupt 通过在调用点抛出一个特殊异常来暂停执行。如果你将 interrupt 调用包裹在 try/catch 块中,你会捕获这个异常,中断将不会传回给图。
- ✅ 将
interrupt调用与容易出错的代码分开 - ✅ 如有需要,有条件地捕获错误
- 🔴 不要将
interrupt调用包裹在裸 try/catch 块中
不要重新排序节点内的 interrupt 调用
在单个节点内使用多个中断是很常见的,但如果不小心处理,可能会导致意外行为。
当一个节点包含多个中断调用时,LangGraph 会维护一个特定于执行该节点的任务的恢复值列表。每当执行恢复时,它都会从节点的开头开始。对于遇到的每个中断,LangGraph 都会检查任务的恢复列表中是否存在匹配的值。匹配是严格基于索引的,因此节点内中断调用的顺序很重要。
- ✅ 保持
interrupt调用在节点执行之间一致
不要在 interrupt 调用中返回复杂的值
根据所使用的检查点记录器,复杂的值可能无法序列化(例如,你无法序列化一个函数)。为了使你的图能够适应任何部署,最佳实践是仅使用可以合理序列化的值。
- ✅ 向
interrupt传递简单的、可 JSON 序列化的类型 - ✅ 传递包含简单值的字典/对象
- 🔴 不要向
interrupt传递函数、类实例或其他复杂对象
interrupt 之前调用的副作用必须是幂等的
由于中断会重新运行调用它们的节点,因此在 interrupt 之前调用的副作用(理想情况下)应该是幂等的。作为背景,幂等性意味着同一个操作可以被多次应用,而不会改变初始执行之外的结果。
例如,你可能会在节点内部有一个更新记录的 API 调用。如果在该调用之后又调用了 interrupt,那么当节点恢复时,该调用会被多次重新运行,可能会覆盖初始更新或创建重复记录。
- 🔴 不要在
interrupt之前执行非幂等的操作 - 🔴 不要在未检查记录是否存在的情况下创建新记录
与作为函数调用的子图一起使用
当在节点内调用子图时,父图将从调用子图并且触发interrupt 的节点的开头恢复执行。同样,子图也将从调用 interrupt 的节点开头恢复。
使用中断进行调试
要调试和测试图,你可以使用静态中断作为断点,一次一个节点地单步通过图执行。静态中断是在节点执行之前或之后的已定义点触发的。你可以在编译图时通过指定interruptBefore 和 interruptAfter 来设置它们。
静态中断不推荐用于人工介入工作流。请改用
interrupt 函数。- 编译时设置
- 运行时设置
- 断点在
compile时设置。 interruptBefore指定在节点执行之前应暂停的节点。interruptAfter指定在节点执行之后应暂停的节点。- 需要使用检查点记录器来启用断点。
- 图运行直到遇到第一个断点。
- 通过传入
null作为输入来恢复图。这将运行图直到遇到下一个断点。
使用 LangSmith Studio
你可以使用 LangSmith Studio 在 UI 中为你的图设置静态中断,然后再运行图。你也可以使用 UI 在执行中的任意点检查图状态。
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

