尊敬的各位专家、开发者们:
欢迎来到今天的讲座,我们将深入探讨LangGraph框架中一个至关重要且极具实践价值的特性——“中断”(Interrupts)。在构建复杂的AI Agent系统时,我们常常需要赋予Agent强大的自动化能力,但同时,也必须警惕自动化可能带来的风险,尤其是在执行“危险”或不可逆操作(如发送邮件、修改数据库、调用外部API)之前。今天的核心议题,就是如何在这些关键时刻,强制LangGraph图进入挂起状态,以便人工审查、确认或干预,从而实现Agent与人类的无缝、安全的协作。
第一章:引言 – LangGraph与自动化决策的挑战
LangGraph,作为LangChain生态系统中的核心组件,为构建有状态、多步骤的AI Agent提供了强大的图形化编程模型。它允许开发者通过定义节点(代表Agent的动作或思考步骤)和边(代表状态流转的逻辑),来编排复杂的决策链和任务流程。其核心优势在于能够管理Agent的内部状态,并在不同步骤间传递信息,从而实现长期记忆和复杂推理。
然而,随着Agent能力的增强,其自动化执行的范围也随之扩大。想象一个Agent,它能够根据收到的信息自动回复邮件、预订会议、甚至执行财务操作。这些能力固然强大,但也伴随着巨大的风险。一个错误的决策,一次未经审查的自动操作,都可能导致严重的后果。例如:
- 发送邮件: 邮件内容不准确、收件人错误、发送时机不当。
- 数据库操作: 错误地修改或删除了重要数据。
- API调用: 触发了昂贵或不可逆的外部服务。
- 资金转移: 授权了错误的金额或账户。
在这些场景下,我们迫切需要一个机制,允许系统在执行危险操作前“暂停”,将控制权交还给人类用户进行最终确认。这不仅是出于安全考虑,也是为了在自动化与人工监督之间找到最佳平衡点,让AI成为更可靠的助手,而非失控的自动化机器。LangGraph的“中断”机制,正是解决这一挑战的利器。
第二章:LangGraph的挂起机制:Interrupts与Checkpoints
LangGraph的核心是一个状态机,它根据定义的图结构,一步步地处理输入,更新内部状态,并产生输出。为了实现中断和恢复,LangGraph依赖于两个关键概念:中断(Interrupts) 和 检查点(Checkpoints)。
2.1 LangGraph的运行模型与状态管理
在LangGraph中,每次图的执行都伴随着一个可变的GraphState对象。这个状态在节点之间传递,每个节点接收当前状态,执行逻辑,然后返回更新后的状态。这种有状态的特性是构建复杂Agent的基础。
一个典型的LangGraph执行流程如下:
- 初始化: 创建
GraphState的初始实例。 - 输入处理: 将外部输入合并到
GraphState中。 - 节点执行: 根据图的定义,选择并执行当前节点。
- 状态更新: 节点执行的结果用于更新
GraphState。 - 边评估: 根据更新后的状态,评估出下一条要执行的边和节点。
- 循环: 重复步骤3-5,直到达到
END节点或触发中断。
这个过程中,如果我们需要在某个点暂停执行,并能够稍后从该点恢复,那么就必须将当前的状态持久化下来。
2.2 持久化基石:Checkpoints (检查点)
检查点是LangGraph实现中断和恢复的基础。它允许我们将图在任意时刻的完整状态(包括所有节点执行的历史、当前的状态变量等)保存到一个持久化存储中。
工作原理:
当你使用Graph.invoke()或Graph.stream()方法时,可以传递一个config字典,其中包含一个configurable键。在这个configurable键下,可以指定一个checkpoint_id。如果提供了checkpoint_id,LangGraph会在每次状态更新时,自动将当前状态保存到配置的持久化存储中(例如SqliteSaver)。
默认与自定义持久化:
LangGraph提供了一个默认的SqliteSaver,它将检查点存储在一个SQLite数据库文件中。这对于开发和测试非常方便。在生产环境中,你可能需要使用更健壮的持久化方案,如RedisSaver、PostgresSaver等。
示例:配置SqliteSaver
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.sqlite import SqliteSaver
from typing import TypedDict, Annotated, List, Dict
import operator
# 定义图的状态
class AgentState(TypedDict):
current_task: str
email_subject: str
email_recipient: str
email_body: str
needs_confirmation: bool
is_confirmed: Annotated[bool, operator.attrgetter("is_confirmed")] # 使用Annotated标记为可更新
# 配置持久化器
memory = SqliteSaver.from_file("langgraph_checkpoints.sqlite")
2.3 显式中断:graph.interrupt()方法
LangGraph提供了一个直接的方法来中断正在进行的执行:graph.interrupt()。虽然这个方法通常不直接在图的节点逻辑中调用(因为节点逻辑应是纯函数,不应包含外部副作用),但在外部系统需要强制停止一个运行中的图时非常有用,例如在调试、用户取消操作或资源耗尽等场景。
然而,对于我们今天讨论的“危险操作前强制挂起”场景,我们更倾向于在图的逻辑内部,通过条件判断来触发一个“逻辑中断”,即引导图进入一个等待人工干预的状态,而不是粗暴地终止执行。
2.4 隐式中断:通过条件路由实现挂起
在图的节点内部,我们通常不会直接调用graph.interrupt()。更常见且更灵活的做法是,在发现需要人工干预时,让当前节点返回一个特定的状态标志,并通过条件边将图的执行流路由到一个“等待确认”的逻辑分支。当图进入这个分支,并且没有后续的自动化节点来处理,那么图就会自然地在最后一次状态更新后停止,等待外部系统通过修改状态来“恢复”它。
这是实现“危险操作前挂起”的核心策略。
2.5 查看和恢复挂起状态
当图被中断或自然停止在一个需要人工干预的状态时,我们可以通过检查点系统来查看其状态,并在人工干预后恢复执行。
获取可达状态:graph.get_reachable_states()
这个方法允许你获取指定检查点ID下所有可能的(通常只有一个)最新状态。它返回一个字典,其中键是thread_id(对于单线程执行通常是None),值是ThreadState对象,包含了完整的图运行历史和当前状态。
# 假设我们有一个checkpoint_id
checkpoint_id = {"thread_id": "email_workflow_123"}
# 获取最新状态
latest_checkpoint = memory.get(checkpoint_id)
if latest_checkpoint:
print(f"Latest state for thread {checkpoint_id['thread_id']}:")
print(latest_checkpoint.current_state) # current_state是AgentState的实例
else:
print(f"No checkpoint found for thread {checkpoint_id['thread_id']}")
恢复执行:graph.invoke()或graph.stream()配合checkpoint
恢复执行的关键在于,在调用invoke或stream时,传入之前保存的checkpoint_id。LangGraph会从该检查点加载状态,并从上次停止的地方继续执行。
更进一步,如果我们需要在恢复前修改状态(例如,将is_confirmed设置为True),我们可以先加载状态,修改它,然后通过graph.update_state()将修改后的状态写回检查点,最后再通过invoke或stream从这个新的检查点开始执行。
# 假设我们已经获取了 latest_checkpoint
# 模拟人工确认,修改状态
modified_state = latest_checkpoint.current_state.copy()
modified_state["is_confirmed"] = True
# 更新检查点状态
memory.update(checkpoint_id, modified_state)
# 从更新后的检查点恢复执行
final_state = app.invoke({"input": "resume"}, config={"configurable": checkpoint_id})
第三章:架构一个带中断的LangGraph
现在,我们来设计一个具体的LangGraph架构,用于实现“危险操作前挂起”的需求。我们将以“邮件发送确认”为例。
3.1 核心思想:在危险操作前插入“决策节点”
为了实现中断,我们需要在执行实际的危险操作(例如发送邮件)之前,插入一个特殊的“决策节点”。这个节点负责检查是否需要人工确认。如果需要,它将图的状态调整为“待确认”模式,并引导图的执行流进入一个“挂起”状态。
关键组件:
- GraphState设计: 包含所有必要的业务数据,以及用于控制中断流程的标志。
- 准备节点: 负责收集或生成危险操作所需的所有数据。
- 决策/检查节点: 核心中断逻辑所在。它根据
GraphState中的标志来决定是继续执行还是挂起。 - 危险操作节点: 实际执行危险操作的节点。
- 恢复输入/外部机制: 虽然不是图的一部分,但需要一个外部机制来接收人工确认,并更新图的状态以允许恢复。
3.2 GraphState设计
为了支持中断和恢复,我们的GraphState需要包含以下信息:
- 业务数据: 邮件的主题、收件人、内容等。
- 中断标志:
needs_confirmation: bool:指示是否需要人工确认。这通常在业务逻辑中设定。is_confirmed: bool:指示是否已经通过人工确认。这是外部系统修改以恢复图的关键。action_details: Dict:存储待确认操作的详细信息,方便人工审查。
from typing import TypedDict, Annotated, List, Dict
import operator
# 定义图的状态
class EmailAgentState(TypedDict):
current_step: str # 用于跟踪当前所处的步骤,方便调试
email_subject: str
email_recipient: str
email_body: str
needs_confirmation: bool # 业务逻辑判断是否需要确认
is_confirmed: Annotated[bool, operator.attrgetter("is_confirmed")] # 人工确认状态
error_message: str # 错误信息,如果有的话
# 初始化一个空的状态,方便后续合并
initial_state = EmailAgentState(
current_step="start",
email_subject="",
email_recipient="",
email_body="",
needs_confirmation=False,
is_confirmed=False,
error_message=""
)
3.3 节点设计与实现
我们将创建三个核心节点:
generate_email_draft_node: 模拟生成邮件草稿。check_confirmation_status_node: 检查是否需要确认以及是否已确认。这是触发中断的核心。send_email_node: 模拟发送邮件。
节点 1: generate_email_draft_node
这个节点负责根据某种输入(例如用户请求)生成邮件的草稿。在这个示例中,我们直接模拟生成。为了演示中断,我们在这里将needs_confirmation设置为True。
def generate_email_draft_node(state: EmailAgentState) -> EmailAgentState:
print(f"--- Node: generate_email_draft_node --- (Current step: {state['current_step']})")
# 模拟LLM生成邮件草稿
subject = "重要通知:关于系统维护的更新"
recipient = "[email protected]"
body = "尊敬的团队成员,我们计划在今晚进行系统维护,预计影响时间为2小时。请提前做好准备。谢谢。nn此邮件内容由AI助手生成。"
print(f"Generated Draft: To: {recipient}, Subject: {subject}")
# 将状态更新为需要确认
return EmailAgentState(
current_step="email_draft_generated",
email_subject=subject,
email_recipient=recipient,
email_body=body,
needs_confirmation=True, # 明确标记需要人工确认
is_confirmed=False # 初始未确认
)
节点 2: check_confirmation_status_node (核心中断逻辑)
这个节点是整个中断机制的核心。它会根据needs_confirmation和is_confirmed两个标志来决定图的下一步走向。
- 如果
needs_confirmation为True且is_confirmed为False:这意味着操作需要人工确认,但尚未得到确认。此时,节点会返回一个特殊值(或更新状态使其满足条件边),将图引导至一个“等待”状态。图将在此处停止,等待外部干预。 - 如果
needs_confirmation为False或is_confirmed为True:这意味着要么不需要确认,要么已经确认。图可以继续执行。
def check_confirmation_status_node(state: EmailAgentState) -> EmailAgentState:
print(f"--- Node: check_confirmation_status_node --- (Current step: {state['current_step']})")
if state["needs_confirmation"] and not state["is_confirmed"]:
print("ACTION REQUIRED: Email draft needs human confirmation before sending.")
# 这里,我们不直接引发Python的Exception,而是返回一个状态,
# 让条件边来决定下一步是挂起还是继续。
# LangGraph在默认情况下,当没有后续的边可走时,就会自然停止。
# 我们也可以更新current_step来明确表示等待
return EmailAgentState(
current_step="awaiting_confirmation",
email_subject=state["email_subject"],
email_recipient=state["email_recipient"],
email_body=state["email_body"],
needs_confirmation=True,
is_confirmed=False
)
else:
print("Confirmation check passed. Proceeding with action.")
return EmailAgentState(
current_step="confirmation_passed",
email_subject=state["email_subject"],
email_recipient=state["email_recipient"],
email_body=state["email_body"],
needs_confirmation=state["needs_confirmation"],
is_confirmed=state["is_confirmed"]
)
# 定义一个路由函数,根据current_step来决定下一步
def route_on_confirmation(state: EmailAgentState) -> str:
if state["current_step"] == "awaiting_confirmation":
return "await_input" # 一个虚拟的“等待”路径,实际上会导致图在此处停止
elif state["current_step"] == "confirmation_passed":
return "send_email"
else:
# 如果不是这两个状态,说明是初始状态,或者其他非预期状态
# 我们可以根据业务逻辑选择抛出错误或进入默认路径
print(f"Routing error: Unexpected current_step: {state['current_step']}")
return "error_path" # 或者直接END
节点 3: send_email_node
这个节点模拟实际的邮件发送操作。只有当check_confirmation_status_node允许通过后,才会执行到这里。
def send_email_node(state: EmailAgentState) -> EmailAgentState:
print(f"--- Node: send_email_node --- (Current step: {state['current_step']})")
if state["is_confirmed"]:
print(f"Sending Email:")
print(f" To: {state['email_recipient']}")
print(f" Subject: {state['email_subject']}")
print(f" Body:n{state['email_body']}")
print("Email sent successfully!")
return EmailAgentState(
current_step="email_sent",
email_subject=state["email_subject"],
email_recipient=state["email_recipient"],
email_body=state["email_body"],
needs_confirmation=state["needs_confirmation"],
is_confirmed=state["is_confirmed"]
)
else:
# 理论上,如果is_confirmed为False,不应该走到这里
print("Error: Attempted to send email without confirmation.")
return EmailAgentState(
current_step="send_error",
error_message="Email not confirmed, cannot send.",
email_subject=state["email_subject"],
email_recipient=state["email_recipient"],
email_body=state["email_body"],
needs_confirmation=state["needs_confirmation"],
is_confirmed=state["is_confirmed"]
)
3.4 图的构建与边定义
现在,我们将这些节点组合成一个LangGraph图。
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.sqlite import SqliteSaver
# 配置持久化器
memory = SqliteSaver.from_file("langgraph_checkpoints.sqlite")
# 构建LangGraph
workflow = StateGraph(EmailAgentState)
# 添加节点
workflow.add_node("generate_draft", generate_email_draft_node)
workflow.add_node("check_confirmation", check_confirmation_status_node)
workflow.add_node("send_email", send_email_node)
# 设置入口点
workflow.set_entry_point("generate_draft")
# 添加边
workflow.add_edge("generate_draft", "check_confirmation")
# 添加条件边:根据check_confirmation_status_node的输出路由
workflow.add_conditional_edges(
"check_confirmation",
route_on_confirmation, # 使用路由器函数
{
"await_input": END, # 如果需要等待,图在此处自然停止,因为没有后续节点
"send_email": "send_email",
"error_path": END # 错误路径也结束
}
)
# 邮件发送成功后结束
workflow.add_edge("send_email", END)
# 编译图
app = workflow.compile(checkpointer=memory)
print("LangGraph workflow compiled successfully.")
第四章:实践案例:邮件发送确认系统演示
现在我们来演示这个邮件发送确认系统的工作流程。
4.1 首次运行:触发中断
第一次运行,我们期望图在check_confirmation节点处挂起,因为needs_confirmation被设置为True,而is_confirmed是False。
import uuid
# 为每次运行生成一个唯一的检查点ID
# 在实际应用中,这可能是用户的Session ID或任务ID
thread_id = str(uuid.uuid4())
checkpoint_config = {"configurable": {"thread_id": thread_id}}
print(f"n--- Starting First Run (Thread ID: {thread_id}) ---")
print("Expecting interruption for confirmation.")
try:
# 第一次invoke,此时is_confirmed为False
# 我们不需要传递任何input,因为generate_draft不依赖外部input
# 或者可以传递一个空字典,表示触发初始流程
for s in app.stream({"input": "start_email_workflow"}, checkpoint_config):
print(s)
print("-" * 20)
except Exception as e:
# LangGraph在没有后续路由时会自然停止,而不是抛出中断异常
print(f"Graph execution stopped as expected. Reason: {e}")
print("n--- First Run Completed/Interrupted ---")
print("Graph should now be awaiting confirmation.")
预期输出分析:
在generate_email_draft_node执行后,needs_confirmation会被设置为True。
接着check_confirmation_status_node会发现needs_confirmation为True且is_confirmed为False,因此它会打印“ACTION REQUIRED”并更新current_step为awaiting_confirmation。
route_on_confirmation函数会根据current_step路由到await_input,而await_input被映射到END。这意味着图会在check_confirmation节点处理完后停止,状态被保存到检查点。
4.2 获取挂起状态并模拟人工确认
图现在处于挂起状态。我们需要通过检查点加载其最新状态,模拟人工确认,然后更新状态。
print(f"n--- Retrieving State for Thread ID: {thread_id} ---")
# 获取当前线程的最新检查点状态
latest_checkpoint_state = memory.get(checkpoint_config["configurable"])
if latest_checkpoint_state:
print(f"Current State before confirmation:")
# latest_checkpoint_state.current_state 是EmailAgentState类型
print(f" current_step: {latest_checkpoint_state.current_state['current_step']}")
print(f" email_subject: {latest_checkpoint_state.current_state['email_subject']}")
print(f" needs_confirmation: {latest_checkpoint_state.current_state['needs_confirmation']}")
print(f" is_confirmed: {latest_checkpoint_state.current_state['is_confirmed']}")
# 模拟人工审查后,用户点击“确认发送”
print("n--- Simulating Human Confirmation ---")
# 创建一个修改后的状态副本
confirmed_state = latest_checkpoint_state.current_state.copy()
confirmed_state["is_confirmed"] = True
confirmed_state["current_step"] = "human_confirmed" # 更新步骤,方便追踪
# 将修改后的状态保存回检查点
# 注意:这里我们使用memory.update来直接修改检查点状态
# 也可以通过app.invoke(..., config={"configurable": checkpoint_config, "resume_at": "checkpoint_id", "state": confirmed_state})
# 但直接update更清晰地表达了外部干预
memory.update(checkpoint_config["configurable"], confirmed_state)
print("State updated: is_confirmed set to True.")
else:
print("Error: No checkpoint state found for the given thread ID.")
4.3 恢复运行:完成邮件发送
现在状态已经被更新为is_confirmed: True。我们可以再次调用app.stream(),LangGraph将从保存的检查点(现在已包含更新后的is_confirmed)恢复执行。
print(f"n--- Resuming Run (Thread ID: {thread_id}) ---")
print("Expecting email to be sent.")
try:
# 恢复执行。LangGraph会从上次停止的地方(check_confirmation后)加载状态继续
# 此时,check_confirmation会发现is_confirmed为True,从而路由到send_email
for s in app.stream({"input": "resume_workflow"}, checkpoint_config):
print(s)
print("-" * 20)
except Exception as e:
print(f"Graph execution finished. Reason: {e}")
print("n--- Second Run Completed ---")
# 验证最终状态
final_checkpoint_state = memory.get(checkpoint_config["configurable"])
if final_checkpoint_state:
print(f"nFinal State for Thread {thread_id}:")
print(f" current_step: {final_checkpoint_state.current_state['current_step']}")
print(f" is_confirmed: {final_checkpoint_state.current_state['is_confirmed']}")
print(f" email_subject: {final_checkpoint_state.current_state['email_subject']}")
else:
print("Error: Final checkpoint state not found.")
预期输出分析:
图会从check_confirmation节点恢复。由于is_confirmed现在是True,check_confirmation_status_node会允许执行继续。route_on_confirmation会路由到send_email节点。send_email_node将模拟邮件发送并最终结束。
4.4 完整的运行流程概览
| 步骤序号 | 操作 | GraphState变化(关键字段) | LangGraph行为 | 外部交互 |
|---|---|---|---|---|
| 1 | 调用 app.stream() (首次) |
current_step="start" |
从entry_point(generate_draft)开始执行 |
– |
| 2 | generate_email_draft_node |
email_subject, email_recipient, email_body 被填充;needs_confirmation=True, is_confirmed=False |
执行完毕,状态更新,转向check_confirmation |
– |
| 3 | check_confirmation_status_node |
current_step="awaiting_confirmation" |
检查到需要确认但未确认,返回特定状态,触发条件路由 | 打印“ACTION REQUIRED”提示 |
| 4 | route_on_confirmation |
– | 路由到await_input (映射到END) |
图在此处停止,状态被保存到检查点 |
| 5 | 人工干预 | – | – | 外部系统(如Web UI)接收到挂起通知,展示邮件内容,等待用户点击“确认发送” |
| 6 | 外部系统更新状态 | is_confirmed=True, current_step="human_confirmed" |
通过 memory.update() 更新检查点中的状态 |
用户点击“确认发送”后,外部系统调用 memory.update() |
| 7 | 调用 app.stream() (恢复) |
从检查点加载已更新的状态 | 从上次停止点恢复执行,重新评估 check_confirmation 后的路由 |
– |
| 8 | check_confirmation_status_node (再次) |
current_step="confirmation_passed" |
检查到已确认 (is_confirmed=True),允许继续 |
– |
| 9 | route_on_confirmation (再次) |
– | 路由到 send_email |
– |
| 10 | send_email_node |
current_step="email_sent" |
执行邮件发送逻辑 | 打印“Email sent successfully!” |
| 11 | 图结束 | – | 达到 END 节点 |
– |
第五章:深度探讨与高级模式
我们已经成功地构建了一个基本的邮件发送确认系统。但LangGraph的中断机制远不止于此,以下是一些更深入的思考和高级模式。
5.1 显式中断与隐式中断的权衡
- 显式中断 (
graph.interrupt()): 通常用于调试、紧急停止或由外部系统触发的强制中断。它会立即停止图的执行,并抛出一个异常。在生产环境中,直接在节点内部调用这个方法并不常见,因为它破坏了节点的纯函数特性,也使得错误处理变得复杂。 - 隐式中断(通过条件路由): 这是我们示例中采用的方法。通过精心设计的
GraphState和条件边,我们可以将图的执行流引导到一个“死胡同”或END节点,从而自然地停止图的执行,等待外部干预。这种方式更加优雅,符合LangGraph的图式编程范式,也更容易管理状态和恢复逻辑。
在大多数需要人工干预的场景中,隐式中断是更推荐的做法。它将中断的逻辑封装在图的结构中,使得图的行为更可预测。
5.2 持久化层选择:从开发到生产
SqliteSaver: 如我们示例所示,非常适合本地开发、测试和简单的单实例应用。它将所有检查点存储在一个SQLite数据库文件中。RedisSaver: 对于需要高性能、并发访问和分布式部署的生产环境,Redis是一个优秀的选择。它提供了快速的键值存储,非常适合存储和检索LangGraph的检查点状态。PostgresSaver/MongoDBSaver等: 如果你的系统已经依赖于关系型数据库或NoSQL数据库,并且希望将LangGraph的检查点也存储在其中,可以使用相应的Saver实现。这些Saver通常需要额外的数据库连接配置。
选择合适的持久化层对于确保系统的可靠性、可伸缩性和高可用性至关重要。
5.3 用户界面集成:将LangGraph与前端结合
在实际应用中,人工确认往往需要一个直观的用户界面。
- 前端通知: 当LangGraph图进入挂起状态时(即
check_confirmation_status_node返回awaiting_confirmation),后端服务可以监听检查点状态的变化,或者通过webhook通知前端。 - 展示待确认信息: 前端收到通知后,根据检查点中保存的
email_subject、email_recipient、email_body等信息,渲染出待确认的邮件内容。 - 用户操作: 用户在UI上点击“确认发送”或“取消”。
- 后端API调用: 前端将用户的选择(例如
confirmed=True)发送给后端API。 - 更新状态与恢复: 后端API接收到确认后,会执行类似我们示例中的
memory.update()操作,将is_confirmed标志设置为True,然后调用app.stream()或app.invoke()来恢复LangGraph的执行。
5.4 超时与重试机制
如果人工确认长时间未完成,系统可能需要采取进一步措施:
- 超时: 设置一个确认的截止时间。如果超过时间仍未确认,可以将任务标记为超时,通知相关人员,甚至自动执行取消操作。
- 重试/提醒: 在超时前,可以发送提醒通知给用户,例如通过邮件、短信或应用内通知。
- 取消: 用户也可以主动取消待确认的操作。这需要在UI上提供“取消”按钮,并在后端映射为更新状态(例如
is_cancelled=True),然后图可以路由到清理或终止流程。
5.5 安全性与权限管理
人工确认环节是安全的关键点。需要考虑:
- 认证与授权: 只有经过身份验证并拥有相应权限的用户才能查看和确认敏感操作。
- 审计日志: 记录每次确认(或拒绝)操作的时间、执行人以及具体内容,以便追溯。
- 隔离: 待确认的数据应妥善隔离,防止未授权访问。
5.6 幂等性
恢复执行后,确保危险操作的幂等性非常重要。例如,如果邮件发送失败后再次恢复,需要确保不会发送两封相同的邮件。
- 唯一事务ID: 为每个危险操作生成一个唯一的事务ID,并在操作执行时记录。
- 检查重复: 在执行危险操作前,先检查该事务ID是否已经成功执行过。例如,在
send_email_node中,可以查询数据库,如果发现邮件已发送,则直接返回成功。
5.7 错误处理与回滚
如果危险操作在执行过程中失败,或者人工确认后发现有误需要撤销,LangGraph可以与错误处理机制和补偿事务结合:
- 错误节点: 定义一个专门的错误处理节点,当特定错误发生时路由到此节点。
- 回滚/补偿: 在错误处理节点中,可以执行回滚操作(如果可能)或触发补偿事务来撤销部分已完成的操作。
第六章:Agent与人类协作的未来
LangGraph的“中断”机制,不仅仅是一个技术特性,它更代表了人与AI协作模式的一种演进。在未来,AI Agent将不再是完全自主的黑箱,而是可以与人类深度融合的智能伙伴。通过这种灵活的挂起与恢复机制,我们可以构建出:
- 更安全的自动化系统: 确保关键决策始终经过人类审查。
- 更可靠的Agent: 允许人类纠正Agent的错误或引导其行为。
- 更透明的AI应用: 用户可以清晰地看到Agent的思考过程和待执行的操作。
LangGraph为我们提供了一个坚实的基础,去探索和构建这种“人机协同智能”的新范式,让AI在提供高效服务的同时,始终保持在人类的掌控之中。
感谢各位的聆听,希望今天的讲座能帮助大家更好地理解和运用LangGraph的“中断”机制,从而构建出更加智能、安全、可靠的AI Agent应用。