首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Agentic 智能体 React 模式实现

Agentic 智能体 React 模式实现

作者头像
AI老马
发布2026-07-28 10:15:14
发布2026-07-28 10:15:14
1080
举报
文章被收录于专栏:AI前沿技术AI前沿技术

普通的大模型调用是一问一答,问完就结束了。但真实的 Agent 场景不是这样 -- 大模型需要自己判断:我现在信息够不够?不够的话该调用什么工具去补充?拿到结果之后怎么继续推理?

这种"思考 -> 行动 -> 再思考"的循环能力,就是 ReAct(Reasoning + Acting) 模式要解决的问题。

这篇文章从代码实现的角度拆解 ReAct 模块,主要回答四个问题:

1)ReAct 循环的本质结构和两个分支

2)上下文治理 -- 上下文越来越长怎么办

3)工具执行引擎的并发与串行模式

4)钩子机制 -- 如何在不改主流程的前提下扩展行为

关注“AI老马” —【获取资源】&【进群交流】

1,ReAct 的本质:一个带条件的 for 循环

把所有概念剥掉之后,ReAct 的核心代码结构就是一个 for 循环。

每次循环做一件事:让大模型生成回复,然后检查回复里有没有工具调用请求。

如果有工具调用 -- 把参数提取出来,交给工具执行引擎,拿到结果后塞回上下文,然后 continue 进入下一轮循环。这就是"行动之后再思考"。

如果没有工具调用 -- 说明大模型认为已经可以给出最终答案了,直接输出结果,跳出循环。整个 ReAct 过程结束。

当然,不能让它无限循环下去。循环开始之前要设置一个最大迭代次数(比如 10 次或 20 次),到了上限强制终止,避免用户体验失控和 API 调用成本爆炸。

所以整个 ReAct 的骨架就这么点东西:

代码语言:javascript
复制
for i in range(max_iterations):
    context = govern_context(context)       # 上下文治理
    response = llm.chat(context)            # 大模型思考
    if has_tool_call(response):
        result = execute_tools(response)    # 执行工具
        context += result                   # 结果回填
        continue                           # 继续循环
    else:
        return response                     # 输出最终答案

两个分支,逻辑清晰。复杂的不在循环本身,而在循环内部的细节处理。

2,上下文治理:五步法控制窗口长度

ReAct 循环每转一圈,上下文就会变长 -- 加入了大模型的推理结果、工具调用的请求、工具返回的结果。转个十圈八圈,上下文可能就超出了模型的窗口限制。

所以每轮循环的第一步,必须是上下文治理。这里有一套五步处理的标准化流程:

第一步:清理孤儿数据。 工具调用是成对出现的 -- 有请求就该有对应的结果。如果上下文里出现了只有结果没有请求、或只有请求没有结果的孤立数据,说明中间出了异常(比如工具执行超时)。这些孤儿数据一律清除,避免干扰后续推理。

第二步:压缩早期结果。 前几轮的工具调用结果对当前决策的价值已经不大了,但完全丢弃又怕丢失关键信息。折中方案是:保留最近 N 轮(比如最近 10 次)的原始结果,更早的结果压缩为一行摘要。既省空间,又不丢核心信息。

第三步:持久化关键数据。 将重要的中间结果(比如搜索到的文档、查询到的数据库记录)写入持久化存储。这样即使后续上下文被裁剪掉了,需要的时候还能找回来。相当于给大模型装了一个"外部记忆"。

第四步:结果格式化。 确保每个工具调用的输出都按照统一格式整理,方便大模型解析和使用。杂乱无章的工具返回只会增加理解成本。

第五步:历史裁剪。 当前四步做完之后,如果总长度仍然超过阈值,就从最早的消息开始裁剪,只保留系统提示词(System Prompt)和最近的消息。这是最后的保底措施。

这五步的目标只有一个:让上下文保持在模型窗口限制之内,同时尽可能保留有价值的信息。

3,工具执行:并发还是串行?

大模型一次可能要求调用多个工具。这些工具之间有没有依赖关系?能不能并行执行?这决定了执行策略。

设计上支持两种模式:

串行模式:按顺序逐个执行工具,前一个的结果可以作为后一个的输入。适用于工具之间存在依赖关系的场景 -- 比如先用搜索工具找到文件路径,再用读取工具打开文件内容。

并发模式:将多个独立的工具调用打包成一个 Batch,同时发起执行,最后汇总所有结果一起返回。适用于工具之间互不相关的场景 -- 同时查天气、查股价、查日历,谁也不依赖谁。

具体用哪种模式,可以根据工具的属性配置来决定,不需要硬编码。执行引擎内部会自动判断和分发。

4,错误恢复:别让一次失败搞崩全局

工具调用不可能次次成功。网络超时、API 报错、参数不合法 -- 异常情况随时可能发生。

错误恢复机制的核心原则是:局部失败不影响整体流程。

具体的策略包括:

  • 空响应重试:工具返回空结果时,自动重试 1~2 次,排除偶发性问题
  • 阶段级容错:单轮迭代最多允许恢复 N 次(比如 3 次),超出后跳过本轮继续下一轮
  • 错误信息透传:工具执行的错误不会吞掉,而是包装成明确的错误提示返回给大模型。大模型看到错误后可以自行决定是换参数重试、换工具尝试,还是直接基于已有信息给出答案

这个设计体现了 ReAct 模式的一个重要理念:异常处理也是大模型推理的一部分。不需要在代码层面把所有异常路径都穷举出来,告诉大模型发生了什么,让它自己想办法。

5,钩子机制:在不改动主流程的前提下扩展行为

ReAct 主循环的逻辑是固定的,但在实际使用中,不同场景有不同的附加需求:有的要在每轮迭代前打印日志,有的要实时推送流式结果给前端,有的要做调用埋点和监控。

如果在主流程里到处加 if-else,代码很快就会变成一团乱麻。

解决方案是钩子(Hook)模式。在 ReAct 执行类的关键节点预留出"挂钩点",用户可以通过继承 Hook 类并实现特定方法来注入自定义行为:

  • • 迭代开始前做什么(before_iteration
  • • 是否启用流式输出(should_stream
  • • 流式内容怎么回写(on_stream
  • • 迭代结束后做什么(after_iteration

定义好 Hook 类之后,传给 ReAct 的数据包装类就行。主循环在执行到对应节点时,会自动检查并调用 Hook 中已实现的方法。主流程本身一行都不用改。

更进一步,如果需要同时生效多种 Hook(既要打日志又要推流式),可以用一个 CompositeHook 组合多个 Hook,按序依次执行。本质上又是一个"套壳"的设计 -- 一个壳子里装多个具体实现,对外还是一个 Hook。

写在最后

回过头来看,ReAct 模块的实现并不神秘:一个 for 循环 + 两条分支 + 五步上下文治理 + 可插拔的 Hook 扩展。 真正值得关注的工程细节是上下文治理那部分 -- 怎么在有限的空间里保留最多的有效信息,这直接决定了 Agent 在多轮交互后的推理质量。

而对于想要自建 Agent 框架的同学来说,这套设计的可借鉴之处在于它的分层思路:主循环只管流转逻辑,上下文治理、工具执行、错误恢复、扩展钩子各自独立封装,互不耦合。加功能不用动主干,修 bug 不用牵连全身。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-27,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 1,ReAct 的本质:一个带条件的 for 循环
  • 2,上下文治理:五步法控制窗口长度
  • 3,工具执行:并发还是串行?
  • 4,错误恢复:别让一次失败搞崩全局
  • 5,钩子机制:在不改动主流程的前提下扩展行为
  • 写在最后
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档