欢迎光临
我们一直在努力

AI Agent 三大核心架构精讲:ReAct / CodeAct / Plan-and-Execute 原理 + 手撕源码

文章目录

  • AI Agent 三大核心架构精讲:ReAct / CodeAct / Plan-and-Execute 原理 + 手撕源码
  • 前言:从"调用工具"到"自主决策",Agent 架构的三次进化
  • 一、ReAct 完整原理剖析
    • 1.1 Agent 的"原始痛点":为什么需要 ReAct
    • 1.2 标准循环三段式(论文核心结构)
    • 1.3 原生论文实现 vs 现代 Function Calling(关键时间线)
  • 二、CodeAct 完整原理剖析
    • 2.1 来源与核心思想
    • 2.2 CodeAct 四大核心优势
      • 优势 1:无限制动作空间
      • 优势 2:工具自由组合,大幅减少交互轮次
      • 优势 3:自带纠错能力
      • 优势 4:表达能力更强
    • 2.3 CodeAct 的短板
  • 三、Plan-and-Execute 原理剖析
    • 3.1 核心思想
    • 3.2 适用场景
    • 3.3 DAG 调度模式
  • 四、ReAct 完整源码手撕
    • 4.1 项目结构
    • 4.2 项目配置
    • 4.3 LLM 封装层(`src/llm.ts`)
    • 4.4 工具定义层(`src/tools.ts`)
    • 4.5 Agent 核心循环(`src/agent.ts`)—— 重中之重
    • 4.6 入口文件(`src/index.ts`)
    • 4.7 运行效果
  • 五、CodeAct 重要源码讲解
    • 5.1 项目结构
    • 5.2 沙箱模块(`src/sandbox.ts`)—— CodeAct 的心脏
    • 5.3 Agent 核心循环(`src/agent.ts`)—— 与 ReAct 的本质区别
  • 六、Plan-and-Execute 重要源码讲解
    • 6.1 项目结构
    • 6.2 规划器(`src/planner.ts`)—— 任务拆解引擎
    • 6.3 执行器(`src/executor.ts`)—— DAG 调度核心
    • 6.4 Agent 核心(`src/agent.ts`)
    • 6.5 运行效果
  • 七、三大模式全景对比
    • 7.1 核心维度对比
    • 7.2 实战数据对比(同一计算题:小明买书买笔)
  • 八、业务场景选型指南
    • 8.1 ReAct 最佳场景:不确定路径的动态任务
    • 8.2 CodeAct 最佳场景:批量数据处理
    • 8.3 Plan-and-Execute 最佳场景:标准化长链路任务
  • 九、延伸拓展
    • 9.1 从单模式到混合模式
    • 9.2 基于三者可扩展的完整 Agent 系统
    • 9.3 其他值得关注的 Agent 架构
  • 十、总结

AI Agent 三大核心架构精讲:ReAct / CodeAct / Plan-and-Execute 原理 + 手撕源码


前言:从"调用工具"到"自主决策",Agent 架构的三次进化

2022 年 10 月,一篇名为《ReAct: Synergizing Reasoning and Acting in Language Models》的论文横空出世,首次将推理(Reasoning) 和行动(Acting) 融合为一个闭环,Agent 从此不再是"只会调用工具的机器人",而是能边思考边行动的智能体。

两年后,Apple 机器学习团队提出 CodeAct,把"调用预定义工具"升级为"直接生成代码并执行",突破了工具数量的天花板。与此同时,LangChain 社区将 Plan-and-Execute 模式封装为 DAG 调度引擎,让长链路任务变得可控、可监控、可重试。

直至今日,这三种模式,依旧构成了现代 AI Agent 架构的三大基石。本文将从论文原理 + 完整源码 + 实战拆解三个维度,以加减乘除计算器为统一案例,带你彻底搞懂它们。之所以选择计算器而不是复杂业务,是为了让你聚焦 Agent 的循环逻辑本身,不被业务代码干扰。一旦吃透核心循环,无论是反诈风险研判、报表运算还是文档解析流水线,都是换壳而已。


一、ReAct 完整原理剖析

1.1 Agent 的"原始痛点":为什么需要 ReAct

在 ReAct 出现之前,大模型解决复杂问题有两种主流方案,但各有致命缺陷:

方案做法致命缺陷
纯推理(CoT 思维链) 让模型一步步思考 只会脑补,无法联网/调用工具,知识过时易幻觉
纯工具调用(如早期 WebGPT) 让模型搜索/调用 API 只会无脑搜索,没有逻辑规划,无法串联多轮结果

论文经典案例:问模型"除了 Apple Remote,还有什么设备能控制它管理的设备?"

  • 纯模型:直接输出"iPad"——纯幻觉,完全错误
  • 纯 CoT:思考文本变长,但无外部数据支撑,推导不出正确答案
  • 纯搜索:只会搜"Apple Remote",无法关联多条搜索结果
  • ReAct:第一轮搜索 Apple Remote 基础信息 → 发现配套软件 Front Row → 第二轮搜索 Front Row → 第三轮搜索 Front Row software → 观测维基百科结果,发现键盘也可控制 → 得出正确答案

这就是 ReAct 的核心价值:把推理和行动串成一个闭环,让模型在思考中行动,在行动中思考。

1.2 标准循环三段式(论文核心结构)

ReAct 的每一轮交互固定包含三个部分,多轮循环直到模型认为不需要工具、可以直接输出答案:

Thought(思考)→ Action(行动)→ Observation(观察)
^ |
+——- 循环直到完成 —————-+

  • Thought(思考):大模型输出推理逻辑,规划需要调用什么工具、调用顺序
  • Action(行动):输出工具调用指令,执行具体操作
  • Observation(观察):外部工具执行后的返回结果,追加到上下文,送入下一轮模型推理
  • 1.3 原生论文实现 vs 现代 Function Calling(关键时间线)

    这是一个非常重要的知识点,很多人都搞混了:

    维度原生 ReAct(2022.10)现代 Function Calling 版
    时间 2022 年 10 月 6 日 2023 年 6 月 13 日(OpenAI 发布 Function Calling)
    实现方式 纯文本提示词约束模型输出固定格式 利用 Function Calling 的 JSON Schema 结构化输出
    解析方式 字符串暴力分割 Thought/Action 直接取 tool_calls 字段
    稳定性 模型服从度差时格式混乱,解析失败率高 结构化输出,解析准确率接近 100%
    代表实现 LangChain 早期版本 LangChain 现代版、本文实战代码

    一句话总结:原版 ReAct 论文发表时还没有 Function Calling,所以只能靠提示词工程约束模型输出。现代实现直接利用 Function Calling 的 tool_calls 机制,稳定性和准确率大幅提升。


    二、CodeAct 完整原理剖析

    2.1 来源与核心思想

    CodeAct(Code + Acting) 由 Apple 机器学习团队提出,Apple 的 Menas 产品底层就采用了这个思路。其核心是让模型自主编写代码来解决开放式任务,而非调用预定义工具。

    概念区分:市面上还有更广义的"Code Agent"概念(泛指一切能生成代码的 Agent),与 Apple 论文中定义的 CodeAct 并不完全等同。本文讨论的 CodeAct 特指 Apple 论文中的"Code as Action"模式。

    核心改进:把 ReAct 中"调用预定义工具"替换为大模型直接生成完整代码,在安全沙箱中运行。

    ReAct 的 Action: 调用 calculator({operation: "add", a: 1, b: 2})
    CodeAct 的 Action: 生成并执行一段 JavaScript 代码 → console.log(1 + 2)

    2.2 CodeAct 四大核心优势

    优势 1:无限制动作空间

    ReAct 必须提前手动定义全部工具,想加一个 avg 计算就得写一个新工具。CodeAct 直接用编程语言标准库,for 循环、if 判断、map 遍历,想写什么写什么,无需额外封装。

    优势 2:工具自由组合,大幅减少交互轮次

    这是最核心的优势。看一个对比:

    ReAct 做复合计算(小明买书买笔):

    第 1 轮: 调用 calculator (3 × 12 = 36)
    第 2 轮: 调用 calculator (2 × 5 = 10)
    第 3 轮: 调用 calculator (36 + 10 = 46)
    第 4 轮: 调用 calculator (50 – 46 = 4)
    → 4 次工具调用,5 轮交互

    CodeAct 做同样的计算:

    const bookCost = multiply(3, 12); // 36
    const penCost = multiply(2, 5); // 10
    const totalCost = add(bookCost, penCost); // 46
    const remaining = subtract(50, totalCost); // 4
    console.log(`小明还剩 ${remaining}`);
    console.log(`花费占比: ${(totalCost / 50 * 100).toFixed(1)}%`);

    → 1 次代码执行,2 轮交互,效率提升 4 倍

    优势 3:自带纠错能力

    代码运行报错 → 错误信息作为 Observation 传入下一轮 → 模型自动修复代码。这个闭环和程序员写代码、跑测试、修 bug 的流程一模一样。

    优势 4:表达能力更强

    支持循环、条件判断、绘图、数据处理等复杂逻辑。比如"计算数组 [12,24,36,48,60] 的总和与平均值",ReAct 需要多次调用或专门写一个工具,CodeAct 一段 for 循环搞定。

    2.3 CodeAct 的短板

  • 对模型代码生成能力要求高:2022 年早期大模型代码能力不足,所以当时优先流行 ReAct;现代代码大模型下 CodeAct 效果更好
  • 代码块提取依赖正则:需要从模型输出中解析代码块,格式不稳定时可能失败
  • 安全风险:代码执行必须放在沙箱中,生产环境绝不能直接 eval

  • 三、Plan-and-Execute 原理剖析

    3.1 核心思想

    Plan-and-Execute = Plan(规划)+ Execute(执行),核心思想是:把复杂任务先拆解为子任务 DAG(有向无环图),再按依赖关系有序执行。

    ReAct: 边走边看,下一步做什么取决于上一步结果
    Plan-and-Execute: 先画好地图,再按图索骥

    3.2 适用场景

    Plan-and-Execute 最适合标准化、长链路任务,特点是:

  • 任务步骤可预知:可以先规划好再执行
  • 步骤间有依赖关系:后面的步骤依赖前面的结果
  • 需要监控和重试:每步可独立监控,失败可单步重试
  • 需要可控性:知道当前进度、哪些步骤已完成
  • 典型场景:

    • 批量文档解析流水线(下载 → 解析 → 提取 → 入库 → 通知)
    • 反诈风险研判的多维度分析(身份核验 → 行为分析 → 关系图谱 → 风险评估)
    • 财务报表生成(数据采集 → 清洗 → 计算 → 汇总 → 导出)

    3.3 DAG 调度模式

    Plan-and-Execute 的核心是 DAG(有向无环图)调度,以"小明买书买笔"为例:

    step1: 3 x 12 = 36 –+
    step2: 2 x 5 = 10 –+–> step3: 36 + 10 = 46 –> step4: 50 – 46 = 4

    关键设计:step1 和 step2 无依赖 → 可并行执行;step3 依赖 step1 和 step2 → 等两者都完成;step4 依赖 step3 → 顺序执行。

    说明:本文实现为静态规划版本(一次性生成完整 DAG,全程不修改任务)。进阶方案支持执行失败或中途发现新信息时,调用 LLM 重新调整任务 DAG,即动态 Plan-and-Execute——这也是原始论文的核心思路:先规划,执行过程中允许动态修正计划。


    四、ReAct 完整源码手撕

    以下为 ReAct Agent 的完整 TypeScript 实现。项目结构按文件夹组织,共 5 个文件。

    4.1 项目结构

    react-agent/
    – package.json # 项目配置与依赖
    – tsconfig.json # TypeScript 编译配置
    – .env.example # 环境变量模板
    – src/
    – llm.ts # LLM 封装层(对接 DeepSeek API)
    – tools.ts # 工具定义层(计算器 + 注册中心)
    – agent.ts # Agent 核心循环(Thought->Action->Observation)
    – index.ts # 入口文件 + 测试用例

    4.2 项目配置

    package.json —— 核心依赖:openai(LLM 调用)、zod(参数校验)、zod-to-json-schema(生成工具 Schema):

    {
    "name": "react-agent",
    "version": "1.0.0",
    "description": "ReAct (Reasoning + Acting) Agent 手撕实现",
    "type": "module",
    "scripts": {
    "dev": "tsx src/index.ts"
    },
    "dependencies": {
    "openai": "^4.73.0",
    "zod": "^3.23.8",
    "zod-to-json-schema": "^3.23.5",
    "dotenv": "^16.4.5"
    },
    "devDependencies": {
    "@types/node": "^22.0.0",
    "tsx": "^4.19.0",
    "typescript": "^5.5.0"
    }
    }

    tsconfig.json:

    {
    "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "skipLibCheck": true
    },
    "include": ["src/**/*.ts"]
    }

    .env.example:

    DEEPSEEK_API_KEY=your-api-key-here
    DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
    DEEPSEEK_MODEL=deepseek-chat

    4.3 LLM 封装层(src/llm.ts)

    这是整个 Agent 的"大脑接口",负责和 DeepSeek API 通信。关键设计:temperature: 0 保证确定性,tool_choice: "auto" 让模型自主判断是否需要调用工具。

    import OpenAI from "openai";
    import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";

    export interface LLMConfig {
    apiKey: string;
    baseURL: string;
    model: string;
    }

    /** 创建 OpenAI 兼容的 LLM 客户端(支持 DeepSeek 等任意兼容接口) */
    export function createLLMClient(config: LLMConfig): OpenAI {
    return new OpenAI({
    apiKey: config.apiKey,
    baseURL: config.baseURL,
    });
    }

    /**
    * 封装一次 LLM 调用
    * @param client OpenAI 客户端
    * @param model 模型名称
    * @param messages 对话历史
    * @param tools 工具定义(OpenAI Function Calling 格式)
    * @returns LLM 返回的消息
    */

    export async function chat(
    client: OpenAI,
    model: string,
    messages: ChatCompletionMessageParam[],
    tools?: OpenAI.Chat.Completions.ChatCompletionTool[],
    ): Promise<OpenAI.Chat.Completions.ChatCompletionMessage> {
    const response = await client.chat.completions.create({
    model,
    messages,
    tools, // ← 关键:传入工具定义
    temperature: 0, // 工具调用场景必须保证确定性
    tool_choice: tools ? "auto" : undefined, // 让模型自己决定是否调用工具
    });

    const choice = response.choices[0];
    if (!choice) {
    throw new Error("LLM 返回了空响应");
    }
    return choice.message;
    }

    设计要点:

    • temperature: 0:工具调用场景必须保证确定性,不能用随机性
    • tool_choice: "auto":让模型自主判断是否需要调用工具,而不是强制调用
    • 类比 Java 后端:相当于 RestTemplate 封装 HTTP 调用,只是这里封装的是 LLM 调用

    4.4 工具定义层(src/tools.ts)

    每个工具是 Zod 参数 Schema + execute 执行逻辑 + 注册到 ToolRegistry 的高内聚模块。

    import { z } from "zod";
    import { zodToJsonSchema } from "zod-to-json-schema";
    import type OpenAI from "openai";

    // ============================================================
    // 工具类型定义
    // ============================================================

    export interface ToolExecutionContext {
    signal?: AbortSignal;
    }

    export interface ToolDefinition {
    name: string;
    description: string;
    parameters: z.ZodObject<any>;
    execute: (args: Record<string, any>, ctx: ToolExecutionContext) => Promise<string>;
    toOpenAITool: () => OpenAI.Chat.Completions.ChatCompletionTool;
    }

    // ============================================================
    // 工具工厂函数
    // ============================================================

    /**
    * 创建一个工具定义
    * 参考 GitHub: @lamemind/react-agent-ts 中的 DynamicTool 模式
    */

    export function createTool(config: {
    name: string;
    description: string;
    parameters: z.ZodObject<any>;
    execute: (args: Record<string, any>, ctx: ToolExecutionContext) => Promise<string>;
    }): ToolDefinition {
    return {
    name: config.name,
    description: config.description,
    parameters: config.parameters,
    execute: config.execute,
    toOpenAITool() {
    return {
    type: "function" as const,
    function: {
    name: this.name,
    description: this.description,
    parameters: zodToJsonSchema(this.parameters),
    },
    };
    },
    };
    }

    // ============================================================
    // 计算器工具:加减乘除
    // ============================================================

    /**
    * 完整的四则运算工具
    * – Zod schema 定义参数结构,模型必须按这个格式传参
    * – execute 做实际计算,返回字符串结果
    * – 支持 add、subtract、multiply、divide 四种运算
    */

    export const calculatorTool = createTool({
    name: "calculator",
    description:
    "执行四则运算。支持加(add)、减(subtract)、乘(multiply)、除(divide)四种运算。" +
    "当你需要进行数学计算时,请使用此工具。",
    parameters: z.object({
    operation: z
    .enum(["add", "subtract", "multiply", "divide"])
    .describe("运算类型:add=加, subtract=减, multiply=乘, divide=除"),
    a: z.number().describe("第一个操作数"),
    b: z.number().describe("第二个操作数"),
    }),
    async execute(args, _ctx) {
    const { operation, a, b } = args as {
    operation: "add" | "subtract" | "multiply" | "divide";
    a: number;
    b: number;
    };

    let result: number;
    switch (operation) {
    case "add":
    result = a + b;
    break;
    case "subtract":
    result = a b;
    break;
    case "multiply":
    result = a * b;
    break;
    case "divide":
    if (b === 0) {
    return "错误:除数不能为零";
    }
    result = a / b;
    break;
    default:
    return `错误:不支持的运算类型 '${operation}'`;
    }

    return `${a} ${getOperationSymbol(operation)} ${b} = ${result}`;
    },
    });

    function getOperationSymbol(op: string): string {
    switch (op) {
    case "add": return "+";
    case "subtract": return "-";
    case "multiply": return "×";
    case "divide": return "÷";
    default: return "?";
    }
    }

    // ============================================================
    // 工具注册表:统一管理所有工具
    // 类比 Java 后端:一个 Map<String, Service> 的注册中心
    // ============================================================

    export class ToolRegistry {
    private tools: Map<string, ToolDefinition> = new Map();

    register(tool: ToolDefinition): void {
    this.tools.set(tool.name, tool);
    }

    get(name: string): ToolDefinition | undefined {
    return this.tools.get(name);
    }

    /** 获取所有工具的 OpenAI Function Calling 格式 */
    toOpenAITools(): OpenAI.Chat.Completions.ChatCompletionTool[] {
    return Array.from(this.tools.values()).map((t) => t.toOpenAITool());
    }

    /** 列出所有工具名称 */
    listNames(): string[] {
    return Array.from(this.tools.keys());
    }
    }

    设计要点:

    • Zod 校验:z.object({…}) 定义参数结构,自动校验模型传入的参数是否合法
    • zod-to-json-schema:将 Zod Schema 自动转为 OpenAI Function Calling 需要的 JSON Schema
    • ToolRegistry:一个 Map<String, ToolDefinition> 的注册中心,类比 Java 后端的服务注册中心
    • createTool 工厂函数:参考 LangChain 的 DynamicStructuredTool 设计,让工具定义更简洁

    4.5 Agent 核心循环(src/agent.ts)—— 重中之重

    一个 while 循环驱动"思考→行动→观察"的闭环:

    import type OpenAI from "openai";
    import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";
    import { chat } from "./llm.js";
    import type { ToolRegistry } from "./tools.js";

    // ============================================================
    // 类型定义
    // ============================================================

    export interface ReActResult {
    /** 最终答案 */
    answer: string;
    /** 执行了多少轮循环 */
    turns: number;
    /** 调用了多少次工具 */
    toolCalls: number;
    /** 完整的对话历史(用于调试和日志) */
    history: ChatCompletionMessageParam[];
    }

    export interface ReActConfig {
    client: OpenAI;
    model: string;
    tools: ToolRegistry;
    /** 最大循环轮次(防止死循环) */
    maxTurns?: number;
    /** 系统提示词 */
    systemPrompt?: string;
    /** 是否打印详细日志 */
    verbose?: boolean;
    }

    // ============================================================
    // ReAct Agent 核心
    // ============================================================

    /**
    * ReAct Agent
    *
    * 核心流程(while 循环):
    * 1. Thought(思考): 模型分析当前状态,决定下一步
    * 2. Action(行动): 需要工具则调用,不需要则直接输出答案
    * 3. Observation(观察): 工具结果注入上下文 → 回到步骤 1
    */

    export class ReActAgent {
    private client: OpenAI;
    private model: string;
    private tools: ToolRegistry;
    private maxTurns: number;
    private systemPrompt: string;
    private verbose: boolean;

    constructor(config: ReActConfig) {
    this.client = config.client;
    this.model = config.model;
    this.tools = config.tools;
    this.maxTurns = config.maxTurns ?? 10;
    this.verbose = config.verbose ?? false;
    this.systemPrompt =
    config.systemPrompt ??
    `你是一个能够使用工具的 AI 助手。

    你需要按照 ReAct(Reasoning + Acting)模式工作:
    1. 思考(Thought):分析用户问题,判断是否需要使用工具
    2. 行动(Action):如果需要工具,调用对应工具;如果不需要,直接回答
    3. 观察(Observation):根据工具返回结果,继续思考或给出最终答案

    重要规则:
    – 当你能直接给出答案时,不要再调用工具
    – 每次工具调用的结果会作为 Observation 反馈给你
    – 你的回答应该清晰、准确,使用中文`;
    }

    /**
    * 执行 Agent
    * @param question 用户问题
    * @returns 执行结果
    */

    async run(question: string): Promise<ReActResult> {
    // 初始化对话历史
    const messages: ChatCompletionMessageParam[] = [
    { role: "system", content: this.systemPrompt },
    { role: "user", content: question },
    ];

    let turnCount = 0;
    let toolCallCount = 0;
    const openAITools = this.tools.toOpenAITools();

    this.log(`\\n ReAct Agent 启动`);
    this.log(` 用户问题: ${question}`);
    this.log(` 可用工具: ${this.tools.listNames().join(", ")}`);

    // ============================================================
    // 核心循环:ReAct 的 while 循环
    // ============================================================
    while (turnCount < this.maxTurns) {
    turnCount++;
    this.log(`\\n 第 ${turnCount} 轮循环`);

    // Step 1: Thought(思考 & 决策)
    // 调用 LLM,让模型决定是调用工具还是直接回答
    const response = await chat(
    this.client,
    this.model,
    messages,
    openAITools
    );

    // 如果模型返回了 tool_calls,说明它需要调用工具
    if (response.tool_calls && response.tool_calls.length > 0) {
    this.log(
    `Thought: 模型决定调用 ${response.tool_calls.length} 个工具`
    );

    // 将 assistant 消息(包含 tool_calls)加入对话历史
    messages.push({
    role: "assistant",
    content: response.content,
    tool_calls: response.tool_calls,
    });

    // Step 2: Action(执行工具调用)
    for (const toolCall of response.tool_calls) {
    toolCallCount++;
    const toolName = toolCall.function.name;
    const rawArgs = toolCall.function.arguments;

    this.log(` Action: 调用工具 '${toolName}'`);
    this.log(` 参数: ${rawArgs}`);

    const tool = this.tools.get(toolName);
    if (!tool) {
    const errorMsg = `错误:未找到工具 '${toolName}'`;
    messages.push({
    role: "tool",
    tool_call_id: toolCall.id,
    content: errorMsg,
    });
    this.log(`${errorMsg}`);
    continue;
    }

    // 解析参数并执行
    try {
    const parsedArgs = JSON.parse(rawArgs);
    // Zod 校验参数
    const validatedArgs = tool.parameters.parse(parsedArgs);
    // 执行工具
    const result = await tool.execute(validatedArgs, {});

    this.log(`结果: ${result}`);

    // Step 3: Observation(将工具返回结果注入上下文)
    messages.push({
    role: "tool",
    tool_call_id: toolCall.id,
    content: result,
    });
    } catch (error) {
    const errorMsg = `工具执行错误: ${
    error instanceof Error ? error.message : String(error)
    }
    `
    ;
    messages.push({
    role: "tool",
    tool_call_id: toolCall.id,
    content: errorMsg,
    });
    this.log(`${errorMsg}`);
    }
    }
    } else {
    // 模型没有调用工具,直接返回了答案
    const answer = response.content ?? "抱歉,我无法回答这个问题。";
    this.log(` 最终答案: ${answer}`);
    this.log(
    `\\n 统计: ${turnCount} 轮循环, ${toolCallCount} 次工具调用`
    );

    return {
    answer,
    turns: turnCount,
    toolCalls: toolCallCount,
    history: messages,
    };
    }
    }

    // 达到最大轮次,强制结束
    const fallbackAnswer = "已达到最大执行轮次,无法完成任务。";
    this.log(` ${fallbackAnswer}`);
    return {
    answer: fallbackAnswer,
    turns: turnCount,
    toolCalls: toolCallCount,
    history: messages,
    };
    }

    private log(message: string): void {
    if (this.verbose) {
    console.log(message);
    }
    }
    }

    核心逻辑拆解:

    第 1 轮: Thought "需要计算器" → Action: calculator(add, 15, 27) → Observation: "15 + 27 = 42"
    第 2 轮: Thought "已有答案" → 直接返回: "15 + 27 = 42"

    循环终止条件:模型返回 finish_reason: stop(无 tool_calls)→ 直接输出答案;或达到 maxTurns(默认 10 轮)→ 强制终止,防止死循环。

    关键设计决策:while 而非递归(递归易栈溢出);tool_calls 为数组(支持并行工具调用);maxTurns 上限(防止模型陷入死循环)。

    4.6 入口文件(src/index.ts)

    import "dotenv/config";
    import { createLLMClient } from "./llm.js";
    import { calculatorTool, ToolRegistry } from "./tools.js";
    import { ReActAgent } from "./agent.js";

    async function main() {
    // 1. 初始化 LLM 客户端(DeepSeek,兼容 OpenAI 协议)
    const client = createLLMClient({
    apiKey: process.env.DEEPSEEK_API_KEY!,
    baseURL: process.env.DEEPSEEK_BASE_URL || "https://api.deepseek.com/v1",
    model: process.env.DEEPSEEK_MODEL || "deepseek-chat",
    });

    // 2. 注册工具:计算器(加减乘除)
    const toolRegistry = new ToolRegistry();
    toolRegistry.register(calculatorTool);

    // 3. 创建 ReAct Agent
    const agent = new ReActAgent({
    client,
    model: process.env.DEEPSEEK_MODEL || "deepseek-chat",
    tools: toolRegistry,
    maxTurns: 10,
    verbose: true,
    });

    // 4. 测试用例
    const testCases = [
    // 简单计算:单轮工具调用
    "请帮我计算 15 + 27 等于多少?",
    // 复合计算:需要多轮工具调用
    "请先计算 100 除以 4,然后用结果加上 30,最后告诉我结果",
    // 复杂计算:需要多轮工具调用
    "小明有 50 元,买了 3 本书每本 12 元,又买了 2 支笔每支 5 元,请问他还剩多少钱?",
    ];

    console.log("=".repeat(60));
    console.log(" ReAct Agent 演示 —— 计算器实战");
    console.log("=".repeat(60));

    for (const [index, question] of testCases.entries()) {
    console.log(`\\n${"=".repeat(60)}`);
    console.log(` 测试用例 ${index + 1}: ${question}`);
    console.log("=".repeat(60));

    try {
    const result = await agent.run(question);
    console.log(`\\n 最终答案: ${result.answer}`);
    console.log(
    ` 统计: ${result.turns} 轮循环, ${result.toolCalls} 次工具调用`
    );
    } catch (error) {
    console.error(` 执行失败:`, error);
    }
    }
    }

    main().catch(console.error);

    4.7 运行效果

    $ npx tsx src/index.ts

    === 测试用例 1: 15 + 27 ===
    1 轮: Thought → Action: calculator(add, 15, 27)15 + 27 = 42
    2 轮: 最终答案: 15 + 27 = 42
    统计: 2 轮循环, 1 次工具调用

    === 测试用例 2: 小明有 50 元,买书买笔... ===
    1 轮: multiply(3, 12) = 36
    2 轮: multiply(2, 5) = 10
    3 轮: add(36, 10) = 46
    4 轮: subtract(50, 46) = 4
    5 轮: 最终答案: 小明还剩 4
    统计: 5 轮循环, 4 次工具调用

    关键观察:复合计算需要 5 轮循环、4 次工具调用。每一步依赖上一步结果,模型必须等一轮结束才能开始下一轮——这是 ReAct 的固有特性,也是 CodeAct 要解决的痛点。


    五、CodeAct 重要源码讲解

    CodeAct 与 ReAct 最大的区别:不需要工具注册,核心是沙箱代码执行。以下重点讲解差异部分。

    5.1 项目结构

    codeact-agent/
    – package.json # 依赖更少:无需 zod、zod-to-json-schema
    – tsconfig.json
    – .env.example
    – src/
    – llm.ts # LLM 封装(纯文本,不走 Function Calling)
    – sandbox.ts # 代码沙箱(核心新增)
    – agent.ts # Agent 循环(代码提取 -> 沙箱执行 -> Observation)
    – index.ts

    5.2 沙箱模块(src/sandbox.ts)—— CodeAct 的心脏

    相当于 ReAct 中"工具注册表 + 工具执行"的合体,核心机制:劫持 console.log → 收集输出 → 隔离作用域执行 → 恢复 console。

    /**
    * 代码沙箱 —— CodeAct 的核心
    *
    * 设计理念(参考 Apple ML CodeAct 论文):
    * – ReAct 的 Action = 调用预定义工具
    * – CodeAct 的 Action = 执行一段代码
    * – 代码运行在沙箱中,输出捕获为 Observation
    *
    * 安全说明:
    * – 演示环境使用 AsyncFunction 简化实现
    * – 生产环境必须使用 isolated-vm / Docker 等真隔离方案
    * – 严禁在生产环境直接使用 eval / Function 构造器
    */

    export interface SandboxResult {
    success: boolean;
    output: string; // console.log 的输出
    error?: string;
    duration: number; // 执行耗时(毫秒)
    }

    export class CodeSandbox {
    async run(code: string): Promise<SandboxResult> {
    const startTime = Date.now();
    const outputs: string[] = [];
    const originalLog = console.log; // 保存原始 console.log

    try {
    // 1. 劫持 console.log,收集所有输出
    console.log = (args: any[]) => {
    const formatted = args.map(arg =>
    typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
    ).join(" ");
    outputs.push(formatted);
    originalLog("[沙箱]", formatted);
    };

    // 2. 准备沙箱上下文:预置加减乘除等函数
    const sandboxContext = {
    add: (a: number, b: number) => a + b,
    subtract: (a: number, b: number) => a b,
    multiply: (a: number, b: number) => a * b,
    divide: (a: number, b: number) => {
    if (b === 0) throw new Error("除数不能为零");
    return a / b;
    },
    sum: (arr: number[]) => arr.reduce((a, b) => a + b, 0),
    avg: (arr: number[]) =>
    arr.length === 0 ? 0 : arr.reduce((a, b) => a + b, 0) / arr.length,
    console: {
    log: (args: any[]) => {
    const formatted = args.map(arg =>
    typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
    ).join(" ");
    outputs.push(formatted);
    originalLog("[沙箱]", formatted);
    },
    },
    };

    // 3. 使用 AsyncFunction 在隔离作用域中执行代码
    const AsyncFunction = Object.getPrototypeOf(
    async function () {}
    ).constructor;

    const contextKeys = Object.keys(sandboxContext);
    const contextValues = Object.values(sandboxContext);
    const executor = new AsyncFunction(contextKeys, `"use strict"; ${code}`);
    await executor(contextValues);

    const duration = Date.now() startTime;
    return { success: true, output: outputs.join("\\n"), duration };
    } catch (error) {
    const duration = Date.now() startTime;
    return {
    success: false,
    output: outputs.join("\\n"),
    error: error instanceof Error ? error.message : String(error),
    duration,
    };
    } finally {
    console.log = originalLog; // 4. 恢复原始 console.log
    }
    }
    }

    设计要点:console.log 劫持收集输出作为 Observation;AsyncFunction 构造独立作用域避免变量污染;预置 add/subtract/multiply/divide/sum/avg 供模型直接调用。生产环境必须使用 isolated-vm 或 Docker 真隔离。

    5.3 Agent 核心循环(src/agent.ts)—— 与 ReAct 的本质区别

    CodeAct 的循环和 ReAct 有本质区别:不需要工具注册,只需要代码提取和沙箱执行。

    /**
    * CodeAct Agent 核心循环
    *
    * 与 ReAct 的核心区别:
    * – ReAct: 调用预定义工具(Function Calling)
    * – CodeAct: 生成代码 → 沙箱运行 → 输出 = Observation
    */

    export class CodeActAgent {
    private client: OpenAI;
    private model: string;
    private maxTurns: number;
    private sandbox: CodeSandbox;

    async run(question: string): Promise<CodeActResult> {
    const messages: ChatCompletionMessageParam[] = [
    { role: "system", content: this.systemPrompt },
    { role: "user", content: question },
    ];

    let turnCount = 0;
    let codeExecutions = 0;

    while (turnCount < this.maxTurns) {
    turnCount++;

    // Step 1: 调用 LLM(纯文本,不走 Function Calling)
    const response = await chat(this.client, this.model, messages);

    // Step 2: 提取代码块
    const codeBlocks = extractCodeBlocks(response);

    if (codeBlocks.length > 0) {
    // 有代码块 → 送入沙箱执行
    messages.push({ role: "assistant", content: response });

    for (const code of codeBlocks) {
    codeExecutions++;
    const result = await this.sandbox.run(code);

    // Step 3: Observation → 将沙箱输出注入上下文
    messages.push({
    role: "user",
    content: `[代码执行结果]\\n${result.output}\\n\\n请根据以上结果继续处理。`,
    });
    }
    } else {
    // 没有代码块 → 最终答案
    return { answer: response, turns: turnCount, codeExecutions, history: messages };
    }
    }
    }
    }

    /** 从 LLM 回复中提取 JavaScript 代码块 */
    function extractCodeBlocks(text: string): string[] {
    const blocks: string[] = [];
    // 匹配 ```javascript … ```格式
    const regex = /```(?:javascript|js)\\n([\\s\\S]*?)```/g;
    let match;
    while ((match = regex.exec(text)) !== null) {
    blocks.push(match[1].trim());
    }
    return blocks;
    }

    关键 System Prompt 设计:

    你是一个 CodeAct Agent,能够通过编写和执行 JavaScript 代码来完成任务。

    ## 沙箱中可用的函数
    – add(a, b) / subtract(a, b) / multiply(a, b) / divide(a, b)
    – sum(arr) / avg(arr)
    – console.log(…) → 输出结果

    ## 重要规则
    1. 所有计算结果必须通过 console.log 输出
    2. 复杂计算尽量写在一段代码中完成,减少交互轮次
    3. 代码执行出错时,分析错误信息,修复后重新执行
    4. 得到最终结果后,直接回复用户,不要再写代码块

    与 ReAct 的核心区别:ReAct 走 Function Calling(tools + tool_calls),CodeAct 走纯文本(代码块 → 沙箱执行);ReAct 的工具调用是结构化 JSON,CodeAct 的代码执行是图灵完备的。


    六、Plan-and-Execute 重要源码讲解

    Plan-and-Execute 的核心是"两阶段":先规划(Planner),再执行(Executor)。以下重点讲解规划器和执行器的 DAG 调度逻辑。

    6.1 项目结构

    plan-and-execute-agent/
    – package.json # 依赖最简:仅 openai + dotenv
    – tsconfig.json
    – .env.example
    – src/
    – llm.ts # LLM 封装
    – planner.ts # 规划器(LLM 拆解任务为 JSON 子任务 DAG)
    – executor.ts # 执行器(Kahn 拓扑排序 + 引用解析 + 失败重试)
    – agent.ts # Agent 核心(Phase 1 规划 + Phase 2 执行)
    – index.ts

    6.2 规划器(src/planner.ts)—— 任务拆解引擎

    使用 LLM 将用户问题拆解为 JSON 格式的子任务 DAG:

    /**
    * 子任务定义
    */

    export interface SubTask {
    id: string; // step1, step2, …
    description: string; // 任务描述
    dependsOn: string[]; // 依赖的任务 ID 列表
    operation: "add" | "subtract" | "multiply" | "divide";
    operandA: number | string; // 可以是数字或引用(如 "$step1")
    operandB: number | string;
    }

    export interface Plan {
    question: string;
    tasks: SubTask[];
    }

    /**
    * Plan-and-Execute 规划器
    * 使用 LLM 将用户问题拆解为可执行的子任务 DAG
    */

    export class Planner {
    private client: OpenAI;
    private model: string;

    async createPlan(question: string): Promise<Plan> {
    const systemPrompt = `你是一个任务规划专家。将用户的计算问题拆解为有序的子任务。

    ## 规则
    1. 每个子任务是一个四则运算(add/subtract/multiply/divide)
    2. 子任务按依赖关系排序,后面的任务可以引用前面任务的结果
    3. 引用前面步骤的结果时,使用 $step1, $step2 等格式
    4. 输出必须是合法的 JSON 格式

    ## 输出格式
    {
    "tasks": [
    {
    "id": "step1",
    "description": "计算书的总价",
    "dependsOn": [],
    "operation": "multiply",
    "operandA": 3,
    "operandB": 12
    },
    {
    "id": "step3",
    "description": "计算总花费",
    "dependsOn": ["step1", "step2"],
    "operation": "add",
    "operandA": "$step1",
    "operandB": "$step2"
    }
    ]
    }`;

    const messages = [
    { role: "system" as const, content: systemPrompt },
    { role: "user" as const, content: `请将以下问题拆解为子任务:\\n${question}` },
    ];

    const response = await chat(this.client, this.model, messages);

    // 从 LLM 回复中提取 JSON
    const jsonMatch = response.match(/```json\\s*([\\s\\S]*?)```/);
    const jsonStr = jsonMatch ? jsonMatch[1].trim() : response.trim();
    const parsed = JSON.parse(jsonStr);
    return { question, tasks: parsed.tasks };
    }
    }

    6.3 执行器(src/executor.ts)—— DAG 调度核心

    这是 Plan-and-Execute 最核心的模块,实现了三个关键能力:拓扑排序(Kahn 算法)→ 引用解析($step1 替换)→ 失败重试。

    export interface StepResult {
    stepId: string;
    success: boolean;
    result: number;
    description: string;
    expression: string; // 如 "3 × 12 = 36"
    error?: string;
    retries: number;
    }

    export interface ExecutionResult {
    success: boolean;
    steps: StepResult[];
    finalAnswer: string;
    log: string[];
    }

    export class Executor {
    private maxRetries: number;

    constructor(maxRetries: number = 3) {
    this.maxRetries = maxRetries;
    }

    /** 执行完整计划 */
    async execute(plan: Plan): Promise<ExecutionResult> {
    const log: string[] = [];
    const stepResults: Map<string, StepResult> = new Map();

    // Step 1: 拓扑排序 —— 按依赖关系确定执行顺序
    const executionOrder = this.topologicalSort(plan.tasks);
    log.push(`🔗 执行顺序: ${executionOrder.map((t) => t.id).join(" → ")}`);

    // Step 2: 按序执行每个子任务
    let allSuccess = true;
    for (const task of executionOrder) {
    // 解析 $step1 等引用 → 替换为实际值
    const a = this.resolveValue(task.operandA, stepResults);
    const b = this.resolveValue(task.operandB, stepResults);

    // 执行计算(带重试)
    const stepResult = await this.executeWithRetry(task, a, b, log);
    stepResults.set(task.id, stepResult);

    if (!stepResult.success) {
    allSuccess = false;
    }
    }

    // Step 3: 汇总结果
    const finalAnswer = this.buildFinalAnswer(plan, stepResults, log);
    return { success: allSuccess, steps: Array.from(stepResults.values()), finalAnswer, log };
    }

    /**
    * Kahn 算法拓扑排序
    * 时间复杂度 O(V + E),空间复杂度 O(V + E)
    */

    private topologicalSort(tasks: SubTask[]): SubTask[] {
    const inDegree = new Map<string, number>();
    const adjacency = new Map<string, string[]>();
    const taskMap = new Map<string, SubTask>();

    // 构建入度表和邻接表
    for (const task of tasks) {
    taskMap.set(task.id, task);
    if (!inDegree.has(task.id)) inDegree.set(task.id, 0);
    if (!adjacency.has(task.id)) adjacency.set(task.id, []);
    }

    for (const task of tasks) {
    for (const depId of task.dependsOn) {
    if (!adjacency.has(depId)) adjacency.set(depId, []);
    adjacency.get(depId)!.push(task.id);
    inDegree.set(task.id, (inDegree.get(task.id) ?? 0) + 1);
    }
    }

    // BFS:入度为 0 的节点先执行
    const queue: SubTask[] = [];
    for (const task of tasks) {
    if ((inDegree.get(task.id) ?? 0) === 0) {
    queue.push(task);
    }
    }

    const sorted: SubTask[] = [];
    while (queue.length > 0) {
    const current = queue.shift()!;
    sorted.push(current);
    for (const neighbor of adjacency.get(current.id) ?? []) {
    const newDegree = (inDegree.get(neighbor) ?? 1) 1;
    inDegree.set(neighbor, newDegree);
    if (newDegree === 0) {
    const neighborTask = taskMap.get(neighbor);
    if (neighborTask) queue.push(neighborTask);
    }
    }
    }

    if (sorted.length !== tasks.length) {
    throw new Error("DAG 中存在循环依赖,拓扑排序失败");
    }
    return sorted;
    }

    /**
    * 解析操作数:将 $step1 等引用替换为实际值
    */

    private resolveValue(
    operand: number | string,
    results: Map<string, StepResult>
    ): number {
    if (typeof operand === "number") return operand;

    // 检查是否是引用格式($step1, $step2 等)
    if (typeof operand === "string" && operand.startsWith("$")) {
    const refId = operand.slice(1); // 去掉 $ 前缀
    const refResult = results.get(refId);
    if (!refResult) throw new Error(`引用的步骤 '${refId}' 未找到或尚未执行`);
    if (!refResult.success) throw new Error(`引用的步骤 '${refId}' 执行失败`);
    return refResult.result;
    }

    // 尝试解析为数字
    const parsed = Number(operand);
    if (isNaN(parsed)) throw new Error(`无法解析操作数: ${operand}`);
    return parsed;
    }

    /**
    * 带重试的步骤执行
    */

    private async executeWithRetry(
    task: SubTask,
    a: number,
    b: number,
    log: string[]
    ): Promise<StepResult> {
    for (let attempt = 0; attempt < this.maxRetries; attempt++) {
    try {
    const result = calculate(task.operation, a, b);
    const expression = `${a} ${getOpSymbol(task.operation)} ${b} = ${result}`;
    log.push(` ${expression}`);
    return { stepId: task.id, success: true, result, description: task.description, expression, retries: attempt };
    } catch (error) {
    log.push(`${attempt + 1} 次尝试失败`);
    if (attempt < this.maxRetries 1) {
    log.push(` 准备重试…`);
    }
    }
    }
    return { stepId: task.id, success: false, result: 0, description: task.description, expression: "", retries: this.maxRetries };
    }
    }

    /** 四则运算 */
    function calculate(operation: string, a: number, b: number): number {
    switch (operation) {
    case "add": return a + b;
    case "subtract": return a b;
    case "multiply": return a * b;
    case "divide":
    if (b === 0) throw new Error("除数不能为零");
    return a / b;
    default: throw new Error(`不支持的运算类型: ${operation}`);
    }
    }

    核心设计:Kahn 算法拓扑排序(BFS,O(V+E));$step1 引用解析实现步骤间数据传递;每步最多重试 3 次。

    6.4 Agent 核心(src/agent.ts)

    export class PlanAndExecuteAgent {
    private planner: Planner;
    private executor: Executor;

    async run(question: string): Promise<PlanAndExecuteResult> {
    // Phase 1: Plan(规划)
    const plan = await this.planner.createPlan(question);

    // Phase 2: Execute(执行)
    const result = await this.executor.execute(plan);

    return { answer: result.finalAnswer, log: result.log, success: result.success };
    }
    }

    6.5 运行效果

    $ npx tsx src/index.ts

    === 测试用例: 小明有 50 元,买书买笔... ===
    Phase 1 规划: 4 个子任务
    step1: 3×12=36 → step2: 2×5=10 → step3: 36+10=46 → step4: 50-46=4
    Phase 2 执行: step1 → step2 → step3 → step4
    最终结果: 4


    七、三大模式全景对比

    7.1 核心维度对比

    维度ReActCodeActPlan-and-Execute
    全称 Reasoning + Acting Code + Acting Plan-and-Execute
    决策方式 边走边看,每一步动态决策 代码即行动,一段代码搞定 先规划后执行,按图索骥
    Action 形式 调用预定义工具函数(JSON) 生成完整代码,沙箱运行 拆解为子任务 DAG,有序执行
    工具约束 必须提前定义所有工具 无限制,编程语言标准库 子任务定义在 Plan 中
    多步骤计算 分多轮调用,交互次数多 单段代码嵌套完成,轮次少 按 DAG 依赖逐步执行
    交互轮次 多(每步一轮) 少(批量处理) 中(规划 1 轮 + 执行 N 步)
    模型要求 基础推理能力即可 强代码生成能力 强规划 + 执行能力
    可控性 低(黑盒循环) 中(代码可审查) 高(每步可监控)
    失败处理 整体重试,上下文丢失 修改代码重新执行 单步重试,上下文保留
    适用场景 不确定路径的动态任务 批量数据处理、复杂运算 标准化长链路流水线

    7.2 实战数据对比(同一计算题:小明买书买笔)

    指标ReActCodeActPlan-and-Execute
    循环轮次 5 轮 2 轮 2 轮(1 规划 + 1 执行)
    工具调用/代码执行 4 次工具调用 1 次代码执行 4 步子任务执行
    核心依赖 openai + zod + zod-to-json-schema openai openai
    扩展新运算 需要注册新工具 写代码即可 规划器自动适配

    八、业务场景选型指南

    8.1 ReAct 最佳场景:不确定路径的动态任务

    反诈风险研判:无法提前确定需要调用多少个工具,需要根据多模态识别结果动态决定是否调取知识库、是否触发监护人预警。

    用户举报 → 身份核验 → 发现异常 → 查询关系图谱 → 发现多个关联风险账号
    → 调取历史行为数据 → 风险评估 → 触发监护人预警

    每一步的结果决定下一步做什么,路径不确定,这正是 ReAct 的优势。

    8.2 CodeAct 最佳场景:批量数据处理

    报表运算、复杂文件解析:不想为每一类数据处理单独开发工具,直接让模型生成代码处理。

    用户上传 Excel → 模型生成 JS 代码 → 沙箱执行:读取数据、清洗、计算、汇总 → 输出结果

    8.3 Plan-and-Execute 最佳场景:标准化长链路任务

    批量文档解析流水线:先拆解完整子任务,有序执行,可控性更强,方便做任务监控、失败重试。

    Plan: 下载文件 → 解析格式 → 提取文本 → 清洗数据 → 入库 → 通知用户
    Execute: 按 DAG 依赖逐步执行,每步记录日志,失败自动重试


    九、延伸拓展

    9.1 从单模式到混合模式

    实际生产环境中,很少有系统只用单一模式。常见的混合方案:

    • ReAct + CodeAct 混合:日常工具调用用 ReAct,遇到复杂计算时切换到 CodeAct
    • Plan-and-Execute + ReAct 混合:先用 Plan-and-Execute 规划整体流程,每个子任务内部用 ReAct 动态执行
    • 三层架构:Plan-and-Execute(顶层调度)→ ReAct(中层决策)→ CodeAct(底层计算)

    9.2 基于三者可扩展的完整 Agent 系统

    在三种模式的基础上,可以叠加以下能力构建完整 Agent:

  • 记忆系统:短期记忆(对话历史)+ 长期记忆(向量数据库)
  • RAG(检索增强生成):接入外部知识库,让 Agent 能回答私有数据问题
  • 多轮自我反思:Agent 执行完任务后,自我评估结果质量,自动修正
  • MCP 协议:统一标准化所有工具调用,兼容 ReAct / CodeAct / Plan-and-Execute 的工具层
  • 9.3 其他值得关注的 Agent 架构

    • HuggingGPT:多模型分工调度,不同任务分配不同模型
    • AutoGPT:自主任务分解 + 执行 + 反思的完整闭环
    • MetaGPT:多 Agent 协作,模拟软件公司角色分工

    十、总结

    三种 Agent 模式并非互相替代,而是互补关系:

    • ReAct 给你"边思考边行动"的灵活性,适合未知路径的探索。就像一个灵活应变的前线侦察兵,根据现场情况动态决策
    • CodeAct 给你"代码即行动"的效率,适合批量计算和复杂逻辑。就像一个高效的工程师,一段代码解决所有计算问题
    • Plan-and-Execute 给你"先规划后执行"的可控性,适合标准化长链路任务。就像一个靠谱的项目经理,先做计划,再按步骤推进

    选型的核心原则:没有银弹,只有合适的场景。理解每种模式的本质,才能在正确的场景下做出正确的选择。


    运行方式:

    cd react-agent # 或 codeact-agent / plan-and-execute-agent
    npm install
    cp .env.example .env # 填入 DeepSeek API Key
    npx tsx src/index.ts

    参考文献:

    • ReAct 论文:Yao et al., “ReAct: Synergizing Reasoning and Acting in Language Models”, 2022.10
    • CodeAct 论文:Apple ML, “CodeAct: Code as Action in Language Model Agents”, 2024
    • Plan-and-Execute 架构参考:LangGraph 源码 github.com/langchain-ai/langgraph
    • E2B 代码沙箱:github.com/e2b-dev/e2b
    赞(0)
    未经允许不得转载:171主机测评 » AI Agent 三大核心架构精讲:ReAct / CodeAct / Plan-and-Execute 原理 + 手撕源码
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址