规划:Agent的核心能力

AI Agent与聊天机器人的本质区别在于规划能力——将复杂目标分解为可执行步骤并动态调整的能力。从简单的ReAct循环到复杂的树搜索规划,Agent规划算法经历了快速演进。

ReAct:推理与行动的交错

基本循环

ReAct(Reasoning + Acting)是Agent规划的基石,核心思想是交错推理和行动:

Thought: 用户要查北京天气,我需要调用天气API
Action: search_weather(city="北京")
Observation: 北京今天晴,25°C
Thought: 获取到天气信息,可以回答用户了
Answer: 北京今天天气晴朗,气温25°C,适合外出活动。

实现细节

class ReActAgent:
    def __init__(self, llm, tools, max_steps=10):
        self.llm = llm
        self.tools = tools
        self.max_steps = max_steps
    
    def run(self, task):
        trajectory = []
        for step in range(self.max_steps):
            # 生成下一步思考和行为
            prompt = self._build_prompt(task, trajectory)
            response = self.llm.generate(prompt)
            
            thought, action = self._parse(response)
            trajectory.append({"thought": thought, "action": action})
            
            if action["type"] == "finish":
                return action["answer"]
            
            # 执行工具
            if action["type"] == "tool":
                result = self.tools[action["name"]](**action["params"])
                trajectory.append({"observation": result})
        
        return "达到最大步数限制"
    
    def _build_prompt(self, task, trajectory):
        prompt = f"""任务:{task}

可用工具:{list(self.tools.keys())}

历史:
"""
        for item in trajectory:
            if "thought" in item:
                prompt += f"Thought: {item['thought']}\n"
                prompt += f"Action: {item['action']}\n"
            elif "observation" in item:
                prompt += f"Observation: {item['observation']}\n"
        
        prompt += "Thought:"
        return prompt

ReAct的局限

  • 无记忆反馈:失败的经验不会影响后续尝试
  • 线性思维:无法回溯到之前的选择点尝试其他路径
  • 容易陷入循环:在复杂任务中反复尝试相同的失败方案

Reflexion:从失败中学习

核心改进

Reflexion在ReAct基础上增加了自我反思机制。当任务执行失败时,Agent会生成反思并存储到长期记忆中:

class ReflexionAgent(ReActAgent):
    def __init__(self, llm, tools, max_steps=10, max_trials=3):
        super().__init__(llm, tools, max_steps)
        self.max_trials = max_trials
        self.reflections = []
    
    def run(self, task):
        for trial in range(self.max_trials):
            result = super().run(task)
            
            if self._is_success(result):
                return result
            
            # 生成反思
            reflection = self._reflect(task, self.trajectory, result)
            self.reflections.append(reflection)
            
            # 带着反思重新尝试
            task_context = f"""
            任务:{task}
            
            过去的尝试和反思:
            {self.reflections[-1]}
            
            避免重复之前的错误。
            """
            task = task_context
        
        return result
    
    def _reflect(self, task, trajectory, result):
        prompt = f"""分析以下失败的执行过程,总结经验教训:

任务:{task}
执行过程:{trajectory}
结果:{result}(失败)

请反思:
1. 哪一步出了问题?
2. 为什么会出错?
3. 下次应该怎么避免?
"""
        return self.llm.generate(prompt)

反思的效果

在HotpotQA多跳推理任务上:

  • ReAct:成功率48%
  • Reflexion(3次尝试):成功率65%
  • 反思带来的提升:+17%

LATS:树搜索规划

核心思想

Language Agent Tree Search(LATS)将Agent规划建模为蒙特卡洛树搜索(MCTS):

                    根节点(初始状态)
                   /        |        \
            子节点A      子节点B      子节点C
           /    \         |          |
        A1     A2        B1         C1
        |
        A11

实现架构

class LATSAgent:
    def __init__(self, llm, tools, n_expansions=5, depth_limit=5):
        self.llm = llm
        self.tools = tools
        self.n_expansions = n_expansions
        self.depth_limit = depth_limit
    
    def run(self, task):
        root = StateNode(task=task, state=None, parent=None)
        
        for _ in range(self.depth_limit):
            # 1. 选择:UCB选择最有前景的节点
            node = self._select(root)
            
            # 2. 扩展:生成可能的行动
            children = self._expand(node)
            
            # 3. 评估:用LLM评估每个子节点的价值
            for child in children:
                child.value = self._evaluate(child)
            
            # 4. 模拟:快速估算该路径的最终收益
            for child in children:
                child.reward = self._simulate(child)
            
            # 5. 回溯:更新路径上所有节点的值
            self._backpropagate(children)
            
            # 检查是否找到解
            best = max(children, key=lambda c: c.value)
            if best.is_terminal and best.is_success:
                return self._extract_path(best)
        
        # 返回最优路径
        return self._extract_best_path(root)
    
    def _expand(self, node):
        """生成多个可能的下一步行动"""
        prompt = f"""当前状态:{node.state}
任务:{node.task}
历史:{node.get_path()}

生成{self.n_expansions}个不同的下一步行动方案:
"""
        responses = self.llm.generate_multiple(prompt, n=self.n_expansions)
        return [StateNode(
            task=node.task,
            state=self._execute(r),
            parent=node,
            action=r
        ) for r in responses]
    
    def _evaluate(self, node):
        """用LLM评估节点价值"""
        prompt = f"""评估当前状态距离完成任务的距离:
任务:{node.task}
当前状态:{node.state}
已完成步骤:{node.get_path()}

评分(0-10):"""
        return float(self.llm.generate(prompt))

LATS的优势

在复杂推理任务上,LATS显著优于ReAct和Reflexion:

方法HotpotQAALFWorldWebShop
ReAct48%65%55%
Reflexion65%75%62%
LATS72%82%70%

代价是计算开销大——每个决策点需要多次LLM调用。

Plan-and-Execute:先规划后执行

分离规划与执行

与前述方法的交错式规划不同,Plan-and-Execute先生成完整计划再执行:

class PlanExecuteAgent:
    def __init__(self, planner, executor):
        self.planner = planner
        self.executor = executor
    
    def run(self, task):
        # 1. 生成初始计划
        plan = self.planner.generate_plan(task)
        
        while not plan.is_complete():
            # 2. 执行下一步
            step = plan.current_step()
            result = self.executor.execute(step)
            
            # 3. 评估是否需要重新规划
            if self._needs_replan(task, plan, result):
                plan = self.planner.replan(task, plan, result)
            else:
                plan.advance()
        
        return plan.get_final_result()

动态重规划

def needs_replan(self, task, plan, result):
    # 检测执行结果是否与预期不符
    if not result.success:
        return True
    if result.side_effects:
        return True
    # 检测剩余步骤是否仍然可行
    remaining = plan.remaining_steps()
    feasibility = self.llm.evaluate(
        f"给定当前状态{result.state},以下步骤是否可行:{remaining}"
    )
    return not feasibility

规划能力的评估

规划质量评估框架

class PlanningEvaluator:
    def evaluate(self, task, plan, execution_result):
        return {
            "completeness": self._completeness(task, plan),
            # 计划是否覆盖了任务的所有方面
            "correctness": self._correctness(plan),
            # 计划的逻辑是否正确
            "efficiency": self._efficiency(plan, execution_result),
            # 是否存在冗余或可合并的步骤
            "adaptability": self._adaptability(plan, execution_result),
            # 遇到意外时的调整能力
            "granularity": self._granularity(task, plan),
            # 步骤粒度是否合适——太粗无法执行,太细浪费时间
        }

实践建议

选择规划方法的决策树

任务步骤 < 5?
  → ReAct(简单高效)

任务步骤 5-15?
  → Plan-and-Execute(先规划再执行)

任务步骤 > 15 或有多条可能路径?
  → LATS(树搜索)

任务需要多轮尝试?
  → Reflexion(从失败中学习)

结语

规划能力是Agent从"工具使用者"到"问题解决者"的关键跃升。当前最好的Agent在简单任务上已接近人类水平,但在需要深度推理和创造性规划的任务上仍有差距。随着推理时计算扩展技术的发展——特别是类似o1的隐式推理能力——Agent的规划能力将迎来下一个突破。