
把单轮对话升级成规划型智能体,很多团队的做法是给模型加一句“先制定计划再执行”,然后接上工具循环。系统跑起来了,模型也确实输出了带编号的步骤,但很快暴露出一个根本问题:它“看起来”在规划,实际上只是在把每一步的即时反应包装成计划的形式。真正的规划能力不是提示词能赋予的,它要求系统在架构上回答三个问题:什么时候值得规划、计划执行到一半发现错了怎么办、以及怎么判定任务已经完成。这三个问题不解决,规划型智能体只是一个更慢、更贵、更难调试的单轮对话。
规划本身有成本:一次计划生成至少多一轮大模型调用,计划校验、步骤分解、每步执行后的状态确认都会增加延迟和 token 消耗。把一个“现在几点”送进规划器,是架构层面的浪费。更隐蔽的问题是,规划器面对过于简单或过于模糊的任务时,会生成形式正确但内容空洞的计划——三步“分析需求、执行处理、总结结果”,每一步都不可执行,但看起来像一个完整的规划。
工程上的第一道门槛是在入口处做任务分级,只有真正需要多步推理的请求才进入规划路径:
from enum import Enum
class Route(str, Enum):
DIRECT = "direct" # 单轮对话,直接回答
TOOL = "tool" # 单工具调用
PLAN = "plan" # 需要多步规划
def classify(query: str, history: list) -> dict:
signals = {
"multi_target": sum(q in query for q in ("然后", "接着", "同时", "分别")) >= 1,
"conditional": any(k in query for k in ("如果", "当", "除非")),
"long_horizon": len(history) >= 4 and "继续" in query,
"explicit_plan": any(k in query for k in ("步骤", "计划", "方案")),
}
score = sum(signals.values())
if score >= 2 or signals["explicit_plan"]:
return {"route": Route.PLAN, "signals": signals,
"max_steps": 8, "budget_tokens": 6000}
if signals["conditional"] or signals["multi_target"]:
return {"route": Route.TOOL, "signals": signals,
"max_steps": 3, "budget_tokens": 2000}
return {"route": Route.DIRECT, "signals": signals,
"max_steps": 1, "budget_tokens": 1000}max_steps 和 budget_tokens 随路由一起下发,而不是在规划器内部临时决定。这意味着路由层同时决定了“要不要规划”和“给规划多少空间”。signals 被完整返回,让分级决策可以被审计——当某个请求被错误地送进规划路径时,日志里能直接看到是哪几个信号触发的。
规划型智能体最常见的失控方式是计划一旦生成就变成了只读的脚本。执行器按步骤往下走,某一步返回的结果与计划假设矛盾——比如计划假设“先查库存再下单”,但查库存返回“缺货”——执行器不会主动停下来,它会继续执行下一步,因为计划里写了下一步是“下单”。这个行为不会报错,只会产生一个基于错误前提的订单。
正确的架构是在每个步骤执行之后引入重新规划检查点:评估当前结果是否使后续计划失效,失效则触发局部重规划而不是继续执行:
def execute_plan(plan: list[dict], executor, replanner,
max_replans: int = 2) -> dict:
state, done, replans = {}, [], 0
while len(done) < len(plan):
step = next(s for s in plan if s["id"] not in done)
result = executor(step["tool"], step["args"], state)
state[step["id"]] = result
if not result.get("ok"):
return {"status": "failed", "step": step["id"],
"error": result.get("error")}
remaining = [s for s in plan if s["id"] not in done
and s["id"] != step["id"]]
verdict = replanner(step, result, remaining)
if verdict["action"] == "replan":
if replans >= max_replans:
return {"status": "replan_exhausted", "step": step["id"]}
plan = verdict["new_plan"]
done, replans = done + [step["id"]], replans + 1
elif verdict["action"] == "abort":
return {"status": "aborted", "reason": verdict["reason"]}
else:
done.append(step["id"])
return {"status": "completed", "state": state}replanner 的返回值必须是结构化的 action,而不是一段自然语言建议。max_replans 的存在防止重规划本身变成死循环——一个持续推翻计划的智能体和一个持续重试工具的智能体是同一种失败。state 按步骤 ID 累积,让重规划器能看到“已经确认了哪些事实”,而不是从零开始推断。
规划型智能体最危险的状态是它声称完成了,但实际上只是走到了计划的最后一步。计划里写了三步,执行器走完三步,模型输出“任务已完成”——这不是完成,这是循环退出。真正的完成判定应该基于计划中每个步骤的验收条件是否满足,而不是基于步数是否耗尽。
这要求计划在生成时就为每一步附带可检查的验收条件,而不是只在最后加一句“确认结果正确”:
def verify_completion(plan: list[dict], state: dict) -> dict:
unmet = []
for step in plan:
for cond in step.get("acceptance", []):
field, op, expected = cond["field"], cond["op"], cond["value"]
actual = state.get(step["id"], {}).get(field)
ok = {"eq": actual == expected,
"gte": isinstance(actual, (int, float)) and actual >= expected,
"exists": actual is not None}.get(op, False)
if not ok:
unmet.append({"step": step["id"], "field": field,
"expected": expected, "actual": actual})
return {"complete": not unmet, "unmet": unmet,
"checked": sum(len(s.get("acceptance", [])) for s in plan)}acceptance 的每一条是 (field, op, value) 三元组,这意味着验收条件是可被程序执行的断言,而不是一句“确保结果正确”。“确保结果正确”只能由模型自己判断,而模型对自己刚执行完的操作有天然的确认偏误。unmet 列表返回具体的偏差,让上层能决定是重试某一步、触发重规划,还是带着明确的未完成状态返回给用户。
从单轮对话到规划型智能体,真正的工程增量不在“加一个规划提示词”,而在三个约束的同时建立:入口分级决定值不值得规划,否则简单请求被过度工程化、复杂请求又被仓促处理;执行中重新规划决定计划错了怎么办,否则计划一旦生成就变成不可推翻的脚本;结构化验收决定怎么算完成,否则“走完步数”会被误认为“完成任务”。这三件事分别对应规划的准入、修正和退出——缺任何一个,智能体都会以一种看起来很忙碌的方式,走向一个没有被验证的终点。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。