Plan-and-Solve

在我们掌握了 ReAct 这种反应式的、步进决策的智能体范式后,接下来将探讨一种风格迥异但同样强大的方法,Plan-and-Solve。顾名思义,这种范式将任务处理明确地分为两个阶段:先规划 (Plan),后执行 (Solve)

如果说 ReAct 像一个经验丰富的侦探,根据现场的蛛丝马迹(Observation)一步步推理,随时调整自己的调查方向;那么 Plan-and-Solve 则更像一位建筑师,在动工之前必须先绘制出完整的蓝图(Plan),然后严格按照蓝图来施工(Solve)。事实上我们现在用的很多大模型工具的Agent模式都融入了这种设计模式。

4.3.1 Plan-and-Solve 的工作原理

Plan-and-Solve Prompting 由 Lei Wang 在2023年提出[2]。其核心动机是为了解决思维链在处理多步骤、复杂问题时容易“偏离轨道”的问题。

与 ReAct 将思考和行动融合在每一步不同,Plan-and-Solve 将整个流程解耦为两个核心阶段,如图4.2所示:

  1. 规划阶段 (Planning Phase): 首先,智能体会接收用户的完整问题。它的第一个任务不是直接去解决问题或调用工具,而是将问题分解,并制定出一个清晰、分步骤的行动计划。这个计划本身就是一次大语言模型的调用产物。
  2. 执行阶段 (Solving Phase): 在获得完整的计划后,智能体进入执行阶段。它会严格按照计划中的步骤,逐一执行。每一步的执行都可能是一次独立的 LLM 调用,或者是对上一步结果的加工处理,直到计划中的所有步骤都完成,最终得出答案。
import os
import ast
from agent_client import HelloAgentsLLM
from dotenv import load_dotenv
from typing import List, Dict

# 加载 .env 文件中的环境变量,处理文件不存在异常
try:
    load_dotenv()
except FileNotFoundError:
    print("警告:未找到 .env 文件,将使用系统环境变量。")
except Exception as e:
    print(f"警告:加载 .env 文件时出错: {e}")

# --- 1. LLM客户端定义 ---
# 假设你已经有llm_client.py文件,里面定义了HelloAgentsLLM类

# --- 2. 规划器 (Planner) 定义 ---
PLANNER_PROMPT_TEMPLATE = """
你是一个顶级的AI规划专家。你的任务是将用户提出的复杂问题分解成一个由多个简单步骤组成的行动计划。
请确保计划中的每个步骤都是一个独立的、可执行的子任务,并且严格按照逻辑顺序排列。
你的输出必须是一个Python列表,其中每个元素都是一个描述子任务的字符串。

问题: {question}

请严格按照以下格式输出你的计划,```python与```作为前后缀是必要的:
```python
["步骤1", "步骤2", "步骤3", ...]
```
"""

class Planner:
    def __init__(self, llm_client: HelloAgentsLLM):
        self.llm_client = llm_client

    def plan(self, question: str) -> list[str]:
        prompt = PLANNER_PROMPT_TEMPLATE.format(question=question)
        messages = [{"role": "user", "content": prompt}]
        
        print("--- 正在生成计划 ---")
        response_text = self.llm_client.think(messages=messages) or ""
        print(f"✅ 计划已生成:\n{response_text}")
        
        try:
            plan_str = response_text.split("```python")[1].split("```")[0].strip()
            plan = ast.literal_eval(plan_str)
            return plan if isinstance(plan, list) else []
        except (ValueError, SyntaxError, IndexError) as e:
            print(f"❌ 解析计划时出错: {e}")
            print(f"原始响应: {response_text}")
            return []
        except Exception as e:
            print(f"❌ 解析计划时发生未知错误: {e}")
            return []

# --- 3. 执行器 (Executor) 定义 ---
EXECUTOR_PROMPT_TEMPLATE = """
你是一位顶级的AI执行专家。你的任务是严格按照给定的计划,一步步地解决问题。
你将收到原始问题、完整的计划、以及到目前为止已经完成的步骤和结果。
请你专注于解决“当前步骤”,并仅输出该步骤的最终答案,不要输出任何额外的解释或对话。

# 原始问题:
{question}

# 完整计划:
{plan}

# 历史步骤与结果:
{history}

# 当前步骤:
{current_step}

请仅输出针对“当前步骤”的回答:
"""

class Executor:
    def __init__(self, llm_client: HelloAgentsLLM):
        self.llm_client = llm_client

    def execute(self, question: str, plan: list[str]) -> str:
        history = ""
        final_answer = ""
        
        print("\n--- 正在执行计划 ---")
        for i, step in enumerate(plan, 1):
            print(f"\n-> 正在执行步骤 {i}/{len(plan)}: {step}")
            prompt = EXECUTOR_PROMPT_TEMPLATE.format(
                question=question, plan=plan, history=history if history else "无", current_step=step
            )
            messages = [{"role": "user", "content": prompt}]
            
            response_text = self.llm_client.think(messages=messages) or ""
            
            history += f"步骤 {i}: {step}\n结果: {response_text}\n\n"
            final_answer = response_text
            print(f"✅ 步骤 {i} 已完成,结果: {final_answer}")
            
        return final_answer

# --- 4. 智能体 (Agent) 整合 ---
class PlanAndSolveAgent:
    def __init__(self, llm_client: HelloAgentsLLM):
        self.llm_client = llm_client
        self.planner = Planner(self.llm_client)
        self.executor = Executor(self.llm_client)

    def run(self, question: str):
        print(f"\n--- 开始处理问题 ---\n问题: {question}")
        plan = self.planner.plan(question)
        if not plan:
            print("\n--- 任务终止 --- \n无法生成有效的行动计划。")
            return
        final_answer = self.executor.execute(question, plan)
        print(f"\n--- 任务完成 ---\n最终答案: {final_answer}")

# --- 5. 主函数入口 ---
if __name__ == '__main__':
    try:
        llm_client = HelloAgentsLLM()
        agent = PlanAndSolveAgent(llm_client)
        question = "一个水果店周一卖出了15个苹果。周二卖出的苹果数量是周一的两倍。周三卖出的数量比周二少了5个。请问这三天总共卖出了多少个苹果?"
        agent.run(question)
    except ValueError as e:
        print(e)

终端输出内容:

(.venv) MacBook-Air section4 % python Plan_and_Solve.py 

--- 开始处理问题 ---
问题: 一个水果店周一卖出了15个苹果。周二卖出的苹果数量是周一的两倍。周三卖出的数量比周二少了5个。请问这三天总共卖出了多少个苹果?
--- 正在生成计划 ---
🧠 正在调用 coding-glm-5-free 模型...
✅ 大语言模型响应成功:
```python
["从问题中提取周一卖出的苹果数量", "根据周一的数量计算周二卖出的苹果数量(周一数量乘以2)", "根据周二的数量计算周三卖出的苹果数量(周二数量减去5)", "将周一、周二和周三的销量相加以计算总数"]
```
✅ 计划已生成:
```python
["从问题中提取周一卖出的苹果数量", "根据周一的数量计算周二卖出的苹果数量(周一数量乘以2)", "根据周二的数量计算周三卖出的苹果数量(周二数量减去5)", "将周一、周二和周三的销量相加以计算总数"]
```

--- 正在执行计划 ---

-> 正在执行步骤 1/4: 从问题中提取周一卖出的苹果数量
🧠 正在调用 coding-glm-5-free 模型...
✅ 大语言模型响应成功:
15
✅ 步骤 1 已完成,结果: 15

-> 正在执行步骤 2/4: 根据周一的数量计算周二卖出的苹果数量(周一数量乘以2)
🧠 正在调用 coding-glm-5-free 模型...
✅ 大语言模型响应成功:
30
✅ 步骤 2 已完成,结果: 30

-> 正在执行步骤 3/4: 根据周二的数量计算周三卖出的苹果数量(周二数量减去5)
🧠 正在调用 coding-glm-5-free 模型...
✅ 大语言模型响应成功:
25
✅ 步骤 3 已完成,结果: 25

-> 正在执行步骤 4/4: 将周一、周二和周三的销量相加以计算总数
🧠 正在调用 coding-glm-5-free 模型...
✅ 大语言模型响应成功:
70
✅ 步骤 4 已完成,结果: 70

--- 任务完成 ---
最终答案: 70

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐