第 16 期 | 多智能体架构探秘:Flat vs Hierarchical

更新于 2026/4/15

AI 创作机构到底是采取扁平讨论制好,还是上下级金字塔式汇报好?

欢迎回到《LangGraph 多智能体专家课》。我是你们的导师。

在过去的 15 期里,我们的「AI 万能内容创作机构 (AI Content Agency)」从零起步,已经拥有了 Planner(策划)、Researcher(研究员)、Writer(主笔)和 Editor(主编)四位得力干将。之前,我们让他们通过简单的线性流(Linear Flow)接力完成了一篇篇爆款文章。

但是,同学们,现实世界的业务哪有这么理想化? 昨天,机构接到了一个大单:“请针对苹果最新发布的 Vision Pro 撰写一篇深度行业分析,同时输出一篇小红书种草文案,并配上对应的 Twitter 推广线索。

如果还是用以前的“接力赛”模式,Researcher 查完资料丢给 WriterWriter 瞬间懵逼:“我是先写深度分析,还是先写小红书?” 整个流程直接卡死。

当业务复杂度呈指数级上升时,单线流必死,多智能体架构的重构迫在眉睫。 今天,我们就来深度探讨并实操多智能体架构的两大核心流派:扁平化(Flat)层级化(Hierarchical)。我们将为机构引入真正的“主理人”机制,让你的 Agent 团队从“草台班子”蜕变为“正规军”。

敲黑板,集中注意力,我们要开始烧脑了!


🎯 本期学习目标

  1. 认知升级(道):深刻理解 Flat(扁平网络)与 Hierarchical(层级金字塔)架构的底层逻辑与适用场景。
  2. 架构重构(术):掌握在 LangGraph 中引入 Supervisor(主管/路由)节点的标准设计模式。
  3. 实战落地(用):使用 Python + LangGraph 重构我们的 Content Agency,实现由 Planner 统筹分发、各司其职的复杂工作流。
  4. 状态管理(深):解决多 Agent 频繁交互导致的上下文爆炸(Context Bloat)问题。

📖 原理解析:草台班子 vs 现代企业

在多智能体系统(Multi-Agent System, MAS)中,Agent 之间的协作拓扑结构决定了系统的上限。我们来看看两种最经典的架构。

1. Flat Architecture(扁平化/点对点架构)

想象一下初创公司:老板、产品、研发坐在一起。遇到问题,大家在群里七嘴八舌地讨论。

  • 机制:Agent 之间可以直接相互通信,或者通过一个共享的黑板(Blackboard)自由发言。
  • 优点:沟通成本极低,灵活性极高。适合头脑风暴、剧本杀、辩论赛等需要发散性思维的场景。
  • 缺点失控。当任务复杂时,极容易陷入无限循环的“扯皮”中(比如 Writer 觉得资料不够打回给 Researcher,Researcher 觉得 Writer 不懂技术又打回去)。

2. Hierarchical Architecture(层级化/主管架构)

随着公司做大,必须引入“科层制”。我们需要一个包工头(Supervisor)。

  • 机制:设立一个中心化的 Supervisor(在我们的项目中就是 Planner)。所有 Worker Agent(Researcher, Writer, Editor)不能直接互相交流。Worker 完成任务后,必须把结果汇报给 Supervisor,由 Supervisor 决定下一步是交给另一个 Worker,还是结束任务。
  • 优点:秩序井然,逻辑严密,极度适合目标导向的复杂任务分解。
  • 缺点:Supervisor 成了性能瓶颈(Bottleneck)。如果主管是个“傻子”(Prompt 没写好或 LLM 能力弱),整个团队就瘫痪了。

对于我们的 AI Content Agency 来说,面对多渠道、多格式的内容生成需求,Hierarchical(层级化)是唯一的解药。

下面这张图,直观地展示了我们今天要重构的架构走向:

graph TD
    subgraph "❌ 过去的痛点:扁平/线性架构 (草台班子)"
        R1[Researcher] -->|资料| W1[Writer]
        W1 -->|初稿| E1[Editor]
        E1 -->|打回修改?| W1
        style R1 fill:#ffcccc,stroke:#333,stroke-width:2px
        style W1 fill:#ffcccc,stroke:#333,stroke-width:2px
        style E1 fill:#ffcccc,stroke:#333,stroke-width:2px
    end

    subgraph "✅ 今天的重构:Hierarchical 层级架构 (正规军)"
        User((客户需求)) --> S{Planner\n(Supervisor 主管)}
        
        S -->|1. 分配调研任务| R2[Researcher]
        R2 -.->|2. 提交报告| S
        
        S -->|3. 分配撰写任务| W2[Writer]
        W2 -.->|4. 提交初稿| S
        
        S -->|5. 分配审校任务| E2[Editor]
        E2 -.->|6. 提交终稿| S
        
        S -->|7. 任务全部完成| FINISH(((交付输出)))
        
        style S fill:#ff9900,stroke:#333,stroke-width:4px,color:#fff
        style R2 fill:#cce5ff,stroke:#333,stroke-width:2px
        style W2 fill:#cce5ff,stroke:#333,stroke-width:2px
        style E2 fill:#cce5ff,stroke:#333,stroke-width:2px
        style FINISH fill:#ccffcc,stroke:#333,stroke-width:2px
    end

看懂了吗?在新的架构中,Planner 变成了整个 Graph 的路由中枢(Routing Hub)。它不干脏活累活,它只做两件事:思考(Think)派单(Delegate)


💻 实战代码演练

废话不多说,我们直接上代码。我们将使用 LangGraph 的 StateGraph 来构建这个层级网络。为了确保稳定输出路由决策,我们将使用 OpenAI 的 Structured Output(结构化输出)特性来武装我们的 Supervisor。

1. 环境准备与状态定义

首先,我们需要定义整个机构的“共享账本”——AgentState

import operator
from typing import Annotated, Sequence, TypedDict, List
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
from langgraph.graph import StateGraph, START, END

# 1. 定义系统状态 (The State of the Agency)
# 这里继承 TypedDict,messages 使用 operator.add 来实现消息的追加
class AgencyState(TypedDict):
    # 记录所有的历史对话和工作成果
    messages: Annotated[Sequence[BaseMessage], operator.add]
    # 记录当前应该由谁来接手下一个任务
    next_agent: str 

2. 打造核心大脑:Supervisor (Planner)

这是本期的灵魂代码。我们要强迫大模型输出一个特定的 JSON 结构,告诉 LangGraph 下一步该往哪走。

# 2. 定义 Supervisor 的路由结构 (Structured Output)
# 我们机构目前有三个打工人
MEMBERS = ["Researcher", "Writer", "Editor"]

class RouterDecision(BaseModel):
    """Supervisor decides who should act next."""
    # 强制 LLM 只能从这几个选项里挑,或者输出 FINISH
    next_agent: str = Field(
        description="The next agent to act. Choose from 'Researcher', 'Writer', 'Editor', or 'FINISH' if the whole project is done."
    )
    reasoning: str = Field(
        description="Brief explanation of why this agent was chosen."
    )

# 初始化聪明的大脑 (建议用 gpt-4o,主管不能太笨)
llm = ChatOpenAI(model="gpt-4o", temperature=0)

# 使用 with_structured_output 绑定 Pydantic 模型
supervisor_chain = llm.with_structured_output(RouterDecision)

# 编写 Supervisor 节点的逻辑
def supervisor_node(state: AgencyState):
    """
    Supervisor Node: Analyzes the current state and routes to the next agent.
    主管节点:分析当前进度,并派发给下一个 Agent。
    """
    system_prompt = (
        "You are the Chief Planner of an elite AI Content Agency.\n"
        "Your team members are: {members}.\n"
        "Your job is to read the conversation/work history and decide who should act next.\n"
        "Rule 1: Always start with 'Researcher' to gather facts.\n"
        "Rule 2: Pass to 'Writer' to draft the content based on research.\n"
        "Rule 3: Pass to 'Editor' to review and refine the draft.\n"
        "Rule 4: If the Editor has approved the final content and all requirements are met, output 'FINISH'.\n"
        "DO NOT do the work yourself. Just route it."
    ).format(members=", ".join(MEMBERS))
    
    messages = [{"role": "system", "content": system_prompt}] + state["messages"]
    
    # 调用 LLM 进行决策
    print("🧠 [Planner] is thinking...")
    decision = supervisor_chain.invoke(messages)
    print(f"🎯 [Planner] Decision: Next up is -> {decision.next_agent}. Reason: {decision.reasoning}")
    
    # 关键点:返回更新后的 state,特别是 next_agent 字段
    return {"next_agent": decision.next_agent}

3. 定义打工人节点 (Worker Nodes)

为了演示清晰,我们用简单的 Prompt 来模拟这三个专家的工作。在真实的业务代码中,你可以为他们挂载各自的 Tools(比如 Researcher 挂载 Tavily 搜索,Writer 挂载 Markdown 格式化工具)。

# 3. 定义 Worker Nodes
# 辅助函数:将 Worker 的输出包装成 AIMessage,并标明身份
def worker_node_factory(role_name: str, system_instruction: str):
    def node(state: AgencyState):
        print(f"🛠️ [{role_name}] is working on the task...")
        worker_llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
        messages = [{"role": "system", "content": system_instruction}] + state["messages"]
        response = worker_llm.invoke(messages)
        
        # 必须在消息前缀加上名字,让 Supervisor 知道是谁干的
        final_message = AIMessage(
            content=response.content, 
            name=role_name # 标记消息来源
        )
        return {"messages": [final_message]}
    return node

# 实例化三个打工人
researcher_node = worker_node_factory(
    "Researcher", 
    "You are a meticulous Researcher. Read the request, provide detailed bullet points of facts and data. Do not write the final article."
)

writer_node = worker_node_factory(
    "Writer", 
    "You are an expert Writer. Take the research provided by the Researcher and draft a compelling piece of content based on the user's request."
)

editor_node = worker_node_factory(
    "Editor", 
    "You are a strict Editor. Review the Writer's draft. Fix any typos, improve the tone, and output the FINAL polished version. Explicitly state 'FINAL VERSION APPROVED' at the end."
)

4. 组装图网络:构建金字塔

现在,我们要把主管和打工人用 LangGraph 的边(Edges)连接起来。这是 Hierarchical 架构的核心体现。

# 4. 构建 LangGraph
workflow = StateGraph(AgencyState)

# 添加所有节点
workflow.add_node("Supervisor", supervisor_node)
workflow.add_node("Researcher", researcher_node)
workflow.add_node("Writer", writer_node)
workflow.add_node("Editor", editor_node)

# 所有的 Worker 工作完成后,必须无条件汇报给 Supervisor
for member in MEMBERS:
    workflow.add_edge(member, "Supervisor")

# 定义条件路由逻辑
def router(state: AgencyState):
    # 根据 Supervisor 设置的 next_agent 来决定走向
    next_node = state["next_agent"]
    if next_node == "FINISH":
        return END
    return next_node

# Supervisor 的下一步是条件边(Conditional Edge)
workflow.add_conditional_edges(
    "Supervisor", # 起点
    router,       # 路由函数
    {
        "Researcher": "Researcher",
        "Writer": "Writer",
        "Editor": "Editor",
        END: END
    }
)

# 设定图的入口:任务进来,先找主管 Planner
workflow.add_edge(START, "Supervisor")

# 编译图
agency_app = workflow.compile()

5. 模拟运行 Demo

让我们来看看这个“正规军”是如何处理复杂任务的。

# 5. 运行测试
if __name__ == "__main__":
    task_prompt = "Write a short, engaging tweet about the latest breakthrough in Quantum Computing. Make it accessible to the public."
    
    print(f"🚀 User Request: {task_prompt}\n")
    print("-" * 50)
    
    initial_state = {
        "messages": [HumanMessage(content=task_prompt)],
        "next_agent": ""
    }
    
    # 设定递归上限,防止死循环
    config = {"recursion_limit": 15}
    
    for chunk in agency_app.stream(initial_state, config=config):
        # 打印当前执行完毕的节点名称
        if "__end__" not in chunk:
            node_name = list(chunk.keys())[0]
            print(f"✅ [{node_name}] finished its turn.\n")
            print("-" * 50)
            
    print("🎉 Project Completed Successfully!")

预期终端输出模拟:

🚀 User Request: Write a short, engaging tweet about the latest breakthrough in Quantum Computing...

🧠 [Planner] is thinking... 🎯 [Planner] Decision: Next up is -> Researcher. Reason: Need to gather the latest facts on quantum computing breakthroughs first. ✅ [Supervisor] finished its turn.

🛠️ [Researcher] is working on the task... ✅ [Researcher] finished its turn.

🧠 [Planner] is thinking... 🎯 [Planner] Decision: Next up is -> Writer. Reason: Research is complete, now we need to draft the tweet. ✅ [Supervisor] finished its turn.

... (直到 FINISH) 🎉 Project Completed Successfully!


💣 坑与避坑指南 (高阶视角的排错经验)

作为有着 10 年经验的老兵,我必须告诉你们,跑通上面的 Demo 只是第一步。在真实的生产环境中,Hierarchical 架构有几个致命的坑,踩进去就是万劫不复。

坑一:Supervisor 陷入“死循环” (Infinite Loop)

现象Editor 觉得文章不行,打回给 WriterWriter 改了又给 EditorEditor 还是不满意。两人通过 Supervisor 互相踢皮球,你的 API Token 余额瞬间清零。 避坑

  1. 硬性阻断:在 workflow.compile() 时必须设置 recursion_limit(如代码中的 15)。
  2. Prompt 约束:在 Supervisor 的 Prompt 中明确规定:“最多允许修改 2 次,超过次数强制 FINISH”。
  3. 状态注入:在 AgentState 中加入一个 revision_count: int 字段,每次打回加 1,达到阈值直接路由到 END。

坑二:上下文爆炸 (Context Bloat)

现象:由于所有的 Worker 都要把结果汇报给 Supervisor,messages 列表会越来越长。到了第 10 轮交互,每次调用 LLM 都要带上几万 Token 的废话。 避坑: 不要无脑使用 operator.add 累加所有消息。引入**状态压缩(State Summarization)**机制。或者在 State 中区分 scratchpad(打草稿用,定期清空)和 final_artifacts(最终成果,只保留最新版)。

坑三:杀鸡用牛刀 (Over-engineering)

现象:客户只是要求“把这句话翻译成英文”,你却启动了 Planner -> Researcher -> Writer -> Editor 完整流程,耗时 30 秒,花费 0.5 元。 避坑: 架构没有绝对的好坏,只有适不适合。如果你的业务 80% 是简单任务,请在 Supervisor 前面加一个 Triage Node(分诊台节点)。如果是简单任务,直接调用轻量级模型单次输出;复杂任务,再进入层级化网络。


📝 本期小结

今天,我们完成了一次史诗级的重构。

我们探讨了 Flat 架构的灵活与混乱,以及 Hierarchical 架构的严谨与可控。通过引入 LangGraph 的 add_conditional_edges 和大模型的结构化输出能力,我们成功打造了一个拥有独立思考和派单能力的 Supervisor (Planner)

你的 AI Content Agency 现在不再是几个自顾自干活的散兵游勇,而是一个由大脑统帅、各司其职的现代化 AI 生产流水线

思考题留给大家: 在今天的代码中,Supervisor 每次只能派发给一个 Agent。如果客户要求“同时去查百度和谷歌”,我们能让两个 Researcher 并行(Parallel) 工作,然后再汇总给 Writer 吗?

这涉及到 LangGraph 的高级分支与合并(Fan-out / Fan-in)机制。别着急,我们下期《第 17 期 | 并行处理与 Map-Reduce:让你的团队拥有分身术》再见!

下课!同学们记得把代码跑起来,别光看不练!