中断如何工作
LangGraph 智能体支持中断,即智能体将控制权交还给客户端的显式暂停点。当智能体触发中断时:- 智能体停止执行并发出中断负载
useStream钩子通过stream.interrupt展示中断- 您的 UI 渲染一个带有批准/拒绝/编辑选项的审核卡片
- 用户做出决定
- 您的代码调用
stream.submit()并传递恢复命令 - 智能体从它离开的地方继续执行
设置 useStream
将 useStream 连接到您的人机协作智能体。当图触发中断时,该钩子会在 stream.interrupt 上公开待处理的负载。当该值被设置时,渲染一个批准卡片,然后在用户批准、拒绝或编辑操作后,使用 stream.submit(null, { command: { resume: response } }) 恢复运行。
The code examples use
useStream<typeof myAgent> for type-safe stream state. See Type inference for Python or JavaScript backends.中断负载
当智能体暂停时,stream.interrupt 包含一个 HITLRequest,其结构如下:
决策类型
HITL 模式支持四种决策类型:批准
用户确认操作应按原样继续:拒绝
用户拒绝该操作,并可提供可选原因。工具不会被执行:当操作被拒绝时,智能体会收到拒绝原因,并可以决定如何继续。如果您省略
message,后端将使用默认消息,告知模型工具未被执行,除非用户要求,否则不要重试相同的工具调用。对于有副作用的工具,请传递明确的消息,告知智能体是放弃该操作、提出后续问题还是尝试更安全的替代方案。编辑
用户在批准之前修改操作的参数:回复
用户为“询问用户”类型的工具提供直接回复。message 成为工具结果,工具本身不会被执行:
当工具旨在作为人工输入的占位符时使用
respond,例如一个 ask_user 工具,提示智能体从用户那里收集信息。不要使用 respond 来拒绝提议的操作,因为它会作为成功的工具结果返回给模型。构建 ApprovalCard
以下是审批卡片使用的决策连接。UI 可以将每个操作拆分为自己的卡片,但恢复负载是一个单一的HITLResponse,每个待处理操作对应一个决策:
恢复流程
在用户做出决定后,完整的流程如下:- 调用
stream.submit(null, { command: { resume: hitlResponse } }) useStream钩子将恢复命令发送到 LangGraph 后端- 智能体接收
HITLResponse并继续执行。decisions中的每个条目可能是以下之一:{ type: "approve" }:智能体继续执行该操作{ type: "reject", message }:工具不被执行,智能体在决定下一步之前会收到拒绝消息{ type: "edit", editedAction }:智能体使用编辑后的参数运行工具{ type: "respond", message }:用户的消息直接作为工具结果返回,而不执行工具
interrupt属性在智能体恢复流式传输时重置为null
处理多个待处理操作
当智能体希望同时执行多个操作时,一个中断可以包含多个actionRequests。为每个操作渲染一个卡片,并在恢复之前收集所有决策:
自定义中断表单
恢复流程 使用humanInTheLoopMiddleware,它用一个通用的批准/拒绝/编辑/回复卡片包装一个工具。有时单一的按钮组是不够的:预订航班、批准退款和审核社交媒体帖子各自需要一个不同的表单,具有自己的字段、验证和文案。为此,从工具内部触发 interrupt() 并让负载描述 UI 应该渲染的精确表单。每个工具都可以呈现完全不同的界面。
在中断负载中描述表单
interrupt() 接受任何可 JSON 序列化的值,这允许您提供一个前端知道如何渲染的“卡片”,例如表单类型、标题、人类正在审核的上下文以及要收集的字段。interrupt() 是对其输入和返回类型通用的 (interrupt<I, R>(value: I): R),因此您可以为发送的卡片 (InterruptCard) 和用户用来解析的值 (ReviewDecision) 定义类型。导出这些类型以便前端可以导入并保持同步:
formType(例如 "refund-approval"、"content-review"),以便前端可以切换并渲染匹配的表单。
每个工具渲染不同的表单
在客户端,卡片作为stream.interrupt.value 到达。从您的智能体模块导入 InterruptCard 和 ReviewDecision 类型,以便表单和负载保持同步,根据 formType 切换以选择正确的表单,并将 fields 传递到您的输入中:
使用 respond(decision, { update }) 保持卡片在屏幕上
当您解析一个普通中断时,卡片会在中断清除的瞬间消失,只有工具结果返回。这意味着一个丰富的审核卡片会在运行中途消失。为了保持它在屏幕上,使用 useStream 的 respond 在同一个超步骤中解析中断并提交一条携带卡片的消息到状态:
respond(response, { update }) 会乐观地应用 update:卡片立即绘制,并在恢复的运行回显相同消息后通过 ID 进行协调。后端不会重新发出卡片,因此在(可能较慢的)工具运行期间,它将保持渲染而不闪烁。通过从消息中读回它来渲染解析后的卡片:
最佳实践
实施 HITL 工作流时,请牢记以下准则:- 显示清晰的背景信息。始终显示智能体想要做什么以及为什么。包括操作描述和完整的参数。
- 使批准成为最简单的路径。如果操作看起来正确,批准应该是单击一次。为拒绝/编辑保留多步骤流程。
- 验证编辑后的参数。当用户编辑操作参数时,在发送前验证 JSON 结构。对格式错误的输入显示行内错误。
- 持久化中断状态。如果用户刷新页面,中断应仍然可见。
useStream通过线程的检查点处理此问题。 - 记录所有决策。对于审计跟踪,记录每个批准/拒绝/编辑决策,包括时间戳和做出决策的用户。
- 谨慎设置超时。长时间运行的智能体不应无限期地阻塞在人工审核上。考虑显示智能体已等待了多长时间。
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

