一个任务丢给 Agent,很多时候都会得到一份漂亮但没法落地的计划。我在调 Pi agent 的时候就撞上过这类问题:让它做稍微复杂一点的事,它要么把简单任务拆出十来个步骤,要么在执行中反复重新评估,迟迟不调用工具,看起来像在“空转”。后来我把 Pi agent 的任务规划与推理模式彻底推倒重做了一遍,这中间踩过的坑和沉淀下来的设计思路,值得单独写一篇聊聊。
Pi agent 本质上是一个以语言模型为核心的自动化智能体原型,负责接收自然语言任务、拆分执行步骤、按需调用工具、最终把结果整理成交付内容。它能做的事很多,但真正决定它“看起来聪不聪明”的,恰恰是任务规划(Task Planning)和推理模式(Reasoning Mode)这两块。如果你正在自研 Agent 框架,或者想在现有项目里引入更可控的任务调度逻辑,这篇文章应该能给你一些能直接落地的参考。
1. 规划先行还是边干边想:任务拆解的两种基本姿态
先说一个核心矛盾:任务规划到底应该一次性做完,还是边执行边规划?
这两种思路在 Agent 领域里都有成熟实践。一次性规划,也就是常说的 Plan-then-Execute,先把大任务拆成完整步骤清单,再逐步执行;动态规划则更像 ReAct 那种边推理边行动的循环,每一步都基于当前观察决定下一步。我最早把 Pi agent 做成了纯 ReAct 风格,结果发现它在短任务上表现不错,但一旦任务链条变长,它很容易忘记最初的目标,在细枝末节上打转。
后来我给 Pi agent 设计了一套两层结构:
- 粗规划层:任务进来后,先生成一个高层次的步骤框架,只定大阶段,不细化到具体动作。
- 细规划层:执行到某个阶段时,再根据当前上下文和工具返回结果,动态生成该阶段内的详细操作。
举个例子,让它“整理会议室预约记录并生成一份周报”。粗规划层给出的框架是:收集数据、清洗字段、汇总分析、生成周报。而细规划层会在实际执行到“收集数据”阶段时,才决定具体查哪个系统、拉哪个时间段的记录、遇到缺失值怎么补。这样一来,规划成本被控制在较低水平,又不会因为计划太死板而无法应对执行中的变化。
1.1 粗规划层的生成策略
粗规划层本质上是一个“先想后做”的过程。实现时需要注意,模型生成的步骤数量不能没有上限,否则就会出现我开头说的那种过度规划。
我加了一个步骤数约束:根据任务输入长度和涉及的工具数量,动态计算一个合理区间。通常 3 到 7 步,超过 7 步的任务会被要求重新归纳、合并同类项。实测下来,这个约束直接让后续执行阶段的平均耗时下降了不少——因为步骤越少,上下文越干净,模型做决策时的干扰项就越少。
1.2 细规划层的触发条件
细规划触发得太频繁也不行。每个子步骤都重新调用 LLM 推理,成本和延迟都扛不住。我的做法是:只在三种情况下触发细规划。
- 进入一个新的大阶段
- 工具返回了异常或预期外的结果
- 当前步骤执行失败,需要重新规划替代路径
这三种触发条件覆盖了绝大多数需要调整计划的场景,又不会无谓地消耗推理资源。有人可能会问:为什么不干脆每个子步骤都做一次动态规划?原因很简单,LLM 调用的延迟是毫秒到秒级的,一次任务执行中如果调用几十次,用户会明显感觉到“卡”,这种体验在自动化任务里是不能接受的。
2. 快思考与慢思考:推理模式为什么不能二选一
推理模式是另一个容易踩坑的设计点。最早我只给 Pi agent 配了一种默认推理模式,所有判断都走标准的“指令+上下文+生成”流程。结果发现,查询类任务它回答得还算利落,但需要多层逻辑推导的任务就开始胡说。
后来我参考了双系统认知的理论思路,把推理拆成了两种显式模式:直出模式(Fast Mode)和推演模式(Deep Mode)。
直出模式适合确定性高的操作,比如查记录、算个数值、拼接字符串,这类任务“根据输入直接产生输出”即可,不需要长篇推理。推演模式则适合多约束权衡的场景,比如排期冲突、多条件筛选、方案对比,这种时候模型需要在内部展开一步多分支推演,再收敛出一个结论。
2.1 切入推演模式的判定信号
问题来了:系统怎么知道当前任务需要用哪种模式?不可能让用户手动指定,那样体验太差。我设计了一个轻量级的调度判定器,它会综合下面几个信号来做决定:
- 任务文本中是否包含因果词、比较词、条件约束
- 当前步骤涉及的工具返回结果是否存在冲突
- 用户对结果有明确精度要求(比如“详细分析”“对比一下”)
当这些信号出现时,调度器会把这次推理标记为 Deep Mode,并且强制要求 LLM 先生成推理链摘要,再输出最终结论。如果信号不足,则走 Fast Mode,直接输出动作指令。
2.2 模式之间的动态切换
模式一旦选定并不是锁死的。执行过程中经常出现的最坏情况是:一个任务开始时看着很简单,走 Fast Mode 之后才发现工具返回的数据互相矛盾,此时就必须切换到 Deep Mode。
我在实现里留了一个统一的中断检查点:每次工具调用结束后,Pi agent 都会快速判断一下结果是否符合预期。如果发现矛盾、空数据、或者置信度低于阈值,就把当前上下文标记成“需深度分析”,强制切入 Deep Mode 重新做一轮综合判断。这个检查点的开销很低,但对最终效果的提升非常明显。
3. 从规划到执行的调度细节:工具编排与上下文管理
规划做完之后,真正的工程挑战才开始。Pi agent 的执行层需要同时管三件事:工具编排、上下文压缩、断点恢复。这三个问题如果处理不好,再完美的规划也只是纸上谈兵。
3.1 工具编排:规划出来的步骤不能想当然
规划层会给出类似“调用某系统查询数据,再调用某函数做清洗”的描述,但实际执行时,工具的参数格式、返回结构、异常行为都可能跟预期不一致。我的做法是:给每个工具维护一份 schema 描述,执行前把规划步骤里的自然语言参数映射到 schema 字段上;映射失败时,不硬猜,而是回到细规划层重新生成一次参数。
这里有一个很实用的细节:工具返回结果的长度差别很大。有的工具返回几行文本,有的返回上千行的表格。如果把这些内容全部塞给 LLM,上下文很快会被撑爆。我的做法是给工具结果做一个摘要层——大块数据先做统计摘要,保留关键字段和行数,只有在 Deep Mode 需要看明细时,才按需展开原始数据。
3.2 上下文管理:不能让规划撑爆窗口
规划本身也占上下文。粗规划层的输出如果完整保留在前缀里,加上后续追加的历史对话、工具结果,长任务跑到一半就会提示超长。我的解决思路是“分层保留”:
- 高层规划始终保留,因为它定义了全局骨架
- 细规划结果只保留最近一段,更早的细步骤被压缩成“已完成的动作摘要”
- 工具结果在任务流中的保留策略是:最近一次的结果完整保留,历史结果只留摘要
这样设计之后,即使任务是那种二三十步的长流程,上下文也能维持在一个稳定开销范围内。
3.3 断点恢复:执行中断时怎么接上
Pi agent 跑批处理任务时,经常遇到外部服务超时、网络抖动、或者进程被系统回收的情况。一旦中断,如果整个规划要从头再来,代价太大。
我做了一个轻量级的任务状态快照机制:每完成一个细步骤,就把当前步骤索引、已完成结果摘要、未执行步骤列表写入一个本地 JSON 文件。下次启动时,Pi agent 检测到快照存在,会先恢复步骤索引,再根据未执行列表继续往下跑,而不是重新规划全局。
这个机制的实现成本很低,但价值非常高。有一次我跑一个涉及十二个步骤的数据整理任务,跑到第七步时服务崩了,重启后它直接接续完成,没有重复采集,也没有重新生成计划。那一刻我确实觉得这套设计值得写下来分享。
4. 实测中暴露的四个典型问题与调优记录
任何 Agent 系统都会在实际使用中暴露一堆问题,Pi agent 也不例外。我把调试过程中最典型的四个问题整理成了一张表,然后逐个说一下解决思路:
| 问题 | 表现 | 根因 | 调优方案 |
|---|---|---|---|
| 规划过度 | 简单任务拆出 8-10 个步骤,迟迟不执行 | 粗规划缺少步骤数约束 | 加入步骤数上限聚类合并 |
| 循环徘徊 | 连续多次重新评估当前状态,不动作 | Deep Mode 触发阈值过低 | 提高切换阈值,限制连续评估次数 |
| 上下文爆炸 | 跑到一半提示超长,后续动作变形 | 工具结果和细规划未分层压缩 | 引入摘要层+分层保留策略 |
| 单点失败全盘重来 | 某个步骤失败后直接清空计划 | 缺少局部重规划机制 | 增加失败后的局部替代路径生成 |
4.1 规划过度:约束比能力更重要
规划过度的根子在于 LLM 倾向于“表现得很严谨”,宁愿多列步骤也不愿漏掉可能。但步骤一多,上下文就长,执行效率反而更低。我加入步骤数约束之后还做了一步:同一个阶段里如果有连续两步都属于同一类操作,就让模型把它们合并成一步。比如“查询 A 系统数据”和“查询 B 系统数据”会合并成“查询 A、B 两个系统的数据”,然后在细规划时再单独展开。
这个细小的改动,让整个任务的平均执行时长缩短了不少,而且用户看起来更整洁。
4.2 循环徘徊:给“思考”设置边界
循环徘徊是个很隐蔽的问题。表面上看,Agent 一直在输出分析文本,似乎很努力,实际上它并没有推进任何实质性动作。最常见的场景是:模型在 Deep Mode 里反复权衡要不要调整计划,每次输出都说“考虑到……需要进一步确认……”,然后又一次调用分析。
我给出的限制是:连续评估次数不允许超过两次,第三次必须输出动作指令。加这个硬边界之后,系统的整体任务完成率有了明显提升。这个经验也让我意识到,给语言模型的思考过程设置边界非常重要。
4.3 上下文爆炸:摘要不是偷懒,是必需品
在长任务里,原始数据的保留策略直接决定上下文的可用空间。我做摘要层的原则是:保结构、保关键值、舍细节。比如一段销售记录,摘要保留总行数、总金额、异常值数量、几个关键维度分组,而不是完整表格。只有 Deep Mode 需要输出对比分析时,才会按需拉取明细。
这套机制并不是为了压成本,而是为了给推理留出足够的有效空间。模型在上下文快满时的表现退化速度很快,远远早于硬编码的 token 上限。
4.4 单点失败的处理:局部重规划比全局重试有效
如果步骤 3 失败,是把规划清空重新生成,还是只在步骤 3 的位置做局部替代?我跳过全局重试方案,原因很简单:全局重放会把规划成本放大好几倍,而且生成的计划不一定比原来更好。
局部重规划的做法是:保留已完成步骤的结果和未执行步骤的清单,只针对失败节点做一次重新生成,尝试生成替代动作。同时给替代动作设定一个最大尝试次数,比如两次内仍失败就直接终止任务并汇报失败原因,避免在同一个节点永久重试。
5. 验证效果:一套可复用的评估口径
最后聊聊怎么评估任务规划与推理模式调优的效果。没有量化指标的调优都容易变成玄学,所以我建了一套相对简单的评估口径,供参考。
我准备了二十五个测试任务,覆盖四条类型:简单查询、多步数据整理、工具结果冲突消解、长链条流程。每个任务都记录三个指标:完成率、步骤冗余度、修正次数。
- 完成率:最终是否产出符合预设标准的输出
- 步骤冗余度:实际执行步骤数与最优参考步骤数的比值,越接近 1 越好
- 修正次数:执行过程中触发局部重规划或者 Deep Mode 二次判断的次数
完成率是最终目标,冗余度衡量规划效率,修正次数则能反映推理模式的敏感度。把这套指标跑了几轮之后,我明显看到几个变化:简单任务的冗余度降了下来,因为步骤数约束起了作用;带冲突场景的任务完成率提了上来,因为 Deep Mode 触发条件更合理;而长链条任务的修正次数集中在必要的节点上,而不是全流程里频繁修正。
这套评估口径不一定适合所有项目,但它给你提供了一个思路:不要只看“能不能完成”,还要看“完成得是否经济”“过程是否可控”。Agent 的能力不只体现在最终结果上,也体现在过程的质量上——这也是 Pi agent 这次重构给我最大的启发。
如果让我说一个最值得先动手做的小改动,我建议你先看自己的 Agent 有没有“无边界思考”的问题,给所有推理过程都加一个动作强制出口,效果往往立竿见影。