🔧 LangGraph 实战:用动态断点实现「可中断、可恢复」的智能工作流

💡 一句话总结:NodeInterrupt + MemorySaver = 让 AI 工作流学会「暂停思考」和「人工介入」


🎯 为什么需要动态断点?

在传统的工作流引擎中,流程一旦启动就会一路执行到底。但在真实的 AI 应用场景中,我们常常需要:

  • 🔍 人工审核:敏感内容生成后暂停,等待人工确认
  • 🔄 动态决策:根据中间结果决定下一步走哪条分支
  • 🛑 异常拦截:输入不符合预期时及时中断,避免资源浪费
  • 💾 状态持久:服务重启后能从断点继续,不丢失进度

LangGraph 的 NodeInterrupt 机制,正是为解决这些问题而生。


🧩 代码拆解:三步构建可中断工作流

📦 第一步:定义状态结构

1
2
3
4
from typing_extensions import TypedDict

class State(TypedDict):
input: str # 输入字符串

✨ 使用 TypedDict 保证类型安全,让状态流转更清晰可控。


⚙️ 第二步:编写含断点逻辑的节点

1
2
3
4
5
6
7
8
9
from langgraph.errors import NodeInterrupt

def step_2(state: State) -> State:
# 🎯 动态断点:输入长度 > 5 时中断
if len(state['input']) > 5:
raise NodeInterrupt(f"输入过长: {state['input']}")

print("---Step 2---")
return state

🔑 核心技巧:在任意节点中抛出 NodeInterrupt 异常,即可触发工作流暂停,且自动保存当前状态。


🔗 第三步:构建图 + 启用记忆检查点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver

# 构建图
builder = StateGraph(State)
builder.add_node("step_1", step_1)
builder.add_node("step_2", step_2) # 含断点
builder.add_node("step_3", step_3)
builder.add_edge(START, "step_1")
builder.add_edge("step_1", "step_2")
builder.add_edge("step_2", "step_3")
builder.add_edge("step_3", END)

# 🧠 启用 MemorySaver:支持中断后恢复
memory = MemorySaver()
graph = builder.compile(checkpointer=memory)

🗂️ MemorySaver 是 LangGraph 的「记忆中枢」,负责持久化每个线程的状态,让「暂停 - 修改 - 继续」成为可能。


🔄 执行流程演示:中断 → 查看 → 修复 → 继续

🚨 场景:输入 "hello world"(11字符)触发断点

1
2
3
4
5
6
initial_input = {"input": "hello world"}
thread_config = {"configurable": {"thread_id": "1"}}

# 执行到 step_2 时自动中断
for event in graph.stream(initial_input, thread_config, stream_mode="values"):
print(f"状态更新: {event}")

输出

1
2
---Step 1---
状态更新: {'input': 'hello world'}

✅ 此时工作流暂停在 step_2,状态已自动保存,等待人工干预。


🔍 查看中断详情

1
2
3
state = graph.get_state(thread_config)
print(f"下一个节点: {state.next}") # 输出: step_2
print(f"中断信息: {state.tasks[0].interrupts}")

📋 可获取:当前节点、中断原因、任务状态等,便于前端展示或日志记录。


🛠️ 修复状态:修改输入,绕过断点

1
2
3
4
5
# 将长输入替换为短输入
graph.update_state(
thread_config,
{"input": "hi"} # 2字符,满足条件
)

💡 update_state 是「人工介入」的关键 API,允许你在中断点修改状态,实现动态纠偏。


▶️ 恢复执行:从断点继续

1
2
3
# 传入 None 表示从上次中断处继续
for event in graph.stream(None, thread_config, stream_mode="values"):
print(f"状态更新: {event}")

输出

1
2
3
4
---Step 2---
状态更新: {'input': 'hi'}
---Step 3---
状态更新: {'input': 'hi'}

🎉 工作流顺利走完剩余节点,全程状态无缝衔接!


🧠 核心知识点总结

概念 作用 关键代码
NodeInterrupt 动态中断工作流 raise NodeInterrupt("msg")
MemorySaver 持久化线程状态 compile(checkpointer=memory)
thread_id 隔离不同执行实例 {"configurable": {"thread_id": "1"}}
update_state 人工修改中断状态 graph.update_state(config, new_values)
stream(None, ...) 从断点恢复执行 传入 None 作为输入

🌰 实际应用场景推荐

✅ 场景 1:内容审核工作流

1
用户输入 → 敏感词检测 → [中断] → 人工审核 → 继续生成 → 输出

✅ 场景 2:多轮决策代理

1
收集信息 → 判断是否足够 → [中断] → 请求用户补充 → 继续推理 → 给出建议

✅ 场景 3:长任务分步执行

1
数据预处理 → 模型推理 → [中断] → 人工校验中间结果 → 后处理 → 输出报告

💡 所有需要「人在环路(Human-in-the-loop)」的场景,都是 NodeInterrupt 的用武之地。


🎨 视觉化建议(公众号配图思路)

📌 根据技术博客美学偏好,推荐以下插图风格:

  1. 流程图插画

    • 风格:扁平化矢量 + 科技蓝/电光青配色
    • 内容:用箭头连接 START → step_1 → step_2(⚠️) → step_3 → END,在 step_2 添加「暂停」图标和「人工介入」气泡
  2. 状态机示意图

    • 风格:3D 等距 + 发光节点
    • 内容:展示 input: "hello world" 触发中断 → update_state 修改 → 继续执行的三阶段状态变化
  3. 架构组件图

    • 风格:赛博朋克线框 + 脉冲光效
    • 内容:LangGraph Engine 居中,连接 MemorySaver(数据库图标)、NodeInterrupt(警示灯)、Human UI(用户头像)

🖼️ 可使用 Mermaid 快速生成基础流程图,再用 Figma/Illustrator 添加品牌视觉元素。


📚 延伸学习