第四章:Agent 设计范式¶
4.1 什么是 Agent 设计范式¶
同样是“搜索资料后生成报告”,可以每查到一条结果就决定下一步,也可以先列计划再执行,还可以对初稿反复核验。Agent 设计范式描述的正是这些控制方式:
Agent 如何组织推理、规划、行动、观察、验证与重试。
它不是某个特定框架,也不只是一个 Prompt 模板,而是一种运行时控制策略。
本章选取三类便于比较的基础范式,它们不是互斥或穷尽的分类:
- ReAct:一边观察、一边决定下一步;
- Plan-and-Execute:先建立全局计划,再执行和动态重规划;
- Reflection / Reflexion:通过评估和反馈修订结果;其中 Reflexion 是带情景记忆的具体研究方法。
这三类范式经常混用,实际系统里更常见的是分层组合:
%%{init: {"flowchart": {"nodeSpacing": 16, "rankSpacing": 16, "padding": 10}}}%%
flowchart TB
G["用户目标"] --> WF["Workflow / 安全边界"]
WF --> P["Planner / 全局计划"]
P --> E["Executor"]
E --> R["局部 ReAct 循环"]
R --> V["Verifier / Evaluator"]
V -->|通过| DONE["完成"]
V -->|局部失败| R
V -->|计划失效| P
V -->|需要人工判断| H["Human-in-the-loop"]
4.2 ReAct:推理与行动交替¶
ReAct(Reasoning and Acting)将推理与外部行动结合起来。经典表达是:
Thought → Action → Observation → Thought
这是 ReAct 原论文【268】的示意,不要求每次行动前都输出一段 Thought:原文在决策任务中允许稀疏出现推理步骤,也用这些步骤生成、跟踪和更新计划。其主要实验通过上下文示例运行,不在每次工具调用后更新模型权重;论文另有微调实验,不能与提示式 ReAct 混为一谈。
%%{init: {"flowchart": {"nodeSpacing": 16, "rankSpacing": 16, "padding": 10}}}%%
flowchart TB
T["Thought / Decide"] --> A["Action"]
A --> O["Observation"]
O --> T
T --> F["Final Answer"]
4.2.1 一轮 ReAct 如何运行¶
Thought¶
模型分析当前目标、状态和观察结果,并决定下一步策略。
Action¶
模型生成结构化动作,例如调用搜索工具。以下是调用语义示意,实际字段和调用 ID 由所用 API 决定:
Observation¶
Runtime 执行 Tool,并将真实结果或错误返回给模型。模型基于新证据进入下一轮决策。
4.2.2 现代实现不应暴露完整 Thought¶
早期 ReAct 示例会让模型显式输出 Thought。工程实现不应把这段自由文本当成稳定的控制接口,更不必依赖向用户展示完整隐藏思维链来调试。
例如模型说“已经查到最新版价格”,运行轨迹却只有一次失败的搜索调用,应以工具结果为准。系统应记录目标、计划、调用参数、真实返回值及状态变化,并把“为什么继续搜索”表达为可核验的简短理由。循环因此更适合写成:
Observe → Decide → Act → Observe
这些记录支持检查与追溯,但不等于模型内部计算的完整解释;推理文本的忠实性问题见第五章 §5.5.3。
4.2.3 ReAct 的决策形式¶
设当前目标为 \(g\)、状态为 \(s_t\)、观察为 \(o_t\)、可用上下文为 \(c_t\),下一步动作可表示为:
Runtime 执行动作后得到新的观察。用 eₜ 表示环境真实状态,区别于 Agent 保存的状态 sₜ:
Agent 随后更新状态:
观察可能不完整、过期或只表示请求已受理。更新的是 Agent 对环境的记录,不能据此假设它已经掌握全部真实状态。
4.2.4 ReAct 的优势¶
- 实现简单;
- 能及时利用最新环境反馈;
- 适合无法预先获得完整信息的任务;
- 工具失败后可以立即调整;
- 可用于短任务和探索性任务,收益取决于工具返回的信息是否有用。
原论文覆盖 HotpotQA、FEVER、ALFWorld 和 WebShop。检索可补充事实,但错误查询或无关结果也会误导后续决策;这些结果不证明 ReAct 在所有任务上优于 CoT,更不保证工具调用次数越多越准确。
4.2.5 ReAct 的局限¶
ReAct 常被概括为“走一步看一步”,其主要风险包括:
- 默认不强制维护可调度的全局任务结构,但可以在推理中制定计划;
- 串行的“调用工具后再决策”需要模型往返,批量调用可减少部分开销;
- 容易重复搜索或调用相同工具;
- 长任务中目标和约束可能被上下文噪音稀释;
- 局部合理的动作未必形成全局最优路径;
- 完成条件模糊时容易过早停止或持续循环。
这里的“局部最优”是一个直观类比,不是严格的优化保证。模型选择的动作甚至不一定是当前局部最优,只是根据当前上下文生成的候选动作。
4.2.6 改进 ReAct¶
生产系统通常加入:
- 始终可见的目标和验收条件;
- 结构化任务状态;
- Todo 或阶段检查点;
- Tool Call 去重;
- 无进展检测;
- 最大步骤、时间和费用预算;
- 周期性全局目标复核;
- 关键步骤的外部验证。
%%{init: {"flowchart": {"nodeSpacing": 16, "rankSpacing": 16, "padding": 10}}}%%
flowchart TB
O["Observation"] --> D["Decide"]
D --> C["动作是否无进展或越权?"]
C -->|是| RP["重新规划或停止"]
C -->|否| A["Action"]
A --> U["更新结构化状态"]
U --> G["仍符合全局目标?"]
G -->|是| O
G -->|否| RP
4.3 Plan-and-Execute:规划与执行解耦¶
Plan-and-Execute 将全局规划与局部执行分开。成熟实现通常包含三个角色:
- Planner:生成带依赖关系的计划;
- Executor:执行一个或多个计划步骤;
- Replanner:根据结果更新剩余计划或结束任务。
Planner、Executor 和 Replanner 可以使用不同模型,也可以由同一个模型在不同上下文中承担。
生成并执行计划。
flowchart TB
G[目标]
P[Planner]
PLAN[计划 / DAG]
E[Executor]
O[执行结果]
G --> P
P --> PLAN
PLAN --> E
E --> O
检查执行是否使计划失效。
%%{init: {"flowchart": {"nodeSpacing": 10, "rankSpacing": 16, "padding": 6}}}%%
flowchart TB
PLAN["计划 / DAG"]
E["Executor"]
O["执行结果"]
V["计划仍然有效?"]
RP["Replanner"]
PLAN --> E
E --> O
O --> V
V -->|否| RP
RP --> PLAN
区分剩余步骤与整体验收。
%%{init: {"flowchart": {"nodeSpacing": 10, "rankSpacing": 16, "padding": 6}}}%%
flowchart TB
V["计划仍然有效?"]
N["还有步骤?"]
E["Executor"]
ACCEPT["整体验收通过?"]
DONE["完成"]
RP["Replanner"]
V -->|是| N
N -->|是| E
N -->|否| ACCEPT
ACCEPT -->|是| DONE
ACCEPT -->|否| RP
V -->|否| RP
4.3.1 计划不应只是自然语言列表¶
一个可靠的计划步骤最好包含:
- 唯一 ID;
- 目标;
- 依赖步骤;
- 所需输入;
- 推荐 Tool 或执行器;
- 预期输出;
- 验收条件;
- 风险等级;
- 失败和回退策略。
{
"id": "compare-products",
"goal": "比较竞品 A 与竞品 B 的核心能力",
"depends_on": ["research-a", "research-b"],
"inputs": ["artifact://research-a", "artifact://research-b"],
"success_criteria": [
"至少覆盖功能、定价和目标用户",
"每项关键结论包含来源"
]
}
结构化计划比自由文本列表更容易调度、验证和恢复。
但“列表中的步骤都做完了”不等于用户目标已经完成。例如竞品 A 和 B 各自的报告都有来源,却分别使用年付价和月付价,比较结果仍然不成立。因此图中的整体验收要检查跨步骤约束,而不能只数 done 状态。
4.3.2 动态重规划¶
稳定、充分已知的任务可以执行一次性计划;环境或前提会变化时,需要重规划机制。每个关键步骤完成后,Replanner 应判断:
- 执行结果是否达到验收条件;
- 关键假设是否仍然成立;
- 后续步骤是否仍有必要;
- 是否需要插入、删除或重排步骤;
- 是否可以并行执行;
- 是否需要人工确认。
设当前计划为 \(P_t\),新观察为 \(o_{t+1}\),重规划可以表示为:
其中 \(R\) 表示 Replanner。
4.3.3 动态插入步骤示例¶
原始计划:
执行第一步后发现竞品 A 刚发布重大版本,计划更新为:
此时计划仍提供全局方向,但可以根据环境反馈演化。
4.3.4 Plan-and-Execute 的优势¶
- 对复杂任务具有更强的全局视野;
- 可以显式表达步骤依赖;
- 计划可以在执行前由人工审核;
- 容易分配不同模型和工具;
- 可以将独立步骤并行化;
- 更适合 checkpoint 和故障恢复。
4.3.5 Plan-and-Execute 的局限¶
- 规划和重规划增加延迟与成本;
- 初始计划可能建立在错误假设上;
- 规划器可能生成不可执行或过度细化的步骤;
- 频繁重规划可能退化成高成本 ReAct;
- Planner 与 Executor 之间可能出现语义偏差;
- 长计划可能在环境变化后迅速失效。
因此,计划粒度应与任务稳定性匹配:环境变化越快,计划越应保持高层和短周期。
4.4 减少往返与支持并行的变体¶
4.4.1 ReWOO¶
ReWOO(Reasoning WithOut Observation)将 Planner、Worker 和 Solver 解耦:Planner 在获取工具观察前生成带变量引用的计划,Worker 执行并绑定结果,Solver 结合计划与证据生成答案。“Without Observation”限定规划阶段,不表示最终答案无需工具观察。
以上是教学伪代码,不是通用工具协议。Worker 必须把 #E1、#E2 替换为实际输出,检查引用与依赖,而不是把变量名原样送给搜索工具。它减少了规划模型的往返,但无法预知所有条件分支;依赖返回内容才能决定是否添加新步骤时,仍需重规划或退回交互式执行。
4.4.2 DAG Planning¶
当计划包含明确依赖时,可以将其表示为有向无环图:
%%{init: {"flowchart": {"nodeSpacing": 16, "rankSpacing": 16, "padding": 10}}}%%
flowchart TB
A["调研竞品 A"] --> D["对比分析"]
B["调研竞品 B"] --> D
C["收集行业趋势"] --> E["趋势影响分析"]
D --> F["生成报告"]
E --> F
数据依赖已满足、没有共享写冲突且资源允许的步骤可以并行执行。DAG 只表达一版计划内的无环依赖;重试和重规划循环应由外层状态机管理。
4.4.3 LLMCompiler¶
LLMCompiler 类架构通常包含:
- Planner:生成或流式输出任务 DAG;
- Task Fetching Unit:依赖满足后立即调度任务;
- Executor:实际执行已就绪的工具任务。
这是 LLMCompiler 论文【454】列出的三个组件;带重规划的实现还可以加入 Joiner,汇总结果并决定结束或继续。不要把 Joiner 当作执行工具的 Executor。
这类设计关注的不只是规划质量,也关注执行并行度、模型调用次数和总体延迟。
4.5 Reflection:通过反馈改进结果¶
Reflection 在生成或执行之后加入评估环节:
%%{init: {"flowchart": {"nodeSpacing": 16, "rankSpacing": 16, "padding": 10}}}%%
flowchart TB
G["Generate / Execute"] --> E["Evaluate"]
E --> D["达到标准?"]
D -->|是| DONE["完成"]
D -->|否| FB["生成反馈"]
FB --> G
评估可以发生在:
- 单个步骤完成后;
- 一个里程碑完成后;
- 整个任务完成后;
- 只有高风险或低置信度时。
4.5.1 验证器的优先级¶
在工程实现里,Reflection 不能停留在“让同一个 LLM 再看一遍”。只要拿得到确定性或外部验证信号,就优先用这些信号:
- 编译器、单元测试和静态分析;
- Schema、规则和约束检查;
- 数据库或 API 返回的真实状态;
- 人工审核;
- 独立模型或 LLM-as-a-Judge;
- 同一模型的自我评价。
这不是固定的可信度排名。编译通过不等于业务正确,测试可能漏测,API 成功可能只代表受理;应按每项验收条件选择证据。LLM Judge 不得以“总体质量不错”为由覆盖测试失败或权限拒绝。
4.5.2 Reflection 的适用场景¶
- 代码生成与修复;
- 文案和报告优化;
- 翻译;
- 需要来源完整性的研究;
- 具有明确评分规则的结构化输出;
- 可以通过模拟器或测试环境验证的任务。
4.5.3 Reflection 的风险¶
- 评估模型可能与生成模型共享相同盲点;
- 没有明确标准时,反思可能只是改写;
- 多轮优化可能出现质量退化;
- 反思文本可能污染后续上下文;
- Agent 可能针对评分规则“投机”而非真正完成目标;
- 成本和延迟随轮数增加。
因此,需要最大反思轮数、最低改进阈值和清晰的成功标准。
4.6 Reflexion:带经验记忆的反思¶
Reflexion 是 Reflection 的一种具体范式。它不更新模型权重,而是把任务反馈转化为自然语言经验,并将其保存在情景记忆中供下一次尝试使用。
原方法包含 Actor、Evaluator、Self-Reflection 三个功能模块,并用情景记忆保存反馈:
- Actor:执行任务;
- Evaluator:评价轨迹或结果;
- Self-Reflection:将失败信号总结为可操作经验;
- Episodic Memory:在后续尝试中提供这些经验。
这里不是要求调用四个独立模型:记忆是存储,Evaluator 也可以使用环境奖励、规则或测试。模块如何实现取决于任务能提供什么反馈。
%%{init: {"flowchart": {"nodeSpacing": 16, "rankSpacing": 16, "padding": 10}}}%%
flowchart TB
A["Actor"] --> ENV["环境 / 工具"]
ENV --> TRAJ["执行轨迹与结果"]
TRAJ --> E["Evaluator"]
E --> PASS["成功?"]
PASS -->|是| DONE["结束"]
PASS -->|否| SR["Self-Reflection"]
SR --> MEM["情景记忆"]
MEM --> A
4.6.1 “错题本”类比¶
普通重试可能只是再次生成;Reflexion 会先总结:
- 哪个假设错误;
- 哪一步行动无效;
- 哪个反馈被忽略;
- 下一次应该采用什么不同策略。
这些经验作为额外上下文加入下一次尝试,因此类似“做错题、分析原因、带着经验重做”。
4.6.2 HumanEval 结果应如何解读¶
Reflexion 论文报告:在其 2023 年的实验设置中,基于 GPT-4 的 Reflexion 在 HumanEval Python 上达到 91.0% pass@1,表 1 中 GPT-4 单次生成基线为 80.1%(摘要取整为 80%)。
这里的 pass@1 指最终提交一个候选接受评测,不表示整个系统只生成一次或只调用一次模型。Reflexion 使用自生成测试、执行反馈和多次修订,再以保留的基准测试评价最终程序;反思循环不能访问用于最终计分的隐藏测试。单次生成基线与这个循环的计算预算不同,因此不能把差值全部归因于“反思提示词”。
这个数字说明反思与执行反馈在特定实验中具有价值,但不能直接推导为:
- 所有模型都能从 80% 提升到 91%;
- 所有代码任务都能获得相同提升;
- 生产项目中的仓库级任务也有相同效果;
- 增加反思轮次一定持续提高质量。
同一论文的 MBPP Python 结果反而从 80.1% 降到 77.1%,说明测试质量和任务分布会改变效果方向。模型版本、Prompt、测试生成方式和基准污染也会影响结果;实际评估应增加等预算重采样、仅测试修复等对照。
4.6.3 记忆污染问题¶
模型生成的反思不一定正确。如果未经验证就写入长期记忆,错误经验可能影响未来任务。
更安全的策略是:
- 默认将反思保留在当前任务的临时记忆中;
- 使用测试、环境反馈或人工审核验证;
- 只有稳定、可复用的经验才晋升为长期记忆、Skill 或规则;
- 为长期经验记录来源、版本和适用范围。
4.7 三种范式如何组合¶
实际系统里常见的分层组合如下:
flowchart TB
P[Plan-and-Execute] --> R[各步骤的 ReAct]
R --> V[反思与验证]
V -->|局部失败| RETRY[局部重试]
V -->|计划失效| P
V -->|通过| DONE[完成]
目标进入 Plan-and-Execute,生成全局里程碑以及第 1 至 N 个步骤。每一步都有自己的 ReAct 循环,负责局部探索与工具调用,所有步骤循环汇入同一反思与验证阶段。图中一个 ReAct 方框表示各步骤重复采用的循环,不意味着共享同一个上下文,也不表示这些步骤必须串行执行。
职责划分为:
- Plan-and-Execute:保持全局方向;
- ReAct:处理局部未知和工具反馈;
- Reflection:检查质量并产生改进反馈;
- Workflow:限制整体路径、权限和预算。
图中的完成出口还需要整体验收:确认当前计划的必要节点已完成、Artifact 版本一致,且跨步骤约束满足。单个子任务通过 Verifier,不代表整个目标完成。
4.8 Agentic Workflow:生产环境里的常见做法¶
Agentic Workflow 用确定性流程包围概率性决策:
按 Anthropic《Building Effective Agents》的术语,Router、固定并行分支和 Evaluator-Optimizer 都可以是 Workflow:分别负责分流、聚合独立工作、按反馈迭代。循环或多次 LLM 调用本身不构成自主 Agent;关键在于后续路径是预先编码,还是由模型在运行时动态选择。
%%{init: {"flowchart": {"nodeSpacing": 16, "rankSpacing": 16, "padding": 10}}}%%
flowchart TB
IN["输入"] --> V["校验"]
V --> ROUTE["固定路由"]
ROUTE --> AG["受限 Agent 节点"]
AG --> CHECK["确定性验证"]
CHECK -->|通过| OUT["输出"]
CHECK -->|可修复| AG
CHECK -->|高风险| HUMAN["人工审核"]
以客服系统为例:
- 意图识别、权限检查和输出审核由 Workflow 控制;
- 知识检索节点可以使用 ReAct 动态决定查询方式;
- 复杂问题使用 Plan-and-Execute 拆分;
- 最终答案使用引用检查或 Reflection;
- 退款、改价等写操作必须经过权限和业务规则检查;超出预授权范围时再转人工确认。
这种方式将自主性限制在真正需要灵活性的局部范围内。
4.9 如何选择范式¶
| 任务特征 | 推荐范式 |
|---|---|
| 步骤少、信息需要边做边获取 | ReAct |
| 步骤多、依赖复杂、需要全局视野 | Plan-and-Execute |
| 子任务存在明确依赖且可并行 | DAG Planning |
| 每次工具调用都咨询大模型成本过高 | ReWOO 或分层执行 |
| 输出质量要求高且存在验收标准 | Reflection |
| 希望从失败经验中改进下一次尝试 | Reflexion |
| 主流程稳定、局部存在未知 | Agentic Workflow |
| 高风险、强合规、路径完全已知 | 确定性 Workflow |
还可以从两个基础维度判断:
%%{init: {"quadrantChart": {"chartWidth": 440, "chartHeight": 440, "quadrantTextTopPadding": 100}}}%%
quadrantChart
title 复杂度与质量要求
x-axis "低复杂度" --> "高复杂度"
y-axis "较低质量要求" --> "较高质量要求"
quadrant-1 "规划与执行加反思"
quadrant-2 "ReAct 加反思"
quadrant-3 "简单工作流"
quadrant-4 "规划与执行"
ReAct: [0.30, 0.40]
"规划": [0.78, 0.48]
"反思": [0.40, 0.82]
"混合": [0.82, 0.85]
图中“规划”指 Plan-and-Execute,“反思”指 Reflection,“混合”指混合型 Agent。
二维图只是帮助理解。实际选择还需考虑风险、延迟、成本、可验证性和环境变化速度。
4.10 停止、预算与无进展检测¶
所有范式都必须具有停止条件:
- 达到明确成功标准;
- 达到最大步骤数;
- 达到 Token 或费用预算;
- 超过运行时间;
- 连续多轮没有产生新信息;
- 在没有新信息、合理轮询或可恢复错误的情况下重复相同 Tool Call;
- 反思后评分不再改善;
- 触发安全策略;
- 需要人工判断;
- 用户主动取消。
可以定义一个受限执行预算:
其中:
- \(N_{max}\):最大步骤数;
- \(T_{max}\):最大运行时间;
- \(C_{max}\):最大费用或 Token;
- \(R_{max}\):最大重试或反思次数。
当预算耗尽时,系统应明确报告未完成状态和已有结果,而不是伪装成成功。
4.11 生产级设计检查表¶
ReAct¶
- 是否持续保留目标和成功标准?
- 是否检测重复动作和无进展循环?
- Observation 是否来自真实工具结果?
- Tool 错误是否以结构化形式返回?
Plan-and-Execute¶
- 计划是否具有依赖、输入和验收条件?
- 任务前提会变化时,是否有重规划入口?
- 什么事件会触发重规划?
- 能否只重规划受影响的局部步骤?
Reflection / Reflexion¶
- 是否有客观验证器?
- 评价标准是否明确?
- 最大优化轮数是多少?
- 反思是否可能污染长期记忆?
- 改进是否值得额外延迟和成本?
Agentic Workflow¶
- 哪些节点必须由确定性代码控制?
- 哪些节点确实需要 Agent 自主性?
- 高风险动作是否经过审批?
- 是否保留完整 Trace、状态和审计记录?
4.12 Anthropic 原则的准确理解¶
“能用 Workflow 解决,就不要用 Agent”是对 Anthropic 工程建议的通俗概括,但不是原文中的绝对规则。
更接近原意的说法是:
从能够满足需求的最简单方案开始,只有在更高复杂度能够带来可测量收益时,才升级为多步 Workflow 或自主 Agent。
Anthropic 的区分是:
- 路径明确、需要一致性和可预测性时,优先使用 Workflow;
- 路径无法预先确定、需要模型动态决策时,才使用 Agent;
- 很多问题通过单次 LLM 调用、检索和示例优化就能解决。
复杂度本身不是能力。只有当任务成功率、质量或可扩展性得到可验证提升时,增加 Agent 自主性才有价值。
4.13 本章总结¶
ReAct、Plan-and-Execute 与 Reflection 分别解决三个不同问题:
- ReAct:如何根据最新环境反馈选择下一步;
- Plan-and-Execute:如何维持复杂任务的全局结构;
- Reflection / Reflexion:如何利用验证和失败经验提升质量。
组合时应明确每个控制环修改什么状态、由谁验收,以及何时停止。短任务不必配置全部角色;增加 Planner 或 Critic 后,仍要检验其收益是否超过往返延迟、状态管理和误判成本。
参考资料¶
本章的参考资料、阅读建议与来源说明见集中参考资料章节。