Google ADK这把轻量级快刀,正在切开LangGraph没啃下的审批流骨头

去年秋天,我接手了一个中型制造企业的采购审批流改造项目。需求听起来平淡无奇:一笔超过5万的采购申请,必须先过部门经理,再根据金额分叉——10万以下只需财务主管批,超过10万还要拉上分管副总,每一步都同步邮件通知,审批通过后自动在HR系统里记一笔归档。这种流程在企业里烂大街,但麻烦的是,他们当时的实现是两千多行Python脚本,靠if-else和全局变量硬撑,每次加一个审批节点就崩一次。更可怕的是,那套脚本里塞满了time.sleep轮询——部门经理批完,要等HR系统回调?不存在的,直接Sleep 30秒然后查数据库,活脱脱一个定时炸弹。

我带着团队用LangGraph重写了一版,图节点的编排确实优雅,但很快就被三个问题卡住脖子:一是每个节点都要显式定义状态字典,跨服务调用稍一复杂,那个字典就膨胀成怪物;二是LangGraph的checkpointer虽然能持久化状态,但在高并发下和HR系统的交互总出现竞态,恢复机制极其脆弱;三是整个工作流被图结构锁死,临时加一个“财务总监会签”的需求,得改边、改条件、改checkpoint序列,跟拆炸弹似的。折腾了两个月,我把LangGraph那套架构扔了,机缘巧合下开始用Google内部的一个轻量级多智能体框架重新落地——这个框架后来被整理成Agent Development Kit(ADK)。现在我敢下判断:对于80%的企业审批类工作流,ADK这种显式事件驱动状态机,比LangGraph这类图编排模型轻一个数量级,而且跨服务集成时的确定性明显更高。

30秒速览

  • - Google ADK用显式事件驱动状态机替代图编排,在审批类确定性工作流中健壮性碾压LangGraph
  • - ADK核心三抽象(Agent/Event/StateMachine)实现跨服务解耦,让副作用延迟提交并支持事件溯源
  • - 以企业采购审批为例,展示了从单体脚本到LangGraph再到ADK的三阶段演进,突出了轻量级抽象的选择价值
  • - 预测Google会将ADK整合进Vertex AI Agent Builder,2025下半年多智能体编排将进入“状态机 vs 图”之争

ADK的设计哲学:为什么它选择“反图灵完备”这条路

市面上多智能体编排框架已经卷成了春秋战国。LangChain有LangGraph,微软有AutoGen,CrewAI在Github上星标涨得飞快,Meta的Magentic-One也在路上。但如果你掰开它们的核心抽象看,绝大多数都选择了图模型——有向无环图或条件图,节点是Agent或函数,边是数据流动。图模型的好处是直观,把流程画出来就能懂;但它隐含了一个代价:状态转移被耦合在拓扑结构里,一旦业务规则从“顺序审批”变成“会签+任意一人驳回即终止”,图就得重构。更要命的是,图模型在处理外部事件中断时,天然要依靠持久化的checkpoint与事件监听结合,这层胶水代码最容易出生产事故。

ADK走了一条几乎相反的路:它的核心抽象只有三个——Agent、Event和StateMachine。Agent不是图里的节点,而是一个挂载在状态机上的独立执行单元;Event是Agent之间唯一的通信机制,所有跨服务调用、审批动作、超时信号,全部建模为不可变事件;StateMachine则负责解释事件、决定状态转移。这套设计哲学我称之为“反图灵完备”——它故意削减了抽象的表达力,放弃用一张图描述所有可能路径,而是要求你显式声明有限状态和合法转移。听起来像是往回退,但实际跑起来,确定性工作流(审批、订单履约、合规检查)的健壮性大幅提升,因为任何未声明的状态转移都会被状态机直接拒绝,没有“不小心在图里漏了一条边”这种bug。(延伸阅读:我让两个LLM互相攻击了三个月,才看清安全评测自动化的七寸在哪里——一个红队框架的架构决策全记录

为什么LangGraph没啃下审批流这根骨头

我绝不是在黑LangGraph。我本人是LangChain生态的深度用户,LangGraph在对话式AI、研究型Agent探索的领域的灵活性无可挑剔。但审批流的特点是:路径高度确定,异常分支远比正常分支多,跨服务副作用(发邮件、记日志、调HR系统)必须与状态转移严格一致。LangGraph用图表达审批流时,你容易写出这样的图:start->manager_approval->finance_approval->end。看起来完美,但一旦加一个“财务总监会签”,图就变成manager_approval通过后,同时分叉到finance_approval和director_cosign,两个都完成才到end。这在LangGraph里用条件边和多个节点能实现,但你要管理并行节点的状态合并,并且如果其中一个人驳回,整个图要回滚到某个失败状态——此时checkpointer的恢复行为完全依赖你的实现,稍有不慎就会出“审批已驳回,但邮件还是发出去了”这种典型事故。

ADK的做法完全不同。它把审批流的每一次动作都映射为事件:ManagerApproved、FinanceRejected、Timeout、CoSignRequired。状态机只关心当前状态+新事件=下一个状态。这种模型下,并行审批就是从一个“等待多结果”的状态同时监听多个事件,状态机声明了每个事件组合的转移规则。任何未声明的事件到达,状态机抛出异常,根本不会有意外路径。更关键的是,ADK的事件都是不可变且可重放的,一旦出现外部服务失败,你可以精确重放从某个事件点开始的状态转移,而不用恢复整张图。

特性 LangGraph ADK
核心抽象 图节点+边+条件边 Agent+Event+StateMachine
状态转移 隐含在图结构中 显式状态转移表
事件驱动 需要额外实现监听 原生事件通道
跨服务集成 通过节点内调用 通过Agent发送事件
确定性保障 依赖checkpointer和实现 状态机拒绝未声明转移
学习曲线 中等 低(状态机人人会)
适用场景 探索性Agent、复杂对话 确定性工作流、审批、履约

棋局解读:Google这步棋,下在了编排层的裂缝上

从行业棋局看,Google在这个时候整理出ADK并内部推广,绝不是无心之举。第一,Google在做什么——它将自身在事件驱动基础设施上的积累(Cloud Pub/Sub、Eventarc、Workflows)下沉到多智能体编程模型,把Agent编排的主动权从LangChain这种第三方框架手里抢回来,瞄准的是企业内部最头疼的确定性工作流自动化。第二,为什么选轻量状态机而不是另一个图编排——因为Google云上已经有Workflows这样的全托管状态机服务,企业客户天然理解“状态机驱动审批流”的模型,而LangGraph的图模型在企业IT部门推广时阻力巨大,IT负责人更愿意相信一个他们能审计每一个状态转移的系统。第三,我判断接下来三个月,Google有很大概率会将ADK的核心抽象整合进Vertex AI Agent Builder,形成一个“ADK设计模型+Vertex托管”的组合拳;而LangChain将被迫在LangGraph中增加显式状态机模式,否则企业级审批场景的蛋糕会被切走。如果这个判断坐实,那2025年下半年的多智能体编排战场,将从“图 vs. 图”变成“图 vs. 状态机”。(延伸阅读:多模态Agent的评测,我们一直在用错尺子——从轨迹对齐到目标达成的严格考试

事件声明与Agent间通信协议:ADK的血肉

ADK中,事件不是简单的消息,而是带有类型、负载、因果ID和不可变签名的一等公民。每个Agent在启动时会向事件总线注册自己感兴趣的事件类型;当Agent执行一个动作(比如调用外部服务),它必须通过发布事件来驱动整个流程,而不是直接调用下一个Agent的方法。这种设计让Agent之间彻底解耦,也为跨服务集成提供了天然切面。

回到审批流的实现。我设计了一个ApprovalOrchestrator作为主状态机,下面挂载了四个Agent:ManagerAgent(模拟部门经理审批)、FinanceAgent(调用财务系统接口)、EmailAgent(发送邮件)、HRAgent(调用HR系统归档)。每个Agent都实现一个简单接口:on_event(event, context) -> list[Event]。当管理器收到事件,它根据当前状态决定调用哪个Agent,并把Agent返回的新事件灌回状态机。

# ADK事件定义与Agent声明
from adk import Event, Agent, StateMachine, event_bus

@event_bus.register("approval.requested")
class ApprovalRequested(Event):
    request_id: str
    amount: float
    applicant: str

@event_bus.register("manager.approved")
class ManagerApproved(Event):
    request_id: str
    manager: str

@event_bus.register("manager.rejected")
class ManagerRejected(Event):
    request_id: str
    reason: str

class ManagerAgent(Agent):
    def on_event(self, event: Event, context):
        if isinstance(event, ApprovalRequested):
            # 实际集成时,这里调用经理审批接口或等待回调
            decision = self.call_manager_approval(event.request_id)
            if decision == "approved":
                return [ManagerApproved(event.request_id, manager=context.user)]
            else:
                return [ManagerRejected(event.request_id, reason=decision["reason"])]
        return []

这段代码透露了ADK的核心协议:Agent永远不对全局状态负责,它只负责把输入事件转化成输出事件。至于这些事件会触发什么状态转移,那是状态机的事。这种职责切分在跨服务集成时威力巨大——比如HRAgent调用内部系统归档时挂了,它只要不发布HRAchived事件,状态机就会停在“等待归档”状态,超时机制会自动触发重试或告警,而不会污染其他Agent的执行结果。(延伸阅读:我用三个框架跑了同一批模型,结果只有一个活得过生产环境

状态机驱动的审批流转:从硬编码分支到声明式转移

审批流真正的复杂度不在单步动作,而在分支组合。我改造的那个采购审批,路径有:经理驳回直接结束;经理通过但金额=10万进财务审批+副总签批并行;任何一人驳回则终止;超时触发经理催办邮件;财务系统不可用时降级为人工。LangGraph实现这一套时,条件边和节点数膨胀到13个节点、20多条边,调试时恨不得画一张A3纸。而在ADK中,状态机用一条条转移规则就覆盖了全部路径,每一条规则都像一个单元测试,清晰到审计员都能看懂。

# ADK状态机定义:审批流转移规则
from adk import StateMachine, Transition

machine = StateMachine("purchase_approval", initial="draft")

machine.add_transition(Transition(
    from_state="draft",
    trigger=ApprovalRequested,
    to_state="pending_manager",
    action=ManagerAgent
))
machine.add_transition(Transition(
    from_state="pending_manager",
    trigger=ManagerApproved,
    to_state="pending_finance_or_cosign",
    guard=lambda ctx: ctx.data["amount"] = 100000,
    action=[FinanceAgent, CoSignAgent, EmailAgent("通知副总")]
))
machine.add_transition(Transition(
    from_state=["pending_finance_or_cosign", "pending_cosign_and_finance"],
    trigger=FinanceApproved,
    to_state="completed",
    action=[HRAgent, EmailAgent("归档并通知")]
))
machine.add_transition(Transition(
    from_state="*",
    trigger=ManagerRejected | FinanceRejected | CoSignRejected,
    to_state="rejected",
    action=[EmailAgent("驳回通知")]
))
# 超时事件
machine.add_transition(Transition(
    from_state="pending_manager",
    trigger=Timeout(seconds=86400),
    to_state="pending_manager",
    action=[EmailAgent("催办经理")]
))

这个例子展示了ADK的三个实用武器:guard函数实现金额分叉,多trigger合并处理驳回(通配符from_state=”*”),以及同状态内部转移的超时重发(to_state不变,发催办邮件)。对比LangGraph,这些逻辑需要散落在节点函数和条件边里,而ADK把它们收拢到一组可读的转移声明中。当CFO突然要求“被驳回的单子也要归档”,我只需要在rejected转移的action列表里加上HRAgent,不用改动任何Agent逻辑。

集成外部服务:把副作用锁进事件的笼子

跨服务集成的痛点不在于怎么调用API,而在于调用失败后的状态一致性。传统脚本里发邮件、调HR接口都是就地执行,一旦中间崩了,前面的调用没法回滚,后面也无法重试。ADK把每个外部调用封装成Agent发布的事件,只有状态机确认转移发生后,事件才会被真正执行。这实现了一种延迟的副作用提交——当事件序列是[ManagerApproved, EmailSent, HRArchived]时,如果HRAgent在发布事件后但外部HR系统宕机,ADK的事件总线和重试机制会持续尝试,直到HR系统响应或超时升级为人工事件,中间不会丢失上下文。(延伸阅读:我让Codestral Mamba在256k上下文中跑补全,速度是GPT-4的3倍,但上下文管理差点让我翻车

具体到邮件集成,EmailAgent接收到“发送通知”的事件后,不会立刻调用SMTP,而是把邮件内容序列化进事件,事件总线持久化后才执行发送。如果发送中途进程被杀,事件依旧在总线的待发送队列中,恢复后自动重试。这比LangGraph里在节点函数里直接调SMTP、靠checkpointer保存“已发送”标志的做法可靠得多,因为标志位与真实发送之间的窗口期消失了。

HR系统集成更典型。企业内部HR系统往往老旧,接口超时、503、返回格式不符是家常便饭。我设计的HRAgent采用了指数退避+事件时间戳校验:重试三次后如果还失败,就发出一个ManualHRTask事件,通知运维人工介入,同时状态机进入“等待人工”状态,而不是整体卡死。这种降级策略在ADK里只需要在状态转移规则里加一条fallback转移路径,不用在图里画一堆异常处理节点。

错误处理与重试机制:不让一个失败事件腐化整个工作流

ADK对错误的态度很明确:任何Agent在on_event中抛出的异常都会被事件总线包裹成AgentError事件,推送到专门的ErrorAgent处理。这意味着你在设计状态机时,可以显式声明“当FinanceAgent发生错误时,转移到finance_failed状态并触发告警”,而不是靠一个全局try-catch大兜底。我最初用LangGraph时,最怕的就是某个节点throw异常后,checkpointer保存了一个半残的状态,下次resume时直接卡在奇怪的分支。ADK通过不可变事件和显式错误事件彻底避开了这个坑。(延伸阅读:我把代码重构的AI赌注押在JetBrains AI Assistant上:一个后端架构师的三个月实战复盘

重试机制则分为两层:Agent层和状态机层。Agent层负责瞬时故障(如网络超时),支持指数退避和事件幂等令牌;状态机层负责业务级别的重试——比如审批超时后,状态机可以转移到一个“re_notify”动作,重新发布一个催办事件,而不是重新执行整个审批步骤。这种分层保证了重试不会放大副作用。

监控与可视化追踪:用事件溯源重建每一个决策瞬间

从单体脚本演进到可伸缩工作流,最后一个不可回避的命题是观测性。审批流出了问题,你不能指望重现整个对话或数据库状态去定位,必须能清晰回答“这个单子为什么卡在财务审批,谁在什么时候做了决定”。ADK因为所有状态转移都由事件驱动,天然支持事件溯源——整个审批流的过程就是一组有序事件流,你随时可以重放事件来重建任何时刻的状态机快照。我在生产中接入了Google Cloud Logging,将事件流记录为结构化日志,再用一个小型前端面板按RequestID展示状态转移轨迹,包括每个Agent的输入事件、输出事件、耗时和重试次数。比LangGraph的checkpointer调试体验强太多,后者导出状态时是一大坨嵌套字典,很难直接给业务人员解释。

可视化追踪方面,我利用ADK状态机的转移声明,自动生成Mermaid状态图,并在图中动态高亮当前状态所在的节点。这个特性在向客户做验收演示时反响强烈,因为非技术出身的采购主管也能一眼看清流程走到了哪一步。这其实暴露了LangGraph一个软肋:虽然它号称图可视化简单,但实际部署中的状态图因为动态边过多,渲染出来像蜘蛛网,反而失去了可解释性。

从单体脚本到可伸缩工作流:我亲历的三阶段演进路径

回过头看,这个项目清晰地走过了三个阶段,每个阶段选择抽象都直接决定了最终系统的可维护性。最初是“脚本为王”阶段,用Python函数和全局变量写审批,代码短平快但零扩展性。第二阶段是“图编排”阶段,借LangGraph把流程画出来,解决了可读性问题,却引入了状态一致性的新坑。第三阶段是“事件驱动状态机”阶段,用ADK把转移规则和副作用完全分离,系统变得确定、可测试、可审计。这个演进路径在企业审批类场景是有普遍性的——一旦你的流程节点超过5个,或者需要集成3个以上外部系统,事件驱动状态机就是那个拐点之后的正确抽象。

这中间最大的教训是:不要过早优化为“通用图模型”。大部分企业内部工作流其实都是有限状态机,强行用图表达,只是把简单问题复杂化。ADK的价值就在于它承认了这种局限,并提供了一套刚好够用的抽象,让你把精力花在业务规则而不是编排逻辑上。

我的判断是,ADK这种设计思想会在2025年下半年开始渗透进主流框架。LangGraph很有可能推出显式状态机构造器,AutoGen也可能在group chat之外提供确定性的状态转移模式。但先发优势在Google这边,因为它的云原生事件基础设施(Pub/Sub、Eventarc)和状态机服务(Workflows)已经铺好了路,ADK只是把这些能力封装成了Agent原语。如果Google在六个月之内将ADK作为Vertex AI Agent Builder的一部分公开预览,那么它将快速抢走一部分LangChain的现有客户,尤其是那些已经在Google Cloud上跑AI工作负载的制造业和金融业用户。

以上是我的判断,但如果发生以下情况,我的分析就全部作废:LangGraph团队在2024年底之前就发布了内置的状态机转译层,而且性能优于ADK的事件总线实现;或者企业市场对事件溯源的采纳速度远低于预期,大家依旧满足于用图编排加手工checkpoint糊完审批流。那时,ADK就可能只是一个内部实验,而不会成为行业里的一个坐标。

本文由 AI 辅助生成,经人工审核后发布。内容由 叶秋 基于实战经验指导完成。

觉得有用?

叶秋

在科技媒体做了4年编辑后转做技术博主,关注AI行业的动态和趋势。比纯工程师更懂表达,比纯媒体人更懂技术。喜欢把复杂的技术变化讲清楚,让更多人理解AI正在怎么改变世界。

发表评论