Plan-and-Execute:先规划再执行
作者:程序员马丁
Ragent AI —— 从 0 到 1 纯手工打造企业级 Agentic RAG,拒绝 Demo 玩具!AI 时代,助你拿个offer。
上一篇收尾时留了一句话:Plan-and-Execute 模式天然具备阶段信号,到那时按任务阶段调整上下文会清晰得多。这一篇就来兑现这个承诺。
前面的篇幅,咱们从 ReAct 循环起步,一路搭建了工具调用、Function Calling、终止控制、短期记忆、持久化、长期记忆、上下文工程——TinyAgent 已经是一个能想、能干、能记住你是谁、还会精打细算 Token 的智能体了。但它的决策方式始终没变:一步一步走,走一步看一步。
这种方式在简单任务上表现不错。用户说“帮我查订单 88231 的物流”,Agent 查订单拿运单号、查物流拿轨迹、给出答复——三步搞定,每一步都很清晰。但如果用户说的是这样一句话呢?
我家老人想要一台扫地机,预算 2000 以内,要好操作的。另外帮我看看订单 88231 到了没,到了的话帮我把那台坏的退掉。
一句话里塞了两个独立任务,其中一个还带条件分支(到了才退)。ReAct 会怎么处理?一步一步摸索。问题是——它不知道前面还有多少步要走,也不知道两个任务之间该怎么安排顺序。这就是 ReAct 的天花板。
这一篇,咱们给 TinyAgent 装上规划能力——先想清楚要干什么、分几步、每步用什么工具,然后再一步一步执行。这就是 Plan-and-Execute 模式。
本项目中具体代码已上传 GitHub TinyAgent,大家 Clone 项目后,将代码分支切换到 1.10.x,默认主分支是最新代码。运行前复制
.env.example为.env,把自己的 API Key 填进去,默认阿里云百炼平台;.env已加入.gitignore,切分支时不会丢。
ReAct 的天花板:走一步看一步的代价
在引入新方案之前,先把问题说透——ReAct 到底在什么场景下会拉胯?
1. 复杂任务的真实困境
拿开头那个例子来分析。用户一句话包含了两个子任务:
- 子任务 A:推荐一台 2000 以内、适合老人用的扫地机
- 子任务 B:查订单 88231 是否签收,如果已签收则申请退款
流程图如下所示:

ReAct Agent 拿到这句话后,第 1 圈的 Thought 里确实可以想“用户有两个任务,先处理退款再推荐”——ReAct 不禁止在 Thought 里做规划。但问题是,这个规划只存在于 Thought 的一段自然语言文字里,不会被结构化保存。随着轮次增加、Observation 堆积,这段最初的规划越来越容易被大模型的注意力机制淡化。假设它先查了订单:
第 1 圈:查订单 88231 → 拿到订单详情,状态“已签收”
第 2 圈:查物流确认签收 → 拿到物流轨迹
第 3 圈:申请退款 → 拿到退款单号
第 4 圈:……然后呢?
走到第 4 圈,messages 里已经堆了三轮退款相关的 Observation。虽然原始 user message 还在上下文里,推荐扫地机的需求不会凭空消失,但退款信息占据了大量上下文空间,大模型的注意力可能偏移——它有可能在这一圈就以为任务已完成,直接输出 Final Answer,漏掉推荐。更糟的是,如果中间某一圈大脑跳到推荐任务,查了知识库,然后下一圈又跳回退款——整条轨迹就变成了一条逻辑交错的线。
这不是 TinyAgent 的 bug,而是 ReAct 范式的结构性局限——它没有为多子任务提供显式的结构化保障,导致在复杂任务上表现不够稳定。