人机协作 #
本文档中引用的文件
目录 #
简介 #
LangGraphGo 提供了强大的人机协作功能,通过动态中断(Dynamic Interrupt)机制实现了灵活的工作流控制。这种机制允许工作流在特定节点处暂停执行,等待人工干预或外部输入,然后从断点恢复执行。这对于需要人工审核、决策或数据输入的业务流程至关重要。
本文档将深入探讨 LangGraphGo 的人机协作功能,重点介绍动态中断机制的实现方式,包括静态中断配置、状态恢复、异常处理等核心概念,并提供实际应用示例和最佳实践建议。
动态中断机制概述 #
动态中断是 LangGraphGo 实现人机协作的核心机制,它允许节点在运行时暂停执行并等待外部输入。与静态中断不同,动态中断可以在节点逻辑内部根据条件决定是否中断。
核心概念 #
flowchart TD
A["节点执行开始"] --> B{"检查中断条件"}
B --> |满足| C["调用 graph.Interrupt()"]
B --> |不满足| D["继续执行"]
C --> E["返回 GraphInterrupt 错误"]
E --> F["捕获中断异常"]
F --> G["保存当前状态"]
G --> H["等待外部输入"]
H --> I["恢复执行"]
I --> J["传递 ResumeValue"]
J --> K["继续节点执行"]
D --> L["节点完成"]
K --> L
图表来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L43-L50)
- [examples/dynamic_interrupt/main.go](https://github.com/smallnest/langgraphgo/blob/main/examples/dynamic_interrupt/main.go#L17-L30)
中断类型 #
LangGraphGo 支持两种主要的中断类型:
- 静态中断(Static Interrupt):通过配置在特定节点前或后暂停
- 动态中断(Dynamic Interrupt):在节点执行过程中根据条件决定是否中断
核心组件架构 #
GraphInterrupt 结构体 #
动态中断的核心是 GraphInterrupt 结构体,它包含了中断发生时的所有关键信息:
classDiagram
class GraphInterrupt {
+string Node
+interface State
+[]string NextNodes
+interface InterruptValue
+Error() string
}
class Config {
+[]string InterruptBefore
+[]string InterruptAfter
+[]string ResumeFrom
+interface ResumeValue
+[]CallbackHandler Callbacks
+map[string]interface Metadata
+[]string Tags
}
class Node {
+string Name
+func(ctx, state) (interface, error) Function
}
GraphInterrupt --> Config : "配置"
GraphInterrupt --> Node : "中断节点"
图表来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L24-L34)
- [graph/callbacks.go](https://github.com/smallnest/langgraphgo/blob/main/graph/callbacks.go#L40-L71)
章节来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L24-L41)
- [graph/callbacks.go](https://github.com/smallnest/langgraphgo/blob/main/graph/callbacks.go#L40-L71)
上下文管理 #
中断机制依赖于上下文(Context)系统来传递恢复值:
sequenceDiagram
participant Node as "节点函数"
participant Context as "上下文"
participant Interrupt as "Interrupt()"
participant Resume as "恢复执行"
Node->>Interrupt : graph.Interrupt(ctx, value)
Interrupt->>Context : 检查 ResumeValue
Context-->>Interrupt : 返回 nil 或 ResumeValue
alt 第一次调用
Interrupt-->>Node : 返回 GraphInterrupt 错误
else 恢复时调用
Interrupt-->>Node : 返回 ResumeValue
end
Node->>Resume : 继续执行
Resume->>Node : 传入 ResumeValue
图表来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L43-L50)
- [graph/context.go](https://github.com/smallnest/langgraphgo/blob/main/graph/context.go#L8-L16)
章节来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L43-L50)
- [graph/context.go](https://github.com/smallnest/langgraphgo/blob/main/graph/context.go#L8-L16)
静态中断配置 #
静态中断通过 Config 结构体中的 InterruptBefore 和 InterruptAfter 字段来配置。
InterruptBefore 配置 #
InterruptBefore 在指定节点执行之前暂停执行:
flowchart LR
A["入口节点"] --> B["检查 InterruptBefore"]
B --> C{"节点在 InterruptBefore 列表中?"}
C --> |是| D["返回 GraphInterrupt"]
C --> |否| E["执行节点"]
E --> F["下一个节点"]
D --> G["捕获中断异常"]
G --> H["保存状态"]
图表来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L238-L246)
InterruptAfter 配置 #
InterruptAfter 在指定节点执行之后暂停执行:
flowchart LR
A["入口节点"] --> B["执行节点"]
B --> C["更新状态"]
C --> D["检查 InterruptAfter"]
D --> E{"节点在 InterruptAfter 列表中?"}
E --> |是| F["返回 GraphInterrupt"]
E --> |否| G["继续执行"]
F --> H["捕获中断异常"]
H --> I["保存状态和 NextNodes"]
图表来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L439-L451)
章节来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L238-L246)
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L439-L451)
动态中断实现 #
动态中断通过 graph.Interrupt() 函数实现,可以在节点内部的任何位置调用。
Interrupt 函数机制 #
flowchart TD
A["graph.Interrupt(ctx, value)"] --> B["检查 ResumeValue"]
B --> C{"ResumeValue 存在?"}
C --> |是| D["返回 ResumeValue"]
C --> |否| E["返回 GraphInterrupt 错误"]
E --> F["设置 InterruptValue"]
F --> G["传播中断异常"]
图表来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L43-L50)
动态中断示例 #
以下是一个典型的动态中断实现模式:
sequenceDiagram
participant Client as "客户端"
participant Node as "节点函数"
participant Interrupt as "Interrupt()"
participant User as "用户输入"
Client->>Node : 开始执行
Node->>Interrupt : graph.Interrupt(ctx, "请输入姓名")
Interrupt-->>Node : 返回 GraphInterrupt 错误
Node-->>Client : 抛出中断异常
Client->>User : 显示提示信息
User->>Client : 输入响应
Client->>Node : 重新执行,带 ResumeValue
Node->>Interrupt : graph.Interrupt(ctx, "Alice")
Interrupt-->>Node : 返回 "Alice"
Node->>Client : 完成执行
图表来源
- [examples/dynamic_interrupt/main.go](https://github.com/smallnest/langgraphgo/blob/main/examples/dynamic_interrupt/main.go#L17-L30)
章节来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L43-L50)
- [examples/dynamic_interrupt/main.go](https://github.com/smallnest/langgraphgo/blob/main/examples/dynamic_interrupt/main.go#L17-L30)
状态恢复机制 #
状态恢复是人机协作的关键功能,确保中断后可以从正确的位置继续执行。
ResumeFrom 配置 #
ResumeFrom 指定从哪个节点开始恢复执行:
flowchart TD
A["捕获 GraphInterrupt"] --> B["提取中断节点"]
B --> C["设置 ResumeFrom"]
C --> D["准备恢复配置"]
D --> E["重新调用 Invoke"]
E --> F["从指定节点开始执行"]
F --> G["继续完整流程"]
图表来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L186-L189)
状态一致性保证 #
LangGraphGo 通过以下机制保证状态一致性:
- 不可变状态设计:状态在节点间传递时保持不可变
- 原子操作:每个节点的执行是原子性的
- 回滚支持:可以通过重新执行恢复到一致状态
sequenceDiagram
participant Original as "原始执行"
participant Interrupt as "中断点"
participant Recovery as "恢复执行"
participant State as "状态管理"
Original->>Interrupt : 执行到中断点
Interrupt->>State : 保存当前状态
State-->>Interrupt : 确认保存
Interrupt-->>Original : 返回中断错误
Recovery->>State : 加载保存的状态
State-->>Recovery : 返回状态快照
Recovery->>Original : 从中断点继续
Original->>State : 更新状态
State-->>Original : 确认更新
图表来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L186-L202)
- [graph/resume_test.go](https://github.com/smallnest/langgraphgo/blob/main/graph/resume_test.go#L45-L56)
章节来源
- [graph/graph.go](https://github.com/smallnest/langgraphgo/blob/main/graph/graph.go#L186-L202)
- [graph/resume_test.go](https://github.com/smallnest/langgraphgo/blob/main/graph/resume_test.go#L45-L56)
实际应用场景 #
审批流程示例 #
以下是基于 examples/human_in_the_loop/main.go 的审批流程实现:
stateDiagram-v2
[*] --> process_request
process_request --> human_approval : 处理完成
human_approval --> finalize : 审批通过
human_approval --> [*] : 审批拒绝
finalize --> [*] : 流程结束
note right of human_approval
此节点配置为 InterruptBefore
等待人工审批
end note
图表来源
- [examples/human_in_the_loop/main.go](https://github.com/smallnest/langgraphgo/blob/main/examples/human_in_the_loop/main.go#L24-L47)
用户界面集成 #
在实际应用中,动态中断通常与用户界面集成:
flowchart TD
A["工作流执行"] --> B["检测到中断"]
B --> C["发送通知给前端"]
C --> D["显示审批界面"]
D --> E["用户输入审批结果"]
E --> F["提交审批结果"]
F --> G["恢复工作流执行"]
G --> H["继续后续步骤"]
章节来源
- [examples/human_in_the_loop/main.go](https://github.com/smallnest/langgraphgo/blob/main/examples/human_in_the_loop/main.go#L24-L47)
高级特性与扩展 #
回调机制 #
LangGraphGo 提供了丰富的回调机制来监控和控制中断过程:
classDiagram
class CallbackHandler {
<<interface>>
+OnChainStart()
+OnChainEnd()
+OnChainError()
+OnToolStart()
+OnToolEnd()
+OnToolError()
}
class GraphCallbackHandler {
<<interface>>
+OnGraphStep(stepNode, state)
}
class Config {
+[]CallbackHandler Callbacks
+map[string]interface Metadata
+[]string Tags
}
CallbackHandler <|-- GraphCallbackHandler
Config --> CallbackHandler : "包含多个"
图表来源
- [graph/callbacks.go](https://github.com/smallnest/langgraphgo/blob/main/graph/callbacks.go#L8-L37)
监听器系统 #
通过监听器系统可以实时监控中断事件:
sequenceDiagram
participant Node as "节点"
participant Listener as "监听器"
participant Handler as "事件处理器"
Node->>Listener : 触发中断事件
Listener->>Handler : OnNodeEvent(event, node, state)
Handler->>Handler : 处理中断逻辑
Handler-->>Listener : 确认处理
Listener-->>Node : 继续执行
图表来源
- [graph/listeners.go](https://github.com/smallnest/langgraphgo/blob/main/graph/listeners.go#L51-L55)
章节来源
- [graph/callbacks.go](https://github.com/smallnest/langgraphgo/blob/main/graph/callbacks.go#L8-L37)
- [graph/listeners.go](https://github.com/smallnest/langgraphgo/blob/main/graph/listeners.go#L51-L55)
生产环境最佳实践 #
超时处理 #
在生产环境中,必须考虑超时处理:
flowchart TD
A["启动工作流"] --> B["设置超时时间"]
B --> C["开始执行"]
C --> D{"超时检查"}
D --> |未超时| E["正常执行"]
D --> |已超时| F["触发超时中断"]
F --> G["记录超时事件"]
G --> H["清理资源"]
H --> I["返回超时错误"]
E --> J["完成执行"]
异常恢复策略 #
flowchart TD
A["捕获异常"] --> B{"异常类型判断"}
B --> |中断异常| C["保存状态"]
B --> |其他异常| D["记录错误"]
C --> E["提供恢复选项"]
E --> F["用户选择恢复方式"]
F --> G{"选择恢复类型"}
G --> |重试| H["重新执行"]
G --> |跳过| I["跳过当前节点"]
G --> |终止| J["终止流程"]
H --> K["继续执行"]
I --> K
J --> L["清理资源"]
安全考量 #
- 访问控制:确保只有授权用户可以恢复中断的工作流
- 审计日志:记录所有中断和恢复操作
- 状态验证:验证恢复时的状态完整性
- 并发控制:防止并发恢复导致的状态冲突
章节来源
- [graph/callbacks.go](https://github.com/smallnest/langgraphgo/blob/main/graph/callbacks.go#L57-L58)
- [graph/listeners.go](https://github.com/smallnest/langgraphgo/blob/main/graph/listeners.go#L128-L157)
故障排除指南 #
常见问题及解决方案 #
| 问题类型 | 症状 | 可能原因 | 解决方案 |
|---|---|---|---|
| 中断未触发 | 工作流正常完成 | 配置错误或条件不满足 | 检查 InterruptBefore/After 配置 |
| 恢复失败 | 恢复时出现错误 | 状态不一致或节点不存在 | 验证状态和节点配置 |
| 死锁 | 工作流无法继续 | 循环依赖或条件错误 | 检查节点依赖关系 |
| 性能问题 | 中断处理缓慢 | 监听器过多或回调复杂 | 优化回调逻辑 |
调试技巧 #
- 启用详细日志:使用监听器记录详细的执行信息
- 状态快照:在关键节点保存状态快照
- 单元测试:为中断逻辑编写专门的测试
- 可视化工具:使用图形化工具查看工作流状态
章节来源
- [graph/interrupt_test.go](https://github.com/smallnest/langgraphgo/blob/main/graph/interrupt_test.go#L10-L64)
- [graph/resume_test.go](https://github.com/smallnest/langgraphgo/blob/main/graph/resume_test.go#L10-L82)
总结 #
LangGraphGo 的人机协作功能通过动态中断机制提供了强大而灵活的工作流控制能力。主要特点包括:
- 双重中断机制:同时支持静态和动态中断,适应不同的应用场景
- 完善的状态管理:确保中断和恢复过程中的状态一致性
- 丰富的扩展性:通过回调和监听器系统提供高度可定制的功能
- 生产就绪特性:包含超时处理、异常恢复和安全考量
这些特性使得 LangGraphGo 成为构建复杂业务流程的理想选择,特别是在需要人工干预或外部数据输入的场景中。通过合理使用这些功能,开发者可以构建既高效又灵活的人机协作系统。