LangGraph人机协同实战:用interrupt实现Agent暂停与人类审批

为什么Agent需要"人类在环"
随着AI Agent能力的增强,它们已经不再局限于回答问题,而是开始执行真实世界的操作:发送邮件、修改数据库、部署代码,甚至处理金融交易。AI Agent(智能代理)是一种能够感知环境、自主做出决策并执行行动的AI系统,与传统的聊天机器人不同,它不仅能生成文本回复,还能通过工具调用(Tool Use)与外部系统交互。近年来,随着大语言模型推理能力的增强以及函数调用(Function Calling)机制的成熟,Agent已经能够编排多步骤的复杂任务链。函数调用机制最早由OpenAI在2023年中期引入GPT API,其核心思想是让LLM在生成回复时,不仅可以输出自然语言文本,还可以输出结构化的函数调用请求——包括函数名称和参数。API调用方(通常是Agent框架)解析这些结构化请求后,代为执行对应的外部函数,并将执行结果回传给LLM,形成"推理-行动-观察"(Reason-Act-Observe)的循环。这一机制后来被Anthropic、Google等厂商广泛采纳,成为Agent生态的基础通信协议。
这种从"对话"到"行动"的跨越,带来了巨大的生产力提升,但同时也引入了全新的风险维度——当一个Agent可以直接操作生产数据库或发起资金转账时,一个幻觉(Hallucination)或推理错误就可能造成不可逆的损失。所谓幻觉,是指LLM生成看似合理但事实上错误或虚构的内容,这在纯文本场景中可能只是造成信息误导,但在Agent场景中,幻觉可能直接转化为错误的行动指令。例如,LLM可能"幻觉"出一个不存在的API参数,或者错误地判断应该删除某条数据库记录。更危险的是,LLM在产生幻觉时通常表现得极为自信,不会给出任何不确定性信号,这使得下游系统难以通过置信度等指标来过滤错误决策。
正因为这些操作具有不可逆的后果,我们不能让Agent在没有任何监督的情况下自主行动。这就是**Human-in-the-Loop(HITL,人机协同)**模式的价值所在。HITL是AI安全与治理(AI Safety & Governance)领域的核心概念之一。根据自动化程度的不同,人机协同通常被分为三个层次:Human-in-the-Loop(人类参与每个决策循环)、Human-on-the-Loop(人类监督整体流程,仅在异常时介入)、Human-out-of-the-Loop(完全自主,人类不参与)。这三个层次的划分最早源自军事领域对自主武器系统的分类,后来被引入更广泛的AI系统设计中。Human-in-the-Loop要求人类对每一个关键决策进行确认,适用于高风险、低频次的操作;Human-on-the-Loop则允许系统自动运行,但人类持续监控系统行为并保留随时叫停的能力,类似于自动驾驶中的安全员角色;Human-out-of-the-Loop则意味着系统完全自主运行,人类仅在事后审计。在实际的AI系统设计中,这三种模式往往共存——同一个Agent的不同操作,根据风险等级采用不同的人类参与程度。
欧盟AI法案(EU AI Act)和美国的AI行政命令等监管框架,也明确要求高风险AI系统必须保留人类监督机制。欧盟AI法案于2024年正式生效,采用了基于风险的分级监管方法,将AI系统分为不可接受风险、高风险、有限风险和最小风险四个等级。其中,高风险AI系统(如用于关键基础设施管理、教育评分、信用评估、执法等领域的系统)被明确要求具备"有效的人类监督措施",确保人类操作员能够充分理解系统的能力和局限,能够监控系统运行,并能在必要时介入或停止系统。美国白宫2023年发布的AI行政命令(Executive Order on AI)同样强调了人类监督的重要性,要求联邦机构在部署AI系统时评估人类监督需求。HITL因此不仅是技术选择,更是合规要求。
最近一位开发者在Reddit上分享了他学习LangGraph的实践经验。LangGraph是由LangChain团队开发的一个用于构建有状态、多步骤AI Agent应用的框架。与LangChain的线性链式调用不同,LangGraph基于有向图(Directed Graph)的理念,将Agent的工作流建模为节点(Node)和边(Edge)组成的图结构。每个节点代表一个处理步骤(如调用LLM、执行工具、检查条件),边则定义了步骤之间的流转逻辑。这种图结构的核心优势在于支持循环、分支和条件跳转,使得开发者能够表达复杂的Agent决策逻辑,包括重试、多轮推理和人工干预等场景。在Agent框架的生态中,LangGraph的差异化定位在于它对"状态"和"控制流"的精细管理。与AutoGen(微软推出的多Agent对话框架,侧重Agent间的自主协商)和CrewAI(强调角色分工与任务委派的多Agent编排框架)相比,LangGraph更像是一个底层的工作流引擎——它不预设Agent的交互模式,而是提供图结构的原语(Primitive),让开发者自行定义状态流转逻辑。这种设计哲学与Apache Airflow在数据工程领域的定位类似:不告诉你应该怎么做,而是给你足够的表达能力来描述你想怎么做。LangGraph还内置了状态管理机制,每次节点执行后的状态变更都会被追踪,为持久化和恢复执行提供了基础。
这位开发者没有停留在阅读文档的层面,而是构建了一个极简但完整的示例,来真正理解当一个LangGraph执行流程"暂停"和"恢复"时,底层究竟发生了什么。这个案例虽小,却精准地揭示了HITL的核心机制。

最小可行的HITL场景:Agent发邮件前等待审批
作者选择了一个非常贴近日常的场景:Agent决定要发送一封邮件,此时图(Graph)暂停,交由人类审查这个动作,人类选择批准或拒绝,然后图继续执行。
整个流程可以拆解为清晰的几步:
用户请求
↓
Agent 决定执行某个动作
↓
interrupt() ← 在此暂停
↓
人类审查
↓
批准 / 拒绝
↓
Command({ resume: ... }) ← 携带人类决策恢复执行
↓
图继续执行
你可能没注意到,作者刻意让这个例子保持精简:没有接入真实的LLM,也没有调用真正的邮件API。这个设计选择很有意思——他的目标不是构建一个可用的产品,而是剥离掉一切干扰因素,专注理解LangGraph暂停与恢复的运行原理。这种"做减法"的学习方式,对于掌握复杂框架的核心机制往往比一上来就搭建完整应用更有效。
LangGraph HITL核心机制拆解
这个示例用到了LangGraph的几个关键组件,理解它们的配合方式是掌握Human-in-the-Loop的关键。
interrupt():暂停执行的触发点
interrupt() 是整个流程的核心。当图执行到这一步时,会停下来等待外部输入。作者提到了一个特别有启发的发现:
人类的响应会成为
interrupt()的返回值。
这是一个非常优雅的设计。interrupt() 的设计灵感可以追溯到操作系统中的中断(Interrupt)机制和编程语言中的协程(Coroutine)概念。在操作系统中,硬件中断允许CPU暂停当前任务、保存上下文(寄存器状态、程序计数器等)、处理外部事件后再恢复执行。类似地,LangGraph的 interrupt() 让图执行流在某个节点暂停,将控制权交给外部(人类),待外部响应后再从断点处继续。这与Python中的 yield 关键字在生成器(Generator)中的行为颇为相似——函数执行到 yield 时暂停并返回一个值,外部通过 send() 方法注入新值后函数从暂停处继续。事实上,这种"暂停-恢复"的控制流模式在分布式系统中有广泛应用。例如,Temporal和Cadence等工作流引擎使用了类似的"可持久化协程"(Durable Coroutine)概念,允许长时间运行的工作流在等待外部事件(如人工审批、第三方回调)时暂停,将执行状态持久化到数据库,在事件到达后从断点恢复。这种模式解决了传统轮询或回调方式的复杂性问题,让开发者可以用顺序代码的思维编写本质上是异步的分布式逻辑。
从代码逻辑上看,interrupt() 就像一个普通的函数调用,只不过它的"返回值"不是由程序计算得出,而是由真实的人类在稍后某个时刻提供。这意味着开发者可以用近乎同步的思维方式来编写异步的、跨越人类决策的代码逻辑,极大降低了开发者的认知负担。
MemorySaver与thread_id:状态的持久化
仅仅暂停是不够的,系统还需要记住"暂停在哪里"以及"当时的所有状态"。这正是MemorySaver(检查点保存器)和thread_id发挥作用的地方。
MemorySaver是LangGraph提供的检查点保存器的一种实现,主要用于开发和测试阶段,它将状态保存在内存中。在生产环境中,LangGraph还支持基于SQLite、PostgreSQL等持久化存储的检查点保存器,确保即使服务重启,执行状态也不会丢失。检查点机制的核心是序列化(Serialization)——在每个节点执行完毕后,将当前图的完整状态(包括所有通道中的数据、当前执行位置、历史消息等)序列化并存储。恢复时,系统反序列化该快照并从断点处重新构建执行上下文。值得注意的是,序列化的粒度和策略直接影响系统的性能和存储开销。LangGraph默认采用的是全量快照(Full Snapshot)策略,即每次检查点都保存完整的状态副本,这种方式实现简单、恢复可靠,但在状态数据量较大或检查点频率较高时可能带来显著的存储和计算开销。在高吞吐量的生产场景中,开发者可能需要考虑增量快照(Incremental Snapshot)策略,仅存储自上一个检查点以来发生变化的状态差异。此外,选择何种持久化后端也需要权衡:SQLite适合单机部署和中小规模场景,PostgreSQL则更适合需要高可用性和多实例共享状态的分布式部署。
作者指出,检查点机制加上thread_id,使得同一个图的执行可以在稍后被恢复。thread_id相当于一次对话或一个任务的唯一标识,本质上是一个命名空间隔离机制,确保不同用户的不同任务流之间互不干扰。检查点则保存了该任务在中断时刻的完整快照。当人类做出决策后,系统通过thread_id找回对应的执行上下文,从暂停处无缝继续。这种设计也天然支持了Agent执行的可审计性——每个检查点都是一个可追溯的历史快照,这对于满足金融、医疗等受监管行业的合规审计要求尤为重要。
这种设计让HITL不再受限于"必须立即响应",人类可以在几分钟、几小时甚至几天后再来审批。
Command与条件路由:根据人类决策分发流程
人类的决策通过 Command({ resume: ... }) 注入回图中,而**条件路由(Conditional routing)**则根据批准或拒绝的结果,决定图接下来走向哪个分支——是真正执行发邮件动作,还是终止并反馈拒绝原因。
条件路由是LangGraph中通过 add_conditional_edges 方法实现的一种边类型。与无条件边(总是流向固定的下一个节点)不同,条件边会根据一个路由函数的返回值,动态决定下一步走向哪个节点。在HITL场景中,路由函数会检查人类通过Command注入的决策值——如果是"approved"则路由到执行节点,如果是"rejected"则路由到终止节点。这种模式在工作流引擎中非常常见,类似于BPMN(业务流程模型与符号)中的排他网关(Exclusive Gateway)。BPMN是由OMG(对象管理组织)制定的业务流程建模国际标准,广泛应用于企业级工作流设计中。其中的排他网关(以菱形符号表示)正是用于根据条件表达式将流程路由到不同的分支路径,与LangGraph中条件边的语义完全一致。在更广泛的工作流编排领域,Apache Airflow使用BranchPythonOperator实现类似的条件分支,Temporal通过Workflow代码中的if/else语句实现路由,而LangGraph则通过声明式的条件边配置来表达,使得复杂的分支逻辑能够以声明式的方式表达,而非硬编码在节点内部。这种声明式的分支定义不仅提高了代码可读性,还便于可视化工具自动渲染出图的拓扑结构,帮助开发者和审计人员直观理解Agent的决策逻辑。
HITL在真实项目中的应用场景
作者在帖子末尾抛出了一个很有价值的开放式问题:大家在实际项目中都把HITL用在哪些场景?他列举了几种常见方向:
- 审批工具调用(tool calls):在Agent调用外部工具前进行人工确认,尤其是高风险工具。例如在DevOps场景中,当Agent准备执行kubectl delete或terraform destroy等破坏性命令时,HITL审批可以防止误操作导致的服务中断。
- 审查生成内容:让人类把关AI生成的文案、代码或报告后再发布。这在内容营销、法律文书生成和代码自动生成等领域尤为关键,因为AI生成的内容可能包含事实错误、版权风险或不符合品牌调性的表述。
- 数据库变更:任何写入或删除操作前的人工确认。在数据工程领域,这被称为"变更管理"(Change Management),与数据库迁移工具(如Flyway、Liquibase)中的审批流程理念一致。
- 部署操作:CI/CD流程中的人工放行环节。这与GitHub Actions中的Environment Protection Rules、GitLab CI中的Manual Job等机制异曲同工,本质上都是在自动化流水线中插入人类决策节点。
- 金融操作:涉及资金的交易必须经过人工核准。在金融监管框架中,这对应于"四眼原则"(Four-Eyes Principle)——关键操作必须经过至少两个独立方的审核确认。
这些场景有一个共同点:操作不可逆或代价高昂。HITL本质上是在Agent的自主性与人类的最终控制权之间寻找平衡。对于低风险、高频次的操作,我们希望Agent全自动运行;而对于关键节点,则插入人类检查点作为安全阀。这种分级控制策略正是前文提到的Human-in-the-Loop与Human-on-the-Loop混合运用的典型体现。在实际系统设计中,风险评估矩阵(Risk Assessment Matrix)通常被用来决定每个操作应该采用哪种级别的人类参与——综合考虑操作的影响范围(单个用户 vs. 全平台)、可逆性(是否可以回滚)、频率(每天一次 vs. 每秒千次)以及合规要求等维度。
超越简单的"批准/拒绝":进阶人机协同模式
作者最后还提出了一个进阶思考:除了简单的批准/拒绝流程,还有哪些有用的HITL模式?这实际上指向了人机协同设计的更深层次。
在更成熟的实践中,人机协同远不止二元选择。例如:
- 编辑式介入:人类不仅可以批准或拒绝,还可以直接修改Agent的输出(比如调整邮件措辞)后再放行。这种模式反映了人机协同从简单的"门控"(Gating)向"协作"(Collaboration)演进的趋势——Agent的输出不是最终产品,而是一个草稿或提案,人类可以在此基础上进行修改和完善,这与软件工程中的Code Review流程异曲同工。在LangGraph中实现编辑式介入,可以通过让
interrupt()返回一个包含修改后内容的复合对象来实现,而不仅仅是一个简单的"approved/rejected"字符串。这要求状态定义(State Schema)具有足够的灵活性来承载人类的修改内容。 - 补充信息:当Agent缺少关键信息时,暂停并向人类索取,而非贸然决策。这种模式在客服Agent中尤为常见——当Agent无法确定用户意图或缺少处理工单所需的关键参数时,它可以主动暂停并向人类运营人员请求补充信息,而不是基于不完整的信息做出可能错误的决策。
- 多级审批:不同风险等级的操作触发不同层级的审批链路。例如,小额退款可能只需要客服经理审批,而大额退款则需要财务总监签字。在LangGraph中,这可以通过嵌套的条件路由来实现——第一个审批节点根据金额决定是直接放行还是升级到更高层级的审批节点。
- 反馈学习:将人类的修正作为训练信号,逐步减少需要介入的场景。这种模式引入了RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习)的思想。RLHF最初由OpenAI在训练InstructGPT和ChatGPT时大规模应用,其核心流程是:首先收集人类对模型输出的偏好排序,然后训练一个奖励模型(Reward Model)来模拟人类的偏好判断,最后使用PPO(近端策略优化)等强化学习算法,以奖励模型的输出作为奖励信号来微调基础模型。在Agent的HITL场景中,虽然不一定需要完整的RLHF训练管线,但可以采用类似的思路:系统记录每次人类的修正行为(包括原始Agent输出、人类修改内容、修改原因等),这些数据可以用于微调Agent的提示词策略、调整工具调用的参数阈值,甚至作为Few-shot示例注入到后续的LLM调用中。随着系统不断从人类反馈中学习,需要人类介入的频率逐渐降低,实现从Human-in-the-Loop向Human-on-the-Loop的渐进过渡。这种渐进自主化(Progressive Autonomy)的理念,也是自动驾驶领域从L2(部分自动化)向L4(高度自动化)演进的核心策略——不是一步到位实现完全自主,而是通过持续的数据积累和模型优化,逐步扩大自动化的边界。
结语
这个来自Reddit的小案例,胜在"小而精"。它没有花哨的LLM集成,也没有复杂的业务逻辑,却把LangGraph实现HITL的核心机制——interrupt()、Command、检查点持久化与条件路由——讲得清清楚楚。
对于正在构建生产级Agent应用的开发者而言,Human-in-the-Loop不是可有可无的附加功能,而是让AI系统能够被信任、能够安全落地的关键基础设施。理解暂停与恢复的底层原理,是迈向可控AI Agent的第一步。随着Agent能力的持续增强和应用场景的不断扩展,HITL的实现模式也将从简单的二元审批演进为更加精细化、智能化的人机协同范式——从静态的规则触发走向动态的风险评估,从单一的审批节点走向多层次的协作网络,从被动的人类响应走向主动的反馈学习闭环。感兴趣的读者可以参考作者发布在Medium上的完整示例,动手跑一遍会有更深的体会。
相关推荐

tiun.:为AI开发者打造的一站式认证与支付系统
登顶 Product Hunt 的 tiun. 为 AI 开发者提供认证、支付、账单、客户数据与分析的一体化系统,一条命令即可安装,帮助开发者当天上线付费产品。本文解析其定位、卖点与竞争格局。

Voiskey:能读懂语境的AI语音输入工具
Voiskey是一款登上Product Hunt排名第3的AI语音输入工具,能根据场景和读者自动调整语气,比打字快5倍,支持iOS、macOS、Android、Windows四大平台及100多种语言。

Axari:让AI分身接管你的安全运营琐事
Product Hunt新品Axari主打「AI分身」概念,帮安全团队自动处理重复性运营琐事,可在Slack、MS Teams中指派目标并自主推进任务。本文解析其产品逻辑、行业定位与需要冷静看待的问题。