首页 › ai-agents › Agent审批闸门六栈实测

Agent审批闸门六栈实测:中断、接管与吞吐税的全账

当自主智能体开始触碰支付、发邮件、删库、提交工单这类不可逆副作用时,"它能跑"和"它敢跑"之间隔着一条决定生产成败的鸿沟——人机协作闸门(Human-in-the-Loop Gate)。本期把 2026 年主流的六套 Agent 框架拉到同一条审批流水线上实测:LangGraph、OpenAI Agents SDK、CrewAI、AutoGen/AG2、Microsoft Agent Framework、Pydantic AI。核心结论先行——只有 LangGraph 的 interrupt() 和 OpenAI Agents SDK 的 RunState 真正具备"跨进程、跨天"的持久化中断-恢复能力;CrewAI 与 AutoGen 停留在"会话内征求反馈";Pydantic AI 则是裸奔基线。而真正决定框架生死的不是"能不能加闸门",而是每个闸门要交多少吞吐税。

一、六栈审批闸门对比总表

框架 HITL 原语 审批声明方式 中断/恢复机制 状态持久化 审批作用域 首闸上手 吞吐税
LangGraph interrupt() + Command(resume=) 命令式(节点内调用) 检查点回放 Checkpointer(内存/SQLite/Postgres) 线程级(thread_id) ~15 min 中(可异步)
OpenAI Agents SDK 工具级审批 + RunState 声明式(工具标记 needsApproval) Run 中断 + 状态序列化 RunState 可序列化 运行级(跨 handoff) ~10 min 低
CrewAI human_input=True 任务级标志 阻塞式 stdin 征询 无原生持久化 任务级 ~5 min 高(阻塞)
AutoGen / AG2 UserProxyAgent human_input_mode 配置 会话轮次等待 会话内存(可外挂) 会话级 ~10 min 高(同步)
Microsoft Agent Framework FunctionApprovalRequest 函数工具 approval_required 事件回调 + 恢复 持久化线程 运行级 ~15 min 中
Pydantic AI 无内置 手动拦截 手动暂停/续跑 自行实现 自定义 ~20 min 视实现

一句话读表:上手最快的 CrewAI 恰恰是吞吐税最高的;声明式的 OpenAI Agents SDK 在"审批作用域跨 handoff"这一项上独一份;LangGraph 在"状态可编辑、可时光旅行"上是唯一答案。

二、LangGraph:中断即一等公民

LangGraph 把 HITL 当作核心抽象而非附加功能。它的心智模型是图执行可暂停:任意节点里调用 interrupt(value),整张图冻结,value 被吐回给客户端;人类决策后,用 Command(resume=answer) 续跑,interrupt() 那一行原样返回 answer,节点逻辑无缝继续。

from langgraph.types import interrupt, Command
from langgraph.checkpoint.memory import MemorySaver

def approve_node(state):
    verdict = interrupt({"plan": state["draft"], "risk": state["risk"]})
    # 人类拒绝 → verdict="reject",分支去重写;批准 → 放行
    return {"approved": verdict == "approve"}

graph = builder.compile(checkpointer=MemorySaver())
cfg = {"configurable": {"thread_id": "order-7721"}}
graph.invoke({"draft": plan}, cfg)            # 跑到 interrupt 停下
graph.invoke(Command(resume="approve"), cfg)  # 从检查点回放续跑

强制三件事让它成为长会话首选:①必须挂 checkpointer;②必须给 thread_id;③状态按线程隔离。代价是这套机制默认同步阻塞——节点停在 interrupt() 期间,工作线程被占住。生产里通常把"等待人类"这段挪到外部队列(Redis/Postgres),用 thread_id 当任务号异步恢复,从而把阻塞变成轮询,吞吐税从"高"压回"中"。它的杀手锏还有 get_state_history(cfg):任意历史检查点都能 fork 出分支重放,相当于给 Agent 装了时光机,这是其余五栈都没有的能力。

三、OpenAI Agents SDK:声明式审批与 RunState 序列化

OpenAI Agents SDK 走了一条与 LangGraph 完全相反的路:审批声明在工具上,不在控制流里。工具自己声明"我需要审批",运行结果把待审批项作为中断抛出,RunState 让你把整个运行状态序列化、过一会儿再反序列化续跑。

from agents import Agent, Runner, function_tool

@function_tool(needs_approval=True)
def issue_refund(order_id: str, amount: float) -> str:
    return f"refunded {amount} for {order_id}"

agent = Agent(name="billing", tools=[issue_refund])
result = Runner.run_sync(agent, "给订单 7721 退 200")
# result.interruptions 暴露待审批工具调用
# 人类 approve 后:Runner.run_sync(agent, "...", state=result.state) 续跑

这套设计有两个被低估的优势。第一,审批作用域是运行级而非当前 Agent 级——官方文档明确"the approval surface is run-wide, not limited to the current top-level agent",意味着即便工具调用发生在 handoff 之后的子 Agent 身上,审批照样生效,跨角色协作不漏审。第二,RunState 是序列化对象,天然适配"用户下班了、明天早上审批"这种跨天异步场景,无需自己造 checkpointer。短板也明显:强绑 OpenAI 模型与生态,审批回调的 UI 层要自建,且 needs_approval 这种布尔粒度偏粗——想"按金额分级审批"得自己在工具内拆条件。综合吞吐税最低,是 OpenAI-only 技术栈的甜点选择。

四、CrewAI:human_input 的轻量代价

CrewAI 把人机协作压成了一个布尔标志:给 Task 加 human_input=True,任务执行完会停下来向人类征求反馈。上手确实五分钟不到,代价是它本质是阻塞式 stdin 征询,不是真正的中断-恢复。

review = Task(
    description="起草退款方案",
    expected_output="退款 JSON",
    human_input=True,        # 任务后弹出人工反馈
    agent=analyst,
)

实测三个硬伤。其一,没有原生持久化——一旦会话进程退出,等待中的审批请求随之蒸发,撑不过一次容器重启或五小时长会话。其二,作用域锁死在单个 Task,跨 Crew、跨 Agent 的统一审批策略要靠 @before_kickoff/@after_kickoff 回调自己缝。其三,human_input 只能在任务边界触发,无法在"工具调用前"这种更细粒度的点设卡——对一个准备点"发送"的邮件 Agent 来说,任务级闸门粒度太粗。CrewAI 适合做原型演示和内部低风险流程,但凡涉及不可逆副作用,它的吞吐税(全程阻塞)和持久化缺失就是红线。

五、AutoGen / AG2:UserProxy 的会话级审批

AutoGen 的人机协作原语是 UserProxyAgent,通过 human_input_mode 三档配置控制介入力度:ALWAYS(每轮问)、TERMINATE(终止前问)、NEVER(全自动)。

from autogen import ConversableAgent, UserProxyAgent

user = UserProxyAgent("human", human_input_mode="TERMINATE",
                      is_termination_msg=lambda x: "FINAL" in x.get("content",""))
assistant = ConversableAgent("assistant", llm_config=cfg)
user.initiate_chat(assistant, message="分析并下單")

这套"人类即一个 Agent"的设计在多智能体对话里很自然——人类就是对话图里的一个节点,逢到该他说话就阻塞等待。但它的审批是会话级、同步的:审批请求绑在对话轮次上,进程崩了对话历史得靠外挂记忆恢复,没有像 LangGraph thread_id 那样的稳定恢复句柄。2025–2026 年 AutoGen 进入剧烈动荡期——微软把 AutoGen 与 Semantic Kernel 合并进新的 Microsoft Agent Framework,社区则 fork 出 AG2 续命。这意味着今天选 AutoGen,实质是在"走向 MSAF 的官方线"和"AG2 社区线"之间二选一,迁移成本必须提前计入。

六、Microsoft Agent Framework:FunctionApproval 的统一面

微软把 AutoGen + Semantic Kernel 收编后推出的统一框架,在 HITL 上给出了一套更工程化的方案:函数工具声明 approval_required,框架在调用前抛出 FunctionApprovalRequest 事件,宿主程序拿到事件后回调 approve/reject,运行据此恢复。

# Microsoft Agent Framework(概念示意)
@agent.function_tool(approval_required=True)
def place_trade(symbol: str, qty: int):
    ...

# 运行时订阅
async def on_approval(req: FunctionApprovalRequest):
    if req.args["qty"] < 100:
        return req.approve()
    return await ask_human(req)   # 超阈值转人工

它的差异化在于审批决策可以是程序化的——金额、风险分、用户等级都能写进回调里做条件放行,不必事事打扰人类。结合其内置的持久化线程,FunctionApprovalRequest 能跨进程恢复,作用域是运行级。这套东西对企业特别对味:和 Azure 生态、Copilot Studio、Semantic Kernel 技能复用一脉相承。缺点同样在企业味——抽象层厚、配置项多、学习曲线陡,团队若没有 .NET/Python 双栈和 Azure 基建,首闸上手要 15 分钟起步。

七、Pydantic AI:无闸门的裸奔基线

Pydantic AI 把第六栈的位置留给它,不是因为它闸门强,恰恰相反——它几乎没有内置 HITL。它的强项是类型安全与结构化输出,Agent 循环很薄,要加审批只能"手动拦截":在工具调用前自己插入一个 await 人类确认的协程,状态持久化完全自己实现。

# 手动闸门:把审批做成一个普通函数工具前的钩子
async def guarded_tool(ctx, **args):
    if args["amount"] > ctx.deps.threshold:
        if not await ctx.deps.human.approve(args):
            return "rejected"
    return await do_refund(**args)

把它列进来是为了立一个对照系:当你主动拒绝框架提供的闸门抽象、选择裸写时,你拿到了最大灵活性,也接下了全部持久化、超时、重放、审计的债。 小团队、低风险、短会话场景,这套"依赖注入 + 手动钩子"反而最干净;一旦会话跨小时、审批跨人、需要审计回溯,这些手写的边角代码会迅速膨胀成事实上的私有框架——而那正是其他五栈想替你省掉的。

八、闸门设计的三个真相与吞吐税

把六栈摆在一起,会浮现出三条贯穿性规律。

真相一:闸门粒度决定安全上限,声明方式决定工程体验。 工具级声明(OpenAI、MSAF)比节点级命令(LangGraph)更贴"副作用在哪、审批挂哪"的直觉,但牺牲了"在任意逻辑点叫停"的灵活性。LangGraph 的 interrupt() 可以在条件分支中间、在规划完成后、在校验失败时任意插入,粒度自由度最高。

真相二:没有持久化的审批都是玩具。 CrewAI 和 AutoGen 的同步征询在"用户去开会了"的现实中直接失效。真正过得了关的是把等待态外置——LangGraph 的 checkpointer 把 thread_id 当任务号写进 Postgres,OpenAI 的 RunState 序列化进对象存储,MSAF 的持久化线程。判断一个框架能否上生产,就看它的"等待人类"状态能不能在进程重启后毫秒级恢复。

真相三:吞吐税是隐形定价表。 每个同步阻塞闸门都在序列化整条流水线。一个有四处审批门的 Agent,若全做成阻塞,端到端延迟等于四次人类响应时间之和,且工作线程全程空转。对冲手段只有两个——把闸门异步化(外部队列 + 轮询恢复),或把闸门程序化(MSAF 式条件放行,能自动放行的绝不打扰人)。OpenAI Agents SDK 之所以吞吐税评"低",正是因为 RunState 让异步化几乎零成本。

flowchart TD
    U[用户请求] --> A[Agent Loop 推理]
    A --> T{工具调用?}
    T -->|needsApproval=true| G1[审批门-声明式]
    T -->|高风险节点| G2[中断门-命令式 interrupt]
    G1 --> Q[审批队列-可持久化]
    G2 --> CK[Checkpointer/RunState 持久化]
    Q --> H{人工/规则决策}
    CK --> H
    H -->|approve/timeout放行| EX[执行副作用]
    H -->|reject| A
    H -->|edit state| F[fork历史检查点-时光旅行]
    F --> A
    EX --> D[审计日志-不可抵赖]
    D --> A
    style G1 fill:#ffe0b2
    style G2 fill:#c8e6c9
    style CK fill:#bbdefb
    style Q fill:#bbdefb

九、分场景推荐

一句话收口:2026 年选 Agent 框架,与其问"它能不能加审批",不如问"它的审批等待态能不能在容器重启后 50 毫秒内恢复、能不能不打扰人就不打扰人"。 前者是所有六栈都能做到的表象,后者才是区分生产可用与玩具的分水岭。

参考来源

  1. Human-in-the-loop — OpenAI Agents SDK 官方文档 — 工具声明审批、RunState 序列化与跨 handoff 运行级审批作用域的权威说明。
  2. Interrupts — LangGraph 官方文档 — interrupt() / Command(resume=) 与 checkpointer 回放机制。
  3. How to Gate Agents: LangGraph, AutoGen, CrewAI(2026) — 三栈审批闸门对比与"不杀吞吐量"工程权衡。
  4. CrewAI vs LangGraph vs AutoGen vs OpenAgents — Best AI Agent Framework (2026) — 四栈架构、多智能体与生产就绪度基准对比。
  5. Function tools with human in the loop approvals — Microsoft Learn — Microsoft Agent Framework 的 FunctionApprovalRequest 条件放行机制。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入