
1. 为什么这四个词总被放在一起聊如果你最近在折腾 Agent 开发大概率会在同一个下午里连续刷到 ReAct、Plan-and-Execute、Reflexion、Tree of Thoughts 这四个词。它们经常被塞进同一张架构图里配上箭头和循环看起来像一套组合拳。但真到写代码的时候很多人会卡在一个很实际的问题上这四个东西到底是并列的四种方案还是可以叠在一起用的四层机制我的结论是它们不是同一维度的东西。ReAct 解决的是单步怎么想、怎么动的问题Plan-and-Execute 解决的是多步怎么排、怎么调的问题Reflexion 解决的是做完之后怎么复盘、怎么改的问题Tree of Thoughts 解决的是在关键分叉口怎么并行探索、怎么剪枝的问题。把它们当成四个互斥的选项去选型是新手最容易踩的第一个坑。这篇内容我打算按实际搭一个能跑通的 Agent的顺序来讲而不是按论文发表顺序讲。因为论文顺序会让你觉得它们是四个独立模块而工程顺序会让你发现它们其实是四个可以按需挂载的决策层。适合谁看如果你已经写过最基础的调一次模型、解析一次输出、执行一次工具的循环但发现它在稍微复杂点的任务上就开始胡言乱语、反复绕圈、或者一条道走到黑那这篇就是写给你的。我会把每个机制的核心逻辑拆开讲清楚它到底在解决什么失败模式然后给出可落地的伪代码结构和参数建议最后聊几个我在实际项目里踩过的坑。全程不堆公式尽量用你写代码时会遇到什么的视角来讲。2. ReAct把想和做缝进同一个循环2.1 ReAct 真正解决的问题不是推理而是推理和行动的脱节很多人第一次看 ReAct 的论文会觉得它只是让模型在输出答案前先写一段Thought。这个理解太浅了。ReAct 的核心贡献是把推理轨迹Reasoning trace和动作轨迹Action trace交织在同一个生成序列里让模型在每一步都能看到我上一步做了什么、得到了什么观察、现在该想什么。在没有 ReAct 之前常见的做法是两段式先让模型规划一整串步骤再逐步执行。这个做法在简单任务上没问题但一旦中间某步的工具返回和预期不符整个计划就废了因为模型在规划阶段并没有看到真实的观察结果。ReAct 把观察Observation插回循环里模型每一步都能基于最新事实重新决策这才是它真正的价值。用生活化的类比两段式规划像出门前把一整天的路线全定死ReAct 像边走边看导航遇到堵车就重新算路。前者效率高但脆后者灵活但每步都要多花一点推理成本。2.2 一个最小可用的 ReAct 循环长什么样我不打算贴某个框架的 API 调用因为框架会变逻辑不会变。下面这个结构是我自己反复用过、也推荐给团队新人的骨架def react_loop(task, tools, max_steps8): scratchpad [] for step in range(max_steps): prompt build_prompt(task, scratchpad, tools) output llm.generate(prompt) thought, action, action_input parse(output) scratchpad.append((thought, thought)) if action finish: return action_input observation tools[action](action_input) scratchpad.append((action, action, action_input)) scratchpad.append((observation, observation)) return 达到最大步数仍未完成关键点有三个。第一scratchpad必须把 thought、action、observation 三类都存下来只存 action 和 observation 会让模型丢失推理上下文。第二parse这一步是整个循环最脆弱的地方后面会专门讲。第三max_steps是必须的没有它模型在工具反复报错时会无限循环下去。2.3 解析输出这件事比你想的更容易翻车ReAct 的经典格式是Thought: ... Action: ... Action Input: ...然后靠正则去抽。我早期项目里最常出的问题不是模型不会推理而是模型在 Action 那一行多写了一句解释或者把 Action Input 写成了自然语言而不是结构化参数导致解析失败。我的处理经验是不要指望模型永远守格式要在解析层做容错。具体做法是解析失败时不要直接抛异常终止而是把格式错误本身作为一条 observation 塞回 scratchpad让模型自己纠正。实测下来模型看到你的上一条输出无法解析请严格按 Thought/Action/Action Input 三行格式重写之后第二次基本都能改对。另一个经验是工具数量别一次给太多。当工具超过十个模型选错工具的概率会明显上升因为它要在长列表里做匹配。我的做法是按任务类型分组每轮只暴露当前子任务相关的三到五个工具这个改动对准确率的提升比换更大的模型还明显。2.4 ReAct 的边界它不擅长长程规划ReAct 是贪心的每一步只看当前最优。这在需要五步以上、且步骤之间有强依赖的任务上会出问题。比如先查A根据A的结果决定查B还是C再根据B/C的结果汇总ReAct 经常会在中途忘记最初的目标或者陷入局部最优。这不是模型能力问题是机制问题。贪心策略天然缺乏全局视野。所以当你的任务开始出现必须先规划再执行的特征时就该考虑下一节的 Plan-and-Execute 了。3. Plan-and-Execute先画图纸再动工3.1 它和 ReAct 的分工到底在哪Plan-and-Execute 把流程切成两个阶段Planner 负责把任务拆成一串有序的子步骤Executor 负责逐步执行每个子步骤。执行器本身可以是一个 ReAct 循环也可以是简单的单次工具调用。这个结构的关键在于规划是一次性的全局视角执行是局部的细节处理。为什么这个分工有效因为拆解任务和执行任务需要的思维模式不一样。拆解需要的是全局抽象能力执行需要的是局部精确能力。让同一个模型在同一个上下文里同时干这两件事它容易在细节里迷失全局。分开之后Planner 的上下文里只有任务描述和步骤列表干净Executor 的上下文里只有当前子步骤和工具聚焦。3.2 规划粒度太粗会失控太细会僵化这是 Plan-and-Execute 落地时最需要调的一个参数。规划太粗比如只拆成调研、分析、输出三步那 Executor 在每一步里还是要自己做大量决策等于没规划。规划太细比如把打开网页、定位元素、点击按钮都写进计划那计划一旦遇到页面结构变化就全废而且 Planner 的 token 消耗会爆炸。我的经验值是每个子步骤应该对应一次可独立验证的产出。比如获取某产品的官方定价信息是一个合适的粒度因为它有明确的完成标志拿到价格。而研究市场太粗点击第三个链接太细。你可以用这个标准去检验你的规划输出每个步骤能不能用一句话说清楚做完它之后我手里多了什么。3.3 计划不是圣旨重规划机制怎么加纯 Plan-and-Execute 最大的风险是计划与现实脱节。Executor 执行到第三步发现第二步的假设错了如果还硬着头皮往下走结果必然是错的。所以生产级的 Plan-and-Execute 一定要有重规划Replan机制。我的做法是在 Executor 每完成一步后加一个轻量的检查当前步骤的产出是否满足下一步的前置条件如果不满足触发 Replan把已完成步骤 实际产出 剩余目标重新喂给 Planner让它生成新的剩余计划。这个检查不需要很重有时候就是一次简单的模型判断但它能把一条道走到黑的概率降下来一大截。注意Replan 不要每步都触发否则 Planner 会被频繁调用成本和延迟都上去了。只在产出与预期明显不符或连续两步没有进展时触发性价比最高。3.4 什么时候该用 Plan-and-Execute什么时候别用适合的场景步骤数多五步以上、步骤间有依赖、任务可以提前大致拆解。比如报告生成、多源信息汇总、复杂的表单填写流程。不适合的场景任务高度依赖实时反馈、每一步的结果都会大幅改变后续方向。比如开放式对话、实时调试、探索性搜索。这些场景下 ReAct 的贪心反而更合适因为规划出来的东西大概率用不上。我见过不少团队一上来就上 Plan-and-Execute觉得有规划显得高级结果在交互式任务上表现还不如纯 ReAct。选型要看任务形态不是看机制复杂度。4. Reflexion让 Agent 学会吃一堑长一智4.1 反思不是重试区别很大很多人把 Reflexion 理解成失败了就重试。这是误解。单纯重试是把同样的输入再跑一遍模型大概率犯同样的错。Reflexion 的核心是在失败之后先生成一段语言化的反思说明为什么失败、下次该怎么改然后把这段反思作为额外上下文注入到下一次尝试里。这个区别很关键。重试是盲目重复反思是带信息的迭代。前者靠运气后者靠积累。用生活类比重试是同一道题再做一遍反思是做完之后对答案、分析错因、再做一遍。4.2 反思该反思什么三个层次我在实际项目里把反思分成三个层次按需使用结果层反思只关注最终答案对不对。适合有明确对错标准的任务比如数学题、代码测试。反思内容通常是上次算错了某一步这次注意。过程层反思关注执行路径有没有问题。适合工具调用类任务。反思内容通常是上次选错了工具应该先用搜索再用计算。策略层反思关注整体方法对不对。适合开放式任务。反思内容通常是上次直接给结论太草率应该先收集证据再下判断。层次越高反思越抽象泛化能力越强但也越容易空泛。我的经验是有明确验证信号的任务用结果层工具类任务用过程层只有开放式创作类任务才值得上策略层。4.3 反思记忆怎么存、怎么取Reflexion 要真正发挥作用反思不能只存在当前这次任务的上下文里得存下来下次遇到类似任务能取出来用。这就涉及一个轻量的记忆机制。我的做法是用一个简单的向量库存反思文本每条反思带上任务类型标签。新任务开始时用任务描述去检索最相关的几条反思注入到系统提示里。检索条数控制在三到五条太多会污染上下文太少起不到作用。这里有个容易忽略的点反思要带适用条件。比如遇到需要计算的任务时先确认单位再计算这条反思如果不带条件模型可能在不需要计算的任务上也去确认单位反而添乱。所以存反思的时候最好让它自己生成一句这条经验适用于什么情况。4.4 反思的代价延迟和成本会翻倍Reflexion 不是免费的。每次失败都要多一次模型调用去生成反思如果任务本身要跑好几轮成本会明显上升。所以我的建议是只在失败代价高或同类任务会反复出现的场景下用 Reflexion。一次性任务、失败也无所谓的任务直接重试就够了。另外反思的轮数要有上限。我一般设两到三轮超过还没成功就说明要么任务本身超出能力要么反思方向错了继续下去只是烧钱。5. Tree of Thoughts在关键分叉口做并行探索5.1 ToT 的本质是搜索不是提示词技巧Tree of Thoughts 经常被当成一种高级提示词来讲但它本质上是把推理过程建模成一棵树每个节点是一个中间状态每个分支是一种可能的下一步然后用搜索算法BFS、DFS 或带评估的启发式搜索去探索。它解决的是单条推理链一旦走错就无法回头的问题。ReAct 和 Plan-and-Execute 都是线性的一条路走到黑。ToT 允许你在关键节点展开多个候选评估每个候选的前景然后决定往哪个方向深入。这在需要试错或多角度思考的任务上优势明显比如谜题求解、方案设计、需要权衡取舍的决策。5.2 评估函数是 ToT 的命门ToT 能不能用好九成取决于评估函数。你需要一个机制去判断当前这个中间状态有多大希望通向正确答案。这个评估可以是模型自己打分也可以是用规则或外部工具验证。模型自评的坑在于它倾向于给自己刚生成的候选打高分缺乏区分度。我的应对办法是让评估和生成用不同的提示甚至不同的模型。生成用擅长发散的评估用擅长判断的两者分开评分会客观很多。另一个办法是让评估输出这个状态是否已经确定错误而不是这个状态有多好。二分类比打分更稳定因为模型对明显错了的判断比对有多好的判断可靠得多。用这个思路做剪枝效果比打分排序好。5.3 分支因子和深度两个必须控制的参数ToT 的搜索空间是指数增长的。分支因子为 b、深度为 d 时最坏情况要评估 b 的 d 次方个节点。所以这两个参数必须严格控制。我的经验值分支因子控制在 2 到 3深度控制在 3 到 4。超过这个范围成本和延迟会失控而且大部分分支其实是无效的。如果任务确实需要更深的探索宁可分段做多次 ToT也不要一次性把树铺太大。还有一个实用技巧在展开分支之前先让模型判断当前节点是否值得展开。如果当前状态已经接近答案或者明显是死路就直接跳过展开省下大量评估调用。5.4 ToT 适合嵌在哪里ToT 不适合作为整个 Agent 的主循环因为太贵。它更适合嵌在关键决策点。比如 Plan-and-Execute 里 Planner 拆解任务时如果拆解方案有多种可能可以用 ToT 探索几种拆法再选最优。或者 ReAct 在某一步面临多个工具选择且难以判断时用 ToT 展开评估。把它当成一个重型决策工具只在真正需要权衡的地方调用而不是全程开着。这个定位能让它在成本和效果之间取得平衡。6. 四个机制怎么组合成一个能打的 Agent6.1 分层组合不是四选一是四层可插拔讲到这里组合思路就清楚了。我的推荐架构是外层用 Plan-and-Execute 做骨架负责把任务拆成有序子步骤并在必要时重规划。每个子步骤内部用 ReAct 做执行负责在局部灵活调用工具、处理观察。在 Planner 拆解或 ReAct 遇到关键分叉时按需调用 ToT做多方案探索。整个任务结束后用 Reflexion 做复盘把经验存进记忆供后续任务检索。这四层不是必须全上。简单任务只用 ReAct 就够中等任务加 Plan-and-Execute需要试错的加 ToT需要跨任务积累的加 Reflexion。按需挂载别为了架构完整而堆机制。6.2 一个组合后的执行流程示例假设任务是调研三款竞品并输出对比报告Planner 拆解为确定竞品清单、逐个收集信息、整理对比维度、生成报告。对确定竞品清单这一步如果候选很多用 ToT 展开几种筛选标准评估后选一个。每个收集信息子步骤用 ReAct 执行灵活调用搜索、抓取、解析工具。如果某款竞品信息收集失败触发 Reflexion反思是搜索词不对还是数据源选错带着反思重试。全部完成后Reflexion 生成一条过程层反思比如竞品调研时先确认官方渠道再搜第三方存入记忆。这个流程里四个机制各司其职没有一个是多余的。6.3 状态管理组合架构最容易崩的地方多个机制组合之后状态管理会变成最大的工程挑战。ReAct 有自己的 scratchpadPlan-and-Execute 有步骤列表和执行状态ToT 有搜索树Reflexion 有反思记忆。这些状态如果混在一起模型会晕你调试也会晕。我的做法是分层隔离每个机制维护自己的状态容器机制之间只通过明确定义的接口传递信息。比如 ReAct 完成后只向上返回子步骤产出不把整个 scratchpad 暴露给 Planner。ToT 完成后只返回选定的方案不返回整棵树。这样每个机制的上下文都干净出问题也容易定位。6.4 成本与延迟的现实权衡组合架构的效果通常更好但成本和延迟也更高。我做过一个粗略的对比同样一个中等复杂度的任务架构相对调用次数相对延迟适合场景纯 ReAct1x1x简单工具调用Plan-and-Execute1.5x1.3x多步有依赖任务加 Reflexion2.5x2x需要跨任务积累加 ToT4x 以上3x 以上关键决策需探索这个表不是精确数据是量级参考。核心结论是每加一层机制成本都会上一个台阶。所以选型时要问自己这个任务真的需要这一层吗而不是能不能加上。7. 我在实际项目里踩过的几个坑7.1 坑一把 ReAct 的 max_steps 设太大早期我为了给模型足够空间把 max_steps 设成 20。结果发现模型在工具报错时会反复尝试同一个错误操作一路烧到第 20 步才停。后来改成 8并且在连续两次相同错误时主动中断成本降了一半成功率反而没降。教训是步数上限不是越大越好配合错误检测才有意义。7.2 坑二Reflexion 的反思污染了后续任务有段时间我发现 Agent 在简单任务上也开始过度谨慎明明一步能做完的事它非要先反思一下。排查后发现是反思记忆检索太宽泛把不相关的反思也注入了。修复方法是给每条反思加严格的任务类型标签检索时先按类型过滤再按相似度排序。这个改动之后误注入基本消失了。7.3 坑三ToT 的评估函数和生成用了同一个提示一开始我图省事生成候选和评估候选用的是同一个系统提示只是任务描述不同。结果评估几乎没有区分度选出来的分支和随机选差不多。后来把评估单独拆出来用完全不同的提示明确要求它找出这个方案的致命缺陷评分才变得有参考价值。这个坑让我意识到评估和生成是两种不同的认知任务不能共用一套提示。7.4 坑四组合架构的日志没做分层多机制组合之后调试变成噩梦因为所有机制的日志混在一起。后来我强制要求每个机制的输出带上来源标签日志按机制分层打印。这样出问题时能快速定位是哪一层的问题而不是对着一大坨输出发呆。这个改动看起来是小事但对开发效率的提升非常明显。8. 给不同阶段开发者的上手建议如果你刚接触 Agent我的建议是先把纯 ReAct 跑通重点练两件事工具描述怎么写清楚、输出解析怎么做容错。这两件事做好了后面加任何机制都顺。如果你已经能稳定跑 ReAct下一步加 Plan-and-Execute重点练规划粒度的把控和重规划触发条件的设计。这两个参数调好了多步任务的稳定性会有质的提升。如果你在做需要跨任务积累的产品再加 Reflexion重点练反思的层次选择和记忆检索的精度。别一上来就上策略层反思从结果层开始稳了再往上走。如果你面对的是需要权衡取舍的复杂决策再考虑 ToT重点练评估函数的独立性和分支剪枝策略。记住它是重型工具别全程开着。最后分享一个我自己的判断标准当你发现 Agent 的失败模式是想得不够时加 ToT是记不住时加 Reflexion是没全局观时加 Plan-and-Execute是单步执行不稳时回去打磨 ReAct。对症下药比盲目堆机制有效得多。