Skip to content

ReAct Agent vs DeepAgent:两种执行策略的深度对比

更新: 9/19/2026 字数: 0 字 时长: 0 分钟

开篇:为什么同样的任务,有的 Agent 又快又准,有的却"绕晕在半路"?

做 Agent 开发久了,你一定会碰到这样的分裂体验:

  • 用某个 Agent 查个天气、算个汇率、调一次 API,它反应飞快,一两轮就搞定;
  • 但一旦让它干"把这个 repo 重构一遍""写一份带调研的市场报告"这种大活,它就开始在决策链里打转——想一步、做一步、又忘了整体目标,几十轮下来上下文越堆越乱,最后跑偏或超时。

反过来,有的 Agent 处理复杂长任务稳如老狗,但你让它干个简单查询,它却小题大做:先列个五步计划、再拆子任务,一顿操作猛如虎,烧掉一堆 token 才回你一句本可以秒答的话。

这两种截然不同的"性格",背后正是两种主流的 Agent 执行策略:ReActDeepAgent。理解它们的差异,不是为了记概念,而是为了在实际项目里选对策略——用错了,轻则浪费 token 和延迟,重则任务根本跑不完。这篇文章,我们就从架构、实现到选型,把这两者彻底讲透。

一、ReAct:边想边做的"小步快跑"

ReAct:思考-行动-观察循环

ReAct(Reasoning + Acting,推理+行动)是目前最经典、最广泛使用的 Agent 范式。它的核心理念用一句话概括:把"思考"和"行动"交错进行,想一步、做一步、看一眼结果,再想下一步。[ReAct: Synergizing Reasoning and Acting in Language Models]

1.1 核心循环:Thought → Action → Observation

ReAct 的运行是一个紧凑的循环,前端开发者可以直接把它类比成一个 while 事件循环:

每一轮循环里,模型:

  1. Thought:基于当前已知信息,推理"下一步做什么"(比如"我需要先查一下这个城市的天气");
  2. Action:输出一个结构化的工具调用(比如 getWeather("北京"));
  3. Observation:运行时执行工具,把结果塞回上下文;
  4. 回到第 1 步,直到模型认为任务完成。

1.2 关键特征

  • 无全局规划:ReAct 不预先制定完整计划,而是走一步看一步。决策是"局部贪心"的——每一步只考虑眼下最该做什么;
  • 状态即上下文:它的"记忆"就是不断累积的对话历史(Thought/Action/Observation 依次追加),没有独立的状态存储;
  • 强反应性:能根据每一步的观察结果灵活调整方向,遇到工具报错也能当场"换个思路"。

优点:实现简单、响应快、对短任务极其高效、决策过程透明可追溯。缺点:任务一长,循环轮次暴增,历史上下文急剧膨胀,容易"中间迷失"、目标漂移,甚至陷入无效循环。

二、DeepAgent:先谋后动的"分层深耕"

DeepAgent:规划-分工-深度执行

DeepAgent(这里指以 Claude 的 Deep Agents、LangChain 的 deepagents 为代表的一类"深度智能体"架构)代表了另一种思路:先做完整规划,再分层、分工地深度执行。 它专为那种"步骤多、周期长、需要产出复杂交付物"的任务设计。

2.1 四大支柱

DeepAgent 通常由四个关键组件支撑,这套组合正是它能扛住复杂长任务的原因:

  • ① 显式规划(Planning):开工前先调用一个"规划工具",把任务拆成一份完整的 todo 清单,并在执行中持续更新。这相当于给 Agent 装了一个始终在线的"目标锚点",防止它跑着跑着忘了要干嘛;
  • ② 子代理(SubAgents):把子任务分派给专职的子 Agent 去做。每个子 Agent 有独立的上下文窗口,干完只把结论回传——这是上下文隔离,避免主 Agent 的上下文被细节撑爆;
  • ③ 虚拟文件系统:用一个共享的"文件系统"(可以是内存里的键值存储)存放中间产物、草稿、笔记,而不是把所有东西都堆在对话历史里;
  • ④ 详尽的系统提示:用一份很长、很结构化的 system prompt 规定角色、流程和规范。

2.2 关键特征

  • 规划先行:有明确的"先想清楚全局,再动手"阶段,决策是"全局导向"的;
  • 上下文隔离:通过子代理把不同子任务的上下文分开,主线程只保留高层信息,天然缓解长上下文问题;
  • 持久化状态:借助文件系统和 todo 清单,状态独立于对话历史存在,可以跨很多步骤稳定追踪。

优点:扛复杂任务能力强、长任务不易跑偏、上下文管理更优雅、产出质量高。缺点:架构复杂、实现和维护成本高、简单任务下"杀鸡用牛刀",token 和延迟开销大。

三、正面对比:两种策略到底差在哪

链式小步 vs 树式规划

最直观的差异:ReAct 是一条"链",DeepAgent 是一棵"树"。

ReAct 的执行轨迹是一条线性的链——想、做、看,想、做、看,一路走到底。DeepAgent 则是一棵树——先在根节点做整体规划,再向下分裂出多个子任务分支,每个分支可能又是一个小的执行过程。

快决策 vs 深规划

从决策-行动的节奏看,两者的哲学正好相反:

维度ReActDeepAgent
决策机制局部贪心,走一步看一步全局规划,先谋后动
执行结构线性链式循环分层树状(规划→子任务)
规划阶段无,隐式包含在每步思考里有显式的规划工具/阶段
状态管理累积在对话历史(单一上下文)独立文件系统 + todo 清单,上下文隔离
上下文压力长任务下急剧膨胀子代理隔离,主线程可控
工具调用每轮一次,即时反应主 Agent 调度 + 子 Agent 批量执行
适合任务短、中等、需即时反应长、复杂、多阶段交付物
实现复杂度
资源开销短任务省,长任务反而浪费短任务浪费,长任务更划算

四、实现方案与代码

下面用 TypeScript 实现三个核心模块,直观展示两种策略的差异点。

4.1 策略调度器:两种循环的骨架差异

先看共享的类型定义,再分别实现两种策略的执行器:

typescript
interface ToolCall { name: string; args: Record<string, unknown>; }
interface Message { role: 'system' | 'user' | 'assistant' | 'tool'; content: string; }

interface AgentStrategy {
  run(task: string, tools: ToolRegistry): Promise<string>;
}

// ===== 策略一:ReAct —— 单一循环,历史累积 =====
class ReActStrategy implements AgentStrategy {
  constructor(private llm: LLM, private maxSteps = 15) {}

  async run(task: string, tools: ToolRegistry): Promise<string> {
    const history: Message[] = [
      { role: 'system', content: 'You are a ReAct agent. Think step by step, then act.' },
      { role: 'user', content: task },
    ];

    for (let step = 0; step < this.maxSteps; step++) {
      // 每一轮:基于全部历史,让模型产出 Thought + Action
      const resp = await this.llm.chat(history, { tools: tools.schemas() });

      if (!resp.toolCall) {
        return resp.content; // 无工具调用 → 任务完成
      }
      // 执行工具 → Observation 回填历史(上下文持续膨胀)
      const observation = await tools.execute(resp.toolCall);
      history.push({ role: 'assistant', content: JSON.stringify(resp.toolCall) });
      history.push({ role: 'tool', content: JSON.stringify(observation) });
    }
    return '达到最大步数,任务未完成';
  }
}

// ===== 策略二:DeepAgent —— 先规划,再分派子任务 =====
class DeepAgentStrategy implements AgentStrategy {
  constructor(private llm: LLM, private fs: VirtualFS, private maxSteps = 8) {}

  async run(task: string, tools: ToolRegistry): Promise<string> {
    // 阶段 1:显式规划,生成 todo 清单
    const plan = await this.planning(task);
    this.fs.write('plan.json', JSON.stringify(plan));

    // 阶段 2:逐个子任务分派给子代理(独立上下文)
    for (const todo of plan.todos) {
      const subResult = await this.runSubAgent(todo, tools);
      this.fs.write(`result_${todo.id}.md`, subResult); // 产出存入文件系统
      todo.done = true;
    }

    // 阶段 3:主 Agent 汇总所有子结果(只读高层结论,不含细节)
    const results = plan.todos.map((t) => this.fs.read(`result_${t.id}.md`));
    return this.llm.chat([
      { role: 'system', content: '汇总以下各部分结果,产出最终交付物。' },
      { role: 'user', content: results.join('\n---\n') },
    ]).then((r) => r.content);
  }

  private async planning(task: string) {
    const resp = await this.llm.chat([
      { role: 'system', content: '把任务拆解成有序的 todo 清单,输出 JSON。' },
      { role: 'user', content: task },
    ]);
    return JSON.parse(resp.content) as { todos: { id: string; desc: string; done: boolean }[] };
  }

  // 子代理:独立上下文,内部其实又跑一个小 ReAct 循环
  private async runSubAgent(todo: { desc: string }, tools: ToolRegistry): Promise<string> {
    const subAgent = new ReActStrategy(this.llm, 6); // 上下文隔离的关键
    return subAgent.run(todo.desc, tools);
  }
}

差异一目了然:ReAct 是一个不断累积历史的循环;DeepAgent 是规划→分派→汇总的三段式,且子任务丢给独立的子代理执行(子代理内部可以复用 ReAct)。这也揭示了一个重要事实——DeepAgent 不是 ReAct 的替代品,而常常把 ReAct 作为它的"执行单元"包在里面。

4.2 工具调用适配器:统一两种策略的工具接口

无论哪种策略,工具调用都应统一抽象,方便切换:

typescript
type ToolFn = (args: Record<string, unknown>) => Promise<unknown>;

class ToolRegistry {
  private tools = new Map<string, { fn: ToolFn; schema: object }>();

  register(name: string, fn: ToolFn, schema: object) {
    this.tools.set(name, { fn, schema });
  }

  schemas(): object[] {
    return [...this.tools.values()].map((t) => t.schema);
  }

  async execute(call: ToolCall): Promise<unknown> {
    const tool = this.tools.get(call.name);
    if (!tool) return { error: `未知工具: ${call.name}` };
    try {
      // 带超时的工具执行,防止单点卡死
      return await Promise.race([
        tool.fn(call.args),
        new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 30000)),
      ]);
    } catch (err) {
      // 错误结构化返回:ReAct 会在下一轮"看到"并自我修正
      return { error: String(err), recoverable: true };
    }
  }
}

关键点:工具执行的错误不抛出,而是结构化返回。这对 ReAct 尤其重要——它能在下一轮 Observation 里"看到"错误,当场调整策略;对 DeepAgent,则由子代理消化错误,不污染主线程。

4.3 状态追踪管理器:单一上下文 vs 隔离状态

这是两种策略最本质的分野——如何管理"记忆":

typescript
// ReAct:状态 = 单一的线性历史
class ReActState {
  private history: Message[] = [];
  append(msg: Message) { this.history.push(msg); }
  getContext(): Message[] { return this.history; } // 全量传给模型,越来越长
}

// DeepAgent:状态 = todo 清单 + 虚拟文件系统(隔离 + 持久)
class DeepAgentState {
  private todos: { id: string; desc: string; done: boolean }[] = [];
  private fs = new Map<string, string>();

  setPlan(todos: typeof this.todos) { this.todos = todos; }
  updateTodo(id: string, done: boolean) {
    const t = this.todos.find((x) => x.id === id);
    if (t) t.done = done;
  }
  // 主线程只需高层视图,不含子任务的执行细节
  getHighLevelView(): string {
    const progress = this.todos.filter((t) => t.done).length;
    return `进度 ${progress}/${this.todos.length}:\n` +
      this.todos.map((t) => `[${t.done ? 'x' : ' '}] ${t.desc}`).join('\n');
  }
  writeFile(path: string, content: string) { this.fs.set(path, content); }
  readFile(path: string): string { return this.fs.get(path) ?? ''; }
}

看这里的对比:ReAct 的 getContext() 每次返回全量历史,任务越长它越臃肿;DeepAgent 的 getHighLevelView() 只给主线程一个精简的进度视图,具体细节都沉淀在文件系统里按需读取。这就是 DeepAgent 能扛住长任务的底层秘密——用状态外置和上下文隔离,对抗上下文膨胀。

五、拓展:适用场景、混合策略与趋势

5.1 选型:什么任务用什么策略

任务类型推荐策略理由
单次查询、简单问答、一两次工具调用ReAct快、省、够用,别过度设计
中等任务(3~10 步,需即时反应)ReAct灵活反应,实现简单
复杂长任务(代码库重构、深度调研报告)DeepAgent规划锚定目标、上下文隔离防迷失
需要多个专业角色协作DeepAgent子代理天然对应角色分工
结果需高可靠、可追溯交付物DeepAgenttodo 清单 + 文件系统利于追踪审计

5.2 混合策略:两者不是对立,而是嵌套

前面代码已经埋了伏笔:最实用的架构往往是"DeepAgent 做骨架,ReAct 做血肉"——用 DeepAgent 的规划层锚定全局目标、隔离上下文,每个子任务内部则用轻量 ReAct 循环灵活执行。这样既有全局把控,又保留局部灵活性。

更进一步是自适应策略调度:先用一个轻量分类判断任务复杂度,简单任务直接走 ReAct,复杂任务才启用 DeepAgent 的完整规划-分派流程,把资源花在刀刃上。

typescript
async function adaptiveDispatch(task: string, llm: LLM): Promise<AgentStrategy> {
  const complexity = await llm.chat([
    { role: 'system', content: '判断任务复杂度,只回 simple 或 complex' },
    { role: 'user', content: task },
  ]);
  return complexity.content.includes('complex')
    ? new DeepAgentStrategy(llm, new VirtualFS())
    : new ReActStrategy(llm);
}

5.3 前沿趋势

  • 自适应执行:Agent 根据任务实时在"快反应"和"深规划"之间动态切换,而非固定一种;
  • 多 Agent 协作:DeepAgent 的子代理思想正在向更松耦合的多 Agent 系统演进,不同 Agent 有独立记忆和角色,通过消息协作;
  • 上下文工程精细化:无论哪种策略,如何把有限的上下文"喂对",都成了比选策略本身更受关注的工程课题。

六、性能对比与选型 Checklist

各有所长:怎么选

性能特征速览

指标ReActDeepAgent
短任务延迟低 ✓高(规划开销)
长任务成功率中(易跑偏)高 ✓
Token 消耗(短任务)少 ✓
Token 消耗(长任务)反而多(历史膨胀)相对可控 ✓
开发/维护成本低 ✓
可观测/可调试性高(链路线性) ✓中(树状较复杂)

选型评估 Checklist

  • [ ] 任务步骤数:预计 <10 步 → 倾向 ReAct;>15 步或多阶段 → 倾向 DeepAgent;
  • [ ] 是否需要全局规划:任务成败依赖"先想清楚整体" → DeepAgent;
  • [ ] 上下文压力:是否会处理大量长文档/多来源资料 → DeepAgent 的隔离更稳;
  • [ ] 实时性要求:要求秒级响应的交互场景 → ReAct;
  • [ ] 交付物复杂度:需要结构化、可追溯的复杂产出 → DeepAgent;
  • [ ] 团队与成本:团队小、要快速上线 → 先上 ReAct,复杂了再演进。

性能测试指南

  1. 分档测试:分别用"简单/中等/复杂"三档任务集测两种策略,别只用一种难度;
  2. 核心指标:任务成功率、平均步数/轮次、总 token 消耗、端到端延迟、跑偏率;
  3. 对照实验:同一任务集跑两种策略,横向对比,别只看绝对值。

常见问题排查

现象排查方向
ReAct 陷入无限循环maxSteps 上限;检查工具错误是否被模型误读
ReAct 长任务跑偏/失忆上下文膨胀导致中间迷失 → 考虑切换 DeepAgent 或加摘要
DeepAgent 简单任务太慢/太贵规划阶段被滥用 → 加自适应调度,简单任务直接走 ReAct
DeepAgent 子任务结果对不上检查 todo 拆解粒度;子代理产出格式是否统一
两者都频繁工具报错工具适配器是否做了超时和结构化错误返回

一句话总结:ReAct 是"边想边做的短跑选手",DeepAgent 是"先谋后动的长跑教练"。 ReAct 用一条线性的"思考-行动-观察"循环,以简单、快速、灵活见长,是中短任务的首选;DeepAgent 用"显式规划 + 子代理 + 文件系统"的分层架构,靠上下文隔离和全局锚定扛住复杂长任务。二者并非对立——最成熟的工程实践,往往是用 DeepAgent 搭骨架、用 ReAct 填血肉,再加一层自适应调度,让每个任务都用上最划算的执行方式。选型的核心判断只有一个:你的任务,到底是"跑得快"重要,还是"想得全"重要。