导读:很多人聊 Agent 设计模式,喜欢把 Plan、ReAct、Reflection、Tree of Thoughts 这些词排成一张表。小编一开始也这么看,后来真把 Agent 放进业务流程里才发现:这些模式不是 Prompt 技巧,而是在给模型补一套控制系统。
说白了,模型本身像一个很聪明但状态不稳定的实习生。你不能只跟他说“好好干”,你得给他目标、步骤、工具、日志、检查点、复盘机制和安全边界。Agent 设计模式解决的正是这些东西。
一、先说结论:Agent 模式不是让模型更聪明,而是让系统更可控
小编先把结论放前面:Agent 设计模式的本质,不是提升模型智商,而是管理模型的不确定性。
一个普通 LLM 调用,大概像这样:
1用户输入 -> 模型生成 -> 返回结果这条链路适合问答、总结、改写、生成一段代码。但只要任务变成下面这些情况,单次调用就开始吃力:
- 目标不是一步能完成,需要分解。
- 中间要调用工具,比如搜索、数据库、代码执行、文件读写。
- 执行结果会改变下一步策略。
- 有副作用,比如发消息、下单、改配置、创建工单。
- 失败后不能直接重来,需要知道错在哪里。
这时 Agent 就不是“一个会调用工具的聊天机器人”了,而更像一个小型运行时:
| 工程对象 | 在 Agent 里的对应物 | 解决的问题 |
|---|---|---|
| 控制面 | 计划、路由、状态机、策略选择 | 下一步该做什么 |
| 执行面 | 工具调用、函数执行、外部系统交互 | 真正把事情办掉 |
| 数据面 | 上下文、记忆、检索结果、任务输入 | Agent 基于什么信息行动 |
| 观测面 | 日志、轨迹、评估、告警 | 怎么知道它跑偏了 |
| 安全面 | 权限、确认、回滚、限流、人工介入 | 怎么防止它乱来 |
所以小编更愿意把 Agent 设计模式理解成一组“控制结构”:
- Plan:先想清楚路线。
- ReAct:边想边做,边做边看。
- Reflection:失败后复盘,把经验写回系统。
- Tree of Thoughts:不是只走一条路,而是试几条路再选。
- Plan-and-Execute / LLMCompiler:把计划和执行拆开,甚至并行执行。
名字很多,但核心问题只有一个:当模型不能一次性稳定解决任务时,我们怎么把它变成一个可观察、可约束、可迭代的系统。

二、为什么 Demo 能跑,业务跑不远
很多 Agent Demo 看起来很惊艳:输入一个目标,它自己搜索、分析、调用工具,最后给你一个结果。
但一进业务,小编见过最多的问题不是“模型不会回答”,而是下面这些:
2.1 它会做事,但不知道什么时候该停
比如你让 Agent 分析一个线上问题,它可能查日志、查监控、查代码、再查一遍日志,然后继续查。
人类工程师会在心里有个判断:
- 证据够不够?
- 继续查的收益大不大?
- 现在应该先止血,还是继续定位根因?
- 这个动作有没有风险?
模型没有天然的“工程刹车”。如果系统层不设计停止条件,它就会把“继续努力”理解成“继续调用工具”。
2.2 它会调用工具,但不理解副作用
读文档、查数据库、跑测试,这些是低风险动作。
但发通知、改配置、重启服务、创建 Issue、提交 PR,这些就有副作用了。副作用一旦发生,就不是生成文本那么简单。
这里小编有个判断:所有带副作用的 Agent 行为,都应该先当成生产变更来设计,而不是当成模型能力展示。
最少也要有:
- 权限边界。
- dry run。
- 人工确认。
- 操作日志。
- 回滚方案。
2.3 它会解释错误,但不一定真的学到了
Reflection 很容易被误用。
很多人让模型失败后写一段“反思”,然后下一轮把反思塞回 Prompt。看起来很合理,但问题是:这段反思到底有没有被结构化?有没有绑定到任务类型?有没有进入后续决策?有没有被验证?
如果没有,那它只是“失败后的作文”。
真正有用的反思,应该像事故复盘一样:
| 复盘字段 | 应该回答的问题 |
|---|---|
| 失败现象 | 哪一步失败了 |
| 失败原因 | 是信息不足、工具错误、计划错误,还是约束缺失 |
| 可迁移经验 | 下次遇到同类任务应该怎么改 |
| 触发条件 | 什么情况下启用这条经验 |
| 验证方式 | 怎么知道改进真的有效 |
这才是 Reflection 从“自我感动”变成工程资产的关键。
三、Plan:先计划,不是为了慢,而是为了少走冤枉路
Plan 模式最直观:先让模型生成一个计划,再按计划执行。
它适合什么任务?
- 目标明确,但步骤较多。
- 中间依赖顺序明显。
- 每一步可以被检查。
- 失败成本不低,需要提前识别风险。
比如让 Agent 帮你改一个项目里的 bug,比较靠谱的流程不是直接开写,而是:
11. 复现问题
22. 定位相关模块
33. 阅读现有测试
44. 提出修改方案
55. 实现最小改动
66. 跑测试
77. 总结影响范围这背后不是仪式感,而是把任务拆成可观察的检查点。
Plan 模式可以写成一个很简单的控制结构:
1type Step = {
2 id: string
3 goal: string
4 action: string
5 doneWhen: string
6 risk?: string
7}
8
9type Plan = {
10 objective: string
11 steps: Step[]
12 stopConditions: string[]
13}小编建议,Plan 不要只写“步骤”,还要写 doneWhen 和 stopConditions。
因为 Agent 里最值钱的不是“它知道要做什么”,而是“它知道做到什么程度算够了”。
Plan 的坑也很明显:计划可能一开始就错。
所以 Plan 不适合写死成瀑布流。更好的方式是:
1生成计划 -> 执行一步 -> 观察结果 -> 必要时修订计划 -> 继续执行也就是说,Plan 最后往往会走向 ReAct。
四、ReAct:真正关键的是 Observation,不是 Action
ReAct 来自 “Reasoning + Acting” 这个思路。它的核心不是让模型一边碎碎念一边调用工具,而是把任务过程拆成循环:
1Thought -> Action -> Observation -> Thought -> Action -> Observation...翻译成白话:
- Thought:我现在怎么看这个问题。
- Action:我要调用什么工具。
- Observation:工具返回了什么事实。
- 下一轮 Thought:根据新事实修正判断。
小编觉得 ReAct 最大的价值,是把模型从“闭门造车”拉回到环境里。
比如一个知识问答 Agent,如果只靠模型内部知识,就容易编;如果它能搜索、读取文档、观察返回结果,再继续推理,幻觉会少很多。ReAct 论文里也强调了这种交错方式:推理轨迹帮助模型跟踪和更新行动计划,行动则让模型从外部环境拿到信息。
但工程里用 ReAct,有三个关键点。
4.1 工具结果要短,不要把垃圾塞回上下文
很多 Agent 失败,不是因为工具少,而是工具返回太多。
搜索返回十几页,数据库返回几百行,日志返回几万字,全部塞给模型,模型当然会迷路。
工具层应该做预处理:
1type ToolResult = {
2 summary: string
3 evidence: Array<{
4 source: string
5 quote?: string
6 value?: string
7 }>
8 nextHints?: string[]
9}给模型的是“可推理的证据”,不是“原始垃圾桶”。
4.2 每个 Action 都要有权限等级
小编建议把工具分成三类:
| 工具类型 | 例子 | 策略 |
|---|---|---|
| 只读工具 | 搜索、读文件、查日志 | 可自动执行 |
| 可逆写工具 | 创建草稿、生成临时文件、dry run | 可自动执行但要记录 |
| 不可逆/高风险工具 | 发布、删除、支付、改生产配置 | 必须人工确认 |
这不是保守,这是生产系统基本礼貌。
4.3 Observation 必须进入日志
Agent 的每一次行动都应该能复盘:
1{
2 "step": 3,
3 "thoughtSummary": "怀疑配置读取顺序有问题",
4 "action": "read_file",
5 "input": "src/config.ts",
6 "observation": "发现 env 覆盖默认配置",
7 "decision": "继续检查测试覆盖"
8}注意,小编这里写的是 thoughtSummary,不是把完整隐式思维链暴露出来。工程系统需要的是可审计的决策摘要,不是让模型把所有脑内过程倒出来。
五、Reflection:反思不是再想一遍,而是把失败变成资产
Reflection 模式很诱人,因为它听起来像人:做错了,反思一下,下次变好。
Reflexion 这类方法的核心,是让 Agent 根据任务反馈生成语言形式的经验,并放进记忆里,影响后续尝试。这个方向很有价值,但工程落地时要小心一个问题:反思必须绑定反馈信号。
没有反馈的反思,可信度很低。
比如下面这段就没什么用:
1我应该更加仔细地分析需求,并在执行前充分考虑边界情况。这是正确废话。
更好的反思应该长这样:
1{
2 "taskType": "修改前端表单校验",
3 "failure": "只改了 submit 校验,遗漏了 blur 校验",
4 "rootCause": "没有先搜索同字段的所有校验入口",
5 "lesson": "修改字段规则前,必须搜索 schema、submit、blur、server validation 四类入口",
6 "trigger": "当任务包含 表单/校验/字段规则 时启用",
7 "nextCheck": "提交前列出所有入口和覆盖情况"
8}这就可以进入经验库。
小编更建议把 Reflection 用在三类场景:
| 场景 | 是否适合 Reflection | 原因 |
|---|---|---|
| 单次问答 | 不太适合 | 反馈弱,复盘价值低 |
| 编码任务 | 适合 | 测试结果能提供明确反馈 |
| 多轮工具任务 | 很适合 | 每一步都有轨迹,可定位失败点 |
| 高风险业务动作 | 谨慎使用 | 反思不能替代权限和人工确认 |
Reflection 最怕变成“失败后让模型安慰自己”。真正要做的是把失败归因结构化,然后让下一次计划发生变化。
六、Tree of Thoughts:不是更复杂,而是承认第一条路可能不对
Chain of Thought 是一条线。
Tree of Thoughts 是多条线。
它解决的是另一类问题:有些任务不是按步骤推进就行,而是需要探索、比较、回退。
比如:
- 设计一个复杂架构方案。
- 写一篇有观点的文章。
- 做一道需要尝试路径的推理题。
- 规划多约束下的执行策略。
这类任务如果只让模型生成一条思路,很容易早早押错方向。Tree of Thoughts 的思路是让模型生成多个中间思路,再评估、选择、扩展,必要时回溯。
白话一点:
1不要只问“下一步是什么”
2而要问“可能有哪几种下一步,哪一种更值得继续”工程上可以简化成:
1type Candidate = {
2 idea: string
3 score: number
4 risk: string
5 reason: string
6}
7
8function chooseNext(candidates: Candidate[]) {
9 return candidates
10 .filter(item => item.score >= 7)
11 .sort((a, b) => b.score - a.score)[0]
12}当然,真实系统不会这么粗糙,但思想是这个思想:把模型从“单线程自信”改成“多路径比较”。
Tree of Thoughts 的代价也很明显:贵、慢、复杂。
所以小编不建议普通业务流程一上来就搞搜索树。它更适合:
- 高价值任务。
- 创造性任务。
- 难以一次判断对错的任务。
- 错了会导致大量返工的任务。
如果只是把用户输入转成 SQL,或者总结一段日志,用 Tree of Thoughts 就像骑车去楼下拿快递还带了导航仪。
七、Plan-and-Execute / LLMCompiler:当工具变多,就要像调度系统一样设计
Plan 和 ReAct 都有一个问题:很多时候它们是串行的。
1想一步 -> 调工具 -> 看结果 -> 再想一步 -> 再调工具这很直观,但慢。
如果任务里有很多互不依赖的工具调用,比如:
- 同时查三个服务的日志。
- 同时读取几个配置文件。
- 同时跑多个静态检查。
- 同时查询多个数据源。
那就没必要一条一条等。
LLMCompiler 这类思路,就是把模型生成的计划变成更像执行图的东西:
1Planner -> Task Graph -> Dispatcher -> Parallel Executors -> Join Results这时 Agent 更像一个小型工作流引擎。
小编觉得这类模式特别适合“工具多、延迟敏感、依赖关系清楚”的任务。比如代码仓库分析、运维诊断、资料收集、数据比对。
但这里有一个工程提醒:计划和执行一拆开,状态管理就更重要了。
你需要知道:
- 哪些任务可以并行。
- 哪些任务依赖前置结果。
- 哪个任务失败会影响整体。
- 多个结果回来后如何合并。
- 合并后的结论是否需要模型再判断。
否则并行只会把错误放大得更快。

八、到底怎么选:看不确定性和副作用
Agent 模式不用背,按两个维度选就行:
1不确定性:任务执行过程中,是否需要根据新信息调整策略
2副作用:工具调用会不会改变外部世界可以粗略放进这张表:
| 任务类型 | 推荐模式 | 小编的判断 |
|---|---|---|
| 输入输出清楚、低风险 | Prompt Chain | 别过度设计,简单链路就够 |
| 步骤多但目标明确 | Plan / Plan-and-Execute | 先拆步骤,再逐步检查 |
| 需要边查边改策略 | ReAct | 工具结果必须反过来影响下一步 |
| 失败可反馈、可重试 | Reflection / Reflexion | 把失败归因写成可复用经验 |
| 多方案探索、难以一次判断 | Tree of Thoughts | 生成候选路径,评估后再走 |
| 工具多且可并行 | LLMCompiler / DAG Executor | 把计划变成任务图 |
| 高副作用动作 | 状态机 + 人工确认 | 不要把安全交给模型自觉 |
小编自己的选择顺序一般是:
- 能不用 Agent,就不用 Agent。
- 能用 Prompt Chain,就别上复杂循环。
- 需要外部信息,再考虑 ReAct。
- 需要失败学习,再加 Reflection。
- 需要方案搜索,再用 Tree of Thoughts。
- 需要稳定上线,就补状态机、权限、日志、评估和兜底。
这套顺序听起来不酷,但很工程。
九、一个可落地的 Agent 骨架
如果让我从零设计一个业务 Agent,小编不会先问“用什么模式”,我会先画这个骨架:
1User Goal
2 |
3 v
4Task Router --------------+
5 | |
6 v |
7Planner |
8 | |
9 v |
10Policy / Permission Check |
11 | |
12 v |
13Executor -> Tools -> Observation
14 | |
15 v |
16Evaluator |
17 | |
18 +--> Reflector -> Memory
19 |
20 v
21Final Answer / Human Confirm / Rollback对应到代码,最小也应该有这些对象:
1type AgentState = {
2 goal: string
3 plan: Step[]
4 currentStep: number
5 observations: Observation[]
6 decisions: DecisionLog[]
7 permissions: Permission[]
8 memoryHints: string[]
9}
10
11type AgentRuntime = {
12 plan(state: AgentState): Promise<Step[]>
13 act(step: Step, state: AgentState): Promise<Observation>
14 evaluate(state: AgentState): Promise<"continue" | "revise" | "stop" | "human_review">
15 reflect(state: AgentState): Promise<MemoryHint[]>
16}这里最重要的是 evaluate。
很多 Agent 框架喜欢强调 plan 和 act,但小编觉得真正决定系统质量的是评估层:
- 当前结果够不够?
- 有没有偏离目标?
- 是否触发风险?
- 是否需要人确认?
- 是否要修订计划?
- 是否要停止?
没有评估层,Agent 就是一个会调用工具的 while 循环。
十、几个容易踩的坑
10.1 把模式当银弹
ReAct 不是所有任务都比普通 Prompt 好。
Reflection 也不是加了就会进化。
Tree of Thoughts 更不是免费的深度思考。
模式解决的是结构问题,不是替你解决需求理解、数据质量、工具可靠性和权限治理。
10.2 只看最终答案,不看过程轨迹
Agent 的过程比结果更重要。
因为结果错了,你要知道它错在哪里:
- 目标理解错了?
- 计划错了?
- 工具选错了?
- 工具结果读错了?
- 中间判断错了?
- 安全策略漏了?
如果没有轨迹,你只能说“模型又抽风了”。这句话对排障没有任何帮助。
10.3 让模型自己决定所有边界
高风险系统里,边界不能靠模型“自觉遵守”。
比如:
- 最多调用多少次工具。
- 最多花多少钱。
- 哪些工具需要确认。
- 哪些字段不能输出。
- 哪些动作必须 dry run。
- 哪些异常必须升级给人。
这些应该写在程序里,而不是写在 Prompt 里祈祷模型听话。
10.4 没有离线评估集
如果一个 Agent 每次改 Prompt 都靠肉眼试两条样例,那迟早会变成玄学。
至少要有一批离线任务:
1输入任务 -> 期望轨迹 -> 允许工具 -> 关键断言 -> 风险检查 -> 最终结果Agent 的评估,不应该只看最终回答像不像,还要看:
- 有没有调用不该调用的工具。
- 有没有漏掉关键证据。
- 有没有在信息不足时强行下结论。
- 有没有在高风险动作前请求确认。
- 有没有把失败经验写进正确位置。
十一、最后的判断:Agent 工程不是让模型自由发挥,而是设计可控自由
小编最后想说一句有点绕、但很重要的话:
Agent 的价值,不是让模型想干嘛就干嘛,而是在可控边界里,让模型拥有足够的行动空间。
Plan 给它路线。
ReAct 给它眼睛和手。
Reflection 给它复盘能力。
Tree of Thoughts 给它多路径探索。
状态机、权限、日志、评估、人工确认,给它边界。
所以真正的 Agent 设计,不是把一堆模式名塞进 Prompt,也不是迷信某个框架。它更像搭一台机器:哪里需要齿轮,哪里需要传感器,哪里需要刹车,哪里需要人站在旁边确认。
当你从这个角度看 Agent,很多问题就清楚了。
不是“我要不要用 ReAct”。
而是“这个任务的不确定性在哪里,副作用在哪里,我准备用什么结构把它管住”。
这才是 Agent 设计模式真正有价值的地方。
参考资料
- ReAct: Synergizing Reasoning and Acting in Language Models:https://arxiv.org/abs/2210.03629
- Reflexion: Language Agents with Verbal Reinforcement Learning:https://arxiv.org/abs/2303.11366
- Plan-and-Solve Prompting: Improving Zero-Shot Chain-of-Thought Reasoning by Large Language Models:https://arxiv.org/abs/2305.04091
- Tree of Thoughts: Deliberate Problem Solving with Large Language Models:https://arxiv.org/abs/2305.10601
- An LLM Compiler for Parallel Function Calling:https://arxiv.org/abs/2312.04511