智能体经典范式构建:ReAct、Plan-and-Solve 与 Reflection

智能体经典范式构建:ReAct、Plan-and-Solve 与 Reflection

一句话总览:Agent 的核心不是让模型更会聊天,而是为模型设计三种控制循环:边想边做、先计划再做、做完再改。

这篇文章基于 Datawhale Hello-Agents 第四章整理,但不按原文目录复述。原章用 Python 从零实现 ReAct、Plan-and-Solve 和 Reflection;

快速结论

问题 结论
三种范式分别解决什么问题 ReAct 解决外部信息不确定,Plan-and-Solve 解决复杂任务拆解,Reflection 解决初稿质量不够
什么时候优先用 ReAct 需要搜索、查数据库、调用 API、根据工具反馈调整下一步
什么时候优先用 Plan-and-Solve 任务目标稳定、步骤清楚、多步推理明显
什么时候优先用 Reflection 代码、报告、方案、研究分析等高质量输出
工程上怎么组合 先 Plan 拆任务,中间 ReAct 调工具,最后 Reflection 做质检
最大风险 控制循环越多,成本、延迟、不可控性越高

核心地图

范式 一句话 核心循环 控制权主要来自
ReAct 边想边查 Thought -> Action -> Observation 每一轮环境反馈
Plan-and-Solve 先画路线再走 Plan -> Execute -> Summarize 初始计划
Reflection 先做初稿再评审 Execute -> Reflect -> Refine 事后反馈

#mermaid-svg-1U53lUQUtjgHIg8W{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1U53lUQUtjgHIg8W .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1U53lUQUtjgHIg8W .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1U53lUQUtjgHIg8W .error-icon{fill:#552222;}#mermaid-svg-1U53lUQUtjgHIg8W .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1U53lUQUtjgHIg8W .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1U53lUQUtjgHIg8W .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1U53lUQUtjgHIg8W .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1U53lUQUtjgHIg8W .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1U53lUQUtjgHIg8W .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1U53lUQUtjgHIg8W .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1U53lUQUtjgHIg8W .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1U53lUQUtjgHIg8W .marker.cross{stroke:#333333;}#mermaid-svg-1U53lUQUtjgHIg8W svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1U53lUQUtjgHIg8W p{margin:0;}#mermaid-svg-1U53lUQUtjgHIg8W .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1U53lUQUtjgHIg8W .cluster-label text{fill:#333;}#mermaid-svg-1U53lUQUtjgHIg8W .cluster-label span{color:#333;}#mermaid-svg-1U53lUQUtjgHIg8W .cluster-label span p{background-color:transparent;}#mermaid-svg-1U53lUQUtjgHIg8W .label text,#mermaid-svg-1U53lUQUtjgHIg8W span{fill:#333;color:#333;}#mermaid-svg-1U53lUQUtjgHIg8W .node rect,#mermaid-svg-1U53lUQUtjgHIg8W .node circle,#mermaid-svg-1U53lUQUtjgHIg8W .node ellipse,#mermaid-svg-1U53lUQUtjgHIg8W .node polygon,#mermaid-svg-1U53lUQUtjgHIg8W .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1U53lUQUtjgHIg8W .rough-node .label text,#mermaid-svg-1U53lUQUtjgHIg8W .node .label text,#mermaid-svg-1U53lUQUtjgHIg8W .image-shape .label,#mermaid-svg-1U53lUQUtjgHIg8W .icon-shape .label{text-anchor:middle;}#mermaid-svg-1U53lUQUtjgHIg8W .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1U53lUQUtjgHIg8W .rough-node .label,#mermaid-svg-1U53lUQUtjgHIg8W .node .label,#mermaid-svg-1U53lUQUtjgHIg8W .image-shape .label,#mermaid-svg-1U53lUQUtjgHIg8W .icon-shape .label{text-align:center;}#mermaid-svg-1U53lUQUtjgHIg8W .node.clickable{cursor:pointer;}#mermaid-svg-1U53lUQUtjgHIg8W .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1U53lUQUtjgHIg8W .arrowheadPath{fill:#333333;}#mermaid-svg-1U53lUQUtjgHIg8W .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1U53lUQUtjgHIg8W .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1U53lUQUtjgHIg8W .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1U53lUQUtjgHIg8W .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1U53lUQUtjgHIg8W .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1U53lUQUtjgHIg8W .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1U53lUQUtjgHIg8W .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1U53lUQUtjgHIg8W .cluster text{fill:#333;}#mermaid-svg-1U53lUQUtjgHIg8W .cluster span{color:#333;}#mermaid-svg-1U53lUQUtjgHIg8W div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1U53lUQUtjgHIg8W .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1U53lUQUtjgHIg8W rect.text{fill:none;stroke-width:0;}#mermaid-svg-1U53lUQUtjgHIg8W .icon-shape,#mermaid-svg-1U53lUQUtjgHIg8W .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1U53lUQUtjgHIg8W .icon-shape p,#mermaid-svg-1U53lUQUtjgHIg8W .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1U53lUQUtjgHIg8W .icon-shape .label rect,#mermaid-svg-1U53lUQUtjgHIg8W .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1U53lUQUtjgHIg8W .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1U53lUQUtjgHIg8W .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1U53lUQUtjgHIg8W :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 需要外部反馈
步骤稳定
质量要求高
用户
LLM
判断任务特征
ReAct
Plan-and-Solve
Reflection
候选结果
更可靠的结果

先准备底座:模型客户端和工具执行器

一句话:三种 Agent Loop 的差异在控制流程,底层都需要一个 LLM 客户端和一套工具调用接口。

解决的问题:如果每个范式都自己写模型调用和工具注册,后面会很快失控。先抽底座,可以让 ReAct、Plan-and-Solve、Reflection 复用同一套能力。

适合场景:所有 Agent 原型都应该先做这一步,哪怕只是 demo。

核心机制:LLM 客户端只负责发送消息和返回文本;工具执行器只负责注册、描述和调用工具;Agent Loop 负责决定什么时候调用模型、什么时候调用工具。

最小实现:

bash 复制代码
npm init -y
npm install dotenv

.env

bash 复制代码
LLM_API_KEY="YOUR_API_KEY"
LLM_MODEL_ID="YOUR_MODEL"
LLM_BASE_URL="https://api.openai.com/v1"
SERPAPI_API_KEY="YOUR_SERPAPI_API_KEY"
ts 复制代码
import 'dotenv/config';

export class HelloAgentsLLM {
  constructor({
    model = process.env.LLM_MODEL_ID,
    apiKey = process.env.LLM_API_KEY,
    baseUrl = process.env.LLM_BASE_URL,
    timeoutMs = Number(process.env.LLM_TIMEOUT_MS || 60_000)
  } = {}) {
    if (!model || !apiKey || !baseUrl) {
      throw new Error('LLM_MODEL_ID、LLM_API_KEY、LLM_BASE_URL 必须配置。');
    }

    this.model = model;
    this.apiKey = apiKey;
    this.baseUrl = baseUrl.replace(/\/$/, '');
    this.timeoutMs = timeoutMs;
  }

  async think(messages, { temperature = 0 } = {}) {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), this.timeoutMs);

    try {
      const response = await fetch(`${this.baseUrl}/chat/completions`, {
        method: 'POST',
        signal: controller.signal,
        headers: {
          'content-type': 'application/json',
          authorization: `Bearer ${this.apiKey}`
        },
        body: JSON.stringify({
          model: this.model,
          messages,
          temperature
        })
      });

      if (!response.ok) {
        throw new Error(`LLM API failed: ${response.status} ${await response.text()}`);
      }

      const data = await response.json();
      return data.choices?.[0]?.message?.content?.trim() ?? '';
    } finally {
      clearTimeout(timer);
    }
  }
}

export class ToolExecutor {
  constructor() {
    this.tools = new Map();
  }

  registerTool(name, description, fn) {
    this.tools.set(name, { description, fn });
  }

  getAvailableToolsText() {
    return [...this.tools.entries()]
      .map(([name, tool]) => `- ${name}: ${tool.description}`)
      .join('\n');
  }

  async execute(name, input) {
    const tool = this.tools.get(name)?.fn;
    if (!tool) return `错误:未找到工具 ${name}`;
    return await tool(input);
  }
}

常见坑:

处理方式
LLM 客户端里混入业务循环 保持客户端只做模型调用
工具描述太含糊 描述清楚何时用、输入是什么、返回什么
所有工具一次性塞给模型 工具多时先做检索或路由

什么时候不要展开这一步:一次性脚本可以直接调用模型;但只要准备复用或组合多个 Agent Loop,就应该抽象底座。

ReAct:适合需要外部反馈的任务

一句话:ReAct 让模型每一步都先想清楚,再调用工具,然后用工具结果修正下一步。

解决的问题:只让模型思考,它可能凭空编;只让模型行动,它可能乱调工具。ReAct 把推理和行动交替起来,让外部世界不断校正模型。

适合场景:

场景 为什么适合
查询实时信息 模型自身知识可能过期
调用 API / 数据库 每次返回会影响下一步
搜索和总结 需要边查边缩小问题
工具链任务 不同工具之间存在依赖

核心机制:
#mermaid-svg-fh0QtszqTrrhD0dW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fh0QtszqTrrhD0dW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fh0QtszqTrrhD0dW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fh0QtszqTrrhD0dW .error-icon{fill:#552222;}#mermaid-svg-fh0QtszqTrrhD0dW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fh0QtszqTrrhD0dW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fh0QtszqTrrhD0dW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fh0QtszqTrrhD0dW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fh0QtszqTrrhD0dW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fh0QtszqTrrhD0dW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fh0QtszqTrrhD0dW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fh0QtszqTrrhD0dW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fh0QtszqTrrhD0dW .marker.cross{stroke:#333333;}#mermaid-svg-fh0QtszqTrrhD0dW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fh0QtszqTrrhD0dW p{margin:0;}#mermaid-svg-fh0QtszqTrrhD0dW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fh0QtszqTrrhD0dW .cluster-label text{fill:#333;}#mermaid-svg-fh0QtszqTrrhD0dW .cluster-label span{color:#333;}#mermaid-svg-fh0QtszqTrrhD0dW .cluster-label span p{background-color:transparent;}#mermaid-svg-fh0QtszqTrrhD0dW .label text,#mermaid-svg-fh0QtszqTrrhD0dW span{fill:#333;color:#333;}#mermaid-svg-fh0QtszqTrrhD0dW .node rect,#mermaid-svg-fh0QtszqTrrhD0dW .node circle,#mermaid-svg-fh0QtszqTrrhD0dW .node ellipse,#mermaid-svg-fh0QtszqTrrhD0dW .node polygon,#mermaid-svg-fh0QtszqTrrhD0dW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fh0QtszqTrrhD0dW .rough-node .label text,#mermaid-svg-fh0QtszqTrrhD0dW .node .label text,#mermaid-svg-fh0QtszqTrrhD0dW .image-shape .label,#mermaid-svg-fh0QtszqTrrhD0dW .icon-shape .label{text-anchor:middle;}#mermaid-svg-fh0QtszqTrrhD0dW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fh0QtszqTrrhD0dW .rough-node .label,#mermaid-svg-fh0QtszqTrrhD0dW .node .label,#mermaid-svg-fh0QtszqTrrhD0dW .image-shape .label,#mermaid-svg-fh0QtszqTrrhD0dW .icon-shape .label{text-align:center;}#mermaid-svg-fh0QtszqTrrhD0dW .node.clickable{cursor:pointer;}#mermaid-svg-fh0QtszqTrrhD0dW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fh0QtszqTrrhD0dW .arrowheadPath{fill:#333333;}#mermaid-svg-fh0QtszqTrrhD0dW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fh0QtszqTrrhD0dW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fh0QtszqTrrhD0dW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fh0QtszqTrrhD0dW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fh0QtszqTrrhD0dW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fh0QtszqTrrhD0dW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fh0QtszqTrrhD0dW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fh0QtszqTrrhD0dW .cluster text{fill:#333;}#mermaid-svg-fh0QtszqTrrhD0dW .cluster span{color:#333;}#mermaid-svg-fh0QtszqTrrhD0dW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fh0QtszqTrrhD0dW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fh0QtszqTrrhD0dW rect.text{fill:none;stroke-width:0;}#mermaid-svg-fh0QtszqTrrhD0dW .icon-shape,#mermaid-svg-fh0QtszqTrrhD0dW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fh0QtszqTrrhD0dW .icon-shape p,#mermaid-svg-fh0QtszqTrrhD0dW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fh0QtszqTrrhD0dW .icon-shape .label rect,#mermaid-svg-fh0QtszqTrrhD0dW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fh0QtszqTrrhD0dW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fh0QtszqTrrhD0dW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fh0QtszqTrrhD0dW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户
LLM
Thought
Action
Observation
Finish

模型每一轮输出固定格式:

text 复制代码
Thought: 我现在知道什么,还缺什么
Action: Search[要搜索的问题]

如果信息足够:

text 复制代码
Thought: 信息已经足够
Action: Finish[最终答案]

最小实现:

ts 复制代码
const REACT_PROMPT = `
你是一个可以调用外部工具的智能助手。

可用工具:
{tools}

请严格按下面格式输出:
Thought: 你的思考
Action: 工具名[工具输入] 或 Finish[最终答案]

问题:
{question}

历史:
{history}
`;

function parseAction(text) {
  const match = text.match(/Action:\s*([A-Za-z_][\w]*)\[(.*)\]/s);
  if (!match) return null;
  return {
    toolName: match[1],
    toolInput: match[2].trim()
  };
}

export class ReActAgent {
  constructor({ llm, toolExecutor, maxSteps = 5 }) {
    this.llm = llm;
    this.toolExecutor = toolExecutor;
    this.maxSteps = maxSteps;
  }

  async run(question) {
    let history = '';

    for (let step = 1; step <= this.maxSteps; step += 1) {
      const prompt = REACT_PROMPT.replace('{tools}', this.toolExecutor.getAvailableToolsText())
        .replace('{question}', question)
        .replace('{history}', history || '无');

      const output = await this.llm.think([{ role: 'user', content: prompt }]);
      const action = parseAction(output);

      if (!action) {
        history += `\n模型输出无法解析:\n${output}\n`;
        continue;
      }

      if (action.toolName === 'Finish') {
        return action.toolInput;
      }

      const observation = await this.toolExecutor.execute(action.toolName, action.toolInput);
      history += `\n${output}\nObservation: ${observation}\n`;
    }

    return '达到最大步骤数,未得到稳定答案。';
  }
}

常见坑:

说明 工程处理
输出解析脆弱 模型不一定遵守 Action[...] 用 JSON Schema、函数调用或结构化输出
工具选择错误 模型可能搜索不该搜的问题 增强工具描述,加入工具路由
死循环 一直搜索或重复调用 设置最大步数,检测重复动作
上下文膨胀 Observation 越积越多 对历史做摘要,只保留关键证据

什么时候不要用:任务不需要外部信息、步骤很清楚、答案可以一次性推理出来时,ReAct 可能只是增加调用成本。

Plan-and-Solve:适合路径清楚的复杂任务

一句话:Plan-and-Solve 先生成完整路线,再按路线一步步执行。

解决的问题:复杂任务如果直接让模型回答,很容易漏步骤。Plan-and-Solve 先把任务拆开,让模型从一次大跳跃变成多次小推进。

适合场景:

场景 为什么适合
多步数学题 步骤稳定,推理链清楚
报告大纲生成 先定结构,再填内容
稳定流程任务 不需要频繁依赖外部反馈
代码脚手架生成 可先规划模块,再逐个实现

核心机制:
#mermaid-svg-gHgq4neZd9DCpI27{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gHgq4neZd9DCpI27 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gHgq4neZd9DCpI27 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gHgq4neZd9DCpI27 .error-icon{fill:#552222;}#mermaid-svg-gHgq4neZd9DCpI27 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gHgq4neZd9DCpI27 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gHgq4neZd9DCpI27 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gHgq4neZd9DCpI27 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gHgq4neZd9DCpI27 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gHgq4neZd9DCpI27 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gHgq4neZd9DCpI27 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gHgq4neZd9DCpI27 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gHgq4neZd9DCpI27 .marker.cross{stroke:#333333;}#mermaid-svg-gHgq4neZd9DCpI27 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gHgq4neZd9DCpI27 p{margin:0;}#mermaid-svg-gHgq4neZd9DCpI27 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gHgq4neZd9DCpI27 .cluster-label text{fill:#333;}#mermaid-svg-gHgq4neZd9DCpI27 .cluster-label span{color:#333;}#mermaid-svg-gHgq4neZd9DCpI27 .cluster-label span p{background-color:transparent;}#mermaid-svg-gHgq4neZd9DCpI27 .label text,#mermaid-svg-gHgq4neZd9DCpI27 span{fill:#333;color:#333;}#mermaid-svg-gHgq4neZd9DCpI27 .node rect,#mermaid-svg-gHgq4neZd9DCpI27 .node circle,#mermaid-svg-gHgq4neZd9DCpI27 .node ellipse,#mermaid-svg-gHgq4neZd9DCpI27 .node polygon,#mermaid-svg-gHgq4neZd9DCpI27 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gHgq4neZd9DCpI27 .rough-node .label text,#mermaid-svg-gHgq4neZd9DCpI27 .node .label text,#mermaid-svg-gHgq4neZd9DCpI27 .image-shape .label,#mermaid-svg-gHgq4neZd9DCpI27 .icon-shape .label{text-anchor:middle;}#mermaid-svg-gHgq4neZd9DCpI27 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gHgq4neZd9DCpI27 .rough-node .label,#mermaid-svg-gHgq4neZd9DCpI27 .node .label,#mermaid-svg-gHgq4neZd9DCpI27 .image-shape .label,#mermaid-svg-gHgq4neZd9DCpI27 .icon-shape .label{text-align:center;}#mermaid-svg-gHgq4neZd9DCpI27 .node.clickable{cursor:pointer;}#mermaid-svg-gHgq4neZd9DCpI27 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gHgq4neZd9DCpI27 .arrowheadPath{fill:#333333;}#mermaid-svg-gHgq4neZd9DCpI27 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gHgq4neZd9DCpI27 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gHgq4neZd9DCpI27 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gHgq4neZd9DCpI27 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gHgq4neZd9DCpI27 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gHgq4neZd9DCpI27 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gHgq4neZd9DCpI27 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gHgq4neZd9DCpI27 .cluster text{fill:#333;}#mermaid-svg-gHgq4neZd9DCpI27 .cluster span{color:#333;}#mermaid-svg-gHgq4neZd9DCpI27 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gHgq4neZd9DCpI27 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gHgq4neZd9DCpI27 rect.text{fill:none;stroke-width:0;}#mermaid-svg-gHgq4neZd9DCpI27 .icon-shape,#mermaid-svg-gHgq4neZd9DCpI27 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gHgq4neZd9DCpI27 .icon-shape p,#mermaid-svg-gHgq4neZd9DCpI27 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gHgq4neZd9DCpI27 .icon-shape .label rect,#mermaid-svg-gHgq4neZd9DCpI27 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gHgq4neZd9DCpI27 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gHgq4neZd9DCpI27 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gHgq4neZd9DCpI27 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户
LLM
Plan
Step 1
Step 2
Step 3
Answer

最小实现:

ts 复制代码
const PLAN_PROMPT = `
请把用户任务拆成可以依次执行的步骤。

只输出 JSON,不要输出解释。
JSON 格式:
{
  "steps": [
    { "id": 1, "goal": "这一步要完成什么", "instruction": "具体执行说明" }
  ]
}

用户任务:
{task}
`;

function extractJson(text) {
  const start = text.indexOf('{');
  const end = text.lastIndexOf('}');
  if (start === -1 || end === -1 || end <= start) {
    throw new Error('模型没有返回 JSON 对象。');
  }
  return JSON.parse(text.slice(start, end + 1));
}

export class PlanAndSolveAgent {
  constructor({ llm }) {
    this.llm = llm;
  }

  async plan(task) {
    const prompt = PLAN_PROMPT.replace('{task}', task);
    const output = await this.llm.think([{ role: 'user', content: prompt }]);
    return extractJson(output).steps ?? [];
  }

  async execute(task, steps) {
    const results = [];

    for (const step of steps) {
      const prompt = `
原始任务:
${task}

当前步骤:
${JSON.stringify(step, null, 2)}

之前结果:
${results.join('\n\n') || '无'}

请完成当前步骤,只输出本步骤结果。
`;

      const result = await this.llm.think([{ role: 'user', content: prompt }]);
      results.push(`Step ${step.id}: ${result}`);
    }

    return results;
  }

  async run(task) {
    const steps = await this.plan(task);
    const results = await this.execute(task, steps);
    return await this.llm.think([
      {
        role: 'user',
        content: `请根据以下步骤结果汇总最终答案:\n\n${results.join('\n\n')}`
      }
    ]);
  }
}

常见坑:

说明 工程处理
第一版计划错了 后面执行越认真越偏 加检查点和动态重规划
计划太粗 每一步仍然不可执行 要求每步包含目标、输入、输出
计划太细 成本变高,流程拖长 限制步骤数,合并低价值步骤

动态重规划更像真实系统:
#mermaid-svg-O68nVEE8QkQBTCkA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-O68nVEE8QkQBTCkA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-O68nVEE8QkQBTCkA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-O68nVEE8QkQBTCkA .error-icon{fill:#552222;}#mermaid-svg-O68nVEE8QkQBTCkA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-O68nVEE8QkQBTCkA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-O68nVEE8QkQBTCkA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-O68nVEE8QkQBTCkA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-O68nVEE8QkQBTCkA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-O68nVEE8QkQBTCkA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-O68nVEE8QkQBTCkA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-O68nVEE8QkQBTCkA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-O68nVEE8QkQBTCkA .marker.cross{stroke:#333333;}#mermaid-svg-O68nVEE8QkQBTCkA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-O68nVEE8QkQBTCkA p{margin:0;}#mermaid-svg-O68nVEE8QkQBTCkA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-O68nVEE8QkQBTCkA .cluster-label text{fill:#333;}#mermaid-svg-O68nVEE8QkQBTCkA .cluster-label span{color:#333;}#mermaid-svg-O68nVEE8QkQBTCkA .cluster-label span p{background-color:transparent;}#mermaid-svg-O68nVEE8QkQBTCkA .label text,#mermaid-svg-O68nVEE8QkQBTCkA span{fill:#333;color:#333;}#mermaid-svg-O68nVEE8QkQBTCkA .node rect,#mermaid-svg-O68nVEE8QkQBTCkA .node circle,#mermaid-svg-O68nVEE8QkQBTCkA .node ellipse,#mermaid-svg-O68nVEE8QkQBTCkA .node polygon,#mermaid-svg-O68nVEE8QkQBTCkA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-O68nVEE8QkQBTCkA .rough-node .label text,#mermaid-svg-O68nVEE8QkQBTCkA .node .label text,#mermaid-svg-O68nVEE8QkQBTCkA .image-shape .label,#mermaid-svg-O68nVEE8QkQBTCkA .icon-shape .label{text-anchor:middle;}#mermaid-svg-O68nVEE8QkQBTCkA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-O68nVEE8QkQBTCkA .rough-node .label,#mermaid-svg-O68nVEE8QkQBTCkA .node .label,#mermaid-svg-O68nVEE8QkQBTCkA .image-shape .label,#mermaid-svg-O68nVEE8QkQBTCkA .icon-shape .label{text-align:center;}#mermaid-svg-O68nVEE8QkQBTCkA .node.clickable{cursor:pointer;}#mermaid-svg-O68nVEE8QkQBTCkA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-O68nVEE8QkQBTCkA .arrowheadPath{fill:#333333;}#mermaid-svg-O68nVEE8QkQBTCkA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-O68nVEE8QkQBTCkA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-O68nVEE8QkQBTCkA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-O68nVEE8QkQBTCkA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-O68nVEE8QkQBTCkA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-O68nVEE8QkQBTCkA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-O68nVEE8QkQBTCkA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-O68nVEE8QkQBTCkA .cluster text{fill:#333;}#mermaid-svg-O68nVEE8QkQBTCkA .cluster span{color:#333;}#mermaid-svg-O68nVEE8QkQBTCkA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-O68nVEE8QkQBTCkA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-O68nVEE8QkQBTCkA rect.text{fill:none;stroke-width:0;}#mermaid-svg-O68nVEE8QkQBTCkA .icon-shape,#mermaid-svg-O68nVEE8QkQBTCkA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-O68nVEE8QkQBTCkA .icon-shape p,#mermaid-svg-O68nVEE8QkQBTCkA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-O68nVEE8QkQBTCkA .icon-shape .label rect,#mermaid-svg-O68nVEE8QkQBTCkA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-O68nVEE8QkQBTCkA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-O68nVEE8QkQBTCkA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-O68nVEE8QkQBTCkA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 正常
失败或偏离
完成
用户
LLM
生成计划
执行一步
检查结果
重规划剩余步骤
最终答案

什么时候不要用:任务高度依赖实时反馈、用户目标不断变化、工具结果会强烈改变后续路径时,单纯的静态计划不够。

Reflection:适合高质量输出

一句话:Reflection 让模型先交初稿,再切换成评审员找问题,最后根据反馈修订。

解决的问题:模型一次生成的结果通常只是合格初稿。代码可能能跑但不高效,报告可能完整但不犀利,方案可能合理但漏掉风险。Reflection 把一次性生成变成迭代优化。

适合场景:

场景 为什么适合
代码生成 可以检查复杂度、边界条件、可读性
技术报告 可以检查逻辑、遗漏和证据
研究分析 可以从多个维度反驳初稿
高风险决策 可以在输出前加一道质量门禁

核心机制:
#mermaid-svg-UY1cdQioI9xCHMhg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UY1cdQioI9xCHMhg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UY1cdQioI9xCHMhg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UY1cdQioI9xCHMhg .error-icon{fill:#552222;}#mermaid-svg-UY1cdQioI9xCHMhg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UY1cdQioI9xCHMhg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UY1cdQioI9xCHMhg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UY1cdQioI9xCHMhg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UY1cdQioI9xCHMhg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UY1cdQioI9xCHMhg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UY1cdQioI9xCHMhg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UY1cdQioI9xCHMhg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UY1cdQioI9xCHMhg .marker.cross{stroke:#333333;}#mermaid-svg-UY1cdQioI9xCHMhg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UY1cdQioI9xCHMhg p{margin:0;}#mermaid-svg-UY1cdQioI9xCHMhg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UY1cdQioI9xCHMhg .cluster-label text{fill:#333;}#mermaid-svg-UY1cdQioI9xCHMhg .cluster-label span{color:#333;}#mermaid-svg-UY1cdQioI9xCHMhg .cluster-label span p{background-color:transparent;}#mermaid-svg-UY1cdQioI9xCHMhg .label text,#mermaid-svg-UY1cdQioI9xCHMhg span{fill:#333;color:#333;}#mermaid-svg-UY1cdQioI9xCHMhg .node rect,#mermaid-svg-UY1cdQioI9xCHMhg .node circle,#mermaid-svg-UY1cdQioI9xCHMhg .node ellipse,#mermaid-svg-UY1cdQioI9xCHMhg .node polygon,#mermaid-svg-UY1cdQioI9xCHMhg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UY1cdQioI9xCHMhg .rough-node .label text,#mermaid-svg-UY1cdQioI9xCHMhg .node .label text,#mermaid-svg-UY1cdQioI9xCHMhg .image-shape .label,#mermaid-svg-UY1cdQioI9xCHMhg .icon-shape .label{text-anchor:middle;}#mermaid-svg-UY1cdQioI9xCHMhg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UY1cdQioI9xCHMhg .rough-node .label,#mermaid-svg-UY1cdQioI9xCHMhg .node .label,#mermaid-svg-UY1cdQioI9xCHMhg .image-shape .label,#mermaid-svg-UY1cdQioI9xCHMhg .icon-shape .label{text-align:center;}#mermaid-svg-UY1cdQioI9xCHMhg .node.clickable{cursor:pointer;}#mermaid-svg-UY1cdQioI9xCHMhg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UY1cdQioI9xCHMhg .arrowheadPath{fill:#333333;}#mermaid-svg-UY1cdQioI9xCHMhg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UY1cdQioI9xCHMhg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UY1cdQioI9xCHMhg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UY1cdQioI9xCHMhg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UY1cdQioI9xCHMhg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UY1cdQioI9xCHMhg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UY1cdQioI9xCHMhg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UY1cdQioI9xCHMhg .cluster text{fill:#333;}#mermaid-svg-UY1cdQioI9xCHMhg .cluster span{color:#333;}#mermaid-svg-UY1cdQioI9xCHMhg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UY1cdQioI9xCHMhg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UY1cdQioI9xCHMhg rect.text{fill:none;stroke-width:0;}#mermaid-svg-UY1cdQioI9xCHMhg .icon-shape,#mermaid-svg-UY1cdQioI9xCHMhg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UY1cdQioI9xCHMhg .icon-shape p,#mermaid-svg-UY1cdQioI9xCHMhg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UY1cdQioI9xCHMhg .icon-shape .label rect,#mermaid-svg-UY1cdQioI9xCHMhg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UY1cdQioI9xCHMhg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UY1cdQioI9xCHMhg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UY1cdQioI9xCHMhg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 无需改进
用户
LLM
Execution
Reflection
Refinement
Final

最小实现:

ts 复制代码
export class Memory {
  constructor() {
    this.records = [];
  }

  addRecord(type, content) {
    this.records.push({ type, content });
  }

  getLastExecution() {
    return [...this.records].reverse().find((record) => record.type === 'execution')?.content ?? '';
  }
}

const INITIAL_PROMPT = `
你是一位资深 Node.js 工程师。请根据要求编写 JavaScript 函数。
请只输出代码。

要求:
{task}
`;

const REFLECT_PROMPT = `
你是一位严格的代码评审专家。
请审查下面的 JavaScript 代码,重点找出算法效率、边界条件和可读性问题。

原始任务:
{task}

代码:
\`\`\`js
{code}
\`\`\`

如果有改进空间,请给出具体反馈。
如果已经足够好,请回答:无需改进。
`;

const REFINE_PROMPT = `
请根据评审反馈优化代码。

原始任务:
{task}

上一版代码:
\`\`\`js
{lastCode}
\`\`\`

评审反馈:
{feedback}

请只输出优化后的 JavaScript 代码。
`;

export class ReflectionAgent {
  constructor({ llm, maxIterations = 3 }) {
    this.llm = llm;
    this.maxIterations = maxIterations;
    this.memory = new Memory();
  }

  async run(task) {
    const firstDraft = await this.llm.think([
      {
        role: 'user',
        content: INITIAL_PROMPT.replace('{task}', task)
      }
    ]);
    this.memory.addRecord('execution', firstDraft);

    for (let i = 0; i < this.maxIterations; i += 1) {
      const lastCode = this.memory.getLastExecution();
      const feedback = await this.llm.think([
        {
          role: 'user',
          content: REFLECT_PROMPT.replace('{task}', task).replace('{code}', lastCode)
        }
      ]);

      this.memory.addRecord('reflection', feedback);
      if (feedback.includes('无需改进')) break;

      const nextDraft = await this.llm.think([
        {
          role: 'user',
          content: REFINE_PROMPT.replace('{task}', task)
            .replace('{lastCode}', lastCode)
            .replace('{feedback}', feedback)
        }
      ]);
      this.memory.addRecord('execution', nextDraft);
    }

    return this.memory.getLastExecution();
  }
}

案例:找出 1n 的所有素数。初版可能逐个试除,复杂度接近 O(n * sqrt(n));Reflection 如果专注算法效率,就会推动它改成埃拉托斯特尼筛法。

ts 复制代码
export function findPrimes(n) {
  if (!Number.isInteger(n) || n < 2) return [];

  const isPrime = Array(n + 1).fill(true);
  isPrime[0] = false;
  isPrime[1] = false;

  for (let p = 2; p * p <= n; p += 1) {
    if (!isPrime[p]) continue;
    for (let current = p * p; current <= n; current += p) {
      isPrime[current] = false;
    }
  }

  return isPrime.map((value, index) => (value ? index : null)).filter((value) => value !== null);
}

常见坑:

说明 工程处理
评审太空泛 只说"可以更好" 给评审明确维度,如复杂度、边界、事实性
终止条件粗糙 只靠"无需改进" 加分数、测试、阈值或人工 gate
成本过高 每轮至少多一次评审和一次修订 只给高价值任务启用

什么时候不要用:实时问答、低风险闲聊、一次性简单任务,不值得为 Reflection 付出额外延迟和成本。

组合策略:真实 Agent 很少只用一种循环

最实用的默认组合是:

任务类型 默认组合 原因
实时搜索问答 ReAct 需要外部观察
复杂报告 Plan-and-Solve + Reflection 先定结构,再做质检
多 API 工作流 Plan-and-Solve + ReAct 先规划接口顺序,再按反馈执行
代码生成 Plan-and-Solve + Reflection 先拆模块,再审查优化
高风险业务决策 ReAct + Reflection + 人工 gate 需要证据、反思和最终审批

一个工程化架构可以这样组织:
#mermaid-svg-HAGxbCd6bcenf1lI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HAGxbCd6bcenf1lI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HAGxbCd6bcenf1lI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HAGxbCd6bcenf1lI .error-icon{fill:#552222;}#mermaid-svg-HAGxbCd6bcenf1lI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HAGxbCd6bcenf1lI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HAGxbCd6bcenf1lI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HAGxbCd6bcenf1lI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HAGxbCd6bcenf1lI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HAGxbCd6bcenf1lI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HAGxbCd6bcenf1lI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HAGxbCd6bcenf1lI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HAGxbCd6bcenf1lI .marker.cross{stroke:#333333;}#mermaid-svg-HAGxbCd6bcenf1lI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HAGxbCd6bcenf1lI p{margin:0;}#mermaid-svg-HAGxbCd6bcenf1lI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HAGxbCd6bcenf1lI .cluster-label text{fill:#333;}#mermaid-svg-HAGxbCd6bcenf1lI .cluster-label span{color:#333;}#mermaid-svg-HAGxbCd6bcenf1lI .cluster-label span p{background-color:transparent;}#mermaid-svg-HAGxbCd6bcenf1lI .label text,#mermaid-svg-HAGxbCd6bcenf1lI span{fill:#333;color:#333;}#mermaid-svg-HAGxbCd6bcenf1lI .node rect,#mermaid-svg-HAGxbCd6bcenf1lI .node circle,#mermaid-svg-HAGxbCd6bcenf1lI .node ellipse,#mermaid-svg-HAGxbCd6bcenf1lI .node polygon,#mermaid-svg-HAGxbCd6bcenf1lI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HAGxbCd6bcenf1lI .rough-node .label text,#mermaid-svg-HAGxbCd6bcenf1lI .node .label text,#mermaid-svg-HAGxbCd6bcenf1lI .image-shape .label,#mermaid-svg-HAGxbCd6bcenf1lI .icon-shape .label{text-anchor:middle;}#mermaid-svg-HAGxbCd6bcenf1lI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HAGxbCd6bcenf1lI .rough-node .label,#mermaid-svg-HAGxbCd6bcenf1lI .node .label,#mermaid-svg-HAGxbCd6bcenf1lI .image-shape .label,#mermaid-svg-HAGxbCd6bcenf1lI .icon-shape .label{text-align:center;}#mermaid-svg-HAGxbCd6bcenf1lI .node.clickable{cursor:pointer;}#mermaid-svg-HAGxbCd6bcenf1lI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HAGxbCd6bcenf1lI .arrowheadPath{fill:#333333;}#mermaid-svg-HAGxbCd6bcenf1lI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HAGxbCd6bcenf1lI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HAGxbCd6bcenf1lI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HAGxbCd6bcenf1lI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HAGxbCd6bcenf1lI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HAGxbCd6bcenf1lI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HAGxbCd6bcenf1lI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HAGxbCd6bcenf1lI .cluster text{fill:#333;}#mermaid-svg-HAGxbCd6bcenf1lI .cluster span{color:#333;}#mermaid-svg-HAGxbCd6bcenf1lI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HAGxbCd6bcenf1lI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HAGxbCd6bcenf1lI rect.text{fill:none;stroke-width:0;}#mermaid-svg-HAGxbCd6bcenf1lI .icon-shape,#mermaid-svg-HAGxbCd6bcenf1lI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HAGxbCd6bcenf1lI .icon-shape p,#mermaid-svg-HAGxbCd6bcenf1lI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HAGxbCd6bcenf1lI .icon-shape .label rect,#mermaid-svg-HAGxbCd6bcenf1lI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HAGxbCd6bcenf1lI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HAGxbCd6bcenf1lI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HAGxbCd6bcenf1lI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 外部信息
复杂内部任务
简单任务
低风险
高价值或高风险
用户
用户输入
LLM
任务分类
ReAct 工具循环
Plan-and-Solve
直接回答
候选答案
质量门禁
输出
Reflection 反思优化

取舍与风险

这三种范式不是越复杂越好。它们本质上是在不同位置给模型重新判断的机会。

范式 重新判断发生在哪里 代价
ReAct 每次工具返回后 工具调用多,上下文增长快
Plan-and-Solve 初始计划阶段 计划错了会系统性偏离
Reflection 初稿生成之后 延迟和模型调用成本增加

我的判断是:Agent 架构的核心问题不是模型够不够聪明,而是系统允许它在什么时候重新判断。能重新判断的地方越多,系统越灵活,但也越贵、越慢、越难控。

结论

ReAct 解决的是:我不知道外部世界,所以我要边查边想。

Plan-and-Solve 解决的是:任务太复杂,所以我要先拆路线。

Reflection 解决的是:初稿不够好,所以我要让系统学会改。

理解这三种循环,再去看 LangChain、LlamaIndex、AutoGen、CrewAI 或内部 Agent 平台,就不会只看到框架 API,而能看到它们背后的控制结构。

相关推荐
mldong3 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排4 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60614 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角5 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!5 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰6 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi7 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen8 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马8 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒9 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端