跳过正文
  1. AI/

AI Agent Loop 与 ReAct 模式:思考-行动-观察是怎么循环起来的

7 分钟·
x
作者
x
熟练掌握Spring Boot、Spring Cloud等Java技术栈,专注于分布式系统设计与微服务架构。热爱技术分享,探索编程之美。
目录

现在几乎所有"AI Agent"框架——不管是 Claude Code、各种 Agent 编排工具,还是自己写的一个几十行的工具调用脚本——底层跑的都是同一个骨架:模型不是一次性把答案吐出来,而是反复经历"想一步、做一步、看结果、再想下一步",直到任务完成。这个骨架有个具体的名字,叫 ReAct(Reasoning + Acting),来自 Yao 等人 2022 年的论文《ReAct: Synergizing Reasoning and Acting in Language Models》。这篇聊聊这个循环具体是怎么回事、现代 LLM API 是怎么实现它的,以及实践中最容易踩的几个坑。

一、为什么需要"循环",而不是一次问答
#

最朴素的 LLM 调用是一问一答:把问题丢进去,模型直接给答案。这在纯知识性问答上够用,但遇到需要"先查证、再回答"的任务就会露怯——模型只能基于训练时记住的东西编答案,没法真的去查一下现在几点、这个 API 现在返回什么、这段代码跑起来到底报什么错。

思维链(Chain-of-Thought,CoT)改善了一部分问题:让模型把中间推理过程写出来,而不是直接蹦答案,输出质量确实会好不少。但 CoT 的推理始终是"脑内"的——全程不接触真实世界,模型的中间假设没有任何机会被外部事实纠正,一旦某一步的假设错了,后面全盘跟着错,而且模型自己不会发现。

ReAct 的核心改动很简单:在推理步骤之间插入真实世界的动作。模型每"想"一步,可以选择调用一个外部工具(搜索、查数据库、执行代码……),工具的真实返回结果会被塞回上下文,成为模型下一步推理的依据。推理不再是封闭的自言自语,而是和外部世界交替进行的循环——这也是论文标题里 “Synergizing” 的意思:推理指导行动该做什么,行动的结果又反过来修正推理。

二、循环的三个阶段
#

ReAct 的一轮循环由三部分组成,通常缩写成 Thought → Action → Observation:

  • Thought(思考):模型用自然语言表达当前的推理——我现在知道什么、还缺什么信息、下一步该做什么。
  • Action(行动):基于这一步的思考,模型发出一次具体的工具调用(带上参数),或者判断信息已经够了,直接给出最终答案。
  • Observation(观察):工具执行的真实结果被追加进上下文,成为下一轮 Thought 的输入。

这三步循环往复,直到模型在某一轮 Thought 之后判断"不需要再行动了",输出 Final Answer,循环终止。整个过程可以画成一个简单的状态机:

问题 → Thought → Action → Observation
              ↑______________|
              (重复 N 轮,直到给出 Final Answer)

拿一个具体例子过一遍:问"某个 GitHub 仓库最新一次 release 修了什么 bug"。第一轮 Thought 可能是"我需要先找到这个仓库的 release 列表",Action 调用一个查 GitHub API 的工具,Observation 拿到 JSON 格式的 release 数据;第二轮 Thought 变成"最新那条 release 的 body 里提到了三个 fix,但其中一个 issue 链接需要展开看细节",Action 再调用一次工具去抓那个 issue 的内容,Observation 拿到详情;第三轮 Thought 判断信息已经够回答问题了,直接输出 Final Answer。全程模型没有凭空编造任何一个 bug 描述——每个结论都能追溯到某一轮真实的 Observation。

三、现代 LLM API 里,这个循环长什么样
#

ReAct 论文提出时用的是纯文本 prompt 拼接(在 prompt 里手写 “Thought:"、“Action:"、“Observation:” 这几个字段,靠模型模仿格式续写)。现在的 LLM API 把这套模式变成了结构化的原生能力,不再需要靠字符串解析——以 Claude 的 Messages API 为例:

  • 模型如果决定要"行动”,响应里会带 stop_reason: "tool_use",内容里包含一个或多个结构化的 tool_use 块(对应 Action),而不是靠文本里的 “Action: xxx” 这行字。
  • 调用方执行完对应的工具后,把结果包装成 tool_result 块,塞进下一条消息(对应 Observation)发回去。
  • 模型收到 Observation 后继续推理,如果还需要行动,再次返回 tool_use;如果信息够了,返回 stop_reason: "end_turn",循环结束。

这个"发请求 → 判断 stop_reason → 执行工具 → 把结果拼回消息 → 再发请求"的过程,手写一个 while 循环就是最直接的实现:

messages = [{"role": "user", "content": question}]

while True:
    response = client.messages.create(
        model="claude-opus-5", tools=tools, messages=messages,
    )
    messages.append({"role": "assistant", "content": response.content})

    if response.stop_reason != "tool_use":
        break  # 模型给出了 Final Answer

    tool_results = [execute(block) for block in response.content
                     if block.type == "tool_use"]
    messages.append({"role": "user", "content": tool_results})

值得注意的一个细节:如果一轮响应里模型同时发出了多个 tool_use 块(并行调用多个工具),这些工具的执行结果必须在同一条消息里一次性返回,不能拆成多条消息分批发回去——拆开发会让模型逐渐"学会"不再并行调用,退化成每次只发一个 Action。

这个手写循环之外,SDK 通常也会提供一层封装(比如工具调用循环的辅助函数),把这段 while 循环和工具分发都接管掉,调用方只需要定义好每个工具函数本身。两者本质上是同一个循环,区别只是这个循环是自己控制还是交给库控制。

四、ReAct 和其他几种 Agent 模式的关系
#

模式推理方式特点
Chain-of-Thought一次性把推理过程写完,不接触外部世界简单,但假设无法被中途纠正
ReAct思考和行动逐步交替,走一步看一步每步都能被真实观察修正,但容易短视,缺乏全局规划
Plan-and-Execute先生成一个多步骤的整体计划,再逐条执行全局规划更连贯,但计划一旦定死,中途发现前提错了调整成本高
Reflexion在 ReAct 基础上加一层"事后自我反思”,把反思结果存进记忆,指导下一次尝试适合可以重试的任务(比如反复跑测试直到通过),单次循环内不解决短视问题

实践中这几种模式并不互斥——很多实际系统是 Plan-and-Execute 定好大方向,具体到每一步子任务时用 ReAct 循环去摸索着完成,本质是"高层用计划兜底全局连贯性,底层用 ReAct 应对执行中的不确定性"。

五、实践中容易踩的坑
#

没有终止条件,循环收不住。 模型偶尔会陷入"一直觉得信息不够、不停调用工具"的状态,尤其是工具返回的信息本身有噪音或者和问题不完全对口的时候。生产环境里必须给循环设一个硬上限(最大轮数,或者按 token 数设置一个预算),到达上限后强制中断并让模型基于已有信息给出一个答案,而不是无限跑下去。

上下文被 Observation 挤满。 每一轮 Observation 都会被完整塞进上下文,工具返回的原始数据(比如一整页搜索结果、一份完整的日志)如果不做裁剪,几轮循环下来上下文就被无关细节占满,模型的注意力被稀释,早期给的约束反而被后面的噪音盖过去。这和多智能体协作里"上下文隔离"要解决的是同一类问题——只是这里的隔离手段通常是对工具返回结果做摘要或截断,而不是拆出子智能体。

工具选错或编造不存在的参数。 循环轮数越多,模型偏离最初任务、调用一个看似相关但其实文不对题的工具的概率就越高。给工具定义严格的输入 schema、让 API 校验参数格式,能挡掉一部分"格式对但语义错"的调用,但没法根治"选错工具"本身——这更多要靠工具描述写得足够清晰、工具粒度不要太碎。

把失败的 Action 直接丢弃。 工具调用失败时(比如 API 报错、执行超时),正确做法是把错误信息也作为一次 Observation 返回给模型,让它在下一轮 Thought 里感知到"这条路走不通",而不是静默跳过——静默跳过会让模型继续基于一个从未发生过的假设推理下去。

六、总结
#

ReAct 的贡献不是发明了"调用工具"这件事本身,而是把推理和行动交织在一起,让每一步的思考都能被外部世界的真实反馈及时修正,而不是一口气把整个计划憋出来之后才发现前提错了。这个 Thought → Action → Observation 的循环现在已经是几乎所有 Agent 系统的最小公倍数——不管上层套了多复杂的规划、记忆或多智能体调度逻辑,拆到最底层,负责"和外部世界打交道"的那部分,跑的基本还是这个循环。理解了这个骨架,再去看具体框架的实现细节(工具怎么定义、循环怎么终止、上下文怎么裁剪),会发现大多是在这个基本模式上做工程化的取舍,而不是另起炉灶的新东西。

相关文章

AI Agent的记忆与技能系统:从失忆到越用越懂你

大语言模型本质上是无状态的——每次调用,模型对"你是谁"“上次聊了什么"“你喜欢什么风格"一无所知,除非这些信息被显式塞进当前的上下文窗口。这和 RAG 要解决的问题不是一回事:RAG 补的是模型"没见过的知识”,而这里要聊的是模型"没记住的经历”——同一个用户、同一个项目,换一次会话就打回原形,昨天纠正过的错误今天还会再犯一遍。

AI浪潮下,后端开发岗位正在发生什么

5 分钟
“AI 要取代程序员了"这句话已经被说了三年多,热度不减,但也越说越空。它更像一句情绪表达,而不是一个可以拿来做决策依据的判断。与其纠结这个非黑即白的问题,不如换个更具体的问法:在后端、企业级开发这个具体场景里,AI 已经实际改变了什么,还没有改变什么,正在改变什么。这篇笔记只谈这个。

RAG检索增强生成:原理、数据切片与向量化详解

11 分钟
大语言模型(LLM)虽然拥有海量的通用知识,但它的知识边界止于训练数据的截止日期,也无法访问企业内部文档、私有数据库这类"没见过"的信息。想让模型回答这些问题,通常有两条路:**微调(Fine-tuning)把新知识"炼"进参数里,或者RAG(Retrieval-Augmented Generation,检索增强生成)**在回答前先把相关资料"喂"给模型。本文重点讲后者——它的基本原理、数据切片(Chunking)与向量化(Embedding)的具体做法,以及一个经常被混淆的问题:向量化和大模型训练到底是不是一回事。

OpenClaw 使用指南:用 Skills 实现 AI 全自动操控电脑

11 分钟
在 AI 浪潮席卷全球的今天,我们不再满足于让 AI 仅仅回答问题——我们希望 AI 能够真正帮我们干活。OpenClaw 正是这样一个框架:它让大语言模型(LLM)拥有"手脚",通过可插拔的 Skills(技能) 系统,让 AI 代理能够执行文件操作、运行命令、自动化浏览器、管理进程……几乎所有你能用鼠标键盘做的事,OpenClaw 都能让 AI 替你完成。

MCP的AI上下文管理心得

在使用 MCP(Model Context Protocol,模型上下文协议)构建 AI 应用的过程中,上下文管理是绕不开的核心话题。无论是对话系统、代码助手还是知识库问答,上下文的质量直接决定了 AI 响应的准确性和连贯性。本文结合实际使用经验,聊一聊在 MCP 体系下做好 AI 上下文管理的一些心得。

AI的发展与现状:从传统机器学习到MCP与Skills的新纪元

10 分钟
人工智能(Artificial Intelligence, AI)作为21世纪最具革命性的技术之一,正在深刻地改变着我们的生活方式、工作模式和社会结构。从早期的专家系统到如今的大语言模型,AI技术经历了多个发展阶段,而近期MCP(Model Context Protocol)和Skills的出现,更是将AI应用推向了新的高度。

TLS非对称加密流程详解:从握手到对称加密通信

13 分钟
TLS(Transport Layer Security,传输层安全协议)是互联网上最广泛使用的安全协议之一,它为客户端和服务器之间的通信提供了加密、身份验证和数据完整性保护。本文将详细介绍TLS握手过程中客户端和服务端的具体操作,包括CA证书验证、密钥交换,直到最终生成AES对称加密密钥进行正常通信的完整流程。