摘要 :第一季(第 22~32 篇)讲了十一个模式:Pipeline、MapReduce、Supervisor、黑板、编排引擎、通信协议、中间件、事件驱动、状态管理、网关、Serverless。但**"知道十一个模式"和"知道该用哪个"是两回事**------真实项目里的失败很少是因为"不知道某个模式",更多是因为"选错了模式"或"把两个模式用在了不适合的地方"。本文是第一季收官,做三件事:① 建立模式语言 (十一个模式不是并列清单,它们之间存在组合、替代、前提三类关系,理解关系才能组合出正确架构);② 给出选型决策树 (五个问题的判断顺序,而不是十一个模式的权衡表);③ 提炼反模式清单(十五条,全部来自第一季各篇的真实事故,每条给出症状、根因与正确做法)。最后给出第二季(工程化实战篇)的路线与衔接点。
📌 版本声明 :本文为总结导航类 ,撰写时间 2026 年 10 月。文中所有模式均来自本系列第 22~32 篇,具体实现与版本约束请回到对应篇目查看(如第 23 篇的
asyncio.timeout需 Python 3.11+、第 30 篇依赖 Pydantic V2、第 32 篇的平台配额以 AWS Lambda 为准)。本文的"模式语言"概念借鉴 Christopher Alexander 在《A Pattern Language》中的思想------模式不是孤立的最佳实践清单,而是可以互相组合、互相支撑的一套语言。适用边界 :适用于已理解各个单独模式、需要在真实项目中做架构选型 的读者。如果你是第一次接触 Agent 架构,建议先按第二部分的分类找对应篇目阅读,再回来看关系与决策。本文不重复讲解任何模式的实现细节。
文章目录
-
- 一、为什么需要"模式语言":清单不够用
-
- [1.1 一个真实的选型失败](#1.1 一个真实的选型失败)
- [1.2 清单式知识的三个缺陷](#1.2 清单式知识的三个缺陷)
- [1.3 从清单到语言](#1.3 从清单到语言)
- 二、第一季模式总览:按"解决什么问题"重新分类
-
- [2.1 四维分类](#2.1 四维分类)
- [2.2 用思维导图看全景](#2.2 用思维导图看全景)
- [2.3 四类之间的依赖关系](#2.3 四类之间的依赖关系)
- 三、模式之间的关系:组合、替代、前提
-
- [3.1 替代关系:执行形状的四种选择](#3.1 替代关系:执行形状的四种选择)
- [3.2 组合关系:哪些模式必须搭配](#3.2 组合关系:哪些模式必须搭配)
- [3.3 前提关系:不能跳过的地基](#3.3 前提关系:不能跳过的地基)
- [3.4 演进关系:系统复杂度增长时模式如何叠加](#3.4 演进关系:系统复杂度增长时模式如何叠加)
- [3.5 成本视角:每个模式的价格标签](#3.5 成本视角:每个模式的价格标签)
- 四、选型决策树:五个问题的判断顺序
-
- [4.1 为什么是决策树而不是权衡表](#4.1 为什么是决策树而不是权衡表)
- [4.2 决策树](#4.2 决策树)
- [4.3 五个问题及其判断方法](#4.3 五个问题及其判断方法)
- [4.4 决策树的代码化](#4.4 决策树的代码化)
- 五、反模式清单:十五种"说得出来但会出事"的架构
-
- [5.1 高危反模式(会导致静默错误或数据损坏)](#5.1 高危反模式(会导致静默错误或数据损坏))
- [5.2 中危反模式(会导致成本失控或可用性问题)](#5.2 中危反模式(会导致成本失控或可用性问题))
- [5.3 设计类反模式(架构层面的错配)](#5.3 设计类反模式(架构层面的错配))
- 六、架构评审:六个必问问题
-
- [6.1 决策树的边界:什么时候不该用它](#6.1 决策树的边界:什么时候不该用它)
- 七、第一季回顾与第二季衔接
-
- [7.1 第一季的三条主线](#7.1 第一季的三条主线)
- [7.2 第二季要解决什么](#7.2 第二季要解决什么)
- [7.3 第一季留下的三个未解问题](#7.3 第一季留下的三个未解问题)
- 八、总结
- 参考资料
一、为什么需要"模式语言":清单不够用
1.1 一个真实的选型失败
团队要做一个"多源日志入侵归因分析"系统,需求是:四个数据源(WAF、数据库审计、EDR、威胁情报)各自产出线索,最后汇总成一条归因链。
团队选择了 Supervisor 模式(第 24 篇)------理由很充分:需要"根据情况决定派谁去查",这正是 Supervisor 的强项。
系统上线后出了问题:不同数据源的线索经常互相矛盾 ,而 Supervisor 的架构里没有存放矛盾的机制------主管 Agent 拿到四份报告后会强行给出单一结论,把矛盾悄悄抹平了。
正确的选择是黑板模式 (第 25 篇)------它的核心设施恰恰是冲突记录与消解,而第 25 篇明确写了"黑板模式没有路由错误这种失败模式,但有结论矛盾这种失败模式"。
失败的根源不是"不懂 Supervisor",而是"不知道 Supervisor 和黑板解决的是同一类问题的不同侧面"。
1.2 清单式知识的三个缺陷
把十一个模式背下来,仍会在选型时出错,因为清单式知识有三个缺陷:
| 缺陷 | 说明 | 后果 |
|---|---|---|
| 看不出替代关系 | 不知道哪些模式是同一问题的不同解 | 选了能跑但不适合的 |
| 看不出组合关系 | 不知道哪些模式必须搭配使用 | 架构缺了必需的一半 |
| 看不出前提关系 | 不知道哪个模式是另一个的前提 | 在没打地基的地方盖楼 |
第三类最致命。举个第一季里的真实例子:第 26 篇的编排引擎需要持久化状态才能做断点恢复,而状态持久化是第 30 篇的内容。如果在没读第 30 篇的情况下实现第 26 篇的引擎,断点恢复功能必然是残缺的------而且是"看起来能用、崩溃时才发现没用"的那种残缺。
换句话说,模式清单能回答"有哪些选项",但回答不了"我的情况该选哪个"以及"选了之后还缺什么"。 这两个问题正是本文要补的。
1.3 从清单到语言
Christopher Alexander 在建筑领域提出"模式语言"时的核心洞察是:模式之间可以互相引用、互相支撑,形成一套可以"说出"完整建筑的语言,而不是一堆孤立的最佳实践。
借用到 Agent 架构:
text
模式清单(Catalog) = 十一个模式的并列介绍
模式语言(Language) = 模式之间的三类关系 + 组合规则 + 选型判据
本文的目标就是从清单升级到语言。 具体来说,第二、三章讲关系,第四章给决策树,第五章给反模式(反面约束也是语言的一部分------它告诉你什么话说不出来)。
二、第一季模式总览:按"解决什么问题"重新分类
2.1 四维分类
第一季的十一个模式,按解决的问题分成四类:
| 类别 | 模式 | 篇目 | 核心问题 |
|---|---|---|---|
| 执行编排 | Pipeline | 22 | 顺序固定、线性串联 |
| MapReduce | 23 | 任务独立、可并行后归并 | |
| Supervisor | 24 | 运行时决定派谁 | |
| 黑板 | 25 | 无中心决策者、自主激活 | |
| 编排引擎 | 26 | 把上面四种跑起来的机器 | |
| 通信与数据流 | 通信协议 | 27 | 跨进程后状态与消息怎么传 |
| 事件驱动 | 29 | 上下游解耦、异步响应 | |
| 横切治理 | 中间件 | 28 | 进程内横切能力 |
| 网关 | 31 | 服务级横切能力 | |
| 状态与运行时 | 状态管理 | 30 | 三层状态、持久化、恢复 |
| Serverless | 32 | 按需启动、成本控制 |
注意第五行"编排引擎"的特殊性 :它不是与前四种并列的执行模式,而是承载前四种的机器。第 26 篇的原话是"模式是形状,引擎是机器"。所以严格分类应该是:
text
执行形状的四种选择:Pipeline / MapReduce / Supervisor / 黑板
承载形状的执行器: 编排引擎(第 26 篇)
2.2 用思维导图看全景
#mermaid-svg-AVT2n539Ay1talhm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AVT2n539Ay1talhm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AVT2n539Ay1talhm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AVT2n539Ay1talhm .error-icon{fill:#552222;}#mermaid-svg-AVT2n539Ay1talhm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AVT2n539Ay1talhm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AVT2n539Ay1talhm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AVT2n539Ay1talhm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AVT2n539Ay1talhm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AVT2n539Ay1talhm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AVT2n539Ay1talhm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AVT2n539Ay1talhm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AVT2n539Ay1talhm .marker.cross{stroke:#333333;}#mermaid-svg-AVT2n539Ay1talhm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AVT2n539Ay1talhm p{margin:0;}#mermaid-svg-AVT2n539Ay1talhm .edge{stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .section--1 rect,#mermaid-svg-AVT2n539Ay1talhm .section--1 path,#mermaid-svg-AVT2n539Ay1talhm .section--1 circle,#mermaid-svg-AVT2n539Ay1talhm .section--1 polygon,#mermaid-svg-AVT2n539Ay1talhm .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section--1 text{fill:#ffffff;}#mermaid-svg-AVT2n539Ay1talhm .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-AVT2n539Ay1talhm .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth--1{stroke-width:17;}#mermaid-svg-AVT2n539Ay1talhm .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-0 rect,#mermaid-svg-AVT2n539Ay1talhm .section-0 path,#mermaid-svg-AVT2n539Ay1talhm .section-0 circle,#mermaid-svg-AVT2n539Ay1talhm .section-0 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-AVT2n539Ay1talhm .section-0 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-0{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-0{stroke-width:14;}#mermaid-svg-AVT2n539Ay1talhm .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-1 rect,#mermaid-svg-AVT2n539Ay1talhm .section-1 path,#mermaid-svg-AVT2n539Ay1talhm .section-1 circle,#mermaid-svg-AVT2n539Ay1talhm .section-1 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-1 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-1{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-1{stroke-width:11;}#mermaid-svg-AVT2n539Ay1talhm .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-2 rect,#mermaid-svg-AVT2n539Ay1talhm .section-2 path,#mermaid-svg-AVT2n539Ay1talhm .section-2 circle,#mermaid-svg-AVT2n539Ay1talhm .section-2 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-2 text{fill:#ffffff;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-2{stroke-width:8;}#mermaid-svg-AVT2n539Ay1talhm .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-3 rect,#mermaid-svg-AVT2n539Ay1talhm .section-3 path,#mermaid-svg-AVT2n539Ay1talhm .section-3 circle,#mermaid-svg-AVT2n539Ay1talhm .section-3 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-3 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-3{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-3{stroke-width:5;}#mermaid-svg-AVT2n539Ay1talhm .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-4 rect,#mermaid-svg-AVT2n539Ay1talhm .section-4 path,#mermaid-svg-AVT2n539Ay1talhm .section-4 circle,#mermaid-svg-AVT2n539Ay1talhm .section-4 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-4 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-4{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-4{stroke-width:2;}#mermaid-svg-AVT2n539Ay1talhm .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-5 rect,#mermaid-svg-AVT2n539Ay1talhm .section-5 path,#mermaid-svg-AVT2n539Ay1talhm .section-5 circle,#mermaid-svg-AVT2n539Ay1talhm .section-5 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-5 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-5{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-5{stroke-width:-1;}#mermaid-svg-AVT2n539Ay1talhm .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-6 rect,#mermaid-svg-AVT2n539Ay1talhm .section-6 path,#mermaid-svg-AVT2n539Ay1talhm .section-6 circle,#mermaid-svg-AVT2n539Ay1talhm .section-6 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-6 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-6{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-6{stroke-width:-4;}#mermaid-svg-AVT2n539Ay1talhm .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-7 rect,#mermaid-svg-AVT2n539Ay1talhm .section-7 path,#mermaid-svg-AVT2n539Ay1talhm .section-7 circle,#mermaid-svg-AVT2n539Ay1talhm .section-7 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-7 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-7{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-7{stroke-width:-7;}#mermaid-svg-AVT2n539Ay1talhm .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-8 rect,#mermaid-svg-AVT2n539Ay1talhm .section-8 path,#mermaid-svg-AVT2n539Ay1talhm .section-8 circle,#mermaid-svg-AVT2n539Ay1talhm .section-8 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-8 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-8{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-8{stroke-width:-10;}#mermaid-svg-AVT2n539Ay1talhm .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-9 rect,#mermaid-svg-AVT2n539Ay1talhm .section-9 path,#mermaid-svg-AVT2n539Ay1talhm .section-9 circle,#mermaid-svg-AVT2n539Ay1talhm .section-9 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-9 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-9{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-9{stroke-width:-13;}#mermaid-svg-AVT2n539Ay1talhm .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-10 rect,#mermaid-svg-AVT2n539Ay1talhm .section-10 path,#mermaid-svg-AVT2n539Ay1talhm .section-10 circle,#mermaid-svg-AVT2n539Ay1talhm .section-10 polygon,#mermaid-svg-AVT2n539Ay1talhm .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-10 text{fill:black;}#mermaid-svg-AVT2n539Ay1talhm .node-icon-10{font-size:40px;color:black;}#mermaid-svg-AVT2n539Ay1talhm .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .edge-depth-10{stroke-width:-16;}#mermaid-svg-AVT2n539Ay1talhm .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-AVT2n539Ay1talhm .disabled,#mermaid-svg-AVT2n539Ay1talhm .disabled circle,#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:lightgray;}#mermaid-svg-AVT2n539Ay1talhm .disabled text{fill:#efefef;}#mermaid-svg-AVT2n539Ay1talhm .section-root rect,#mermaid-svg-AVT2n539Ay1talhm .section-root path,#mermaid-svg-AVT2n539Ay1talhm .section-root circle,#mermaid-svg-AVT2n539Ay1talhm .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-AVT2n539Ay1talhm .section-root text{fill:#ffffff;}#mermaid-svg-AVT2n539Ay1talhm .section-root span{color:#ffffff;}#mermaid-svg-AVT2n539Ay1talhm .section-2 span{color:#ffffff;}#mermaid-svg-AVT2n539Ay1talhm .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-AVT2n539Ay1talhm .edge{fill:none;}#mermaid-svg-AVT2n539Ay1talhm .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-AVT2n539Ay1talhm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Agent 架构模式语言
执行编排
Pipeline 顺序固定
MapReduce 独立并行
Supervisor 中心路由
黑板 自主激活
编排引擎 承载机器
通信与数据流
通信协议 跨进程
事件驱动 异步解耦
横切治理
中间件 进程内
网关 服务级
状态与运行时
状态管理 三层与恢复
Serverless 按需启动
2.3 四类之间的依赖关系
这是"语言"的第一个关键内容------四类不是并列的,是分层的:
text
┌─────────────────────────┐
│ 执行编排(选形状) │ ← 你最先要决定的
└───────────┬─────────────┘
│ 需要
┌───────────▼─────────────┐
│ 状态管理(打地基) │ ← 几乎所有模式的前提
└───────────┬─────────────┘
│ 规模变大后
┌───────────▼─────────────┐
│ 通信与数据流(跨进程) │
└───────────┬─────────────┘
│ 需要治理后
┌───────────▼─────────────┐
│ 横切治理(非业务能力) │
└───────────┬─────────────┘
│ 部署形态
┌───────────▼─────────────┐
│ Serverless(运行时) │
└─────────────────────────┘
"状态管理"处在这个栈的第二层,是最容易被忽略的前提。 第 22~29 篇的所有实现都隐含假设"状态在进程内存里",直到第 30 篇才把这个假设显式化。这是第一季在编排上最大的一个结构性遗憾,也是本文要强调的第一条:
任何执行编排模式,都要先回答"状态放哪、进程崩了怎么办"。 这个问题在第 30 篇之前是无解的。

图1:第一季十一模式按"解决什么问题"分为执行编排、通信数据流、横切治理、状态与运行时四类
三、模式之间的关系:组合、替代、前提
3.1 替代关系:执行形状的四种选择
Pipeline / MapReduce / Supervisor / 黑板是同一个问题的四种解:多个 Agent(或步骤)之间如何协调。选择依据是两个问题:
| 判据 | 取值 | 对应模式 |
|---|---|---|
| 顺序在设计时已知吗? | 已知 | Pipeline / MapReduce |
| 运行时才知道 | Supervisor / 黑板 | |
| 任务之间独立吗? | 独立 | MapReduce |
| 有依赖 | Pipeline | |
| 有中心决策者吗? | 有 | Supervisor |
| 无(自主激活) | 黑板 |
一句话概括四种形状的差异:
| 模式 | 一句话 |
|---|---|
| Pipeline | 设计时确定顺序 |
| MapReduce | 设计时确定集合(顺序不重要) |
| Supervisor | 运行时由中心决定路径 |
| 黑板 | 运行时由参与者自主决定 |
1.1 节那个失败案例用这张表就能避免:"线索会互相矛盾"意味着需要"保留矛盾"的机制 ,而这恰恰是黑板的核心设施。Supervisor 的架构里没有存放矛盾的位置------它的 DiagnosisState 是一个单一结论的容器。
3.2 组合关系:哪些模式必须搭配
有些模式单独使用是残缺的:
| 主模式 | 必须搭配 | 原因 |
|---|---|---|
| 编排引擎(26) | 状态管理(30) | 断点恢复需要持久化状态 |
| Supervisor(24) | 编排引擎(26)的循环控制 | 路由与终止必须分开(第 26 篇核心洞察) |
| 事件驱动(29) | 通信协议(27)的 ID 体系 | 排序靠分区、因果靠 causation_id |
| Serverless(32) | 状态管理(30) | 实例随时销毁,状态必须外置 |
| 网关(31) | 中间件(28) | 网关只看请求,需要内部上下文的决策只能放中间件 |
| 黑板(25) | 状态管理(30)的并发控制 | 多源并发写需要版本号乐观锁 |
第二行值得单独说明,这是第 24 篇和第 26 篇之间最重要的一条连线:
第 24 篇的 Supervisor 用一个
route函数同时实现了"选下一个专家"和"决定是否继续" ,结果产生了 47 轮的死循环。第 26 篇指出:这在引擎层面是两件事 ------选谁是路由,是否继续是循环控制。把它们拆成不同机制,正是为了让这个错误无处可藏。
3.3 前提关系:不能跳过的地基
| 要用的模式 | 前提是 |
|---|---|
| 编排引擎的断点恢复 | 状态持久化(30) |
| 分布式的任何模式 | 通信协议的三段 ID(27) |
| 网关的多租户配额 | 网关无状态 + 状态外置(30) |
| Serverless 的长任务 | 任务可拆分 + 步骤幂等(29/30) |
| 中间件的顺序可控 | 钩子链的顺序语义(28) |
第三行有个容易忽略的细节 :第 31 篇说"网关绝对不要有状态",但多租户配额本身就是状态。这不矛盾------配额状态在外部存储,网关只读写它。判断标准是"网关进程内存里有没有必须存在的数据",而不是"网关是否接触状态"。
3.4 演进关系:系统复杂度增长时模式如何叠加
一个 Agent 系统通常不是一开始就上全套模式,而是随着复杂度增长逐步叠加:
#mermaid-svg-bDRDigB4GPVGFqta{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bDRDigB4GPVGFqta .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bDRDigB4GPVGFqta .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bDRDigB4GPVGFqta .error-icon{fill:#552222;}#mermaid-svg-bDRDigB4GPVGFqta .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bDRDigB4GPVGFqta .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bDRDigB4GPVGFqta .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bDRDigB4GPVGFqta .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bDRDigB4GPVGFqta .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bDRDigB4GPVGFqta .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bDRDigB4GPVGFqta .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bDRDigB4GPVGFqta .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bDRDigB4GPVGFqta .marker.cross{stroke:#333333;}#mermaid-svg-bDRDigB4GPVGFqta svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bDRDigB4GPVGFqta p{margin:0;}#mermaid-svg-bDRDigB4GPVGFqta defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-bDRDigB4GPVGFqta g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-bDRDigB4GPVGFqta g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-bDRDigB4GPVGFqta g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-bDRDigB4GPVGFqta g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-bDRDigB4GPVGFqta g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-bDRDigB4GPVGFqta .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-bDRDigB4GPVGFqta .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-bDRDigB4GPVGFqta .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-bDRDigB4GPVGFqta .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-bDRDigB4GPVGFqta .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-bDRDigB4GPVGFqta .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-bDRDigB4GPVGFqta .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-bDRDigB4GPVGFqta .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bDRDigB4GPVGFqta .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bDRDigB4GPVGFqta .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bDRDigB4GPVGFqta .edgeLabel .label text{fill:#333;}#mermaid-svg-bDRDigB4GPVGFqta .label div .edgeLabel{color:#333;}#mermaid-svg-bDRDigB4GPVGFqta .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-bDRDigB4GPVGFqta .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-bDRDigB4GPVGFqta .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-bDRDigB4GPVGFqta .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-bDRDigB4GPVGFqta .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-bDRDigB4GPVGFqta .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bDRDigB4GPVGFqta .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bDRDigB4GPVGFqta #statediagram-barbEnd{fill:#333333;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bDRDigB4GPVGFqta .cluster-label,#mermaid-svg-bDRDigB4GPVGFqta .nodeLabel{color:#131300;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-bDRDigB4GPVGFqta .note-edge{stroke-dasharray:5;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-note text{fill:black;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram-note .nodeLabel{color:black;}#mermaid-svg-bDRDigB4GPVGFqta .statediagram .edgeLabel{color:red;}#mermaid-svg-bDRDigB4GPVGFqta #dependencyStart,#mermaid-svg-bDRDigB4GPVGFqta #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-bDRDigB4GPVGFqta .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bDRDigB4GPVGFqta :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 一个 Agent 直接调用
拆成多个环节
环节变成独立 Agent
需要跨进程部署
多租户与统一管理
单Agent
多步骤
多Agent
分布式
平台化
第 22 篇 Pipeline
或第 23 篇 MapReduce
第 26 篇编排引擎
第 30 篇状态管理
第 24 篇 Supervisor
或第 25 篇黑板
第 27 篇通信协议
第 29 篇事件驱动
第 28 篇中间件
第 31 篇网关
第 32 篇 Serverless
这张图的价值在于告诉你"什么时候该停下来"。 大多数系统走到"多步骤"或"多 Agent"就够了。继续往后走的唯一正当理由是出现了对应的真实问题 ------跨进程的需求(分布式)、多租户管理的需求(平台化)。没有问题而提前上模式,是架构过度设计的主要来源。
3.5 成本视角:每个模式的价格标签
第一季各篇都讨论过成本,但散落在不同篇目里。这里把执行形状的四种选择按成本特征做个横向对比------选型时这是和"功能是否匹配"同等重要的维度:
| 模式 | LLM 调用次数 | 典型延迟 | Token 放大倍数 | 成本敏感点 |
|---|---|---|---|---|
| Pipeline | N(每步一次) | 串行求和 | 1× | 无额外开销,最省 |
| MapReduce | N + 归并次数 | 最长步 + 归并 | 1× + 归并开销 | 归并阶段的输入规模 |
| Supervisor | N + 路由次数 × 轮数 | 串行 + 路由开销 | 取决于轮数 | 轮数失控是主要风险 |
| 黑板 | 不确定(自主激活) | 取决于收敛速度 | 最高 | 知识源的无效激活 |
Pipeline 最省,因为它的调用次数是确定的 N 次。 其余三种都可能超出 N:MapReduce 多了归并,Supervisor 多了路由,黑板完全不确定。
MapReduce 的成本陷阱在归并阶段。 第 23 篇给了实测:600 份结果一次性喂给 LLM 是 9 万 Token,直接超窗且质量退化。解法是树形归并(Tree Reduce) ------让单次输入规模恒定,调用次数变成 O(N) 但每次都很小。这个取舍的本质是"用更多次小调用替代一次大调用",因为大调用的质量退化比多花几次调用更贵。
Supervisor 的成本风险是轮数。 第 24 篇那个 47 轮循环烧掉 23 万 Token 的事故,平均下来每轮近 5000 Token------而正常情况只需要 3~5 轮 。所以 Supervisor 的成本不是一个固定值,而是一个方差很大的分布,必须有硬上限。
黑板最贵且最难预测。 因为知识源的激活是自主的,你无法事先算出会调多少次 LLM 。第 25 篇的做法是加五道闸门(轮次/停滞/加权证据分/冲突/假设),实测把单次分析的 Token 成本从 21 万降到 8.7 万------降幅 59%,代价是收敛轮数只增加 1 轮。
💡 横向对比的实用结论 :如果你的预算敏感,Pipeline 是唯一能给出确定成本预测的模式 。MapReduce 的成本可估算(N + 归并),Supervisor 需要设上限才能估算,黑板本质上无法估算------只能用闸门把它约束到一个经验区间里。做成本预算时应该按这个顺序保守估计。
四、选型决策树:五个问题的判断顺序
4.1 为什么是决策树而不是权衡表
权衡表("模式 A 适合 X,模式 B 适合 Y")的问题在于:读者需要自己判断"我的情况是 X 还是 Y",而这恰恰是最难的部分。
决策树的做法是:给出判断顺序,每个节点只需回答一个是/否问题。
4.2 决策树
#mermaid-svg-57JBZb2PcyUMwibQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-57JBZb2PcyUMwibQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-57JBZb2PcyUMwibQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-57JBZb2PcyUMwibQ .error-icon{fill:#552222;}#mermaid-svg-57JBZb2PcyUMwibQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-57JBZb2PcyUMwibQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-57JBZb2PcyUMwibQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-57JBZb2PcyUMwibQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-57JBZb2PcyUMwibQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-57JBZb2PcyUMwibQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-57JBZb2PcyUMwibQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-57JBZb2PcyUMwibQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-57JBZb2PcyUMwibQ .marker.cross{stroke:#333333;}#mermaid-svg-57JBZb2PcyUMwibQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-57JBZb2PcyUMwibQ p{margin:0;}#mermaid-svg-57JBZb2PcyUMwibQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-57JBZb2PcyUMwibQ .cluster-label text{fill:#333;}#mermaid-svg-57JBZb2PcyUMwibQ .cluster-label span{color:#333;}#mermaid-svg-57JBZb2PcyUMwibQ .cluster-label span p{background-color:transparent;}#mermaid-svg-57JBZb2PcyUMwibQ .label text,#mermaid-svg-57JBZb2PcyUMwibQ span{fill:#333;color:#333;}#mermaid-svg-57JBZb2PcyUMwibQ .node rect,#mermaid-svg-57JBZb2PcyUMwibQ .node circle,#mermaid-svg-57JBZb2PcyUMwibQ .node ellipse,#mermaid-svg-57JBZb2PcyUMwibQ .node polygon,#mermaid-svg-57JBZb2PcyUMwibQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-57JBZb2PcyUMwibQ .rough-node .label text,#mermaid-svg-57JBZb2PcyUMwibQ .node .label text,#mermaid-svg-57JBZb2PcyUMwibQ .image-shape .label,#mermaid-svg-57JBZb2PcyUMwibQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-57JBZb2PcyUMwibQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-57JBZb2PcyUMwibQ .rough-node .label,#mermaid-svg-57JBZb2PcyUMwibQ .node .label,#mermaid-svg-57JBZb2PcyUMwibQ .image-shape .label,#mermaid-svg-57JBZb2PcyUMwibQ .icon-shape .label{text-align:center;}#mermaid-svg-57JBZb2PcyUMwibQ .node.clickable{cursor:pointer;}#mermaid-svg-57JBZb2PcyUMwibQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-57JBZb2PcyUMwibQ .arrowheadPath{fill:#333333;}#mermaid-svg-57JBZb2PcyUMwibQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-57JBZb2PcyUMwibQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-57JBZb2PcyUMwibQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-57JBZb2PcyUMwibQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-57JBZb2PcyUMwibQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-57JBZb2PcyUMwibQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-57JBZb2PcyUMwibQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-57JBZb2PcyUMwibQ .cluster text{fill:#333;}#mermaid-svg-57JBZb2PcyUMwibQ .cluster span{color:#333;}#mermaid-svg-57JBZb2PcyUMwibQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-57JBZb2PcyUMwibQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-57JBZb2PcyUMwibQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-57JBZb2PcyUMwibQ .icon-shape,#mermaid-svg-57JBZb2PcyUMwibQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-57JBZb2PcyUMwibQ .icon-shape p,#mermaid-svg-57JBZb2PcyUMwibQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-57JBZb2PcyUMwibQ .icon-shape .label rect,#mermaid-svg-57JBZb2PcyUMwibQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-57JBZb2PcyUMwibQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-57JBZb2PcyUMwibQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-57JBZb2PcyUMwibQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
是
否
否
是
是
否
是
否
是
否
开始:需要协调多个步骤或 Agent
顺序在设计时已知
各步骤相互独立
是否接受中心决策者
MapReduce 第23篇
Pipeline 第22篇
Supervisor 第24篇
黑板 第25篇
是否跨进程部署
进程内实现
加通信协议 第27篇
失败影响面要求隔离
加事件驱动 第29篇
同步调用即可
负载是否高度波动
考虑 Serverless 第32篇
常驻部署
必须配状态外置 第30篇
是否多租户或需统一治理
加网关 第31篇 + 中间件 第28篇
中间件按需 第28篇
完成
4.3 五个问题及其判断方法
决策树的五个分支问题,每个都有明确的判断方法:
| # | 问题 | 怎么判断 | 常见误判 |
|---|---|---|---|
| 1 | 顺序在设计时已知? | 你能画出固定的流程图吗? | 把"通常的顺序"当成"固定的顺序" |
| 2 | 步骤相互独立? | 步骤 B 需要步骤 A 的输出吗? | 忽略了"最后要汇总"也是一种依赖(但这不影响 MapReduce 适用性) |
| 3 | 接受中心决策者? | 需要一个"总指挥"吗? | 以为中心决策者=单点故障(实际可以是无状态的) |
| 4 | 是否跨进程? | 部署单元会分开吗? | 提前按分布式设计(过度设计) |
| 5 | 负载是否高度波动? | 谷值是否接近零? | 以为"调用量少"就该用 Serverless(关键是不均匀,不是少) |
第一个问题的误判最常见。 举例:合同审查的"先解析、再抽取条款、再识别风险"------看起来顺序固定,但如果某些合同没有表格,抽取步骤会跳过;如果风险识别发现新问题,可能需要回去重新抽取 。这不是固定顺序,是运行时决定的。判断标准是"有没有任何一个分支会是运行时才知道的",有就不是固定顺序。
第五个问题的误判也很多 :Serverless 的成本优势来自负载不均匀,不是"调用量少"。一个每天稳定调用 10 万次、全天均匀分布的系统,用 Serverless 反而更贵(第 32 篇的盈亏平衡点在利用率 50% 左右)。
4.4 决策树的代码化
决策树可以固化成一个检查函数,用于架构评审:
python
"""架构选型检查:把决策树固化成可执行检查。
用途:**架构评审时自动过一遍**,避免遗漏关键问题。
"""
from __future__ import annotations
from dataclasses import dataclass, field
@dataclass
class ArchitectureProfile:
"""架构特征画像。回答这六个问题即可。"""
order_known_at_design: bool # 顺序设计时已知?
steps_independent: bool # 步骤相互独立?
accept_central_decider: bool # 接受中心决策者?
cross_process: bool # 跨进程部署?
load_highly_variable: bool # 负载高度波动(谷值接近零)?
multi_tenant: bool # 多租户或需统一治理?
needs_conflict_resolution: bool = False # 需要保留并消解矛盾结论?
@dataclass
class Recommendation:
execution_pattern: str
required: list[str] = field(default_factory=list)
optional: list[str] = field(default_factory=list)
warnings: list[str] = field(default_factory=list)
def recommend(p: ArchitectureProfile) -> Recommendation:
"""按决策树给出模式组合建议。"""
# ---- 第一层:执行形状 ----
if p.needs_conflict_resolution and not p.accept_central_decider:
shape = "黑板(第 25 篇)"
elif not p.order_known_at_design:
shape = "Supervisor(第 24 篇)" if p.accept_central_decider else "黑板(第 25 篇)"
elif p.steps_independent:
shape = "MapReduce(第 23 篇)"
else:
shape = "Pipeline(第 22 篇)"
rec = Recommendation(execution_pattern=shape)
rec.required.append("状态管理(第 30 篇)") # 所有模式的前提
if shape.startswith(("Supervisor", "黑板")):
rec.required.append("编排引擎的循环控制(第 26 篇)")
rec.warnings.append("终止判据绝不能交给 LLM------必须代码兜底")
# ---- 第二层:通信 ----
if p.cross_process:
rec.required.append("通信协议(第 27 篇)")
rec.warnings.append("三段 ID 缺一不可:correlation / causation / idempotency")
# ---- 第三层:异步解耦 ----
if p.cross_process and p.load_highly_variable:
rec.optional.append("事件驱动(第 29 篇)")
# ---- 第四层:治理 ----
if p.multi_tenant:
rec.required.append("网关(第 31 篇)")
rec.required.append("中间件(第 28 篇)")
rec.warnings.append("限流必须含 Token 维度,只限 QPS 等于没限")
else:
rec.optional.append("中间件(第 28 篇,按需)")
# ---- 第五层:运行时 ----
if p.load_highly_variable:
rec.optional.append("Serverless(第 32 篇)")
rec.warnings.append("Serverless 下状态外置是硬性要求,且长任务必须拆分")
else:
rec.warnings.append("负载平稳时 Serverless 可能更贵,先算盈亏平衡点")
return rec
这个函数的价值不在"自动选型",而在"强制回答六个问题"。 架构评审时最容易出现的情况是:团队讨论了一小时技术细节,却从未明确回答"顺序是否固定"这个最基础的问题。把问题显式化,本身就是最大的收益。
五、反模式清单:十五种"说得出来但会出事"的架构
反面约束也是模式语言的一部分。以下十五条全部来自第一季各篇的真实事故,按危害程度排序。
5.1 高危反模式(会导致静默错误或数据损坏)
| # | 反模式 | 症状 | 根因 | 正确做法 | 出处 |
|---|---|---|---|---|---|
| 1 | 用 LLM 做终止判据 | 循环 47 轮,烧掉 23 万 Token | 终止权交给了概率模型 | 终止权必须在代码里,一行 LLM 都不调用 | 24 / 26 |
| 2 | 冲突结论强行归并 | 矛盾被悄悄抹平,结论可能错 | 架构里没有存放矛盾的位置 | 宁可矛盾挂起,不可错误裁决 | 25 |
| 3 | 状态放进程内存且不分层 | 重跑污染用户偏好;崩溃即全损 | 生命周期不同的数据混在一起 | 会话/任务/全局三层分离 | 30 |
| 4 | 中间件顺序靠猜 | 脱敏排在日志之后,明文进了日志 | 顺序不可预测 | 顺序显式声明并按类型排序 | 28 |
| 5 | 失败做异常而非数据 | gather 中断,部分结果全丢 |
异常会中断并发 | 失败做成 ok=False 的结果对象 |
23 |
第 2 条的隐蔽性最高 :系统不会报错,日志一切正常,只是结论可能是错的。第 25 篇的做法是默认"保留双结论 + 标记 pending_conflict",只在证据权重明显悬殊时才自动裁决。
第 4 条那个事故值得复述 :脱敏中间件排在日志之后,导致身份证明文进了日志。bug 潜伏三个月才被审计发现,功能测试完全看不出来------因为功能测试只看返回值,不看日志内容。
5.2 中危反模式(会导致成本失控或可用性问题)
| # | 反模式 | 症状 | 根因 | 正确做法 | 出处 |
|---|---|---|---|---|---|
| 6 | 用一个 trace_id 应付所有 ID 需求 | 幂等失效或因果链断裂 | 三种 ID 生命周期不同 | correlation / causation / idempotency 三段 | 27 |
| 7 | 只按 QPS 限流 | QPS 达标但实例被长任务占满 | Agent 请求耗时差三个数量级 | 加并发维度 + Token 维度 | 31 |
| 8 | 降级链最后一级会失败 | 全部降级后依然报错 | 最后一级依赖了外部资源 | 最后一级必须是纯常量响应 | 31 |
| 9 | 重试职责不划分 | 平台重试 × 应用重试 = 6 倍流量 | 两层都在重试 | 按错误来源划分,只在一层重试 | 32 |
| 10 | 函数里 sleep 等待 | 为"什么都不做"付费 | 把等待放进了计算单元 | 等待交给编排层 | 32 |
| 11 | 扇出不设上限 | 并发打爆上游,触发限流雪崩 | 没有并发护栏 | 信号量限流 + 压测找拐点 | 23 |
第 7 条的症状特别具有迷惑性 :某租户以每秒 20 条的"温和"速率提交请求,QPS 限流完全不触发,但每条请求占用 Agent 30 秒------2000 条请求就把资源吃光了。监控显示"QPS 正常",其他租户却全部超时。
5.3 设计类反模式(架构层面的错配)
| # | 反模式 | 症状 | 根因 | 正确做法 | 出处 |
|---|---|---|---|---|---|
| 12 | 万能 Agent | 一个 Agent 干所有事,Prompt 越来越长 | 没有拆分 | 按能力边界拆分,用路由分发 | 24 / 31 |
| 13 | 为不需要恢复的东西设计恢复 | 复杂度高但无收益 | 复杂度由"应该"而非需求驱动 | 一次性任务用内存 dict 即可 | 30 |
| 14 | 给不需要网关的系统上网关 | 多一跳延迟,多一个要运维的组件 | "生产系统应该有网关" | 多 Agent + 多供应商 + 多租户占两个才上 | 31 |
| 15 | 事件载荷塞大对象 | 消息中间件被撑爆 | 把事件当成数据传输通道 | 载荷放引用 ID,内容放对象存储 | 29 |
第 13、14 条是同一类错误的两面 :复杂度不是由需求驱动的,而是由"生产级系统应该长这样"驱动的。第一季反复强调的一句话在这里再次适用------能用 20 行 if/else 写清楚的流程,就不要引入引擎(第 26 篇)。
最后要说明一点:这十五条反模式不是"禁止清单",是"成本提示"。 每一条在某些场景下都是合理选择------比如"状态放内存"在一次性任务里就是最优解,"只按 QPS 限流"在单租户内部系统里完全够用。清单的正确用法是:当你准备这么做时,知道代价是什么,并且确认这个代价你付得起。 反模式之所以有害,不是因为它绝对错误,而是因为它常常在当事人不知道代价的情况下被采用。

图2:六类高危反模式------现象、根因、对策三段式速查
六、架构评审:六个必问问题
选型之后,还需要一套评审方法确认架构没有明显漏洞。以下六个问题,任何 Agent 系统架构评审都应该过一遍:
| # | 问题 | 期望的答案 | 答不上来的后果 |
|---|---|---|---|
| 1 | 进程崩溃后,已完成的步骤会重跑吗? | 不会(有 completed_steps) |
崩溃一次,Token 费用翻倍 |
| 2 | 终止条件由代码还是 LLM 决定? | 代码 | 循环失控 |
| 3 | 两个结论矛盾时,系统怎么处理? | 有明确机制(挂起/裁决/人工) | 矛盾被静默抹平 |
| 4 | 失败是数据还是异常? | 并发场景必须是数据 | 部分结果全丢 |
| 5 | 限流包含 Token 维度吗? | 必须包含 | 账单爆炸或上游 429 |
| 6 | 中间件/网关的执行顺序能预测吗? | 能(显式声明) | 脱敏失效类事故 |
这六问来自第一季的六个真实事故,每条背后都有具体的代价:
text
Q1 没答好 → 一个跑 40 分钟的任务在第 38 分钟崩溃,全部重跑
Q2 没答好 → 47 轮循环烧掉 23 万 Token
Q3 没答好 → 矛盾结论被抹平,归因分析给出错误答案
Q4 没答好 → 600 个任务里 3 个失败,599 个的结果全部丢失
Q5 没答好 → 一个租户的批量任务吃光所有资源
Q6 没答好 → 身份证明文进日志,潜伏三个月被审计发现
💡 评审时最该警惕的答案是"应该没问题"。 上面六问的每一条,如果回答是"应该没问题"而不是具体的机制描述(比如"用
completed_steps记录已完成步骤"),那就等于没有答案。架构评审的价值在于把"应该"变成"具体是什么机制"。

图3:架构评审六问速查卡------崩溃恢复、终止判据、冲突处理、失败表示、限流维度、执行顺序
6.1 决策树的边界:什么时候不该用它
决策树是个好工具,但它有三个不适用的场景,必须说清楚:
场景一:需求还在快速变化。 决策树的输入是"顺序是否固定""步骤是否独立"这类架构特征,而早期需求的这些特征每周都在变 。这时用决策树定下的架构很可能两周后就作废。更好的做法是先写一个能跑的简单版本,等需求稳定后再做正式的选型评审。
场景二:团队没有对应模式的经验。 决策树可能给出"用黑板模式",但如果团队从没实现过共享状态与冲突消解,那么引入一个不熟悉的模式带来的风险,往往超过选错模式的风险 。第 26 篇那句判断在这里同样适用------能用团队熟悉的简单方案跑通,就不要引入不熟悉的复杂模式。
场景三:系统规模很小。 单 Agent、单进程、日均几百次调用------这类系统用决策树走一遍会得到"Pipeline + 内存状态 + 无网关 + 无 Serverless"的结论,而这本来就是默认答案,不需要决策树。
⚠️ 还要注意一件事:决策树给出的是"起点"不是"终点"。 它告诉你从哪个模式开始,但真实系统在运行中会发现新的约束,需要调整。第一季各篇的演进案例都说明了这一点 ------第 24 篇的 Supervisor 就是在"路由与终止混在一起出事后"才引入第 26 篇的循环控制。架构是迭代出来的,不是一次选对的。
七、第一季回顾与第二季衔接
7.1 第一季的三条主线
回头看第 22~32 篇,可以归纳出三条贯穿的主线:
主线一:决策权放在哪
这是第一季真正的暗线。从 Pipeline 到黑板,本质上是在移动"谁来决定下一步":
text
Pipeline → 代码决定(设计时写死)
MapReduce → 代码决定(设计时确定集合)
Supervisor → 中心 LLM 决定(运行时)
黑板 → 参与者自主决定(运行时,无中心)
而第 24、26 篇给出的关键结论是:决策权可以给 LLM,但终止权必须留在代码里。
主线二:错误是数据还是异常
从第 23 篇的 MapResult(ok=False) 到第 25 篇的 pending_conflict,再到第 31 篇的 degraded=true,第一季反复出现同一个模式:
Agent 系统的失败往往是"部分失败",而部分失败必须能被表示成数据,否则会被异常机制吞掉。
主线三:静默失效比崩溃更危险
第一季里最有价值的几个洞察都指向同一类问题------系统正常运行、日志干净、但结果是错的:
| 篇目 | 静默失效 |
|---|---|
| 24 Supervisor | 路由走错,专家仍返回看似合理的报告 |
| 25 黑板 | 结论矛盾被抹平;知识源从未激活但日志无痕 |
| 28 中间件 | 脱敏排在日志后,明文入库 |
| 31 网关 | 长期走降级,成功率显示 100% |
| 30 状态 | 恢复机制形同虚设,恢复后跳过步数恒为 0 |
这条主线的实践含义是:Agent 系统的可观测设计重点不是"有没有报错",而是"能不能发现静默失效"。 第 31 篇的降级率告警、第 30 篇的"恢复后跳过步数"指标,都是为此设计的。
7.2 第二季要解决什么
第一季解决的是**"系统怎么组织",第二季(第 34~43 篇,工程化实战篇)解决的是"怎么把它做对并证明它是对的"**:
| 第二季主题 | 解决的第一季遗留问题 |
|---|---|
| 开发环境与脚手架(34) | 第一季的代码散落各篇,没有统一工程结构 |
| 测试与 Mock LLM(35) | LLM 有随机性,怎么测?这是第一季最大的空白 |
| 评估方法论与 Eval 流水线(36) | 路由准确率怎么测(第 31 篇遗留) |
| 错误处理体系(37) | 第一季各篇各自实现了重试,没有统一分类 |
第一季最大的空白是评估。 第 31 篇说"路由准确率只能靠用户反馈回流",但没有给出系统的评估方法;第 24 篇说"准确率掉 2pt",但没有说明怎么测出来的。这些"数字"在第一季是作为结论出现的,第二季才补上"怎么得到这些数字"。
7.3 第一季留下的三个未解问题
诚实地说,第一季有三个问题没有解决,它们是第二季的直接输入:
问题一:LLM 有随机性,传统断言失效,代码怎么测?
第一季的测试都是针对确定性逻辑 的(状态转移、限流计数、幂等跳过)。但 Agent 的核心价值恰恰在 LLM 调用那一层------而这一层每次运行的结果都可能不同 。第一季的应对是"把 LLM 调用隔离成可注入的函数,测试时替换掉",但这只测了外围,没有测 Agent 本身的判断质量。
问题二:怎么量化"好"?
第一季多处出现了质量数字("准确率掉 2pt"、"成本降 74%"),但没有说明这些数字是怎么测出来的。路由准确率、答案质量、工具调用正确率------这些指标的定义和测量方法,第一季只是引用了结论。
问题三:错误处理没有统一体系。
第一季至少有五篇各自实现了重试(第 23、27、29、31、32 篇),每篇的退避策略、错误分类、重试上限都不一样。这在单篇里是清晰的,整合到一个系统里就是五套不一致的行为。 需要一个统一的错误分类与处理框架。
这三个问题分别对应第二季的第 35、36、37 篇。它们的共同点是:第一季解决了"系统怎么组织",但没有解决"怎么证明它是对的"。
八、总结
第一季讲了十一个模式,但真正应该带走的不是这十一个名字,而是三件事:
第一,模式之间有关系,理解关系才能组合。 执行形状四选一(Pipeline/MapReduce/Supervisor/黑板),编排引擎是承载它们的机器,状态管理是所有模式默认依赖却最后才讲清的地基。1.1 节那个失败案例的根源不是不懂 Supervisor,而是不知道它与黑板解决的是同一问题的不同侧面。
第二,选型的判断顺序比权衡表重要。 决策树的五个问题------顺序是否固定、步骤是否独立、是否接受中心决策者、是否跨进程、负载是否波动------每一个都有明确的判断方法和常见的误判。最难的不是权衡,是"我的情况属于哪一类"。
第三,静默失效是第一季最重要的主题。 五个篇目各自出现过一类"系统正常但结果错误"的失效:路由走错、矛盾被抹平、脱敏失效、长期降级、恢复形同虚设。它们的共同点是不报错、日志干净、只能靠设计预防。
给继续往下读的读者一句建议 :第一季的十一个模式,你不需要全部用上。一个跑在单进程里、用 Pipeline 组织、状态放 Redis、失败就整体重跑的 Agent 系统,可能就是你的最优解。判断标准是"有没有出现对应的真实问题",而不是"生产级系统应该长这样"。
落地自检清单(Checklist)
架构设计完成后,逐项确认:
- ✅ 执行形状已按"顺序是否固定 / 步骤是否独立 / 是否有中心"选定
- ✅ 状态放哪、进程崩了怎么办已有明确答案(第 30 篇)
- ✅ 终止判据在代码里,不依赖 LLM
- ✅ 冲突结论有明确处理机制(挂起/裁决/人工)
- ✅ 并发场景的失败是数据而非异常
- ✅ 跨进程部署已配三段 ID(correlation / causation / idempotency)
- ✅ 限流包含 Token 维度,不只是 QPS
- ✅ 中间件/网关执行顺序显式声明且可预测
- ✅ 降级链最后一级永不失败
- ✅ 重试职责在平台层与应用层之间已划分
- ✅ 负载波动时才考虑 Serverless,且状态已外置、长任务已拆分
- ✅ 已过一遍架构评审六问,每问都有具体机制而非"应该没问题"
- ✅ 未过度设计:能用简单方案的地方没有强行上模式
常见问题(FAQ)
Q1:十一个模式我该先学哪个?
按依赖顺序:① 第 22 篇 Pipeline(最基础的执行形状);② 第 30 篇状态管理(所有模式的前提);③ 第 26 篇编排引擎(把形状跑起来的机器)。这三篇构成最小可用集------其余模式按需阅读。
Q2:为什么状态管理放在第 30 篇而不是第 22 篇?
这是第一季编排上的一个结构性遗憾。原因是前面九篇都隐含假设"状态在进程内存里",这个假设在单进程 demo 里成立,直到要讲持久化和恢复时才被显式化。如果你重读第一季,建议把第 30 篇提前到第 22 篇之后读。
Q3:我的系统很简单,需要按决策树走一遍吗?
不需要走完。决策树的五个问题里,前三个回答完就能定执行形状 。如果答案是"顺序固定 + 步骤不独立 + 单进程",那么 Pipeline + Redis 状态就够了------后面四个分支问题(跨进程、异步、Serverless、多租户)都回答"否",决策树自然终止。
Q4:反模式清单里哪条最常见?
按我的观察是第 12 条"万能 Agent" ------一个 Agent 承担所有职责,Prompt 越写越长,最后无人敢改。它的隐蔽之处在于早期运行良好,直到 Prompt 超过某个临界长度、质量开始明显下降时,已经很难拆分了。
Q5:两个模式能不能混用?
能,而且很常见。典型组合:Supervisor 做整体调度 + MapReduce 处理某个可并行的子任务 ;事件驱动做跨服务解耦 + 编排引擎做单个服务内的流程控制。第 3.2 节列出了必须搭配的组合,其余组合按需。
Q6:架构评审六问适用于所有系统吗?
前四问适用(崩溃恢复、终止判据、冲突处理、失败表示)。后两问(限流 Token 维度、执行顺序可预测)只在多租户/多中间件场景下适用------单 Agent 系统不存在这些问题,强行检查会得到一堆"不适用"。
Q7:第一季的代码能直接用吗?
单篇的核心逻辑可以,但需要整合。第一季各篇为了讲解清晰,代码是独立设计的 (比如重试逻辑在第 23、27、29、31 篇各写了一遍)。第二季第 34 篇会给出统一的项目脚手架,把这些碎片整合起来。
Q8:读完第一季还缺什么能力?
三样:① 怎么测 (LLM 有随机性,传统断言失效)------第 35 篇;② 怎么评估 (路由准确率、答案质量怎么量化)------第 36 篇;③ 怎么统一处理错误 (第一季各篇各写了一遍重试)------第 37 篇。其中①是最关键的空白。
参考资料
- Alexander, C. 等 --- A Pattern Language: Towns, Buildings, Construction (模式语言思想的原始出处,本文"从清单到语言"的借鉴来源):https://www.patternlanguage.com/
- Gamma, E. 等 --- Design Patterns: Elements of Reusable Object-Oriented Software (GoF 设计模式,将模式语言引入软件工程):https://en.wikipedia.org/wiki/Design_Patterns
- Hohpe, G. & Woolf, B. --- Enterprise Integration Patterns (消息与集成模式,第 27/29 篇的通信模式参考来源):https://www.enterpriseintegrationpatterns.com/
- Nygard, M. T. --- Release It!(反模式与稳定性设计的系统性论述):https://pragprog.com/titles/mnee2/release-it-second-edition/
- Anthropic --- Building Effective Agents (Agent 模式分类与"何时不该用 Agent"的判断):https://www.anthropic.com/research/building-effective-agents
- LangChain 官方文档 ------ LangGraph 多 Agent 架构模式(Supervisor / 层级 / 网络等拓扑的官方实现参考):https://langchain-ai.github.io/langgraph/concepts/multi_agent/
- Temporal 官方文档 ------ 长流程编排与状态持久化(第 26/30 篇引擎与状态方案的工业级对照):https://docs.temporal.io/
- Google SRE Book ------ Design for Scale 与过载保护(第 31/32 篇治理与降级策略的方法论来源):https://sre.google/sre-book/table-of-contents/