为什么有些 Multi-Agent 工作流不该用 LangGraph:静态编排 vs 动态协作


一、引言

钩子

上周凌晨两点,我接到了前同事阿凯的求救电话,他带着团队花了三周用LangGraph搭的智能客服多Agent系统上线第一天就崩了。原因很简单:运营临时加了一个「物流问题转快递服务商接口」的需求,他为了加这个逻辑,改了7条边的条件,不小心把原来的退款流程的路由给改坏了,导致所有退款请求都跑到了技术支持那里,一晚上接了2000多个投诉。挂了电话我翻了下他的代码,整个Graph定义了23个节点,47条条件边,路由逻辑的代码写了300多行,改一个需求要捋半天的流转路径,稍不留神就踩坑。我给了他一个建议:把前面的身份验证、问题初筛保留LangGraph的静态流程,后面的具体问题处理换成AutoGen的动态群聊协作,他花了一天时间改完,后续加新的客服角色只要加几行Agent定义的代码就行,再也没出过类似的问题。

如果你最近在做多Agent相关的开发,大概率也遇到过类似的困惑:好像现在所有的Multi-Agent教程都在推荐用LangGraph,仿佛它是Multi-Agent开发的银弹,但真的上手之后,遇到流程灵活多变的场景,代码很快就变成了"面条边",维护成本指数级上升。

定义问题/阐述背景

随着大模型技术的成熟,Multi-Agent已经从实验室概念落地到了各行各业:客服系统、科研协作、产品研发、游戏NPC等场景都能看到多Agent的身影。而LangGraph作为LangChain生态推出的多Agent编排工具,凭借其可控的状态管理、完善的可观测性、和LangChain生态的无缝集成,迅速成为了很多开发者的首选。

但很多开发者忽略了一个核心的设计取舍:LangGraph本质上是静态编排的工具,它的所有流转路径、节点逻辑都需要开发者提前预定义,而很多Multi-Agent场景需要的是动态协作的能力:Agent可以自主协商分工、自主决定流转路径、甚至动态增减参与的Agent。把动态协作的需求硬套到静态编排的框架上,本质上是方枘圆凿,只会徒增开发维护成本。

亮明观点/文章目标

读完这篇文章,你将收获:

  1. 彻底搞懂静态编排和动态协作两个核心概念的区别、适用边界、优劣对比
  2. 明确LangGraph的设计目标和适用场景,知道什么时候该用、什么时候不该用
  3. 掌握静态编排和动态协作的选型决策方法,以及两者结合的最佳实践
  4. 通过实战代码对比,直观感受两种范式在不同场景下的开发效率差异

本文不会否定LangGraph的价值——相反,我自己在很多固定流程的场景下也会优先选择LangGraph,本文的核心是帮你避开"为了用LangGraph而用LangGraph"的误区,找到最适合自己场景的技术方案。


二、基础知识/背景铺垫

核心概念定义

在展开讨论之前,我们先把几个核心概念定义清楚,避免后续的理解偏差:

1. Multi-Agent工作流

指由多个具备自主决策能力的Agent共同完成一个特定任务的执行流程,核心要素包括:多个Agent角色、通信机制、任务目标、状态管理。根据流程的可变性,我们可以把Multi-Agent工作流分为两大范式:静态编排和动态协作。

2. 静态编排(Static Orchestration)

指所有的流程节点、流转规则、参与角色都由开发者提前预定义,执行过程中只会按照预先设定的路径流转,最多支持有限的条件分支。核心特征是:决策主体是开发者预定义的规则,而不是Agent本身,所有的执行路径都是可预测、可审计的。LangGraph就是静态编排范式的典型代表。

3. 动态协作(Dynamic Collaboration)

指流程的流转路径、参与角色都不需要开发者提前预定义,Agent根据任务目标、自身角色、当前上下文自主决定下一步的动作:是自己处理、还是转给其他Agent、还是邀请新的Agent加入协作。核心特征是:决策主体是每个Agent本身,执行路径是动态生成的,甚至可以出现超出开发者预期的涌现性协作结果。AutoGen、ChatDev、MetaGPT都是动态协作范式的典型代表。

4. LangGraph核心设计原理

LangGraph的底层是基于状态机的有向图模型,核心组成包括:

  • State(状态):全局共享的状态对象,所有节点的读写都基于这个状态
  • Node(节点):每个节点对应一个Agent、工具或者处理函数,执行特定的逻辑并更新状态
  • Edge(边):定义节点之间的流转规则,包括普通边(固定流转)和条件边(根据状态判断流转方向)
  • 编排器:负责按照预定义的边规则调度节点执行,管理状态的更新

LangGraph的所有流转逻辑都必须由开发者提前编码到边的规则中,执行过程中不会出现超出预定义规则的流转路径。

核心概念对比

我们从10个核心维度对静态编排和动态协作做一个全面的对比,帮你快速区分两者的差异:

对比维度 静态编排(LangGraph为代表) 动态协作(AutoGen为代表)
决策主体 开发者预定义的编排规则 各Agent自主决策(LLM驱动)
流转路径 所有路径提前定义,最多支持有限条件分支 路径完全不固定,随任务上下文动态生成
Agent数量 固定,必须提前注册到图中 动态增减,可按需邀请新Agent加入
可控性 极高,每一步执行都可预测、可审计 较低,可能出现超出预期的协作行为
开发成本(固定流程场景) 低,逻辑清晰,可视化编排门槛低 高,需要定义Agent角色、协商规则、终止条件
开发成本(可变流程场景) 极高,需要枚举所有可能的分支,复杂度随分支数指数上升 低,只需调整Agent角色或任务目标,复杂度线性上升
维护成本 流程变更时需要修改边规则,牵一发动全身 流程变更时只需修改Agent定义,无耦合
容错性 高,出错后可按预定义规则重试、回滚 低,Agent决策错误可能导致流程跑偏
Token开销 低,无额外的Agent决策开销 高,每次交互都需要Agent做决策判断
涌现性 无,所有行为都是预定义的 有,可能出现超出开发者预期的创新协作结果
适用场景 固定流程、可控性要求高的场景:RAG、数据处理、标准化业务流程 开放域、创意类、流程不固定的场景:科研协作、产品设计、复杂客服

核心概念关系与架构图

ER实体关系图

适配固定流程场景

适配可变流程场景

多Agent工作流

string

任务目标

执行日志

全链路记录

状态

全局上下文

静态编排

Node[]

预定义节点

Edge[]

预定义边

function

转移规则

编排器

调度核心

动态协作

Agent[]

角色定义

消息队列

通信中间件

function

决策模型

共识规则

验收标准

静态编排架构图

编排器

Agent1/工具1

Agent2/工具2

Agent3/工具3

全局状态

预定义边规则

动态协作架构图

Agent1

Agent2

Agent3

动态加入的Agent4

全局消息队列

所有Agent

任务目标

角色定义

数学模型定义

静态编排状态转移模型

静态编排的状态转移是完全确定的,所有转移函数都由开发者提前定义:
St+1=F(St,Ot) S_{t+1} = F(S_t, O_t) St+1=F(St,Ot)
其中:

  • StS_tSt是t时刻的全局状态
  • OtO_tOt是t时刻当前节点的输出
  • FFF是开发者预先定义的转移函数,所有可能的取值都已经提前枚举,不存在未知的转移路径
动态协作状态转移模型

动态协作的状态转移是不确定的,由所有活跃Agent的自主决策共同决定:
St+1=⋃i=1Ntfi(St,Mt,Ri,G) S_{t+1} = \bigcup_{i=1}^{N_t} f_i(S_t, M_t, R_i, G) St+1=i=1Ntfi(St,Mt,Ri,G)
其中:

  • NtN_tNt是t时刻活跃的Agent数量,是动态变化的
  • fif_ifi是第i个Agent的决策函数,由大模型驱动,不需要开发者提前定义
  • MtM_tMt是t时刻的全局消息队列
  • RiR_iRi是第i个Agent的角色定义
  • GGG是全局任务目标

三、核心内容:哪些Multi-Agent工作流不该用LangGraph

我们通过三个典型的场景,结合实战代码对比,来直观感受LangGraph在动态协作场景下的痛点,以及动态协作范式的优势。

场景一:开放域任务,无法提前枚举所有流程分支

问题描述

你需要搭建一个科研协作多Agent系统,任务目标是:输入一个科研方向,自动完成文献检索、数据整理、综述撰写、绘图排版的全流程
这个场景的核心痛点是:你根本无法提前枚举所有可能的流程分支:

  • 有些方向需要先做数据清洗,有些不需要
  • 有些方向需要引用外文文献,需要翻译Agent介入
  • 有些方向需要做定量分析,需要调用数据分析Agent
  • 有些方向需要做实验设计,需要临时加入实验专家Agent
    如果你硬要用LangGraph实现,就需要把所有可能的分支都提前预定义,边的数量会随着分支的增加指数级上升,很快就会变成无法维护的"面条边"。
LangGraph实现痛点

我们先看用LangGraph实现的简化版代码,你就能感受到复杂度:

from typing import TypedDict, List
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o")

# 定义状态
class ResearchState(TypedDict):
    topic: str
    papers: List[dict]
    translated_papers: List[dict]
    cleaned_data: List[dict]
    outline: str
    draft: str
    images: List[str]
    final_paper: str
    need_translate: bool
    need_data_clean: bool
    need_experiment: bool

# 节点1:文献检索
def search_papers(state: ResearchState):
    # 调用文献检索工具,返回论文列表
    papers = [{"title": "论文1", "content": "...", "language": "en"}]
    need_translate = any(p["language"] == "en" for p in papers)
    return {"papers": papers, "need_translate": need_translate}

# 节点2:论文翻译
def translate_papers(state: ResearchState):
    # 调用翻译Agent翻译英文论文
    translated = [{"title": "论文1(中文)", "content": "..."}]
    return {"translated_papers": translated}

# 节点3:数据清洗
def clean_data(state: ResearchState):
    # 调用数据清洗Agent处理论文中的数据
    cleaned = [{"data": "..."}]
    return {"cleaned_data": cleaned}

# 节点4:大纲生成
def generate_outline(state: ResearchState):
    # 生成综述大纲
    outline = "1. 引言\n2. 研究现状\n3. 实验结果\n4. 结论"
    need_experiment = "实验" in outline
    return {"outline": outline, "need_experiment": need_experiment}

# 节点5:实验设计
def design_experiment(state: ResearchState):
    # 调用实验专家Agent设计实验
    return {"draft": state["draft"] + "\n实验设计:..."}

# 节点6:草稿生成
def generate_draft(state: ResearchState):
    # 生成综述草稿
    return {"draft": "草稿内容..."}

# 节点7:绘图
def generate_images(state: ResearchState):
    # 调用绘图Agent生成图表
    return {"images": ["fig1.png"]}

# 节点8:最终排版
def format_paper(state: ResearchState):
    # 排版生成最终论文
    return {"final_paper": "最终综述.pdf"}

# 路由逻辑1:检索后判断是否需要翻译
def after_search(state: ResearchState):
    return "translate_papers" if state["need_translate"] else "generate_outline"

# 路由逻辑2:翻译后判断是否需要数据清洗
def after_translate(state: ResearchState):
    return "clean_data" if len(state["papers"]) > 10 else "generate_outline"

# 路由逻辑3:大纲生成后判断是否需要实验设计
def after_outline(state: ResearchState):
    return "design_experiment" if state["need_experiment"] else "generate_draft"

# 路由逻辑4:草稿生成后判断是否需要绘图
def after_draft(state: ResearchState):
    return "generate_images" if "图表" in state["draft"] else "format_paper"

# 构建图
workflow = StateGraph(ResearchState)
# 注册所有节点
workflow.add_node("search_papers", search_papers)
workflow.add_node("translate_papers", translate_papers)
workflow.add_node("clean_data", clean_data)
workflow.add_node("generate_outline", generate_outline)
workflow.add_node("design_experiment", design_experiment)
workflow.add_node("generate_draft", generate_draft)
workflow.add_node("generate_images", generate_images)
workflow.add_node("format_paper", format_paper)
# 定义边
workflow.set_entry_point("search_papers")
workflow.add_conditional_edges("search_papers", after_search, {
    "translate_papers": "translate_papers",
    "generate_outline": "generate_outline"
})
workflow.add_conditional_edges("translate_papers", after_translate, {
    "clean_data": "clean_data",
    "generate_outline": "generate_outline"
})
workflow.add_edge("clean_data", "generate_outline")
workflow.add_conditional_edges("generate_outline", after_outline, {
    "design_experiment": "design_experiment",
    "generate_draft": "generate_draft"
})
workflow.add_edge("design_experiment", "generate_draft")
workflow.add_conditional_edges("generate_draft", after_draft, {
    "generate_images": "generate_images",
    "format_paper": "format_paper"
})
workflow.add_edge("generate_images", "format_paper")
workflow.add_edge("format_paper", END)

app = workflow.compile()

你可以看到,仅仅是简化版的科研流程,我们已经写了8个节点、4个路由逻辑、十几条边,如果要再加一个"引用格式校验"的功能,需要修改至少3个地方的路由规则,稍不留神就会出错。如果要覆盖所有可能的分支,代码量会膨胀到现在的10倍以上。

动态协作实现方案

我们用AutoGen实现同样的功能,代码量不到LangGraph的1/3,而且扩展性极强:

import autogen

llm_config = {"model": "gpt-4o", "api_key": "你的API_KEY"}

# 定义Agent角色,不需要提前定义流转规则
search_agent = autogen.AssistantAgent(
    name="文献检索专家",
    system_message="你是文献检索专家,负责检索指定方向的最新文献,如果有英文文献,自动@翻译专家处理,检索完成后@大纲专家生成综述大纲。",
    llm_config=llm_config
)

translate_agent = autogen.AssistantAgent(
    name="翻译专家",
    system_message="你是翻译专家,负责把英文文献翻译成中文,翻译完成后@大纲专家继续处理。",
    llm_config=llm_config
)

data_agent = autogen.AssistantAgent(
    name="数据处理专家",
    system_message="你是数据处理专家,负责清洗整理文献中的数据,完成后@大纲专家继续处理。",
    llm_config=llm_config
)

outline_agent = autogen.AssistantAgent(
    name="大纲专家",
    system_message="你是大纲专家,负责生成综述大纲,如果大纲中需要实验设计,@实验专家处理,完成后@写作专家生成草稿。",
    llm_config=llm_config
)

experiment_agent = autogen.AssistantAgent(
    name="实验专家",
    system_message="你是实验专家,负责设计实验方案,完成后@写作专家生成草稿。",
    llm_config=llm_config
)

writing_agent = autogen.AssistantAgent(
    name="写作专家",
    system_message="你是写作专家,负责生成综述草稿,如果需要图表,@绘图专家处理,完成后@排版专家生成最终论文。",
    llm_config=llm_config
)

image_agent = autogen.AssistantAgent(
    name="绘图专家",
    system_message="你是绘图专家,负责生成论文需要的图表,完成后@排版专家生成最终论文。",
    llm_config=llm_config
)

format_agent = autogen.AssistantAgent(
    name="排版专家",
    system_message="你是排版专家,负责生成最终的综述论文,完成后回复「任务完成」。",
    llm_config=llm_config
)

user_proxy = autogen.UserProxyAgent(
    name="用户",
    human_input_mode="NEVER",
    is_termination_msg=lambda x: "任务完成" in x.get("content", ""),
    llm_config=llm_config
)

# 创建群聊,所有Agent自主决定流转
groupchat = autogen.GroupChat(
    agents=[user_proxy, search_agent, translate_agent, data_agent, outline_agent, experiment_agent, writing_agent, image_agent, format_agent],
    messages=[],
    max_round=20
)
manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config)

# 启动任务
user_proxy.initiate_chat(manager, message="请帮我研究固态电池的最新进展,生成一篇综述论文。")

你可以看到,我们完全不需要定义任何边和路由规则,Agent会根据自己的角色和任务目标自主决定下一步找谁协作,如果要加一个"引用格式校验"的功能,只需要加一个Agent的定义,放到群聊里就行,不需要修改任何其他代码,扩展性极强。

场景二:Agent数量动态变化的场景

问题描述

你需要搭建一个企业内部的多Agent工单系统,不同的工单需要不同部门的Agent参与:

  • 普通IT工单:只需要IT支持Agent
  • 财务报销工单:需要财务Agent、部门主管Agent
  • 采购工单:需要采购Agent、财务Agent、仓库Agent
  • 特殊工单:可能需要临时拉外部服务商的Agent参与
    如果你用LangGraph实现,需要提前枚举所有可能的Agent组合,定义对应的分支,每新增一种工单类型,就要修改大量的边规则,维护成本极高。

场景三:需要涌现性协作的创意类场景

问题描述

你需要搭建一个多Agent产品设计团队,任务是"设计一款面向老年人的智能手环",这个场景需要Agent自主协商分工、头脑风暴,甚至产生超出开发者预期的创意点。如果你用LangGraph实现,所有的流程都是预定义的,等于直接掐死了涌现性的可能,根本出不来创新的结果。

四、进阶探讨/最佳实践

常见陷阱与避坑指南

  1. 为了用LangGraph而用LangGraph:很多开发者觉得LangGraph是现在的主流,不管什么场景都往上套,结果把动态逻辑硬写到条件边里,代码变成"面条边",维护成本指数级上升。避坑方法:先评估场景的流程确定性,可变分支超过30%就不要用LangGraph。
  2. 用动态协作框架做固定流程任务:比如用AutoGen做RAG流程,结果Agent经常瞎回答,Token开销还高。避坑方法:固定流程优先用LangGraph,可控性高、成本低。
  3. 忽略可观测性:动态协作场景如果没有全链路日志,出了问题根本不知道哪个Agent决策错了。避坑方法:不管用哪种范式,都要加全链路的消息和状态日志,动态协作场景还要加Agent决策的审计日志。

性能与成本考量

指标 静态编排(LangGraph) 动态协作(AutoGen)
执行效率 高,无额外决策开销 低,每次交互都需要LLM做决策
Token开销 低,只有节点处理的Token消耗 高,额外增加Agent决策的Token消耗,一般是静态编排的2-5倍
开发成本(固定流程) 低,人均日产出5-10个节点 高,需要调试Agent角色和协商规则
开发成本(可变流程) 高,分支超过10个之后成本指数上升 低,新增需求只需要调整Agent定义
维护成本(年) 固定流程低,可变流程是开发成本的3倍以上 固定流程高,可变流程是开发成本的0.5倍

最佳实践总结

  1. 选型决策树

开始选型

流程是否90%以上固定?

是否需要强可控、可审计?

选LangGraph静态编排

是否是开放域/创意类/Agent动态变化场景?

选动态协作框架

动静结合:固定部分用LangGraph,可变部分用动态协作

  1. 动静结合是最优解:大部分复杂场景都可以用动静结合的方案:把核心的、固定的流程(比如身份验证、支付、数据合规校验)用LangGraph封装成工具,供动态协作的Agent调用,既保证核心流程的可控性,又保证非核心流程的灵活性。
  2. 给LangGraph用户的建议:如果你的场景确实有部分动态需求,可以在LangGraph的节点中嵌入动态协作的逻辑,比如定义一个"群聊协作"节点,节点内部用AutoGen的动态群聊处理,处理完成后返回结果到LangGraph的状态中,继续后面的固定流程。

五、结论

核心要点回顾

  1. LangGraph是静态编排范式的优秀工具,它的设计目标是可控性和可观测性,适合固定流程、强可控要求的场景,不是所有Multi-Agent场景的银弹。
  2. 静态编排和动态协作是互补的两种范式,没有优劣之分,只有适合不适合的场景:固定流程选静态编排,可变流程选动态协作。
  3. 大部分复杂的企业级Multi-Agent系统都应该采用动静结合的架构,兼顾可控性和灵活性。

展望未来

未来的Multi-Agent框架一定会走向动静融合的路线:开发者可以灵活配置哪些部分用静态编排保证可控,哪些部分用动态协作保证灵活,同时提供统一的可观测、可调试、可审计的能力,甚至可以自动根据任务的特征选择最合适的编排范式,大幅降低Multi-Agent应用的开发门槛。

行动号召

  1. 你可以把自己用LangGraph或者动态协作框架踩过的坑,或者不确定该如何选型的场景,发到评论区,我们一起讨论。
  2. 如果你想深入学习相关技术,可以参考官方资源:
    • LangGraph官方文档:https://langchain-ai.github.io/langgraph/
    • AutoGen官方文档:https://microsoft.github.io/autogen/
    • ChatDev开源地址:https://github.com/OpenBMB/ChatDev
  3. 动手尝试一下动静结合的方案,把你现有LangGraph项目中的可变部分换成动态协作逻辑,感受一下开发效率的提升。

多Agent编排技术发展历史

时间阶段 代表技术/框架 核心范式 核心特点 适用场景
2010年以前 UML活动图、BPEL 人工静态编排 完全人工定义所有流程,无AI参与 传统企业级业务流程
2010-2020年 Airflow、Prefect、Argo 自动化静态编排 支持定时触发、重试回滚,适用于数据调度 固定流程的自动化任务
2022-2023年 LangChain Chain、Dify工作流 LLM辅助静态编排 引入LLM做节点处理,流转规则人工预定义 简单LLM应用,单轮RAG
2023年 LangGraph 可控循环静态编排 支持循环、多轮状态流转,可观测性强 固定流程的多轮LLM应用
2023年底-2024年 AutoGen、ChatDev、MetaGPT 动态自主协作 Agent自主决策流转,支持动态增减角色 开放域、复杂多Agent场景
2024年以后 新一代融合框架 动静混合编排 自动适配场景,兼顾可控性和灵活性 所有多Agent场景

(全文完,约11200字)

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐