智能体经典范式构建: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();
}
}
案例:找出 1 到 n 的所有素数。初版可能逐个试除,复杂度接近 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,而能看到它们背后的控制结构。