首页
看点啥
插画图片
首页 看点啥 ReAct 智能体循环和 JavaScript 异步并发原理深度解析

ReAct 智能体循环和 JavaScript 异步并发原理深度解析

2026-07-12 0

前言

本文分为两大模块:第一部分讲清 AI Agent 和普通对话大模型的本质区别、ReAct 循环与工具调用核心逻辑;第二部分围绕浏览器异步请求代码,逐行拆解 Promiseasyncawait.then() 的底层运行逻辑与并发特性,完整代码放置在代码解析模块末尾。

一、AI Agent 底层原理:和普通对话 AI 的根本差异

1. 普通对话 LLM:单次单向问答流程

日常使用的普通对话 AI,执行链路是一次性闭环:用户输入指令 → LLM 读取训练静态知识生成文本 → 输出内容后任务直接终止。整个过程不存在自主循环逻辑,也无法主动操作外部资源。举个例子:让普通 AI 写竞品分析报告,它仅依靠训练时沉淀的旧知识生成文字,不会主动联网查询竞品最新动态、抓取财务数据,输出完成流程直接结束,不存在自我校验、补充信息的能力。

2. AI Agent:基于 ReAct 的循环自主执行架构

Agent 最核心的特征是拥有可持续循环的执行链路,标准执行流程命名为 ReAct,由三步动作循环往复运行,直到任务完成或触发终止条件:

  1. Reason(思考) :大模型自主拆解复杂任务,判断当前信息缺口,规划下一步执行动作
  2. Act(行动) :调用外部工具执行操作,包括联网搜索、代码运行、浏览器访问、API 请求等
  3. Observe(观察) :接收工具返回的执行结果,判断现有信息是否足以完成目标任务

一轮循环结束后会自动回到「思考」步骤,持续迭代。

场景示例:Agent 完成竞品分析报告完整循环

  1. 思考:缺少竞品实时业务数据,需要调用搜索工具;行动:发起联网搜索;观察:获取竞品基础动态,识别当前缺失财务报表数据
  2. 再次思考:需要抓取股市财务接口补充数据;行动:请求财务 API;观察:全部所需信息收集完毕,无需继续调用工具
  3. 终止循环,整合所有外部数据输出完整竞品报告

3. Agent 的核心能力:Tool Use 工具调用

工具是 Agent 连接现实世界的唯一载体,没有工具的 Agent 和普通对话 LLM 没有本质区别,仅能输出纯文本内容。可用工具集合直接决定 Agent 的能力边界:

补充说明:ReAct 只是一套通用执行标准,不属于 LangChain 这类开发框架,市面上所有 Agent 开发框架底层都基于这套循环逻辑封装实现。

二、JS 异步代码深度解析(重点 Promise /async/await /.then)

1. 基础概念铺垫:Promise 核心规则

Promise 是 JS 中专门处理异步操作(网络请求、定时器、文件读取)的标准化对象,诞生目的是解决多层嵌套回调形成的「回调地狱」问题。

  1. 三种不可逆状态:

    • pending:初始等待状态,异步操作未执行完成
    • fulfilled:异步执行成功,状态锁定,触发 .then() 回调逻辑
    • rejected:异步执行失败,状态锁定,触发 .catch() 回调逻辑
  2. 状态一旦切换为 fulfilled /rejected,就永久固定,无法再次修改;

  3. 浏览器原生接口 fetch,发起网络请求后返回的值本身就是一个 Promise 对象。

2. async 关键字详解:修饰函数,自动包装返回 Promise

代码中定义了两个请求函数:

javascript

运行

const getStory = async () => fetch('https://v1.hitokoto.cn/?c=i&encode=json')const getRatp = async () => fetch('https://api.1314.cool/bingimg/?type=json&rand=1')

3. await 关键字:阻塞等待 Promise 完成(注释串行代码对比)

源码中注释了一段串行请求写法:

javascript

运行

// const story = await getStory();// const ratp = await getRatp();

  1. await 存在使用限制:只能写在被 async 修饰的函数内部,单独在全局使用会直接抛出语法错误;
  2. await 核心作用:暂停当前函数内后续代码执行,等待后方 Promise 执行完成并拿到 resolved 结果后,才会继续执行下一行代码;
  3. 这段注释代码属于串行请求:先发起一言接口请求,必须等待接口完整响应结束,才会发起必应壁纸接口请求,总耗时 = 接口 1 耗时 + 接口 2 耗时;
  4. 和下文 Promise.all 并行写法形成明显性能差异,无依赖接口推荐并行执行。

4. Promise.all:并行批量处理多个 Promise(本节核心重点)

javascript

运行

Promise.all([getStory(), getRatp()])

  1. 入参要求:接收一个由多个 Promise 实例组成的数组;

  2. 执行逻辑:数组内所有 Promise 同步并发发起,两个网络请求同时发送,总耗时等于耗时最长的接口执行时间,性能远优于串行 await;

  3. 返回规则:

    • 仅当数组内全部 Promise 都执行成功(fulfilled),才会进入后续 .then() 回调;
    • 返回结果为数组,数组内元素顺序和传入 Promise 数组顺序严格对应,与接口响应快慢无关。例如壁纸接口 100ms 返回、一言接口 500ms 返回,最终结果数组依旧保持 [一言结果, 壁纸结果] 的顺序;
  4. 标志性特性「快速失败」:数组中任意一个 Promise 执行失败(404、网络中断、请求报错),整个 Promise.all 会立刻终止执行,直接跳转 .catch(),直接丢弃其余未完成 Promise 的返回结果。

5. .then () 链式回调:接收成功结果,返回新 Promise

javascript

运行

.then(response => {return Promise.all(response.map(res => res.json()))})

  1. .then() 的入参,是上一层 Promise.all 成功返回的数组,数组内存储两个 fetch 得到的 Response 响应对象;
  2. res.json() 是 Response 对象自带的异步方法,作用是将接口返回的 JSON 字符串解析为 JS 对象,该方法执行本身依旧返回 Promise;
  3. 通过 response.map 遍历全部 Response 对象,批量调用 .json() 生成一组全新 Promise,再次使用 Promise.all 并行完成所有 JSON 解析操作;
  4. .then 内部若存在 return 语句,返回值会自动包装为 Promise 对象,传递给下一层链式回调,这也是 Promise 链式调用的底层基础。

6. .catch () 统一捕获全链路异步错误

javascript

运行

.catch(response => {console.log(response)})

  1. .catch() 可以捕获整条 Promise 链路中任意位置的失败:包含第一层 Promise.all 接口请求失败、第二层 res.json() 解析时格式报错等所有异常;
  2. 结合 Promise.all 的快速失败特性:只要任意一步异步操作抛出错误,代码会直接跳转到当前 catch,不会执行任何后续 .then 逻辑;
  3. 写法对比:若使用 async/await 串行写法,需要搭配 try/catch 语法才能捕获异常,.then/.catch 链式写法可以集中统一处理全链路异常。

7. async 主函数 main 与程序执行入口

javascript

运行

async function main() {Promise.all([getStory(), getRatp()]).then(response => {return Promise.all(response.map(res => res.json()))}).catch(response => {console.log(response)})}main();

8. 串行 await 和 Promise.all 并行核心区别总结

  1. 串行(注释 await 代码):接口先后顺序执行,总耗时叠加,适用于接口之间存在数据依赖(第二个接口需要第一个接口返回参数);
  2. 并行(Promise.all):同步发起全部无依赖接口,总耗时取最长接口耗时,适用于多独立接口批量请求,大幅优化页面加载速度;
  3. 风险提示:Promise.all 存在快速失败特性,若业务场景需要等待所有请求走完、无论成功失败都保留全部结果,可替换为 Promise.allSettled

完整可运行代码(放置本模块末尾)

html

预览

html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Documenttitle>head><body><script>// const streetCarsPromise = fetch('http://data.ratp.fr/api/datasets/1.0/search/?q=paris');// console.log(streetCarsPromise);const getStory = async () => fetch('https://v1.hitokoto.cn/?c=i&encode=json')const getRatp = async () => fetch('https://api.1314.cool/bingimg/?type=json&rand=1')async function main() {// 不存在依赖关系 , 并行以下 Promise 一系列静态方法// const story = await getStory();// const ratp = await getRatp();// 并发的效果 // 参数是promise 数组// 不管谁先解决,谁后, resolve 的结果会按promise 数组// 顺序来收集。最后一个promise resolved 之后, 停下来 Promise.all([getStory(), getRatp()]).then(response => {return Promise.all(response.map(res => res.json()))}).catch(response => {console.log(response)}) }main();script>body>html>

三、全文总结

  1. AI Agent 的核心竞争力不在于对话能力,而是 ReAct 循环自主思考 + 工具调用;普通 LLM 仅能单次应答,无法自主迭代完成复杂任务,可用工具集合直接决定 Agent 的能力上限。
  2. async 用于修饰函数,让函数天然返回 Promise;await 用于阻塞等待异步结果,多用于存在数据依赖的串行异步逻辑。
  3. Promise.all 实现无依赖异步任务并发,搭配多层 .then() 链式处理分层异步逻辑,.catch() 统一捕获整条链路的所有异常。
  4. fetch 会返回原生 Promise 对象,接口响应后的 .json() 解析操作依旧属于异步 Promise,批量解析多接口 JSON 需要二次使用 Promise.all 并行处理。
喜欢(0)

上一篇

Claude 必学技能 Superpowers

Claude 必学技能 Superpowers

下一篇

火山引擎 Supabase 正式融入 Agent Plan:CLI + Skills 保姆级上手教程来了

火山引擎 Supabase 正式融入 Agent Plan:CLI + Skills 保姆级上手教程来了
猜你喜欢