规划能力是AI Agent的核心竞争力。一个没有规划能力的Agent,只能执行简单的单步任务;而具备强大规划能力的Agent,才能分解复杂问题、处理多步骤工作流、应对意外情况。本文系统梳理Agent规划的主流方法,从理论到代码,帮助你构建真正智能的Agent系统。
为什么规划如此关键
让我们从一个反例开始。假设你的Agent收到任务:"分析我们公司过去三个月的销售数据,找出Top 10产品,并生成一份带图表的报告发给老板"。
一个没有规划能力的Agent会怎么做?它可能直接调用一个工具,发现无法一步完成,然后失败。
一个有规划能力的Agent会怎么做?它会:
- 识别出任务需要多步骤
- 分解为:获取数据→分析排名→生成图表→撰写报告→发送邮件
- 按顺序执行,中间处理可能的错误
- 最终成功完成
这就是规划的价值:将不可直接执行的复杂目标分解为可执行的子任务序列。
ReAct:最经典的规划范式
ReAct(Reason + Act)是目前使用最广泛的Agent规划范式,核心是将推理(Thought)和行动(Action)交替进行:
Thought: 我需要先查询数据库获取销售数据
Action: query_database(query="SELECT * FROM sales WHERE date > '2026-01-01'")
Observation: 返回了12,847条销售记录
Thought: 数据量很大,我需要先聚合再分析
Action: analyze_data(data=..., operation="sum_by_product")
Observation: 得到了各产品的总销售额
Thought: 现在可以找出Top 10了
Action: get_top_n(data=..., n=10, key="revenue")
Observation: 返回了Top 10产品列表
... 继续执行
ReAct的优势在于:每次行动前都有显式的推理步骤,使得过程可解释、可调试。
在LangChain中实现ReAct Agent:
from langchain.agents import create_react_agent, AgentExecutor
from langchain_openai import ChatOpenAI
from langchain.tools import Tool
from langchain import hub
# 获取ReAct提示模板
prompt = hub.pull("hwchase17/react")
# 定义工具
tools = [
Tool(
name="query_database",
func=query_database_fn,
description="查询数据库。输入SQL查询语句,返回查询结果。"
),
Tool(
name="create_chart",
func=create_chart_fn,
description="创建图表。输入数据和图表类型,返回图表文件路径。"
),
Tool(
name="send_email",
func=send_email_fn,
description="发送邮件。输入收件人、主题、正文,返回发送结果。"
),
]
llm = ChatOpenAI(model="gpt-4o", temperature=0)
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=15)
result = executor.invoke({"input": "分析Q1销售数据,找Top 10产品,生成报告发给boss@company.com"})
Plan-and-Execute:先规划再行动
ReAct的问题是规划和执行混在一起,遇到长任务时容易"迷失"——执行了几步后,Agent可能忘记了整体目标。
Plan-and-Execute(规划后执行)的思路是分离这两个阶段:
- 规划阶段:用LLM生成完整的执行计划(任务列表)
- 执行阶段:按顺序执行每个子任务,必要时可以重规划
from langchain_experimental.plan_and_execute import PlanAndExecute, load_agent_executor, load_chat_planner
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# 规划器:生成完整计划
planner = load_chat_planner(llm)
# 执行器:执行每个步骤
executor = load_agent_executor(llm, tools, verbose=True)
# 组合
agent = PlanAndExecute(planner=planner, executor=executor, verbose=True)
result = agent.invoke({"input": "你的复杂任务描述"})
规划阶段会生成如下输出:
计划:
1. 使用query_database工具查询2026年1-3月销售数据
2. 使用analyze_data工具计算各产品销售额
3. 使用sort_and_filter工具获取Top 10产品
4. 使用create_chart工具生成柱状图
5. 使用write_report工具生成分析报告
6. 使用send_email工具发送给指定收件人
这种方式在复杂多步任务中通常比纯ReAct更可靠。
Tree of Thoughts:用搜索解决规划难题
有些问题没有确定性的解决路径,需要探索多种可能性。Tree of Thoughts(ToT)将规划问题建模为树搜索:
- 每个节点是一个中间思考状态
- 从根节点出发,每步可以生成多个候选下一步
- 用评估器(Evaluator)对每个状态打分
- 使用BFS/DFS/Best-first等搜索策略探索
# ToT的简化实现
class TreeOfThoughts:
def __init__(self, llm, n_candidates=3, max_depth=5):
self.llm = llm
self.n_candidates = n_candidates # 每步生成的候选数
self.max_depth = max_depth
def generate_thoughts(self, state: str, problem: str) -> list[str]:
"""从当前状态生成多个候选下一步"""
prompt = f"""
问题: {problem}
当前状态: {state}
请生成{self.n_candidates}个不同的下一步思考方向,每个方向用===分隔:
"""
response = self.llm.invoke(prompt)
thoughts = response.content.split("===")
return [t.strip() for t in thoughts if t.strip()]
def evaluate_state(self, state: str, problem: str) -> float:
"""评估当前状态的质量(0-1)"""
prompt = f"""
问题: {problem}
当前状态: {state}
评估当前状态距离解决问题有多近,输出0-10的分数(只输出数字):
"""
response = self.llm.invoke(prompt)
try:
return float(response.content.strip()) / 10
except:
return 0.5
def solve(self, problem: str) -> str:
"""使用BFS搜索最佳解决路径"""
import heapq
# (负分数, 状态路径)
heap = [(0, [problem])]
while heap:
neg_score, path = heapq.heappop(heap)
current_state = path[-1]
if len(path) > self.max_depth:
continue
# 生成候选下一步
next_thoughts = self.generate_thoughts(current_state, problem)
for thought in next_thoughts:
new_state = current_state + "\n" + thought
score = self.evaluate_state(new_state, problem)
if score > 0.9: # 找到足够好的解
return "\n".join(path + [thought])
heapq.heappush(heap, (-score, path + [thought]))
return "未找到解决方案"
ToT特别适合需要回溯的场景,比如代码生成、数学推理、复杂规划问题。
反思与自我批评:让Agent学会纠错
Reflexion框架引入了"反思"机制:Agent执行失败后,不是简单重试,而是先反思失败原因,然后带着经验重试。
class ReflexionAgent:
def __init__(self, llm, max_trials=3):
self.llm = llm
self.max_trials = max_trials
self.memory = [] # 存储历次反思
def reflect(self, task: str, attempt: str, result: str) -> str:
"""对失败尝试进行反思"""
reflections_context = "\n".join(
[f"第{i+1}次反思: {r}" for i, r in enumerate(self.memory)]
)
prompt = f"""
任务: {task}
本次尝试: {attempt}
执行结果: {result}
历次反思: {reflections_context}
分析这次失败的根本原因,并给出下次应该如何改进(简洁、具体):
"""
reflection = self.llm.invoke(prompt).content
self.memory.append(reflection)
return reflection
def execute_with_reflection(self, task: str) -> str:
for trial in range(self.max_trials):
# 构建包含历次反思的提示
context = ""
if self.memory:
context = "历次尝试的教训:\n" + "\n".join(self.memory)
# 执行任务
result = self.execute_task(task, context)
# 判断是否成功
if self.is_success(result):
return result
# 失败则反思
reflection = self.reflect(task, context, result)
print(f"第{trial+1}次失败,反思: {reflection}")
return "达到最大重试次数,任务失败"
LangGraph中的状态机规划
对于需要复杂控制流的Agent,LangGraph提供了基于状态机的规划框架。你可以定义节点(处理逻辑)和边(转移条件),构建有明确控制流的Agent:
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator
class AgentState(TypedDict):
messages: Annotated[list, operator.add]
plan: list[str]
current_step: int
results: list[str]
def plan_node(state: AgentState) -> AgentState:
"""生成执行计划"""
task = state["messages"][-1].content
plan = generate_plan(task) # 调用LLM生成计划
return {"plan": plan, "current_step": 0}
def execute_node(state: AgentState) -> AgentState:
"""执行当前步骤"""
step = state["plan"][state["current_step"]]
result = execute_step(step) # 执行具体步骤
return {
"results": [result],
"current_step": state["current_step"] + 1
}
def should_continue(state: AgentState) -> str:
"""判断是否继续执行"""
if state["current_step"] >= len(state["plan"]):
return "finalize"
if "error" in state["results"][-1]:
return "handle_error"
return "execute"
# 构建图
workflow = StateGraph(AgentState)
workflow.add_node("plan", plan_node)
workflow.add_node("execute", execute_node)
workflow.add_node("handle_error", error_handling_node)
workflow.add_node("finalize", finalize_node)
workflow.set_entry_point("plan")
workflow.add_edge("plan", "execute")
workflow.add_conditional_edges("execute", should_continue, {
"execute": "execute",
"finalize": "finalize",
"handle_error": "handle_error",
})
workflow.add_edge("handle_error", "execute")
workflow.add_edge("finalize", END)
app = workflow.compile()
规划能力的工程实践建议
根据实际场景选择合适的规划方案:
简单工具调用(1-3步):直接用Function Calling,无需专门的规划框架。
中等复杂度(3-10步,路径确定):ReAct + 合理的工具设计,配合Plan-and-Execute。
高度复杂(>10步,路径不确定):LangGraph状态机 + Reflexion反思机制。
需要探索多种方案:Tree of Thoughts + 评估器。
几个通用原则:
-
工具粒度要合适:工具太粗(做太多事)会让规划失去意义;工具太细(如只能逐字读取文件)会增加规划复杂度。
-
给规划提供足够上下文:在系统提示中明确说明可用工具、各工具的适用场景和限制。
-
设置合理的重试上限:ReAct Agent如果陷入循环,max_iterations是最后的安全网。
-
记录中间状态:使用LangSmith或类似工具追踪每次推理步骤,便于调试。
-
规划质量评估:建立评估集,定期测试Agent在标准任务上的完成率,及时发现回退。
规划能力的提升是一个持续迭代的过程。从最简单的ReAct开始,根据实际问题逐步引入更复杂的规划机制,才是工程上的正确路径。