AI Agent规划能力深度解析:从ReAct到Tree of Thoughts的工程实践

3 阅读1分钟

规划能力是AI Agent的核心竞争力。一个没有规划能力的Agent,只能执行简单的单步任务;而具备强大规划能力的Agent,才能分解复杂问题、处理多步骤工作流、应对意外情况。本文系统梳理Agent规划的主流方法,从理论到代码,帮助你构建真正智能的Agent系统。

为什么规划如此关键

让我们从一个反例开始。假设你的Agent收到任务:"分析我们公司过去三个月的销售数据,找出Top 10产品,并生成一份带图表的报告发给老板"。

一个没有规划能力的Agent会怎么做?它可能直接调用一个工具,发现无法一步完成,然后失败。

一个有规划能力的Agent会怎么做?它会:

  1. 识别出任务需要多步骤
  2. 分解为:获取数据→分析排名→生成图表→撰写报告→发送邮件
  3. 按顺序执行,中间处理可能的错误
  4. 最终成功完成

这就是规划的价值:将不可直接执行的复杂目标分解为可执行的子任务序列

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 10Action: 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(规划后执行)的思路是分离这两个阶段:

  1. 规划阶段:用LLM生成完整的执行计划(任务列表)
  2. 执行阶段:按顺序执行每个子任务,必要时可以重规划
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 + 评估器。

几个通用原则

  1. 工具粒度要合适:工具太粗(做太多事)会让规划失去意义;工具太细(如只能逐字读取文件)会增加规划复杂度。

  2. 给规划提供足够上下文:在系统提示中明确说明可用工具、各工具的适用场景和限制。

  3. 设置合理的重试上限:ReAct Agent如果陷入循环,max_iterations是最后的安全网。

  4. 记录中间状态:使用LangSmith或类似工具追踪每次推理步骤,便于调试。

  5. 规划质量评估:建立评估集,定期测试Agent在标准任务上的完成率,及时发现回退。

规划能力的提升是一个持续迭代的过程。从最简单的ReAct开始,根据实际问题逐步引入更复杂的规划机制,才是工程上的正确路径。