2026 年 AI Agent 开发架构全解:从 ReAct 到多智能体系统的实战指南

深入解析 AI Agent 核心架构模式,涵盖 ReAct、Plan-and-Execute、多智能体协作,附完整代码示例与性能对比,助你构建生产级 Agent 系统。

前端开发 2026-05-30 15 分钟

2026 年,AI Agent 已经从概念验证走向生产落地。据 LangChain 2026 Q1 报告,超过 68% 的企业 LLM 应用采用了某种形式的 Agent 架构,而非简单的单轮问答。但现实是——大多数 Agent 系统在生产环境中表现远不如 Demo,核心原因在于架构设计不合理。本文将从架构模式、工具编排、记忆管理三个维度,深入剖析如何构建真正可靠的 AI Agent 系统。

🏗️ 一、Agent 架构模式对比:选对架构是成功的一半

Agent 的核心问题是:如何让 LLM 有效决策并执行多步任务? 不同架构模式给出了截然不同的答案。

1.1 ReAct 模式:思考-行动循环

ReAct(Reasoning + Acting)是最经典的 Agent 架构。核心思想是让 LLM 在「思考」和「行动」之间交替循环,直到完成任务。

// ReAct Agent 核心循环
async function reactAgent(userQuery, tools, maxSteps = 10) {
  const messages = [
    { role: 'system', content: SYSTEM_PROMPT },
    { role: 'user', content: userQuery }
  ];

  for (let step = 0; step < maxSteps; step++) {
    // 调用 LLM 进行推理
    const response = await llm.chat(messages);
    const thought = extractThought(response);  // 提取思考过程
    const action = extractAction(response);    // 提取行动指令

    // 如果 LLM 认为任务完成,返回最终答案
    if (action.type === 'final_answer') {
      return action.content;
    }

    // 执行工具调用
    const toolResult = await executeTool(action.tool, action.input);

    // 将结果反馈给 LLM 继续推理
    messages.push({ role: 'assistant', content: response });
    messages.push({ role: 'tool', content: JSON.stringify(toolResult) });
  }

  throw new Error('Agent exceeded maximum steps');
}

优势: 实现简单,适合单轮工具调用场景。 劣势: 容易陷入循环,步骤多了容易「迷路」,上下文窗口消耗快。

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

Plan-and-Execute 将任务拆解为「规划」和「执行」两个独立阶段。Planner 负责生成任务计划,Executor 负责逐步执行,Re-planner 负责根据执行结果调整计划。

// Plan-and-Execute Agent
async function planAndExecuteAgent(userQuery, tools) {
  // 阶段 1:生成执行计划
  const plan = await planner.generate({
    query: userQuery,
    availableTools: tools.map(t => t.description)
  });
  // plan = [
  //   { id: 1, action: "搜索用户信息", tool: "search_user" },
  //   { id: 2, action: "获取订单历史", tool: "get_orders", depends: [1] },
  //   { id: 3, action: "生成分析报告", tool: "generate_report", depends: [1, 2] }
  // ]

  const results = {};

  // 阶段 2:按依赖关系执行
  for (const task of topologicalSort(plan)) {
    const context = task.depends.map(id => results[id]);
    results[task.id] = await executor.run(task, context);

    // 阶段 3:检查是否需要重新规划
    if (results[task.id].needsReplan) {
      const newPlan = await replanner.adjust(plan, results);
      return planAndExecuteAgent(userQuery, tools, newPlan);  // 递归重新执行
    }
  }

  return results;
}

⚠️ 警告: Plan-and-Execute 模式对 Planner 的能力要求很高。如果计划本身有缺陷,后续执行再精确也无济于济。建议在 Planner prompt 中加入 few-shot 示例。

1.3 三种模式对比

维度 ReAct Plan-and-Execute Multi-Agent
实现复杂度 ⭐⭐ 低 ⭐⭐⭐ 中 ⭐⭐⭐⭐ 高
任务分解能力 弱(隐式) 强(显式计划) 最强(专门角色)
上下文效率 低(全量传递) 中(分步传递) 高(隔离上下文)
错误恢复 弱(容易卡死) 中(可重新规划) 强(Agent 间监督)
Token 消耗 低(单 Agent 视角)
适用场景 简单工具调用 复杂多步任务 复杂协作任务
推荐指数 ✅ 入门首选 ✅ 生产首选 ⚠️ 高级场景

关键结论: 大多数生产场景推荐 Plan-and-Execute 模式。它在复杂度和可靠性之间取得了最佳平衡。ReAct 适合快速原型,Multi-Agent 适合需要专业分工的复杂场景。

🔧 二、工具编排与可靠性工程

Agent 的价值在于调用工具完成任务,但工具调用也是最容易出问题的环节。本节探讨如何构建可靠的工具编排层。

2.1 工具定义与类型安全

工具定义的质量直接决定了 LLM 能否正确调用。一个常见的坑是:工具描述写得太模糊,LLM 选错工具或传错参数。

// ❌ 错误写法:描述模糊,参数含义不清
const badTool = {
  name: "search",
  description: "搜索",
  parameters: {
    q: { type: "string" },
    n: { type: "number" }
  }
};

// ✅ 正确写法:清晰的描述、完整的参数说明、包含示例
const goodTool = {
  name: "search_users",
  description: "根据条件搜索用户信息。支持按姓名、邮箱、手机号搜索。返回匹配的用户列表,最多返回 50 条结果。",
  parameters: {
    query: {
      type: "string",
      description: "搜索关键词,支持模糊匹配。示例:'张三'、'zhangsan@email.com'、'13800138000'"
    },
    limit: {
      type: "number",
      description: "返回结果数量上限,默认 10,最大 50",
      default: 10,
      minimum: 1,
      maximum: 50
    },
    sort_by: {
      type: "string",
      enum: ["created_at", "name", "last_active"],
      description: "排序字段,默认按创建时间倒序",
      default: "created_at"
    }
  },
  // 返回值说明同样重要
  returns: {
    description: "用户列表,每个用户包含 id、name、email、phone、created_at 字段"
  }
};

💡 提示: 工具描述中加入「何时不该使用」的说明,能显著减少误调用。例如:「注意:此工具不支持搜索已删除的用户,如需搜索已删除用户请使用 search_deleted_users」。

2.2 工具调用的错误处理与重试

生产环境中,工具调用失败是常态而非异常。网络超时、API 限流、参数错误——每一种都需要妥善处理。

// 生产级工具执行器
class ToolExecutor {
  constructor(options = {}) {
    this.maxRetries = options.maxRetries ?? 3;
    this.timeout = options.timeout ?? 30000;
    this.circuitBreaker = new CircuitBreaker({
      failureThreshold: 5,
      resetTimeout: 60000
    });
  }

  async execute(toolName, params) {
    const tool = this.tools.get(toolName);
    if (!tool) {
      return { success: false, error: `Unknown tool: ${toolName}` };
    }

    // 参数校验
    const validation = tool.validate(params);
    if (!validation.valid) {
      return {
        success: false,
        error: `Invalid parameters: ${validation.errors.join(', ')}`,
        suggestion: `请检查参数格式。${validation.suggestion || ''}`
      };
    }

    // 熔断器检查
    if (this.circuitBreaker.isOpen(toolName)) {
      return {
        success: false,
        error: `Tool ${toolName} is temporarily unavailable (circuit breaker open)`,
        retryAfter: this.circuitBreaker.getRetryAfter(toolName)
      };
    }

    // 带重试的执行
    for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
      try {
        const result = await Promise.race([
          tool.run(params),
          this.createTimeout(this.timeout)
        ]);

        this.circuitBreaker.recordSuccess(toolName);
        return { success: true, data: result };

      } catch (error) {
        this.circuitBreaker.recordFailure(toolName);

        if (attempt === this.maxRetries) {
          return {
            success: false,
            error: `Tool execution failed after ${this.maxRetries} attempts: ${error.message}`,
            shouldRetryWithDifferentApproach: true  // 提示 Agent 换个方式
          };
        }

        // 指数退避
        await sleep(Math.pow(2, attempt) * 1000);
      }
    }
  }
}

📌 记住: 工具执行失败时,返回的错误信息要对 LLM 友好。不要返回原始的 stack trace,而是返回 LLM 能理解的自然语言错误描述和建议的修复方向。

2.3 并行工具调用优化

当任务涉及多个独立的工具调用时,串行执行会严重拖慢速度。合理利用并行调用可以大幅提升效率。

// 智能并行工具调度器
class ParallelToolScheduler {
  // 分析任务依赖关系,自动识别可并行的工具调用
  schedule(toolCalls) {
    const graph = new DependencyGraph();

    // 构建依赖图
    for (const call of toolCalls) {
      graph.addNode(call.id, call);
      for (const dep of call.dependsOn || []) {
        graph.addEdge(dep, call.id);
      }
    }

    // 拓扑排序 + 并行执行
    const levels = graph.topologicalLevels();
    const results = {};

    for (const level of levels) {
      // 同一层级的任务可以并行执行
      const levelResults = await Promise.allSettled(
        level.map(async (nodeId) => {
          const call = graph.getNode(nodeId);
          // 将依赖结果注入到参数中
          const resolvedParams = resolveParams(call.params, results);
          return { id: nodeId, result: await this.execute(call.tool, resolvedParams) };
        })
      );

      for (const result of levelResults) {
        if (result.status === 'fulfilled') {
          results[result.value.id] = result.value.result;
        } else {
          // 单个失败不应阻塞整个流程
          results[result.reason.id] = { error: result.reason.message };
        }
      }
    }

    return results;
  }
}

// 使用示例
const toolCalls = [
  { id: 'user', tool: 'get_user', params: { id: 123 }, dependsOn: [] },
  { id: 'orders', tool: 'get_orders', params: { userId: 123 }, dependsOn: [] },
  { id: 'recommendations', tool: 'get_recommendations', params: { userId: 123 }, dependsOn: [] },
  { id: 'report', tool: 'generate_report', params: {}, dependsOn: ['user', 'orders', 'recommendations'] }
];

// user、orders、recommendations 并行执行,report 等待三者完成后执行

关键结论: 并行执行可以将 3 个独立 API 调用的总耗时从 3 秒降低到 1 秒左右。但要注意设置合理的并发上限(建议 5-10),避免触发下游 API 的限流。

🧠 三、记忆管理与上下文工程

Agent 的「智能」很大程度上取决于它能「记住」什么。记忆管理是 Agent 架构中最被低估的环节。

3.1 三层记忆架构

生产级 Agent 通常需要三层记忆:

  1. 工作记忆(Working Memory) — 当前对话的上下文,存在于 messages 数组中
  2. 短期记忆(Short-term Memory) — 跨多轮对话的摘要信息,存储在内存或 Redis 中
  3. 长期记忆(Long-term Memory) — 用户偏好、历史交互模式,存储在向量数据库中
// 三层记忆管理器
class AgentMemoryManager {
  constructor(options) {
    this.workingMemory = [];                    // 当前对话 messages
    this.shortTermStore = new RedisStore();     // 短期记忆(TTL 24h)
    this.longTermStore = new VectorStore();     // 长期记忆(持久化)
    this.maxWorkingTokens = options.maxTokens ?? 8000;
  }

  // 获取完整上下文(组装三层记忆)
  async getContext(userId, currentQuery) {
    // 1. 工作记忆:当前对话
    const working = this.workingMemory;

    // 2. 短期记忆:最近的对话摘要
    const shortTerm = await this.shortTermStore.get(`session:${userId}`);

    // 3. 长期记忆:语义搜索相关的历史记忆
    const relevantMemories = await this.longTermStore.similaritySearch({
      query: currentQuery,
      userId,
      topK: 5,
      minScore: 0.7
    });

    // 组装上下文,控制总 token 数
    return this.assembleContext(working, shortTerm, relevantMemories);
  }

  // 对话结束后,提取关键信息存入记忆
  async consolidateMemory(userId, conversation) {
    // 用 LLM 提取关键信息
    const summary = await llm.chat({
      messages: [{
        role: 'system',
        content: '从以下对话中提取关键信息,包括:用户偏好、重要决策、待办事项、关键事实。以 JSON 格式返回。'
      }, {
        role: 'user',
        content: JSON.stringify(conversation)
      }]
    });

    // 存入短期记忆
    await this.shortTermStore.set(`session:${userId}`, summary, { ttl: 86400 });

    // 提取值得长期保存的信息
    const longTermFacts = extractLongTermFacts(summary);
    for (const fact of longTermFacts) {
      await this.longTermStore.upsert({
        userId,
        content: fact.content,
        embedding: await embed(fact.content),
        metadata: { type: fact.type, timestamp: Date.now() }
      });
    }
  }
}

3.2 上下文窗口管理策略

当对话变长时,上下文窗口会被耗尽。简单的截断策略会丢失重要信息,更好的方法是智能压缩

// ❌ 错误写法:直接截断最旧的消息
function naiveTruncate(messages, maxTokens) {
  let total = countTokens(messages);
  while (total > maxTokens) {
    messages.shift();  // 丢弃最旧的消息,可能丢失关键信息
    total = countTokens(messages);
  }
  return messages;
}

// ✅ 正确写法:分层压缩策略
async function smartCompress(messages, maxTokens) {
  let total = countTokens(messages);
  if (total <= maxTokens) return messages;

  // 第 1 步:压缩工具调用结果(通常占最多 token)
  for (const msg of messages) {
    if (msg.role === 'tool' && countTokens(msg.content) > 500) {
      msg.content = await summarize(msg.content, maxTokens = 200);
    }
  }

  // 第 2 步:将中间轮次的对话压缩为摘要
  if (countTokens(messages) > maxTokens) {
    const systemMsg = messages[0];      // 保留 system prompt
    const recentMsgs = messages.slice(-6);  // 保留最近 6 条
    const middleMsgs = messages.slice(1, -6);  // 中间部分压缩

    const summary = await summarize(middleMsgs);
    messages = [
      systemMsg,
      { role: 'system', content: `[对话历史摘要]\n${summary}` },
      ...recentMsgs
    ];
  }

  // 第 3 步:如果仍然超限,只保留最近 4 条
  if (countTokens(messages) > maxTokens) {
    messages = [messages[0], ...messages.slice(-4)];
  }

  return messages;
}

💡 提示: 在压缩对话时,一定要保留 tool_call_id 的对应关系。如果压缩掉了工具调用的请求,但保留了响应,会导致 API 报错。建议使用专门的消息配对管理器。

3.3 记忆的检索增强生成(RAG)

长期记忆的最佳实践是结合向量搜索,让 Agent 在需要时自动检索相关信息。

// 带 RAG 的 Agent 记忆检索
async function retrieveRelevantContext(userId, query, conversationHistory) {
  // 多路召回策略
  const [semanticResults, keywordResults, recentResults] = await Promise.all([
    // 语义搜索:理解意图
    vectorStore.similaritySearch({
      embedding: await embed(query),
      filter: { userId },
      topK: 5
    }),
    // 关键词搜索:精确匹配
    keywordStore.search({
      keywords: extractKeywords(query),
      filter: { userId },
      topK: 3
    }),
    // 时间衰减:最近的记忆权重更高
    vectorStore.timeDecaySearch({
      userId,
      halfLife: 7 * 24 * 3600,  // 7 天半衰期
      topK: 3
    })
  ]);

  // 合并去重 + 重排序
  const merged = deduplicate([...semanticResults, ...keywordResults, ...recentResults]);
  const reranked = await rerank(merged, query, { topK: 5 });

  return reranked.map(r => ({
    content: r.content,
    relevance: r.score,
    timestamp: r.metadata.timestamp,
    type: r.metadata.type
  }));
}

关键结论: 记忆管理的核心原则是「宁可少,不可错」。低质量的记忆(过时信息、错误事实)比没有记忆更有害。建议对长期记忆设置置信度阈值(0.7+),并定期清理过时记忆。

🚀 四、生产部署:从 Demo 到上线的最后一公里

Agent 系统从 Demo 到生产,需要解决可观测性、成本控制和安全性三个关键问题。

4.1 可观测性:知道 Agent 在想什么

// Agent 执行追踪器
class AgentTracer {
  async trace(execution) {
    const trace = {
      id: generateId(),
      startTime: Date.now(),
      userId: execution.userId,
      query: execution.query,
      steps: [],
      tokenUsage: { input: 0, output: 0, total: 0 },
      totalCost: 0
    };

    // Hook into each step
    execution.on('step', (step) => {
      trace.steps.push({
        type: step.type,          // 'thought' | 'tool_call' | 'observation'
        content: step.content,
        tool: step.tool,
        duration: step.duration,
        tokens: step.tokens
      });
      trace.tokenUsage.input += step.tokens.input;
      trace.tokenUsage.output += step.tokens.output;
      trace.totalCost += calculateCost(step.tokens, step.model);
    });

    execution.on('error', (error) => {
      trace.error = { message: error.message, step: trace.steps.length };
    });

    execution.on('complete', (result) => {
      trace.endTime = Date.now();
      trace.duration = trace.endTime - trace.startTime;
      trace.result = result;
    });

    // 写入可观测性平台(OpenTelemetry / 自建)
    await this.export(trace);
    return trace;
  }
}

⚠️ 警告: 生产环境中,务必对 Agent 的工具调用设置权限边界。不要让 Agent 拥有无限制的数据库写入权限或 API 调用权限。使用最小权限原则,每个工具只授予必要的权限。

4.2 成本控制实战

Agent 的 Token 消耗是普通 LLM 调用的 5-20 倍。成本控制至关重要。

策略 节省比例 实现难度 推荐度
工具结果压缩 30-50% ⭐ 低 ✅ 强烈推荐
小模型做简单任务 40-60% ⭐⭐ 中 ✅ 推荐
缓存高频工具调用 20-40% ⭐ 低 ✅ 推荐
限制最大步骤数 10-20% ⭐ 低 ✅ 必须做
语义缓存 LLM 响应 15-30% ⭐⭐⭐ 高 ⚠️ 场景依赖
// 多模型路由:根据任务复杂度选择模型
async function routeToModel(task) {
  const complexity = await classifyComplexity(task);

  if (complexity === 'simple') {
    // 简单任务用小模型,成本降低 90%
    return { model: 'deepseek-chat', maxTokens: 1024 };
  } else if (complexity === 'medium') {
    return { model: 'deepseek-chat', maxTokens: 4096 };
  } else {
    // 复杂推理任务才用大模型
    return { model: 'deepseek-reasoner', maxTokens: 8192 };
  }
}

✅ 总结与最佳实践清单

构建生产级 AI Agent 系统,核心要点如下:

  • 架构选型: 大多数场景选 Plan-and-Execute,不要上来就搞 Multi-Agent
  • 工具设计: 描述清晰、参数完整、错误信息对 LLM 友好
  • 并行执行: 独立工具调用并行化,但设置并发上限
  • 记忆管理: 三层记忆架构,宁缺毋滥
  • 上下文压缩: 工具结果优先压缩,保留最近对话
  • 成本控制: 多模型路由 + 工具缓存 + 步骤限制
  • 可观测性: 全链路追踪,每次执行都要有 trace
  • 安全边界: 最小权限原则,工具调用必须有权限控制

💡 提示: 推荐使用 MCP(Model Context Protocol) 标准化工具定义和调用,可以获得更好的跨模型兼容性。配合 jsjson.com 开发者工具 进行 JSON 格式化、API 调试等日常开发工作,提升 Agent 开发效率。

构建可靠的 AI Agent 不是一蹴而就的事情。从简单的 ReAct 模式开始,逐步迭代到 Plan-and-Execute,再根据业务需要引入多智能体协作——这是最稳妥的演进路径。记住,Agent 的价值不在于它能做多复杂的事,而在于它能可靠地完成多少事。

📚 相关文章