先把"循环"和"循环里的某种模式"分清楚——这是后面所有讨论的语义底座。
建议先读《什么是 Agent》;如果你是跳读,至少先看本章索引与本页 TL;DR。
课程理论地基,用来建立后续所有判断语言。
先把"循环"和"循环里的某种模式"分清楚——这是后面所有讨论的语义底座。
先问控制流、动作空间、终止时机,再谈 agent 能力。
课程主线:稳定概念 + 经典论文 + 官方机制。
Agent Loop ≠ ReAct。Agent Loop 是一个通用抽象(继承自 RL:感知 → 决策 → 行动 → 再感知);ReAct 只是 LLM 时代实例化这个 loop 的一种具体模式,与它平行的还有 Plan-and-Execute、Reflexion、ReWOO、纯 function-calling、Tree-of-Thoughts 等。
"今天所有 LLM Agent 都是 ReAct" 是一种粗暴说法:它们共享同一个 Agent Loop 骨架,但是否在每一步显式 verbalize "Thought"、是否先规划再执行、是否插入反思环节—— 这些区别决定了它们是不同的 loop 模式。
把 01 章那张 Agent–Environment 图展开成时间线,就是 Agent Loop 的本体:
通用 Agent Loop(RL、机器人、经典 AI、LLM Agent 共享)
这张图不是 ReAct 的图——它是所有 agent 的图。一个扫地机器人、一个 AlphaGo、一个 LLM Agent 都在跑这个 loop。差别仅在于:
ReAct(Yao et al. 2022)的关键贡献,不是"提出了循环"——循环 RL 几十年前就有了;而是观察到:
当 Decide 这一步由 LLM 承担时,让模型在同一次生成里先用自然语言"想一句",再吐出动作,比直接吐动作更可靠——而且把上一步动作的"观察结果"塞回 prompt,模型会基于它继续推理。
于是有了那个著名的三段节奏:
Thought: <模型用自然语言推理>
Action: <模型选择的工具调用>
Observation: <runtime 把工具结果塞回来>
# ... 反复出现 ...
Final Answer: <模型决定结束>
注意:
Thought ⇒ assistant message 的 text/reasoning 内容;Action ⇒ tool_calls 字段;Observation ⇒ tool role 的 message。在同一个 Agent Loop 骨架上,可以跑出多种"花纹"。下表是当下你最该认识的几种:
| 模式 | 核心节奏 | 区别 ReAct 的地方 | 典型场景 |
|---|---|---|---|
| Function-Calling Only | Action → Observation → Action → ...(无显式 Thought) | 不 verbalize 推理;OpenAI/Anthropic 标准 function-calling 默认形态 | 简单工具任务;reasoning model(o1/Claude thinking)的"思考"已隐式承包 |
| ReAct | Thought → Action → Observation → Thought → ... | —— 基准 —— | 需要可解释推理痕迹;需要从 observation 反推下一步 |
| Plan-and-Execute | Plan(一次性)→ Execute step 1 → Execute step 2 → ... | 规划与执行解耦,常用两个不同 LLM;规划完成后执行不再"想" | 步骤可预先列清的中长任务;需要审计计划 |
| ReWOO | Reasoning-WithOut-Observation:一次性规划所有 tool calls 及依赖,然后批执行 | 把 Observation 推到最后;token 成本最低 | tool 调用之间有清晰依赖、无需中途修正的任务 |
| Reflexion | Trial → Reflect → Retry(带"反思" memory) | 多了一个显式"反思"阶段,跨 trial 累积经验 | 失败可重试的任务(编码、解谜) |
| Tree-of-Thoughts | 分叉 → 评估 → 剪枝 → 选最优路径 | 不再是线性 loop,而是搜索 | 需要探索多个解的推理任务 |
看到 create_react_agent / AgentExecutor / create_openai_tools_agent 之类工厂函数,先问三个问题:①是否强制 verbalize Thought?②规划与执行是否解耦?③是否有反思/记忆的显式阶段?把它对到上面这张表里——你会发现 LangChain "ReAct" prebuilt 在新版里其实更像 function-calling-only,名字是历史遗留。
无论是哪种模式,落到工程实现上几乎都用同一套消息事件协议(受 OpenAI Chat Completions 影响):
| 论文里的概念 | 消息协议字段 | 由谁产出 |
|---|---|---|
| Thought(推理) | assistant message 的 content / reasoning_content |
LLM |
| Action(动作) | assistant message 的 tool_calls[](含 name + structured args) |
LLM |
| Observation(观察) | tool role 的 message,带 tool_call_id |
Runtime |
| Final Answer(终止) | assistant message 不再含 tool_calls,只有 content |
LLM 自宣 |
注意命名:这是最小 Agent Loop,不是"最小 ReAct"——它默认不强制 verbalize Thought,是当前主流形态。把它读懂,再去看 LangGraph 的 prebuilt agent,就是把同一段逻辑铺成图、加上中断点 / 持久化 / 中间件。
def agent_loop(user_input: str, tools: dict, llm, max_steps: int = 10):
messages = [{"role": "user", "content": user_input}]
for _ in range(max_steps):
resp = llm.chat(messages, tools=list(tools.values()))
messages.append(resp.message)
# —— 终止判定(C 轴):LLM 不再要 tool ——
if not resp.message.tool_calls:
return resp.message.content
# —— 执行动作(B 轴)+ 把 observation 回灌(C 的 feedback)——
for call in resp.message.tool_calls:
try:
obs = tools[call.name].run(**call.args)
except Exception as e:
obs = f"ERROR: {e}" # 错误也回灌,让 LLM 自我修正
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": str(obs),
})
raise RuntimeError("max_steps exceeded") # 终止:硬熔断
把它升级为"标准 ReAct"只需要一个 system prompt 把 LLM 约束为:"每次产出 tool_calls 之前,先在 content 里写一段 Thought 解释为什么要这样调用"。看到了吗——ReAct 是给 LLM 加约束,loop 本身没变。
| 轴 | 由"Agent Loop 抽象"承包的部分 | 各 loop 模式的差异点 |
|---|---|---|
| A 控制流 | 每一轮"是否继续 / 调哪个 tool"全交给 LLM——这是 loop 之所以 "agentic" 的根本 | Plan-and-Execute / ReWOO 在第一步就把 A 收紧到一个预定义计划里 |
| B 动作空间 | Loop 本身不管 B;B 由"注册了哪些 tool"决定 | 所有模式共享 03 章的 tool calling 协议 |
| C 终止 | 用协议(不再产 tool_calls / Final Answer)让 LLM 自宣,外加 max_steps 兜底 | Reflexion 在"自宣终止"前再加一道反思,可能逆转判断 |
一句话记忆:Agent Loop 兑现 A 和 C;Tool Calling 兑现 B。 二者拼起来是 LLM Agent 的最小可用骨架;具体 loop 模式(ReAct 等)是在这副骨架上加的策略层约束。
| 失败模式 | 触发条件 | 缓解手段 |
|---|---|---|
| 死循环 / 反复横跳 | 模型一直输出同一个 tool_call,或在 2~3 个工具间来回 | max_steps 硬熔断 + 检测重复 tool_call 后强行注入 system 提示 + 引入 planning tool 让模型外化目标 |
| 过早停止(premature stop) | 模型一遇模糊就 final_answer,不再 act | system prompt 明确"未达成 X 之前禁止 final_answer";HITL 模式可在 stop 前加二次确认;Reflexion 模式天然能逆转 |
| 错误 observation 后失忆 | 工具报错后模型不读 ERROR、继续走原计划 | 把错误 observation 包成 ERROR: ... 文案,必要时再追加 system "请基于上一步错误调整方案" |
另有一类更微妙的 注意力衰减:messages 累到几十轮后,开头的 user 目标被 lost-in-the-middle,看起来像 premature stop / 偏题。这是 05 章 Context Window 要解决的事,也是进阶 Agent 框架普遍引入文件系统和 subagent 的根本原因。
| 朴素 ReAct 的弱点 | 进阶框架的常见补法 | 本质上是 loop 的什么变形 |
|---|---|---|
| 长任务里"目标"被新观察淹没 | Planning tool(write_todos) | 把"目标"从短期记忆(messages)外化到一份可读写状态——往 Plan-and-Execute 借了一半思想 |
| Observation 越来越长 ⇒ token 爆 + lost-in-the-middle | Virtual file system | 把"观察"做分页:messages 里只留摘要 + 路径,需要时再读 |
| 单 loop 塞太多目标 ⇒ 决策质量下降 | Subagent | 把一段子 loop 整段切出去跑,主 loop 把它当成一个"复合 action" |
| 任意 tool 立即执行 ⇒ 安全风险 | HITL / 权限层 | 在 Action → Tool 之间插断点;等价于让"人"成为部分动作的策略 π |
每读一个进阶框架特性,问自己:① 它修改了 loop 的哪一段(Perceive / Decide / Act / Observe)?② 它把 ReAct 往哪个谱系拉(Plan-and-Execute?Reflexion?)?③ 在 01 章三轴上落在哪条?
01-frameworks/* —— 进阶 Agent 框架的内核都是被加强过的 Agent Loop;逐个去拆它们的 loop 形态。04-comparative-architectures/* —— Claude Code / Cursor / Codex / OpenAI Swarm / AutoGen 等的 agent 节点几乎都能映射回本章谱系里的某一档。常见误解:把 Agent 当成某个厂商的产品名词。更稳的做法是先回到 RL/AIMA 的闭环抽象,再看具体实现。
最小练习:用本页术语复述你熟悉的一个 agent 或 workflow,明确 A / B / C 三轴分别由谁控制。
下一页会把这页结论推进到《Tool Calling 机制》,帮助你把知识链条接起来。
章节定位:00 · Foundations。