Chapter 01 · 范式觉醒

范式觉醒:从 GoF 失效到双轴框架

起点页给了一句话本质:所有模式都是同一个原子循环在两根轴上的取值。这一章把这句话拆开——先讲为什么旧范式(GoF)会失效、新机制(分布式系统)从哪来,再立起两根轴并教你用它定位与选型,最后用逆向五步法去验证它。

本章你将建立的 schema

  • 为什么 GoF 的确定性契约在概率 actor 上失效,该用分布式系统的哪些机制(幂等、Saga、补偿、重放)补位。
  • 「认知功能 × 执行拓扑」两根轴各回答什么问题、为什么正交、为什么能装下所有模式。
  • 用坐标系给一个已知模式定位,用两个诊断问题把业务需求反推成模式族。
  • 逆向五步法:从可观察行为逐层向内,反推一个成熟 Agent 产品的架构。

这门课要解决一个具体的认知问题:上千个 agent 工程问题,看上去千奇百怪,背后是不是有有限的结构?答案是有。所有这些问题都落在同一个原子循环上——一次 LLM 调用接收一段 context、产出 token,这些 token 被解析成动作并执行,结果作为新的 observation 回填进下一轮 context。28 个设计模式,全部是对这个循环施加约束的不同方式。

拼进 prompt token→解析动作 执行·有副作用 observation 回填 原子循环 28 模式都在给它加约束 Context LLM 一次调用 概率节点 动作 Action 环境 → observation
图 1.0所有 agent 行为都是这个循环的展开。注意:顶上那个节点是概率节点,不是确定函数——同样的 context 进去,出来的 token 不保证一样。整门课的所有麻烦和所有模式,都从这一点长出来。

1.1范式之变:GoF 失效与分布式系统补位

GoF 设计模式假设 actor 是确定的、控制流编译期已知;LLM agent 两条假设都不成立——它是概率节点,控制流在运行时由模型自己决定。

为什么需要它

写过十年面向对象的工程师,手里有一套强大的设计直觉:Strategy 换算法、State 管状态、Chain of Responsibility 串处理链。把这套直觉直接搬到 agent 上,是大多数人踩的第一个、也是最贵的认知错误。它不是不够用,而是会主动误导——因为它的两条地基假设在 agent 上都不成立。

GoF 那 23 个模式,全部建立在两条前提上:actor 是确定的(同样的输入给出同样的输出),控制流编译期已知(哪个分支走哪里,写代码时就定死了)。LLM agent 把这两条都打破。第一,执行是概率性的——模型做的是 token 概率的模式匹配,不是逻辑推断。第二,控制流在运行时由模型自己决定——Anthropic 对 agent 的定义就是"LLM 动态地指挥自己的流程和工具使用"。

底层机制(比"非确定"深一层):很多人以为非确定性是采样噪声,把 temperature 设成 0 就能消掉。这是错的。Thinking Machines 在 2025-09 实测:Qwen3-235B 在 temperature=0 下,同一个 prompt 跑 1000 次产生了 80 个不同的补全,而且分叉发生在第 102 个 token。根因不是浮点不结合律本身,而是服务器负载让 batch size 浮动,导致 RMSNorm/矩阵乘/注意力的归约(reduction)顺序变化,浮点结果随之变化(batch 不变性缺失)。含义很重:你连"同输入同输出"这条最底层的契约都拿不到,GoF 那套基于确定性的设计失去基础。

那该用什么范式补位?答案是分布式系统。一旦 actor 不可靠、步骤之间有网络/工具副作用、又没有跨步骤的事务,你面对的失效集合——部分失败、超时、重复投递、最终一致——正好就是分布式系统十五年前解决过的那一套。这套机制是直接可映射的:消息队列对应 agent 步骤间的任务缓冲;幂等键防止重复的 LLM 调用产生重复副作用;熔断器对应主模型限流时切备用模型;Saga + 补偿处理多步工作流中途失败的回滚;两阶段提交对应不可逆动作前的人工审批门;背压对应并行 LLM 调用的并发上限。下图是这套机制里最常用的一种:Saga 补偿。

每步绑定幂等键:重试命中即 no-op,不重复执行副作用 ① 写订单 ② 调支付 API ③ 发确认邮件 ✗ 失败 补偿·逆序回滚 撤销支付 删除订单
图 1.1没有跨步骤的 ACID 事务,每个有副作用的步骤就得预先配一个逆操作。注意:补偿是逆序触发的——第 3 步失败,先撤第 2 步(退款)再撤第 1 步(删单),顺序反了会留下脏状态。这正是分布式系统的 Saga,被原样搬进多步 agent 流程。
表 1.1 · 把 agent 当什么来设计
把 agent 当成带来什么为什么没选 / 选中
确定的 OOP 对象
(GoF:Strategy / State / Command)
模式成熟、直觉熟悉,上手零成本概率 + 运行时控制流两条假设都不成立,确定性契约不再成立;同名映射(Chain≈routing)是"同名不同物"
更大的 RAG / 写死的 workflow可预测、可调试,多数生产场景够用只覆盖固定路径,处理不了"模型自主决定步数与停止"——这正是 agent 的定义性能力
分布式系统里的不可靠节点
(幂等 / Saga / 补偿 / 背压 / 重放)
失效集合精确对应;崩溃可恢复、重试安全、部分失败可补偿选中——这是与 agent 真实失效结构匹配的范式

下面这段伪码把这套机制收成一个可复用的步骤骨架:幂等键挂在"逻辑操作"上而不是每次推理调用上,外部 oracle 验证而非自检,副作用登记补偿、持久化以便崩溃重放。

distributed_step.py Python
# 分布式系统的机制用于 agent:每个有副作用的步骤 = 幂等键 + 外部验证 + 补偿 + 重放
def run_step(saga, step, inputs):
    # 1) 幂等键挂在"逻辑操作"上,不是每次 LLM 调用
    key = sha256(f"{step.name}:{stable_json(inputs)}")
    if cached := store.get(key):          # 重试策略:命中即 no-op,绝不重算
        return cached                     # (这是 retry,不是 sampling)

    # 2) LLM 这步非确定 → 拿环境 ground truth 校验,失败再"采样"换答案
    for attempt in range(MAX_SAMPLES):    # 采样策略:换答案,独立于上面的重试
        out = llm_call(step.prompt, inputs)
        if validate(out, against=env):    # 独立验证:不靠模型自检
            break
    else:
        saga.compensate_all()             # 都不过 → 逆序补偿已完成步骤
        raise StepFailed(step)

    # 3) 副作用必须可补偿、可重放(否则崩溃重放会重复执行)
    effect = step.apply(out)
    saga.register_compensation(step.undo, effect)   # 登记逆操作
    store.put(key, out)                   # 持久化:崩溃后重放跳过本步
    return out
陷阱 · temperature=0 ≠ 确定性

任何依赖"这步 LLM 输出可复现"的设计都会偶发失败:同 prompt 在 temperature=0 下实测 1000 次产生了 80 种结果(batch 不变性缺失)。别把"关掉采样"当成"拿到了确定函数"——你连重放一致性这个最基本的分布式假设都站不稳,所以每个有副作用的步骤都得显式幂等。

想一想

一个 agent 步骤解析 LLM 输出失败了,你想"重试一次换个答案"。如果这个步骤已经调用过支付 API、并且你用同一个缓存键来做这次重试,会发生什么?

展开答案(先停 10 秒再点)

缓存会命中,一直返回那个坏输出——因为你把两种相反语义混进了一个键。retry 要的是"同样的结果从缓存返回、绝不重算";sampling 要的是"重新生成一个不同答案"。它们必须用不同的键。更糟的情况是:如果没有幂等键,重试会让支付 API 被重复调用——这是把后端世界里几乎无害的"重试一下"直觉,错误地搬到了有副作用 + 非确定输出的 agent 步骤上。

这正是为什么分布式系统的 retry policy 和 sampling policy 是两个独立旋钮,混进一个参数是多数 agent 失效的源头。

1.2双轴框架(上):两根正交的轴

两根轴回答两个不同的问题——纵轴(认知功能)问"一步循环内部在做什么",横轴(执行拓扑)问"循环之间如何连、谁决定下一步"。

§1.1 立住了地基:agent 是概率分布式节点。这一节在地基上立起坐标系。把 1000 个工程问题压缩成有限模式,靠的就是发现:任何一个具体的 agent 设计问题,本质都在回答两件正交的事。

纵轴 = 认知功能,由 CoALA(Cognitive Architectures for Language Agents,TMLR 2024)给出权威划分,回答"这一步循环内部在做什么"。它把动作切成两类:"不碰世界"的内部动作(推理 reasoning、检索 retrieval、学习 learning,只更新工作记忆)和"碰世界"的外部动作(grounding,接到对话/物理/数字环境,有不可逆副作用)。感知、记忆、推理、行动、反思这五个认知功能,本质是这个内部决策周期里被调用的不同动作类型。下图是这个周期的机制。

内部动作:推理·检索(不碰世界) 外部动作:grounding(有副作用) observation 工作记忆 规划 提议→评估→选择 执行 grounding / learning 回填工作记忆
图 1.2单个 agent 内部一个决策周期:规划阶段提议-评估-选择候选动作,执行阶段落地一个内部或外部动作,observation 回填后循环重启。注意:reflection(反思)不是单独一格——它是"把经历写回长期记忆(learning)+下一周期再检索回来"的组合,所以五功能不是平行五个模块。

横轴 = 执行拓扑,由 Anthropic 的工作流构建块和 LangGraph 的多智能体抽象锚定,回答"多个 LLM 调用在控制流上如何连线、谁决定下一步"。最根本的分界是 workflow(控制流写死在代码里)对 agent(LLM 在循环里自主决定)。在这条轴上,从简单到复杂依次是:单 agent 循环(ReAct)、规划-执行(强模型先出计划、弱模型执行)、编排者-工人(中心 LLM 运行时动态分解派发)、多 agent(network 对等 handoff/supervisor 中心调度)。拓扑的本质是 context 的拓扑——每个 box 是一个独立的上下文窗口,箭头是 token 的传递。

为什么两根轴正交:同一套认知功能可以塞进任意拓扑。一个 worker 内部仍然要跑完整的"提议-评估-选择-执行"周期;把 reflection 从单 loop 提到 evaluator-optimizer 拓扑,改的是"谁来反思",不改"反思要产出什么"。所以"这一步做什么"和"循环怎么连"是两个能独立拨动的旋钮——这就是双轴框架的全部威力,也是它能装下所有模式的原因。

表 1.2 · 用什么组织这些模式
组织方式优势为什么没选 / 选中
扁平清单
(chaining / routing / … 一字排开)
上手快、直接对应 Anthropic 原文把正交的两件事(一步做什么 vs 多步怎么连)混进一个维度,且无法回答"下一个模式在哪"
按框架分类
(LangGraph / CrewAI 怎么写)
贴近落地、能直接抄框架会过时,且学到的是 API 不是设计;换框架就重学
认知功能 × 执行拓扑 双轴能解释"为什么是这些模式"、暴露空白格子、跨框架可迁移选中——代价是要先理解两个抽象轴,但一次投入终身复用
想一想

有人说要给 agent 加一个"反思模块",做法是把 perception / memory / reasoning / action / reflection 实现成五个平行的独立模块。按 CoALA 的机制看,这个设计哪里会出冗余?

展开答案(先停 10 秒再点)

perception 和 reflection 在 CoALA 里都不是独立的格子。perception 是 grounding 动作的环境反馈(observation 回填),reflection 是 learning(把经历写回长期记忆)+下一周期 retrieval(重新注入)的组合。把它们做成与 reasoning/action 平级的独立模块,会造出和"工作记忆回写""检索"重复的冗余路径。常见的"感知-记忆-推理-行动-反思"五并列方块图,其实是对 CoALA 的简化误读——五个是认知功能,不是五个实现模块。

1.3双轴框架(下):定位与反推选型

给业务问题问两个诊断问题——步数能否预先列举(定横轴)、是否需要反思/跨任务记忆(定纵轴)——两个坐标的交点就是模式族。

§1.2 立起了坐标系。这一节让它干活:把已知模式钉到坐标上,再反过来用坐标反推选型。关键是,两根轴各自绑定一个真实的成本机制,不是装饰性的分类标签。

横轴绑定"LLM 调用次数 × 串/并行",直接决定延迟和 token 账单。ReAct 的铁律是"每个工具调用 = 一次大模型调用",所以延迟线性累加、还容易近视(一次只为一个子问题规划)。Plan-Execute 把规划从执行剥离——规划器只在开头和重规划时调用,执行步可用廉价模型,成本约"1× 强模型 + N× 弱模型",N>3 时常优于 ReAct。多 agent 把成本推到极限:Anthropic 的研究系统比单 agent 强 90.2%,但烧了约 15× 的 token,而且 token 用量本身解释了约 80% 的性能方差——多 agent 的本质是"用 token 买并行探索的广度"。

纵轴绑定"有限上下文窗口怎么花"。Anthropic 把它重述为注意力预算:transformer 的 n² 注意力让 context 越长召回越差(context rot)。纵轴往上爬的每一档,都是一种对抗 context rot 的记忆机制。下图把几个已知模式钉在了这个坐标系上。

执行拓扑(横轴)· 调用数/并行 ↑ 认知功能(纵轴)· 内省 ↑ 单循环 规划-执行 编排-工人 多 Agent 反应 规划 反思 +记忆 ReAct Plan-Execute Reflexion Orchestrator-Workers Generative Agents
图 1.3把已知模式投影到双轴坐标系。注意:右上角越贵——往右是 LLM 调用数和并行度上涨(延迟/token),往上是上下文预算被记忆与反思占用。选型就是问两个问题、落到一个格子,而不是背模式名。

反推选型只问两个诊断问题,各定一根轴的坐标。下面的伪码把这个判断显式化。

locate_pattern.py Python
# 把一个业务问题投影到「认知功能 × 执行拓扑」坐标系
def locate_pattern(task):
    # —— 横轴:由"步数能否预先列举"决定 ——
    if steps_enumerable_upfront(task):
        topo = "plan_execute" if not subtasks_independent(task) else "parallel"
    else:                                   # 步数不可预测 → 反应式
        topo = "orchestrator" if dynamic_subtasks(task) else "react"

    # —— 纵轴:由"单遍能否做对 / 是否需记忆"决定 ——
    cog = "reactive"
    if needs_iteration_with_feedback(task): cog = "reflective"   # evaluator-optimizer / Reflexion
    if needs_cross_task_memory(task):       cog = "memory"       # 情景记忆 / 压缩 / 笔记

    return (cog, topo)                       # 坐标交点 = 推荐模式族

# 选错坐标 → 可预测的失败模式:
#   (reactive, plan_execute) 用在高动态环境 → 计划僵化、频繁 replan
#   (reactive, react)        用在可预列举任务 → 近视卡循环、延迟白付
#   过度上 (memory, orchestrator) → 上下文分散、决策冲突、token 爆炸
表 1.3 · 选错坐标的失败模式
模式该用在用错场景 → 失败模式
ReAct(单循环·反应)步数不可预测、强环境依赖的探索用在步骤明确的任务 → 每步一次大模型调用、近视卡循环、延迟白付
Plan-Execute(规划-执行)步骤可预先分解、追求低延迟低成本用在高动态环境 → 开头的全局计划迅速过期,频繁 replan 反而更慢
Reflexion(反思+记忆)有明确成功/失败信号、允许多次重试用在无清晰奖励信号的任务 → Self-Reflection 空转、生成漂亮但无用的自我安慰
Orchestrator-Workers(编排)子任务无法预先列举、可并行的广度探索用在强依赖任务(编码调试)→ 子 agent 互不知情、决策冲突、约 15× token
洞察 · 这个坐标区还没有定论

2025-06,Anthropic 公布了强 90.2% 的多 agent 研究系统、力推 orchestrator-workers;同期 Cognition 发表《Don't Build Multi-Agents》,说多 agent 因上下文分散、子 agent 互不知情而脆弱,编码调试这类强依赖任务尤其不该拆。两个顶级团队对同一个坐标区直接对撞——说明"右上角"目前没有标准答案。读到后面第 07 章协作时,带着这个张力去看。

1.4逆向五步法:从产品反推架构

你只能看到 LLM API 边界上的字节流;逆向就是从这层字节流逐层向内反推:行为 → 工具 → 系统提示 → 控制流 → 架构。

前三节给了你一套坐标系和一套来自分布式系统的设计方法。这一节给你验证它们的工具:拿一个成熟 Agent 产品,把它的架构拆出来。这既能让你"带读他人代码",也是检验你是否真懂双轴框架的试金石——能逆向,才算真懂。逆向的本质约束是:无论产品内部多复杂,它和模型之间只能通过 LLM API 边界上的字节流交互,所有"架构"都是从这层字节流向内反推。

由外向内 ↓ 成本与保真度同时上升 ① 观察行为:UI 流式输出、延迟分布、并发路数(零侵入) ② 抓工具集:mitmproxy 反代抓包,读 tools 数组(最高保真) ③ 推系统提示:频率分析剥离静态骨架 vs 动态注入 ④ 重建控制流:message role 序列 → 状态机 ⑤ 拼出架构 workflow? 单/多 agent? 记忆在哪? 模型怎么分级?
图 1.4逆向是逐层向内的:行为几乎免费,抓包要环境,控制流重建要大量样本。注意:第 2 步是性价比最高的一刀——工具的 JSON schema 必须原样发给模型,所以一个反向代理就拿到了最高保真的信号,不需要任何破解。

第 2 步是杠杆点:把 base URL 指向本地 mitmproxy(ANTHROPIC_BASE_URL=http://localhost:8000),截获请求体里完整的 tools 数组(名字 + JSON schema + description)——这是最高保真的信号。第 3 步用频率分析:系统提示被 prompt caching 固定,每轮高频复现,可自动剥离出静态骨架 vs 动态注入(<system-reminder>、<env>、todo 重载)。第 4 步从 message role 序列重建状态机:assistant[tool_use] → user[tool_result] 反复出现即 ReAct 环;出现 Task 工具即 orchestrator-workers。

逆向最反直觉的一个发现:很多产品的多 agent 协调逻辑根本不在代码里,而是写在系统提示的自然语言指令里。工程师以为会看到调度器或消息总线,实际是 prompt。所以"控制流一半在代码、一半在 prompt"——盯着可执行逻辑找状态机会漏掉一半。

为什么逆向是为迁移设计而非抄袭

抄系统提示既脆(对方一改就失效)又有法律风险(系统提示里可埋"金丝雀令牌",一旦出现在你的产品输出里就能溯源到你)。逆向的真正价值,是还原"为什么这样设计"——把对方的控制流选择、记忆分层、工具边界、护栏策略提炼成可迁移的设计原则,套到你自己不同的任务约束上。验证假设要靠三类探测:提示泄漏、输出反演(output2prompt,只用正常输出就能拼回提示,绕过拒答防御)、行为差分(固定探针集做 A/B 假设检验,对抗采样随机性)。

想一想

你逆向一个网页版的 Deep Research 产品,抓了它和服务器之间的最外层请求,发现全程只有一个 agent 在说话。能据此断定它是单 agent 架构吗?

展开答案(先停 10 秒再点)

不能。服务端 agent 的内部子调用发生在服务器内部,你抓的最外层包看不到那些子 agent 的并行探索。把"最外层只有一路输出"当成"单 agent",是把 UI 行为误当架构。判断多 agent 的更可靠信号是行为指纹:中间过程的信息密度突然骤降、主线程上下文异常干净——子 agent 烧几万 token 探索、只回传 1000–2000 token 摘要,这种"摘要式返回"才是子 agent 架构的指纹。能抓包的本地 CLI 类产品(如 Claude Code)才能看到内部的 Task 子调用。

§本章 self-check

先合上教程,把你能想到的答案写在纸上或编辑器里。写完再点开答案对照——直接点开等于把这一节当再读一遍。

  1. GoF 设计模式的两条地基假设是什么?LLM agent 分别怎么打破它们?
  2. 为什么 temperature=0 不能保证 LLM 输出可复现?根因是什么(一个词)?
  3. 双轴框架的两根轴各回答什么问题?用一句话说清它们为什么正交。
  4. 反推选型的两个诊断问题是什么?各定哪一根轴的坐标?
  5. 逆向五步法里,为什么"抓工具集"这一步性价比最高?
答案(先做完再展开)
  1. 两条假设:actor 确定(同输入同输出)、控制流编译期已知。agent 用概率执行打破第一条,用"模型运行时自主决定下一步"打破第二条。
  2. 因为服务器负载让 batch size 浮动,导致归约(reduction)顺序变化、浮点结果变化。根因一个词:batch 不变性(缺失)。
  3. 纵轴(认知功能)问"一步循环内部在做什么",横轴(执行拓扑)问"循环之间如何连、谁决定下一步"。正交是因为:同一套认知功能可以原样塞进任意拓扑,"做什么"和"怎么连"能独立拨动。
  4. 问题一:"步数能否预先列举?"定横轴(能→规划-执行/并行,不能→反应式/编排)。问题二:"是否需要反思/跨任务记忆?"定纵轴(需要迭代→reflective,需要跨任务→memory)。
  5. 因为工具的 JSON schema 必须原样发给模型,所以一个反向代理就能拿到最高保真的信号(名字+schema+description),无需任何破解;其余各层的保真度都低于它。
进阶挑战 · 刚好够不着

给一个"自愈式测试修复"agent 定坐标

设想一个 agent:拿到一个失败的单元测试,反复"读报错 → 改代码 → 重跑测试",直到通过或放弃。请把它定位到双轴坐标系的哪个格子,并指出它和 ReAct 的关键差别在哪一根轴上、为什么这个差别让它在"测试修复"上比纯 ReAct 更可靠。

提示(卡住再展开)

横轴上它仍是单 agent 反应式循环(每轮一次推理)。真正的差别在纵轴:它有一个外部 oracle(单元测试的通过/失败)作为反馈信号。回想 §1.3 表里 Reflexion 那一行的适用条件——"有明确成功/失败信号"。这个外部 ground truth 正是后面第 06 章"自愈循环"可靠的根本原因,也是为什么同样的反思放到没有 oracle 的开放任务上会失灵。