Agent 架构图解:从工作流到事件驱动工单
本文总结用 12 张可以逐步播放的动画图,把工作流、单 Agent、多 Agent 和事件驱动工单放在同一套问题下比较:控制权在谁手里,状态存在哪里,消息怎么流动。
先说结论
市面上的 Agent 架构名字很多,但决定一个系统长什么样的,主要是三个问题:
- 控制权在谁手里:下一步做什么,是代码写死的,还是模型当场决定的?如果有多个 Agent,同一时刻由谁拍板?
- 状态存在哪里:任务做到哪一步、拿到了哪些证据,是存在某个模型的上下文里,还是存在数据库、共享状态这类模型之外的地方?
- 消息怎么流动:Agent 之间是调用与返回、整段交接、轮流发言,还是都去读写同一块黑板?
本文按控制权从“代码”往“模型”再往“系统”的方向,依次画出 12 种结构。每张图都可以播放,小圆点是一条消息,深色描边是这一步正在干活的节点,虚线圈表示此刻谁持有控制权。图右上角的“对比 ↗”会打开 Agent 架构对比台,在那里可以任选两种并排同步播放。
例子沿用 主线 里的报销案:员工问“我上周出差打车超标了,还能报吗?能的话帮我提报销工单”。依据是《差旅费管理办法》第 4.2 条,发票 INV-102 金额 118.5 元,标准 80 元,超标 38.5 元,数字都是示意。每种结构后面都写了它在这个案例里会落在哪儿。
先认一下图里的符号:
一个贯穿全文的判断,出自 Agent 核心:能用 workflow 稳定解决的,不要上 Agent;能用单 Agent + 多 Skill 解决的,不要上多 Agent。 下面的顺序也按这条原则排,能简单就简单。
一、工作流:路径由代码决定
工作流里也会调用大模型,但走哪条路是开发者事先写好的。Anthropic 在 Building Effective Agents 里把它和 Agent 明确分开:工作流按预定义的代码路径编排模型和工具,Agent 则由模型动态决定自己的流程。前者可预测,后者灵活。
1. 固定流水线(Prompt Chaining)
动画图:固定流水线。启用 JavaScript 后可以逐步播放。
把任务拆成几步,上一步的输出是下一步的输入,步骤之间可以插一段代码做检查。每一步的提示词短、目标单一,所以单步准确率高,也容易写测试。
- 适合:流程稳定、能事先写清楚的任务,比如翻译后校对、按固定格式生成报告。
- 代价:只能处理设计时想到的情况;步骤串行,延迟叠加;前一步的错误会一路往下传。
- 报销案里:“员工确认后才建单”就是写死的一段流水线,不允许模型跳过确认这一步。
2. 路由分发(Routing)
动画图:路由分发。启用 JavaScript 后可以逐步播放。
先分类,再把请求交给最合适的处理器,每次只走一条分支。各分支的提示词互不干扰,还能把简单问题交给便宜的小模型。
- 适合:请求类型明确、彼此独立,比如客服意图分流、按难度分配大小模型。
- 代价:路由一错,后面全错;“既要退款又要改地址”这类复合请求不好分。
- 报销案里:入口识别出“这是报销问题”,转给带财务工具的那套提示词和流程。路由器的输出要限制在候选集内,别让它发明一条新路由。
3. 并行扇出聚合(Parallelization)
动画图:并行扇出聚合。启用 JavaScript 后可以逐步播放。
同一个任务切成几块,或者复制几份,并行跑完再聚合。切块(sectioning)是为了快,复制后投票(voting)是为了稳。聚合可以是一段代码,也可以再调一次模型。
- 适合:长文档分段摘要、多角度审查、需要多次采样投票的判断。
- 代价:调用次数成倍增加;子任务之间看不到彼此,聚合时可能遇到冲突。
- 报销案里:规划里的“查制度”和“查发票”互不依赖,可以同时发出去。
二、单 Agent:一个模型决定下一步
从这里开始,控制权交给模型。区别在于模型是一步一步想,还是先想好整份计划,或者写完以后再回头检查。
4. 单体 ReAct 循环
动画图:单体 ReAct 循环。启用 JavaScript 后可以逐步播放。
模型在“想、做、看”之间循环:根据当前信息决定调用哪个工具,看到返回结果后再决定下一步,直到它认为可以结束。ReAct 原论文讨论的就是推理和动作交替进行。现在的编码 Agent,主循环基本都是这个形状。
- 适合:步骤不确定但规模可控的探索任务,比如调一个 bug、查资料回答问题。
- 代价:每一步都要调一次模型;没有全局计划,长任务容易偏题或绕圈;上下文随步数线性变长。必须配步数上限、预算上限和重复动作检测。
- 报销案里:用
taxi查发票返回空列表,模型改用ride_hailing再查一次,找到了 INV-102。看到结果再改主意,这是 ReAct 有用的地方。
5. 规划-执行(Plan-and-Execute)
动画图:规划-执行。启用 JavaScript 后可以逐步播放。
规划器先写出一份带依赖和完成判据的计划,执行器按计划逐条完成,执行时遇到意外再回头重新规划。规划只需调用一次大模型,执行可以交给小模型或代码;计划还能在执行前拿给人审。
- 适合:目标明确、可以拆解的多步任务,比如调研报告、数据分析流程。
- 代价:计划可能在执行中过时,重新规划的质量决定了上限。
- 报销案里:S1 查制度、S2 查发票、S3 查重复报销、S4 判定、S5 请员工确认、S6 建单。S1 和 S2 可以并行;S2 返回空时,只重新规划 S2 之后的部分。详见 规划。
6. 反思 / 评估-优化(Evaluator-Optimizer)
动画图:反思 / 评估-优化。启用 JavaScript 后可以逐步播放。
生成者先出一稿,评估者按标准挑错,生成者带着意见修改,直到达标或者轮数用完。评估者要有用,手里得有生成者没有的信号:测试结果、业务规则、原始需求。只是换个提示词让同一个模型自评,效果有限(Huang et al., 2023)。
- 适合:有客观评判标准的任务,比如代码要通过测试、译文要符合术语表。
- 代价:每轮多一次调用;标准太严会无限返工,要有轮数上限和“够好即可”的判据。
- 报销案里:工单草稿写完,规则检查发现“超标 38.5 元但事由为空”,打回补写。
三、多 Agent:把任务拆给多个上下文
多 Agent 的收益来自三件事:子任务可以并行,每个 Agent 有一份干净的上下文,不同 Agent 可以给不同的权限或模型。代价也很明确:要通信,要同步状态,结论可能冲突,调试时要看好几条轨迹。
动手拆之前,先过一遍这四个问题:
- 子任务之间是不是基本独立?依赖强的任务拆开以后会频繁同步,交接时还会丢信息。
- 单个上下文是不是真的装不下,或者不同资料会互相干扰?
- 是否需要不同的权限或模型,比如审查者只读、执行者可写?
- 有没有和“单 Agent 花同样多 token”做过对比评测?
业界对此有两种声音。Anthropic 介绍它的多 Agent 研究系统时,强调并行子 Agent 在广度型调研上的收益,也承认 token 消耗约为普通对话的 15 倍。Cognition 的 Don't Build Multi-Agents 则主张强耦合任务不要拆,因为子 Agent 看不到完整上下文,容易做出互相冲突的决定。两者并不矛盾:前者的任务能并行,后者的任务强耦合。
7. 主 Agent + 子 Agent(Orchestrator–Workers)
动画图:主 Agent + 子 Agent。启用 JavaScript 后可以逐步播放。
主 Agent 拆解任务,按需派生子 Agent;每个子 Agent 在独立的上下文里干完活,只交回一份压缩后的结论,然后销毁。主 Agent 始终持有控制权,子 Agent 像一次函数调用。这是生产上最常见的多 Agent 形态,因为控制集中,最容易追踪。
- 适合:一次性的大任务,能拆成若干相对独立的调研或修改,比如大范围代码搜索、多来源调研。
- 代价:主 Agent 是瓶颈,所有结论都要经它汇总;子 Agent 交回的是摘要,细节会丢。
- 报销案里:单个员工的报销用不上。如果任务变成“审计全公司上季度差旅”,主 Agent 按销售、研发、行政拆给三个子 Agent 并行跑,每个只拿自己部门的单据和相关条款,交回“疑似超标清单 + 证据”。
8. 层级监督(Hierarchical Teams)
动画图:层级监督。启用 JavaScript 后可以逐步播放。
主从结构再套一层:上级只和直接下属沟通,下属自己也可以是主管。LangGraph 的 Hierarchical Agent Teams 和 CrewAI 的 hierarchical process 都是这种做法。
- 适合:跨职能的大型一次性任务,需要多层分工。
- 代价:每多一层,信息就多被压缩一次;出了错很难定位是哪一层丢的。
- 报销案里:审计任务中研发部单据太多,研发子 Agent 再按月份拆给三个下级。
9. 交接 / Swarm(Handoff)
动画图:交接 / Swarm。启用 JavaScript 后可以逐步播放。
没有常驻的总控。当前 Agent 判断自己不合适,就把整段对话连同控制权一起交给另一个 Agent,之后由对方直接面对用户。OpenAI 的 Swarm 和 Agents SDK 的 handoffs 是代表实现。
- 适合:阶段分明、需要不同专家依次接手的对话,比如客服从分诊到售后。
- 代价:跨领域的问题要来回转交;交出去以后,前一个 Agent 就管不着了。
- 报销案里:通用助手识别出报销问题,把对话整个交给财务助手,员工接下来直接和财务助手说话。
10. 群聊 / 辩论(Group Chat)
动画图:群聊 / 辩论。启用 JavaScript 后可以逐步播放。
多个角色在同一个对话里轮流发言,由主持人或规则决定下一个谁说。AutoGen 的 GroupChat 是典型实现;多 Agent 辩论也属于这一类。
- 适合:头脑风暴、方案评审、需要对抗式检查的推理题。
- 代价:难收敛,容易绕圈,结论归谁负责说不清。生产系统里很少直接用。
- 报销案里:只在制定制度时有点用,比如让“财务”“员工代表”“合规”三个角色讨论第 4.2 条的标准该不该调。
11. 黑板 / 共享状态(Blackboard)
动画图:黑板 / 共享状态。启用 JavaScript 后可以逐步播放。
所有 Agent 围着一块共享黑板读写,彼此不直接说话。控制器看黑板的状态决定此刻该谁出手。LangGraph 的共享 State 就相当于一块黑板:节点读取 State,返回更新,由 reducer 合并,checkpointer 负责持久化。
- 适合:多种专长围绕同一份逐步完善的成果协作,比如复杂诊断、情报分析。
- 代价:所有人都能写,就要定好谁能写哪一块,否则会互相覆盖。
- 报销案里:审计时三个部门的子 Agent 往同一张“疑似问题表”里写,每行带 owner 和证据,最后由人收口。
多 Agent 常见的五种故障
| 故障 | 表现 | 兜底 |
|---|---|---|
| 重复劳动 | 两个 Agent 查了同一批单据 | 每个子任务有明确 owner |
| 信息丢失 | 摘要里漏了关键证据 | 结构化消息,带证据引用 |
| 结论冲突 | 两个 Agent 对同一张单判断相反 | 设仲裁者,或交给人 |
| 递归对话 | Agent 之间互相追问停不下来 | 最大轮次和预算上限 |
| 无人负责 | 出错以后说不清是谁的 | 单一事实来源,每次写入可追溯 |
这些故障大多属于分布式系统问题,和模型能力关系不大。解法也照搬分布式系统:单一事实来源、结构化消息、明确的 owner、超时和仲裁。消息格式可以参考 Agent 核心里研发部子 Agent 交回的那段 JSON。
四、系统级:事件驱动工单
前面 11 种结构都默认“一次提问、一次回答”。当 Agent 要长期在线、同时服务一个团队、从代码仓库和聊天群里接活时,问题就变成了:谁来决定接不接这个活,任务状态存在哪里,人在半路追问时找谁。
DeepSeek 开源的研究原型 dsh-superagent 给出的答案是把它做成一个工单系统:
动画图:事件驱动工单。启用 JavaScript 后可以逐步播放。
- 确定性的 Engine 用状态机和 SQLite 管所有工单。外部事件先落库、去重,再进入流程。
- 准入门是代码:发送者在不在白名单、是不是直接点名,由规则判定,不交给模型。授权记录成不可变的凭证。
- 常驻主 Session 只做路由:它的提示词明确禁止写方案、改写用户原话,只决定接不接、交给谁。
- 每个工单一个持久 Worker:有自己的 Session 和独立 worktree,可以在几周后被同一个线程里的追问唤醒。
- 副作用先落库再发送:回复先写进 Outbox,发送失败按退避重试,服务重启后能精确恢复。
它和主从子 Agent 最容易混,因为都是“一个总控加几个干活的”。区别在于总控管什么:
| 维度 | 主 Agent + 子 Agent | 事件驱动工单 |
|---|---|---|
| 启动方式 | 一次用户提问 | 持续监听事件流,也能按规则主动接活 |
| 总控职责 | 规划、拆解、汇总 | 只做准入和路由 |
| 干活者寿命 | 调用一次就销毁 | 每个工单一个常驻 Session |
| 状态存放 | 主要在主 Agent 的上下文里 | 在数据库里,由状态机唯一写入 |
| 通信方式 | 自然语言摘要层层上报 | 结构化报告、线程订阅扇出 |
| 人的位置 | 只能和主 Agent 对话 | 在原 PR 或话题里直接找对应 Worker |
| 授权 | 通常靠提示词约束 | 代码准入加不可变授权凭证 |
| 失败恢复 | 一般整轮重来 | 先落库再执行,按输入粒度恢复 |
| 代价 | 实现轻 | 工程量大,原型约 2.8 万行 |
打个比方:主从结构像一棵函数调用树,决定都由主 Agent 做;工单结构更像一个有前台的公司,前台只登记和分派,员工各自对工单负责,规章制度写在代码里。
- 适合:面向团队、多渠道接入、长期在线的 Agent 服务,比如仓库维护机器人、运维 Agent。
- 代价:概念多、工程量大;所有请求都要先过评估,简单问题也偏慢。
- 报销案里:如果公司把报销助手做成全员可用的常驻服务,每张报销单就是一个工单。员工两天后在原话题里补一句“事由是客户改了会面地点”,消息直接回到负责这张单的 Worker,不用重新解释一遍。
五、放在一起比
| 结构 | 控制权 | 状态 | 通信 | 能否并行 | 典型失败 |
|---|---|---|---|---|---|
| 固定流水线 | 代码 | 每步的输入输出 | 顺序传递 | 否 | 错误一路下传 |
| 路由分发 | 代码 + 一次分类 | 无共享状态 | 一次分派 | 否 | 分错类 |
| 并行扇出聚合 | 代码 | 各分支独立 | 扇出再聚合 | 是 | 聚合冲突 |
| 单体 ReAct | 模型 | 一份上下文 | 模型与工具往返 | 否 | 绕圈、上下文膨胀 |
| 规划-执行 | 规划器 | 计划 + 执行结果 | 计划下发、结果回填 | 依赖允许时可以 | 计划过时 |
| 反思 / 评估-优化 | 生成与评估交替 | 草稿 + 意见 | 两方往返 | 否 | 无限返工 |
| 主 Agent + 子 Agent | 主 Agent | 主 Agent 的上下文 | 调用与返回摘要 | 是 | 主 Agent 瓶颈、细节丢失 |
| 层级监督 | 多级主管 | 各级上下文 | 逐级上报 | 是 | 层层压缩失真 |
| 交接 / Swarm | 当前持有者 | 随对话转交 | 整段交接 | 否 | 来回转交 |
| 群聊 / 辩论 | 主持人或规则 | 共享对话记录 | 轮流发言 | 否 | 不收敛 |
| 黑板 / 共享状态 | 控制器 | 共享黑板 | 读写黑板 | 是 | 互相覆盖 |
| 事件驱动工单 | 状态机 | 数据库 | 事件、工单、报告 | 是 | 工程复杂 |
想直观比较其中两种,可以在 对比台 里把它们并排播放。
怎么选
从最简单的开始,遇到解决不了的问题再往上走一级:
- 流程能写清楚?用固定流水线;请求类型不同,在前面加路由。
- 子任务互不依赖、想要更快或更稳?加并行扇出聚合。
- 步骤事先写不清,要边查边定?用单体 ReAct,配好步数和预算上限。
- 任务长、依赖清楚、想让人先审计划?换成规划-执行。
- 有客观标准能检查产出?加一层评估-优化。
- 上下文装不下、子任务能并行、或需要权限隔离?才考虑主 Agent + 子 Agent;规模更大时再分层。
- 需要长期在线、多渠道接活、人随时介入?这时问题已经变成系统设计,参考事件驱动工单,把状态和授权交给代码。
真实系统通常是几种结构的组合。报销助手就是这样:入口是路由,主体是一个带规划的 ReAct,建单前是写死的确认流程(见 人在回路),执行层的重试和幂等交给 可靠执行。
来源与说明
- Anthropic, Building Effective Agents:工作流与 Agent 的划分,以及 Prompt Chaining、Routing、Parallelization、Orchestrator-Workers、Evaluator-Optimizer 五种模式。本文的配图风格也参考了这篇文章。
- LangGraph, Multi-agent systems:Supervisor、Hierarchical、Network 等多 Agent 结构,以及共享 State 的做法。
- Anthropic, How we built our multi-agent research system;Cognition, Don't Build Multi-Agents。
- Yao et al., ReAct;Shinn et al., Reflexion;Madaan et al., Self-Refine。
- 事件驱动工单一节来自对 DeepSeek 开源原型 dsh-superagent 代码的阅读,是研究原型,不代表其生产系统。
图中的流程是为讲清结构而简化的示意,同一种结构在不同框架里的实现细节可能差别很大。