先放结论:自主规划不是"让模型随便发挥",而是给 Agent 一套"目标→拆解→执行→反馈→重规划"的闭环机制。 没有这个闭环,Agent 就是个只会按固定流程跑的机器人;有了这个闭环,它才像个有经验的项目负责人——你只给目标,它自己搞定过程。
为什么硬编码流程不够用
回顾前几篇,我们写的 Agent 基本都是这个结构:
const workflow = new StateGraph<AgentState>()
.addNode('step1', step1)
.addNode('step2', step2)
.addNode('step3', step3)
.addEdge('__start__', 'step1')
.addEdge('step1', 'step2')
.addEdge('step2', 'step3')
.addEdge('step3', END);
流程是固定的:step1 → step2 → step3。如果 step1 失败了怎么办?如果 step2 发现需要额外步骤怎么办?如果用户的目标变了怎么办?硬编码流程回答不了这些问题。
硬编码流程的四个瓶颈:
- 无法应对变化:执行过程中环境变了(比如场地订不到、API 挂了),流程不会自动调整
- 无法处理未知:遇到预设流程之外的情况,Agent 直接卡死
- 无法优化路径:明明可以并行执行的任务,硬编码只能串行
- 无法从错误中学习:同样的错误会重复犯,因为没有"反思"机制
自主规划的本质:把"流程"从代码里抽出来,变成 Agent 运行时动态生成的"计划"。计划不是一次性写死的清单,而是一个可维护、可修正、可重规划的动态结构。
自主规划的闭环:感知→规划→执行→反馈→重规划
一个能自主规划的 Agent,核心是这五个环节的闭环:
┌─────────────────────────────────────────────┐
│ 目标输入 │
│ "帮我安排一次本周末从北京出发的两天一夜 │
│ 家庭旅行,预算 2000 元,适合带 5 岁小孩" │
└──────────────────┬──────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ ① 感知:理解目标 + 感知环境 │
│ - 解析约束:预算 2000、两天一夜、带小孩 │
│ - 感知资源:可用工具(天气、酒店、机票API) │
│ - 感知限制:周末、北京出发 │
└──────────────────┬──────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ ② 规划:拆解任务 + 生成执行路径 │
│ - 子任务1:查询北京周边适合亲子游的目的地 │
│ - 子任务2:查询目的地周末天气 │
│ - 子任务3:筛选预算内的酒店 │
│ - 子任务4:查询往返交通方案 │
│ - 子任务5:生成行程单 │
└──────────────────┬──────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ ③ 执行:调用工具 + 执行子任务 │
│ - 调用天气 API → 发现目的地 A 周末下雨 │
│ - 调用酒店 API → 发现目的地 B 酒店满房 │
└──────────────────┬──────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ ④ 反馈:检查结果 + 识别问题 │
│ - 问题1:目的地 A 天气不好,不适合出行 │
│ - 问题2:目的地 B 酒店满房,需要换目的地 │
└──────────────────┬──────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ ⑤ 重规划:调整计划 + 继续执行 │
│ - 重新筛选目的地(排除 A,换其他备选) │
│ - 重新查询酒店和交通 │
│ - 生成新的行程单 │
└─────────────────────────────────────────────┘
关键区别:硬编码流程里,"目的地 A 下雨"这个情况不在预设分支里,Agent 直接报错;自主规划里,Agent 感知到反馈后,自己调整计划,换目的地继续执行。
五种主流规划范式
自主规划不是单一技术,而是一组方法的集合。以下是五种主流范式,各有适用场景:
1. ReAct(Reasoning + Acting)
核心思想:推理和行动交替进行,每执行一步就观察结果,再决定下一步。
思考:用户想查天气,我需要调用天气工具
行动:调用 weather_api(city="北京")
观察:{"temperature": 25, "condition": "晴"}
思考:天气信息已获取,可以回答用户了
行动:返回结果
优点:简单直接,适合短流程、交互式任务。 缺点:缺乏全局视角,容易"走一步看一步",长任务容易跑偏。
LangChain 实现:
import { createReactAgent } from '@langchain/langgraph/prebuilt';
import { ChatOpenAI } from '@langchain/openai';
import { TavilySearchResults } from '@langchain/community/tools/tavily_search';
const model = new ChatOpenAI({ model: 'gpt-4o' });
const tools = [new TavilySearchResults({ maxResults: 3 })];
// ReAct Agent 自动处理 思考→行动→观察 循环
const agent = createReactAgent({
llm: model,
tools,
});
const result = await agent.invoke({
messages: [{ role: 'user', content: '帮我查一下北京今天的天气,并推荐一个适合户外活动的公园' }],
});
2. Plan-and-Execute(规划-执行)
核心思想:先一次性生成完整计划(DAG 或步骤清单),再逐步执行。
第一步:生成计划
LLM 输出:["查询天气", "搜索公园", "评估公园 suitability", "生成推荐"]
第二步:按顺序执行
执行 step 1 → 执行 step 2 → 执行 step 3 → 执行 step 4
优点:有全局视野,适合流程相对固定的场景。 缺点:初始规划如果错了,后续全错;需要配合动态修正机制。
LangGraph 实现:
import { StateGraph, END } from '@langgraph/graph';
import { ChatOpenAI } from '@langchain/openai';
interface PlanState {
goal: string;
plan: string[];
currentStep: number;
results: Record<string, any>;
finalAnswer: string;
}
const model = new ChatOpenAI({ model: 'gpt-4o' });
// 规划节点:生成完整计划
async function planner(state: PlanState): Promise<Partial<PlanState>> {
const prompt = `用户目标:${state.goal}
请将这个目标拆解为可执行的步骤列表,每步一个动作。
输出 JSON 数组格式:["步骤1", "步骤2", ...]`;
const result = await model.invoke(prompt);
const plan = JSON.parse(result.content);
return { plan, currentStep: 0 };
}
// 执行节点:执行当前步骤
async function executor(state: PlanState): Promise<Partial<PlanState>> {
const currentTask = state.plan[state.currentStep];
// 根据任务调用相应工具...
const toolResult = await executeTask(currentTask);
return {
results: { ...state.results, [state.currentStep]: toolResult },
currentStep: state.currentStep + 1,
};
}
// 判断是否完成
function shouldContinue(state: PlanState): string {
return state.currentStep < state.plan.length ? 'executor' : 'finalizer';
}
// 汇总节点:生成最终答案
async function finalizer(state: PlanState): Promise<Partial<PlanState>> {
const prompt = `基于以下执行结果,生成最终回答:\n${JSON.stringify(state.results)}`;
const result = await model.invoke(prompt);
return { finalAnswer: result.content };
}
const workflow = new StateGraph<PlanState>()
.addNode('planner', planner)
.addNode('executor', executor)
.addNode('finalizer', finalizer)
.addEdge('__start__', 'planner')
.addEdge('planner', 'executor')
.addConditionalEdges('executor', shouldContinue)
.addEdge('finalizer', END);
const app = workflow.compile();
3. Tree of Thoughts(思维树)
核心思想:同时探索多条可行路径,评估每条路径的价值,择优或回溯。
目标:解决一个复杂数学问题
路径A:用代数方法 → 评估:可行,但计算量大
路径B:用几何方法 → 评估:简洁,但需要画图
路径C:用数值方法 → 评估:快速,但精度有限
选择路径B → 继续深入探索
优点:适合高难度决策、复杂推理场景。 缺点:Token 消耗大,成本高。
4. 分层规划(Hierarchical Planning)
核心思想:高层 Agent 负责宏观目标拆分,底层 Agent 负责原子子任务执行。
Level 1(战略层):目标"完成市场调研报告"
↓ 拆分为
Level 2(战术层):["竞品分析", "用户调研", "趋势分析"]
↓ 每个子任务再拆分为
Level 3(执行层):["搜索竞品A信息", "搜索竞品B信息", ...]
优点:适合大型复杂项目,是工业级落地首选方案。 缺点:架构复杂,调试困难。
5. 反思与重规划(Reflection & Replanning)
核心思想:执行过程中持续评估计划是否还成立,不成立就重新规划。
初始计划:["订场地A", "发邀请", "准备物料"]
执行中:场地A 被订走了
反思:原计划不可行,需要重规划
新计划:["订场地B", "更新邀请中的地址", "准备物料"]
关键机制:
- 计划校验层:检测循环依赖、逻辑冲突
- 任务状态机:记录待执行/执行中/成功/失败状态
- 增量式调整:只修改受影响的步骤,不是全盘推翻
工程实践:用 LangGraph 实现自主规划 Agent
下面是一个完整的自主规划 Agent 案例,结合了 Plan-and-Execute + 反思重规划:
import { StateGraph, END } from '@langgraph/graph';
import { ChatOpenAI } from '@langchain/openai';
import { TavilySearchResults } from '@langchain/community/tools/tavily_search';
// 定义状态
interface AutoPlanState {
goal: string; // 用户目标
plan: string[]; // 当前计划
stepResults: Record<number, any>; // 每步执行结果
currentStep: number; // 当前执行到哪一步
reflection: string; // 反思结果
maxSteps: number; // 最大步数(防死循环)
finalAnswer: string;
}
const model = new ChatOpenAI({ model: 'gpt-4o' });
const searchTool = new TavilySearchResults({ maxResults: 3 });
// ① 规划节点:根据目标生成计划
async function planner(state: AutoPlanState): Promise<Partial<AutoPlanState>> {
const prompt = `你是一个任务规划专家。用户目标:${state.goal}
请将目标拆解为可执行的步骤列表。每个步骤应该:
1. 具体、可操作
2. 有明确的完成标准
3. 步骤之间逻辑连贯
输出 JSON 数组格式,例如:["步骤1", "步骤2", "步骤3"]`;
const result = await model.invoke(prompt);
const plan = JSON.parse(result.content);
console.log(' 生成计划:', plan);
return { plan, currentStep: 0, maxSteps: plan.length + 3 };
}
// ② 执行节点:执行当前步骤
async function executor(state: AutoPlanState): Promise<Partial<AutoPlanState>> {
const currentTask = state.plan[state.currentStep];
console.log(` 执行步骤 ${state.currentStep + 1}/${state.plan.length}: ${currentTask}`);
// 调用搜索工具(实际项目中根据任务类型选择不同工具)
const toolResult = await searchTool.invoke({ query: currentTask });
return {
stepResults: { ...state.stepResults, [state.currentStep]: toolResult },
currentStep: state.currentStep + 1,
};
}
// ③ 反思节点:评估执行结果,决定是否需要重规划
async function reflector(state: AutoPlanState): Promise<Partial<AutoPlanState>> {
const currentResult = state.stepResults[state.currentStep - 1];
const prompt = `你是任务执行的质检员。
当前目标:${state.goal}
当前步骤:${state.plan[state.currentStep - 1]}
执行结果:${JSON.stringify(currentResult)}
已完成步骤:${state.currentStep}/${state.plan.length}
请评估:
1. 当前步骤是否成功完成?
2. 原计划是否仍然可行?
3. 是否需要调整后续步骤?
输出 JSON 格式:{"success": true/false, "needReplan": true/false, "reason": "原因"}`;
const result = await model.invoke(prompt);
const reflection = JSON.parse(result.content);
console.log(' 反思结果:', reflection);
return { reflection: JSON.stringify(reflection) };
}
// ④ 重规划节点:根据反思结果调整计划
async function replanner(state: AutoPlanState): Promise<Partial<AutoPlanState>> {
const prompt = `你是任务规划专家。原计划执行中遇到问题,需要调整。
用户目标:${state.goal}
原计划:${JSON.stringify(state.plan)}
已执行到第 ${state.currentStep} 步
执行结果:${JSON.stringify(state.stepResults)}
反思结果:${state.reflection}
请基于当前情况,生成新的计划(可以修改后续步骤,也可以增加新步骤)。
输出 JSON 数组格式。`;
const result = await model.invoke(prompt);
const newPlan = JSON.parse(result.content);
console.log(' 重规划:', newPlan);
return { plan: newPlan };
}
// ⑤ 汇总节点:生成最终答案
async function finalizer(state: AutoPlanState): Promise<Partial<AutoPlanState>> {
const prompt = `你是任务执行主管。基于以下执行结果,生成最终回答。
用户目标:${state.goal}
执行结果:${JSON.stringify(state.stepResults)}`;
const result = await model.invoke(prompt);
return { finalAnswer: result.content };
}
// 条件路由:决定下一步去哪
function routeAfterExecute(state: AutoPlanState): string {
// 超过最大步数,强制结束
if (state.currentStep >= state.maxSteps) {
return 'finalizer';
}
// 所有步骤执行完毕,进入汇总
if (state.currentStep >= state.plan.length) {
return 'finalizer';
}
// 否则进入反思
return 'reflector';
}
function routeAfterReflect(state: AutoPlanState): string {
const reflection = JSON.parse(state.reflection);
if (reflection.needReplan) {
return 'replanner';
}
return 'executor';
}
function routeAfterReplan(state: AutoPlanState): string {
return 'executor';
}
// 构建工作流
const workflow = new StateGraph<AutoPlanState>()
.addNode('planner', planner)
.addNode('executor', executor)
.addNode('reflector', reflector)
.addNode('replanner', replanner)
.addNode('finalizer', finalizer)
.addEdge('__start__', 'planner')
.addEdge('planner', 'executor')
.addConditionalEdges('executor', routeAfterExecute)
.addConditionalEdges('reflector', routeAfterReflect)
.addConditionalEdges('replanner', routeAfterReplan)
.addEdge('finalizer', END);
const app = workflow.compile();
// 使用
const result = await app.invoke({
goal: '帮我调研一下 2026 年 AI Agent 领域的最新趋势,并总结三个关键方向',
});
console.log(' 最终答案:', result.finalAnswer);
关键点:
- 规划→执行→反思→重规划 形成闭环,Agent 能根据执行结果动态调整
- maxSteps 防死循环:设置最大步数,防止 Agent 陷入无限重规划
- 条件路由:根据反思结果决定是继续执行、重规划还是结束
- 结构化输出:强制 LLM 输出 JSON,便于程序解析和状态管理
自主规划的三个工程坑
1. 计划漂移
Agent 在执行过程中逐渐偏离原始目标,最后做的事和用户需求没关系了。
对策:
- 每执行 N 步后,让 Agent 回顾原始目标,确认当前方向是否正确
- 在 State 中保留原始 goal,每次规划时都带上
- 设置"目标一致性检查"节点
2. 无限重规划
Agent 不断重规划但始终无法推进,陷入死循环。
对策:
- 设置最大重规划次数(如 3 次),超过后强制结束或人工介入
- 记录重规划历史,检测是否在同一问题上反复打转
- 重规划时必须说明"为什么原计划不行",防止无意义调整
3. Token 爆炸
自主规划需要多次 LLM 调用(规划、执行、反思、重规划),Token 消耗远高于硬编码流程。
对策:
- 用轻量模型做规划和反思(如 gpt-4o-mini),重模型只做最终汇总
- 压缩上下文:只保留关键信息,丢弃中间冗余
- 缓存历史计划:相似目标直接复用历史计划,跳过规划阶段
硬编码流程 vs 自主规划:怎么选
| 维度 | 硬编码流程 | 自主规划 |
|---|---|---|
| 适用场景 | 步骤稳定、规则明确、可穷举 | 路径不可预知、环境动态变化 |
| 开发成本 | 低,流程写死即可 | 高,需要设计规划/反思/重规划机制 |
| 可预测性 | 高,行为确定 | 低,每次执行路径可能不同 |
| 灵活性 | 低,变化需改代码 | 高,自动适应变化 |
| Token 成本 | 低 | 高(多次 LLM 调用) |
| 调试难度 | 低,流程固定 | 高,需要全链路追踪 |
| 容错性 | 低,异常需预设分支 | 高,自动重试/重规划 |
决策原则:
- 能用硬编码就用硬编码:如果任务流程稳定、可穷举,硬编码更可靠、成本更低
- 不确定性高才上自主规划:如果任务路径无法提前确定、环境动态变化,自主规划才有价值
- 混合架构最实用:核心流程硬编码(保证稳定性),异常处理和边界情况交给自主规划(保证灵活性)
小结
- 自主规划的本质:给 Agent 一套"目标→拆解→执行→反馈→重规划"的闭环机制,而不是硬编码流程
- 五种规划范式:ReAct(交替推理行动)、Plan-and-Execute(先规划后执行)、Tree of Thoughts(多路径探索)、分层规划(宏观→微观)、反思重规划(动态调整)
- 三个工程坑:计划漂移、无限重规划、Token 爆炸
- 选型原则:能用硬编码就用硬编码,不确定性高才上自主规划,混合架构最实用
- 核心代码模式:规划节点 → 执行节点 → 反思节点 → 条件路由 → 重规划/汇总