ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ReAct Agent 入门:AI 如何一边推理,一边行动?

ReAct Agent 入门:AI 如何一边推理,一边行动? 当用户说“帮我找到登录超时的原因并修好它”普通聊天模型只能根据已有知识给出建议ReAct Agent 则会搜索代码、读取文件、执行修改并运行测试再根据真实结果决定下一步。本文从这条完整路径出发讲清 ReAct 的核心循环以及它在 LoopAgent 中如何落地。先说明一个容易混淆的地方本文讨论的ReAct是一种 Agent 工作模式不是前端框架 React。它关注的是模型如何把“推理”和“行动”连接起来。读完本文你将理解三个问题为什么一次问答不足以完成真实开发任务Reason、Act、Observe 如何组成可持续推进的循环工具、消息历史和运行器如何把这个循环变成可执行的程序。一次问答为什么不够假设用户提出一个常见需求帮我看看登录超时的报错来自哪里顺手修一下。如果模型只能接收问题并返回一段文本它最多根据经验列出几种可能数据库连接慢、网络不稳定、Token 过期或者 HTTP 客户端的超时时间过短。这些判断听起来都合理但缺少一个关键前提模型还没有看过当前项目。它不知道httpClient的超时时间是多少不知道loginService如何转换底层错误也不知道修改后能否通过测试。此时直接给出结论本质上仍然是在猜测。真实开发任务通常不是“知道答案”这么简单而是包含一条连续的证据链定位相关代码 - 阅读调用关系 - 提出根因假设 - 修改文件 - 运行测试 - 根据结果决定是否继续只要中间任一步出现新信息后续计划就可能改变。模型因此不能在任务开始时一次性决定全部步骤而要像开发者一样先执行当前最合理的一步再根据结果重新判断。这正是 ReAct 要解决的问题。ReAct 的核心Reason Act ObserveReAct 来自Reasoning推理和Acting行动。在工程实现中可以把它理解为三个连续阶段阶段解决的问题典型结果Reason根据当前信息下一步最值得做什么决定搜索关键词或目标文件Act通过工具改变或检查外部环境搜索代码、读取文件、修改内容、运行命令Observe工具返回了什么新事实搜索命中、文件内容、命令输出、测试结果三者不是只执行一次而是形成循环Reason - Act - Observe - Reason - Act - Observe - ... - Final Answer这里最重要的不是“模型会思考”而是Observation 会成为下一轮推理的新输入。模型不再只依赖训练时学到的知识而是不断吸收当前项目刚刚产生的事实。因此ReAct 的价值可以概括为一句话让模型的结论建立在可观察的环境反馈上而不是只建立在语言概率上。用一次登录超时排障看完整循环下面用一条简化但完整的任务路径说明这个过程。第一步定位相关代码模型首先知道的只有用户描述因此最合理的动作不是修改代码而是搜索Reason需要先找到“登录”和“超时”相关实现。 Act搜索 login、timeout、登录超时。 Observe命中 session.ts、loginService.ts、httpClient.ts。搜索结果缩小了范围但还不能证明根因。第二步验证根因假设模型发现httpClient.ts中的默认超时是 3000 毫秒而会话允许等待 15000 毫秒于是继续读取调用链ReasonHTTP 请求可能先于会话超时被中止需要确认错误如何向上传递。 Act读取 loginService.ts 和 httpClient.ts。 Observe请求在 3 秒后被中止上层将该错误转换为“登录超时”。到这一步“HTTP 客户端超时过短”才从猜测变成有代码依据的结论。第三步修改并验证确认根因后模型修改配置并运行受影响测试Reason将 HTTP 超时调整到与登录流程一致并用测试验证。 Act修改 httpClient.ts将超时从 3000 调整为 15000。 Observe文件修改成功。 Reason代码已变更但任务还不能结束需要验证行为。 Act运行 npm test -- login。 Observe相关测试全部通过。最后模型才向用户返回结果根因是什么、修改了哪里、测试是否通过。这条路径展示了 ReAct 与普通问答最本质的差别每个关键结论都有前一步的环境反馈作为依据。Act 从哪里来工具是 Agent 的能力边界模型本身不能直接读取磁盘或执行命令。它必须通过宿主程序提供的工具与外部环境交互。在 LoopAgent 的src/extension/agent/目录中常用能力由独立工具提供用户看到的动作工具文件职责搜索代码exploreCodeTool.ts在代码索引中定位相关实现读取文件readFileTool.ts读取指定文件内容修改文件applyEditTool.ts对文件执行精确编辑运行命令runCommandTool.ts在受控范围内执行 Shell 命令审查代码codeReviewTool.ts检查当前改动中的问题浏览符号browseSymbolsTool.ts列出文件中的函数、类和其他符号这些工具遵循统一的ReactAgentTool约定。核心结构位于reactTypes.tsexporttypeReactAgentTool{name:string;description:string;inputSchema:Recordstring,unknown;resultSchema?:Recordstring,unknown;isConcurrencySafe?:(input:unknown)boolean;invoke(invocation:ReactAgentToolInvocation):|string|ReactAgentToolResult|Promisestring|ReactAgentToolResult;};这几个字段分别承担不同职责name工具的唯一名称模型通过它发起调用description告诉模型工具能做什么、何时应该使用inputSchema约束参数结构避免调用方和工具各自猜测格式resultSchema描述结构化结果便于调用方理解返回值isConcurrencySafe判断该调用能否与其他工具并发执行invoke真正执行搜索、读取、编辑或命令操作。其中最容易被低估的是description和inputSchema。工具代码即使完全正确如果描述含糊、参数约束不清模型仍可能选错工具或传错参数。对 Agent 来说工具定义既是程序接口也是提供给模型的操作说明书。谁在驱动循环Runner 负责调度工具只提供单次能力真正把多次调用串起来的是reactAgentRunner.ts。它负责维护消息历史、请求模型决策、执行工具并把结果重新送回模型。忽略流式输出和错误恢复后主流程可以简化为for(letstepinitialStep;stepmaxSteps;step){constresultawaitmodelTurn({messages,signal,toolChoice:auto});if(result.kindfinal){returnresult.content;}messages.push(result.assistantMessage);for(constrequestofresult.requests){constoutputawaitinvokeTool(request,signal);messages.push({role:tool,requestId:request.id,name:request.name,content:output.content,});}}这段代码做了四件事把当前对话和工具结果交给模型判断模型要直接回答还是继续调用工具执行工具并获得环境反馈将反馈以role: tool消息写回历史进入下一轮。因此messages不只是聊天记录还是整个任务的工作记忆。每次 Observation 被追加进去后下一次modelTurn都能看到最新事实并据此修正计划。ReAct 不等于“调用一次工具”只要模型使用了工具就算 ReAct 吗不一定。如果模型在任务开始时固定生成五个步骤机械执行完再统一返回即使中间调用了搜索和命令也没有真正利用 Observation 调整后续行为。一个有效的 ReAct 循环至少满足三点工具结果会进入后续上下文模型能够根据结果改变下一步动作模型在证据充分时停止行动并给出答案。例如搜索没有命中时下一步应该更换关键词或扩大范围测试失败时下一步应该读取错误并修复根因而不是继续执行原计划中的“提交代码”。这种根据反馈改变路线的能力才是 Agent 比固定工作流更灵活的原因。循环为什么不会无限运行“让模型自己决定下一步”带来灵活性也引入了工程风险重复搜索、工具连续失败、一次请求过多甚至一直无法形成最终答案。因此真实 Runner 不能只有一个for循环还需要明确的停止条件和保护措施。LoopAgent 当前包含这些关键约束步骤上限超过maxSteps后进入收尾流程避免无限循环单步调用上限限制模型一轮能发出的工具请求数量重复调用检测相同工具和相同参数成功执行过后阻止无意义重试连续失败熔断同一工具多次失败时终止运行取消信号用户取消任务后通过AbortSignal停止模型和工具执行检查点保存每轮执行前后保存进度为中断恢复提供基础必要工具门禁任务要求真实检查时不能在尚未获得有效工具结果前直接收尾。这些机制说明一个重要事实ReAct 循环决定 Agent 能不能行动工程护栏决定它能不能可靠地行动。没有护栏的循环很容易在演示中表现惊艳却在真实项目里因为重复调用、失败重试和状态丢失而失控。哪些任务适合 ReActReAct 适合“下一步依赖上一步结果”的任务例如排查跨文件缺陷根据仓库现状实现功能修改代码后运行测试并继续修复收集多处证据后形成审查结论调用外部系统并根据返回状态推进流程。如果问题只是“解释闭包是什么”或“把这段话翻译成英文”模型一次回答就足够。强行启动多轮工具循环只会增加耗时和成本。判断标准并不复杂任务是否需要从环境中获得新信息并根据新信息改变后续动作如果答案是肯定的ReAct 才真正有价值。小结本文从一次登录超时排障出发拆解了 ReAct Agent 的完整工作方式普通问答只能根据已有上下文生成答案无法验证当前项目中的事实ReAct 通过Reason - Act - Observe循环让环境反馈持续影响下一步决策工具定义了 Agent 能做什么Runner 负责选择、执行并回填工具结果消息历史连接了每一轮推理和行动使任务能够根据新证据动态推进步骤上限、重复检测、失败熔断和检查点等护栏让循环从概念演示变成可用系统。理解这一点之后再看复杂 Agent 就不会只看到“模型调用了很多工具”。真正值得关注的是每次调用获得了什么新事实这个事实如何改变下一步以及系统如何保证循环最终安全停止。下一篇将继续讨论经典 ReAct 使用Thought:、Action:、Observation:文本标签而现代 Agent 更常使用结构化工具调用。两种方式的可靠性差异在哪里本文示例来自开源项目LoopAgent一个运行在 VS Code 中的 AI 编码 Agent。
返回列表