Skip to content

智能体框架的编排模型 ​

标签
AI/agent/框架
字数
3841 字
阅读时间
16 分钟

03-ReAct 那种手写方式适合理解机制,但构建多个不同类型、逻辑复杂的应用很快会碰壁。框架的价值是把所有智能体共有的重复工作(主循环、状态管理、工具调用、日志)抽象掉,让人专注在业务逻辑上。

框架抽象掉的四件事 ​

价值具体是什么
代码复用提供通用 Agent 基类或执行器,封装核心循环。ReAct 和 Plan-and-Solve 都能基于同一套组件搭出来
三层解耦强制分离关注点:模型层(可换 OpenAI / Anthropic / 本地模型)、工具层(标准化的定义、注册、执行接口)、记忆层(可切换滑动窗口 / 摘要等策略)
状态管理长时运行应用要处理上下文窗口上限、历史持久化、多轮对话状态跟踪——自己写一遍的成本极高
可观测性通过事件回调(on_llm_start、on_tool_end、on_agent_finish)在生命周期节点自动埋点,比满代码撒 print 系统得多

四种编排模型 ​

新一代框架的分野,本质是用什么结构来编排多个智能体。四种代表:

框架编排单位控制流由什么决定
AutoGen群聊中的发言轮次参与者顺序 + 终止条件
AgentScope消息消息路由(MsgHub)
CAMEL两个角色之间的对话Inception Prompt 里的角色与规则
LangGraph图上的节点与边状态 + 条件函数

四种编排模型的差别在「用什么结构编排多个智能体」。

AutoGen        群聊中的发言轮次
   └─ 控制流由「参与者顺序 + 终止条件」决定
   └─ 一群人按名单轮流说话,谁扮演什么由各自的 system message 定

CAMEL          两个角色之间的对话
   └─ 控制流由 Inception Prompt 里的角色与规则决定
   └─ 提示工程全部发生在对话开始前,开始之后两个 agent 互相提示

AgentScope     消息
   └─ 控制流由消息路由(MsgHub)决定
   └─ 流程控制由通信拓扑表达,而不是由状态转移表表达

LangGraph      图上的节点与边
   └─ 控制流由「状态 + 条件函数」决定
   └─ 唯一的显式状态机,图天然支持循环

               ┌── 建模成本:CAMEL 最低(写三份 prompt),LangGraph 最高(画图)
               └── 控制力  :反过来,LangGraph 最强(可插入检查点与人工介入)

AutoGen:对话轮询 ​

0.7.4 版做过一次彻底重构,从类继承转向组合式架构,最显著的变化是分层和异步优先:

  • autogen-core 封装与模型交互、消息传递等底层能力;autogen-agentchat 在其上提供对话式应用的高级接口
  • 全面转向 async/await——多智能体协作的主要耗时是网络请求,异步让等待一个智能体响应时能处理其他任务,避免线程阻塞

两类核心组件分工清晰:

  • AssistantAgent 封装一个 LLM,是任务的主要解决者;靠不同的 system message 赋予不同专家角色
  • UserProxyAgent 不依赖 LLM 回复,既当人类用户的代言人,又可配置为执行代码或调用工具的执行器。它把「思考」和「行动」显式拆开了

编排用 RoundRobinGroupChat,按 participants 列表顺序依次激活发言者:

python
team_chat = RoundRobinGroupChat(
    participants=[product_manager, engineer, code_reviewer, user_proxy],
    termination_condition=TextMentionTermination("TERMINATE"),
    max_turns=20,
)

三个参数各自的职责不能混:participants 顺序决定发言次序;termination_condition 决定何时结束(这里靠消息里出现 TERMINATE);max_turns 是防无限循环的安全阀。

接非 OpenAI 模型时要显式传 model_info 字典(function_calling、max_tokens、context_length、vision、json_output 等),框架靠它判断模型的能力边界:

python
OpenAIChatCompletionClient(
    model="deepseek-chat",
    base_url="https://api.deepseek.com/v1",
    model_info={"function_calling": True, "max_tokens": 4096,
                "context_length": 32768, "vision": False,
                "json_output": True, "family": "deepseek",
                "structured_output": True},
)

代价:基于 LLM 的对话本质不确定,智能体可能偏离预期走向意外分支甚至循环;出问题时拿到的是一长串对话历史,而不是错误堆栈——「对话式调试」比读堆栈难得多。

CAMEL:角色扮演,把控制写进两个 prompt ​

CAMEL 提供的协作方法叫角色扮演(Role-Playing):只需为两个智能体设定角色和共同任务目标,它们就能自主多轮对话、相互配合完成任务。

它的核心机制是 Inception Prompting——「Inception」取的是「植入」的意思:所有提示工程只发生在对话开始前,一旦对话开始,两个 agent 就自动互相提示,直到终止。

Inception Prompt 由三个 prompt 组成:

prompt作用
Task Specifier Prompt(PT)把初步的想法变成具体、可执行的任务描述。任务指定器 agent 靠想象力做这件事
Assistant System Prompt(PA)助手侧的角色、任务、通信协议、终止条件、约束
User System Prompt(PU)用户侧,与助手侧尽量对称

该文以 AI Society 场景为例给出了完整模板。它的每一条设计选择都对应一个观察到的失败,拆开看才知道为什么这么写:

提示词里的条款防的是什么
Never forget you are a <role> and I am a <role>分配角色并告知对方角色
Never flip roles! Never instruct me!角色翻转——该文观察到助手会突然接管并开始指挥用户,用户照做
You must decline my instruction honestly if you cannot perform... due to physical, moral, legal reasons or your capability禁止产出有害、虚假、违法、误导信息
Unless I say the task is completed, you should always start with: Solution:flake response——含糊的「我会去做某事」这类不完整回复。强制固定开题格式能避免偏离对话结构
Always end your solution with: Next request.保证对话继续往下走
User 侧:You must instruct me ... ONLY in the following two ways: 1. Instruct with a necessary input; 2. Instruct without any input让生成的 instruction-solution 对可以直接拿去微调 LLM——这是「指令跟随」的典型数据结构
User 侧任务完成时只回复一个 end-of-task token无限道别循环——没有这个终止 token,两个 agent 会永远互相「谢谢」「再见」

最后那条尤其值得记:自主多轮对话的终止不能靠两个 agent 自己「感觉好了」,必须有一个显式的、由用户侧单方面发出的结束信号。

另外还有 Critic-In-The-Loop:引入一个 critic agent 从角色扮演 agent 的提议中挑选或给反馈,形成树搜索式的决策。critic 可以是 AI,也可以是人。

CAMEL 的建模成本是四种里最低的——不需要画流程图,只需要写三份 prompt。代价是控制力最弱:对话怎么走全交给模型,中间没有可插入的检查点(除非再加 critic)。

实验用两个 gpt-3.5-turbo 跑,并据此产出了 CAMEL AI Society 和 CAMEL Code 两个对话数据集。数据集的生成链路是:先生成助手角色 → 生成用户角色 → 生成任务 → 用 task specifier 具体化。

CAMEL 的核心机制是:所有提示工程只发生在对话开始前。

   初步想法
      │
      ▼
┌─ 对话开始前(一次性)─────────────────────────────────────┐
│                                                          │
│  Task Specifier Prompt  P_T                             │
│     把初步想法变成具体、可执行的任务描述(任务指定器靠想象力做)│
│                    │                                     │
│         ┌──────────┴──────────┐                          │
│         ▼                     ▼                          │
│  Assistant System       User System                      │
│  Prompt  P_A            Prompt  P_U                      │
│  角色 / 任务 / 协议      与 P_A 尽量对称                   │
│  终止条件 / 约束                                          │
└─────────┬──────────────────────┬─────────────────────────┘
          │                      │
          ▼                      ▼
     ┌──────────┐           ┌──────────┐
     │ 助手 agent│ ◀───────▶ │ 用户 agent│   两人自动互相提示,
     └──────────┘   多轮对话  └──────────┘   直到出现终止 token

每条 prompt 条款都对应一个观察到的失败,拆开才知道为什么这么写
   Never flip roles!                     防角色翻转:助手突然接管并开始指挥用户
   Unless I say the task is completed,
     always start with: Solution:        防 flake response:含糊的「我会去做某事」
   Always end your solution with:
     Next request.                       保证对话继续往下走
   User 侧任务完成时只回复一个 end-of-task token
                                         防无限道别循环
     └─ 自主多轮对话的终止不能靠两个 agent 自己「感觉好了」,
        必须有一个显式的、由用户侧单方面发出的结束信号

AgentScope:消息驱动 ​

选的是组合式架构 + 消息驱动,而不是继承式设计。核心差别在于把智能体交互抽象成消息的发送与接收,而不是函数调用。

消息是统一的结构体(发送者、内容、角色、元数据),带来四个工程属性:

属性含义
异步解耦发送方与接收方在时间上解耦,无需相互等待,天然支持高并发
位置透明智能体无需知道对方在本地进程还是远程服务器,路由由消息系统处理
可观测性每条消息都可记录、追踪、分析
可靠性消息可持久化与重试,故障后仍能保证最终一致性

架构自上而下四层:基础组件层(Message / Memory / Model API / Tool)→ 智能体基础设施层(预构建智能体、ReAct 实现、钩子、并行工具调用、异步执行与实时控制)→ 多智能体协作层(MsgHub + Pipeline 工作流编排)→ 开发与部署层(Runtime + Studio)。

MsgHub 是中枢,三个能力最值得记:多模式路由(点对点 / 广播 / 组播)、消息持久化(自动落 SQLite、MongoDB,长任务可恢复)、原生分布式(跨进程跨服务器靠 RPC 传递,对开发者透明)。

生命周期由统一基类 AgentBase 管理,开发者通常只需要实现 reply(x: Msg) -> Msg,可选实现 observe。内部逻辑与外部通信被这个接口彻底分开了。

一个值得注意的用法:把流程建模成消息交互模式,而不是中心化状态机。例如狼人杀里「狼人私聊」靠 MsgHub 动态创建一个只含狼人玩家的临时私密频道来实现,而不是一次函数调用——流程控制由通信拓扑表达,而不是由状态转移表表达。

AgentScope 的架构自上而下四层。

┌───────────────────────────────────────────────────────────┐
│ 开发与部署层    Runtime + Studio                            │
├───────────────────────────────────────────────────────────┤
│ 多智能体协作层  MsgHub(点对点 / 广播 / 组播)+ Pipeline 工作流编排 │
│                 ├─ 消息持久化:自动落 SQLite、MongoDB,长任务可恢复 │
│                 └─ 原生分布式:跨进程跨服务器走 RPC,对开发者透明  │
├───────────────────────────────────────────────────────────┤
│ 智能体基础设施层  预构建智能体 / ReAct 实现 / 钩子            │
│                  并行工具调用 / 异步执行与实时控制            │
├───────────────────────────────────────────────────────────┤
│ 基础组件层      Message / Memory / Model API / Tool          │
└───────────────────────────────────────────────────────────┘
          ▲ 依赖方向向上(上层依赖下层)

把智能体交互抽象成「消息的发送与接收」而不是函数调用,带来四个工程属性
   异步解耦    发送方与接收方在时间上解耦,无需相互等待,天然支持高并发
   位置透明    无需知道对方在本地进程还是远程服务器,路由由消息系统处理
   可观测性    每条消息都可记录、追踪、分析
   可靠性      消息可持久化与重试,故障后仍能保证最终一致性

生命周期由统一基类 AgentBase 管理,开发者通常只需实现 reply(x: Msg) -> Msg。
内部逻辑与外部通信被这个接口彻底分开。

LangGraph:状态图 ​

把执行流程建模为状态机,用有向图表示。三个基本构成要素:

全局状态(State)——一个 TypedDict,所有节点围绕它读写:

python
class AgentState(TypedDict):
    messages: List[str]
    current_task: str
    final_answer: str

节点(Nodes)——每个节点是一个 state -> state 的 Python 函数,是执行工作的单元:

python
def planner_node(state: AgentState) -> AgentState:
    plan = f"为任务 '{state['current_task']}' 生成的计划..."
    state["messages"].append(plan)
    return state

边(Edges)——常规边固定跳转方向;**条件边(Conditional Edges)**用一个函数读当前状态,动态决定下一步跳哪个节点:

python
def should_continue(state: AgentState) -> str:
    if len(state["messages"]) < 3:
        return "continue_to_planner"
    state["final_answer"] = state["messages"][-1]
    return "end_workflow"

条件函数返回的字符串必须与注册条件边时定义的键匹配。这就是 LangGraph 的独门能力:图天然支持循环,所以实现 Reflection 这种迭代修正的工作流不需要任何特殊技巧——「回到上一个节点」就是一条普通的边。链式结构(LangChain)做不到这一点,信息只能单向流动。

LangGraph 把流程建模成状态机,用有向图表示。

   全局状态(State,一个 TypedDict)被所有节点围绕读写
   ┌──────────────── AgentState ─────────────────┐
   │ messages: List[str]                         │
   │ current_task: str                           │
   │ final_answer: str                           │
   └─────────────────────────────────────────────┘
          ▲                 ▲                  ▲
          │                 │                  │
   ┌──────┴──────┐  ┌──────┴──────┐  ┌─────────┴────────┐
   │   节点      │  │   节点      │  │  条件边           │
   │ state→state │  │ state→state │  │ 读当前状态,       │
   │ 执行工作的单元│  │             │  │ 动态决定下一步跳哪 │
   └──────┬──────┘  └──────┬──────┘  └─────────┬────────┘
          │                │                    │
          └────────────────┴────────────────────┘
              常规边:固定跳转方向 ◀── 条件函数返回的字符串
                                       必须与注册时定义的键匹配

   独门能力是「图天然支持循环」:
      实现 Reflection 这种迭代修正的工作流不需要任何特殊技巧 ——
      「回到上一个节点」就是一条普通的边。
      链式结构(LangChain)做不到这一点,信息只能单向流动。

选哪一类 ​

判据选
流程固定、靠角色分工推进AutoGen(对话轮询)
只需两个角色互相激发,不在意过程控制CAMEL(角色扮演,建模成本最低,控制力最弱)
要持久化、要分布式、要跨进程扩展AgentScope(消息驱动)
需要循环、分支、回溯、人工介入LangGraph(状态图)
需要人始终在环、能随时接管AutoGen(UserProxyAgent 天然提供接口)

一条反过来的判据更实用:框架替你处理的东西,恰好是你出问题时要排查的东西——输出格式解析、工具调用失败重试、防止死循环。所以 03-ReAct 那样先手写一遍,再上手框架,出问题时才知道该往哪看。

相关 ​

  • 03-ReAct —— 手写版的核心循环
  • MCP 协议 —— 工具接入的标准化层,与框架的编排层正交

参考 ​

贡献者 ​

文件历史 ​