006.ReAct 与 Plan-and-Execute 设计模式

为什么需要 Agent 设计模式?

传统AI应用的局限性:

在 Agent 模式出现前,AI 应用大多是"单次问答"模式:

Agent 解决的问题:

  1. 工具调用问题:让 AI 能够操作现实世界工具
    1. 比如:读取文件、执行计算、查询数据库
    2. 传统 AI 只能"说",Agent 能"做"
  2. 复杂任务分解问题:将大任务拆解为可执行的小步骤
    1. 比如:"分析公司数据并生成报告"需要多个阶段
    2. Agent 能像项目经理一样分步执行
  3. 动态调整问题:根据执行结果实时调整策略
    1. 传统 AI:错了就错了,无法修正
    2. Agent:能根据反馈重新思考、重新尝试

Agent 设计模式解决的问题:

Agent 实现了 AI 从“能说”到“能做”的关键问题,但是实现不只是简单地调用模型、提供工具,而是一项系统工程。要想真正发挥 AI 的潜力,离不开良好的架构设计。

这正是 Agent 设计模式的价值,它将 Agent 的实现方式标准化,提升了系统的可用性和准确率。无论是调用工具、分步骤处理复杂任务,还是根据执行结果动态调整策略,这些模式都提供了经过实践验证的架构。它们把常见的设计问题转化为可复用的解决方案,让开发者不必再从零开始摸索如何组织 AI 的思考、行动与规划。

借助这些模式,开发者可以更专注于构建真正实用、可靠的智能系统,让 AI 不仅“能想会说”,更能“动手执行”。

ReAct 设计模式:边思考边行动

核心思想

Pasted image 20260402185438.png

传统大语言模型通常只有推理(Reason Only)或者只有执行(Act Only), 而 ReAct(Reasoning + Acting)的核心是 "在行动中思考"。它模拟了人类解决问题的方式:

  1. 思考当前情况和目标
  2. 然后行动(调用工具)
  3. 观察行动结果
  4. 根据结果再次思考下一步
  5. 循环直到问题解决

Pasted image 20260402185507.png

实现原理分析

关键代码结构:

// 简化版实现逻辑
for (let i = 0; i < maxLoops; i++) {
    // 1. 思考:LLM分析当前情况,决定做什么
    const { thought, action, args, final } = await llmThink();
    
    if (final) {
        // 任务完成
        break;
    }
    
    // 2. 行动:调用具体的工具
    const result = await callTool(action, args);
    
    // 3. 观察:将结果作为下一次思考的输入
    context.push(`观察到:${result}`);
}

为什么需要严格的JSON格式?

// 系统提示词要求:
const SYSTEM = `你必须用这个格式响应:
{
  "thought": "你的思考过程",
  "action": "工具名(可选)",
  "args": {参数},
  "final": "最终结果(可选)"
}`;

原因:

  1. 程序可解析性:非结构化文本难以被程序理解
  2. 确定性:确保每次输出结构一致
  3. 错误处理:格式错误时可以明确识别和修复

工具调用机制:

// 工具注册系统
const tools = {
    "read_file": {
        description: "读取文件内容",
        execute: (args) => fs.readFile(args.path)
    },
    "search_web": {
        description: "搜索网页",
        execute: (args) => fetch(searchAPI + args.query)
    }
};

// 统一调用接口
async function callTool(name, args) {
    const tool = tools[name];
    if (!tool) return { error: "工具不存在" };
    
    try {
        const result = await tool.execute(args);
        return { success: true, data: result };
    } catch (e) {
        return { success: false, error: e.message };
    }
}

执行流程示例:

任务:"读取 report.txt 文件,统计其中'错误'出现的次数"

循环1:
思考:需要先读取文件内容
行动:调用read_file,参数{path: "report.txt"}
观察:文件内容为"系统运行正常,无错误发生"

循环2:
思考:需要统计"错误"一词的出现次数
行动:调用count_string,参数{text: "系统运行正常,无错误发生", target: "错误"}
观察:出现次数为0

循环3:
思考:任务完成,统计结果为0次
最终:在report.txt文件中,"错误"一词出现了0次

ReAct 解决的问题

  1. 工具选择的智能性:LLM 根据当前情况选择最合适的工具
  2. 参数生成的准确性:LLM 根据工具描述生成正确的参数
  3. 结果驱动的迭代:基于观察结果决定下一步行动
  4. 错误恢复能力:工具调用失败时可以尝试其他方法

适用场景

Plan-and-Execute 设计模式:先规划再执行

核心思想

Pasted image 20260402185605.png

Plan-and-Execute 的核心是 "先谋定而后动"。它模拟了专业项目管理:

  1. 规划阶段:先制定完整的执行计划
  2. 执行阶段:按计划逐步执行
  3. 监控阶段:监控执行结果
  4. 重规划阶段:失败时调整计划

Pasted image 20260402185636.png

实现原理分析

三层架构设计:

// 1. 规划层 - 生成蓝图
async function generatePlan(task) {
    // 提示词强调"做什么",而不是"怎么做"
    const prompt = `你是一位项目经理,请将任务分解为3-6个可执行的步骤。
    任务:${task}
    
    要求:
    - 每个步骤描述要达到的目标
    - 不要描述具体实现细节
    - 步骤间有逻辑顺序
    
    输出格式:{ "steps": [{"step": "描述"}] }`;
    
    return await llmGenerate(prompt);
}

// 2. 执行层 - 执行每个步骤(可用ReAct)
async function executeStep(step) {
    // 对每个步骤使用ReAct执行
    return await runReAct({ task: step.step });
}

// 3. 监控层 - 处理失败和重规划
async function monitorExecution(plan, results) {
    for (let i = 0; i < plan.steps.length; i++) {
        const result = results[i];
        
        if (result.failed) {
            // 触发重规划
            const newPlan = await replan({
                originalTask,
                failedStep: plan.steps[i],
                failureReason: result.error,
                completedSteps: results.slice(0, i)
            });
            
            // 用新计划重新开始
            return await executePlan(newPlan);
        }
    }
}

重规划机制详解:

async function replan(context) {
    const prompt = `原任务:${context.originalTask}
    
    执行情况:
    - 已完成:${context.completedSteps.length}个步骤
    - 失败步骤:${context.failedStep.step}
    - 失败原因:${context.failureReason}
    
    请生成新的计划,避免同样的失败。`;
    
    // LLM会分析失败原因,调整后续步骤
    const newPlan = await llmGenerate(prompt);
    
    return {
        ...newPlan,
        // 保留已成功的步骤
        completedSteps: context.completedSteps
    };
}

为什么需要"高层规划"?

  1. 视野问题:LLM 单次思考只能看到局部,规划让 AI 看到全局
  2. 顺序问题:复杂任务有依赖关系(先 A 后 B)
  3. 资源问题:提前考虑可能需要哪些工具和数据
  4. 容错问题:提前识别可能的失败点

执行流程示例:

任务:"分析系统日志,找出错误,生成报告"

阶段1:规划
{
  "steps": [
    {"step": "收集所有日志文件"},
    {"step": "分析日志中的错误模式"},
    {"step": "统计错误频率和时间分布"},
    {"step": "生成分析报告"}
  ]
}

阶段2:执行
步骤1:收集日志 → 成功
步骤2:分析错误 → 失败(日志格式不一致)

阶段3:重规划
新计划:
{
  "steps": [
    {"step": "收集所有日志文件"},
    {"step": "统一日志格式"},
    {"step": "分析错误模式"},
    {"step": "统计错误信息"},
    {"step": "生成分析报告"}
  ]
}

阶段4:继续执行...

Plan-and-Execute 解决的问题

  1. 复杂任务分解:将大问题拆解为可管理的小问题
  2. 执行顺序优化:合理安排步骤顺序,避免无效尝试
  3. 失败处理系统化:不是简单重试,而是调整策略
  4. 进度可追踪:明确知道完成了多少,还剩多少

与 ReAct 的关键区别

方面 ReAct Plan-and-Execute
思考粒度 细粒度(每一步) 粗粒度(每个阶段)
规划时间 实时规划 预先规划
错误处理 立即调整 重新规划
适用规模 中小任务 中大任务
资源消耗 较低 较高(多次调用)

适用场景

选择指南

选择 ReAct :

  1. 任务相对简单直接
  2. 需要快速响应和迭代
  3. 工具调用路径清晰
  4. 不需要长期规划

选择 Plan-and-Execute :

  1. 任务复杂,有多个阶段
  2. 步骤间有依赖关系
  3. 可能遇到多种失败情况
  4. 需要可追踪的执行进度

本质区别:思考的时空维度

总结:为什么需要 Agent 设计模式

解决的本质问题

  1. 连接 AI 与现实世界
    1. 传统 AI:停留在语言层面
    2. Agent:能实际操作工具,影响现实
  2. 处理复杂度超越人类单次思考的任务
    1. 传统 AI:受限于单次对话长度和结构
    2. Agent:能分步骤、分阶段解决复杂问题
  3. 实现自我修正和适应
    1. 传统 AI:输出即结束
    2. Agent:能根据反馈调整策略

参考资料

![[agent-desgin-pattern-demo-main.zip]]