AI Agent 和普通聊天机器人的关键区别,不是模型参数更大,也不是提示词写得更长,而是它背后有一个能持续运行的循环。
普通聊天机器人通常是“一问一答”:用户给一段输入,大语言模型(Large Language Model,LLM)生成一段输出,然后流程结束。AI Agent 则不同,它会在多轮迭代中观察环境、分析当前状态、选择工具、执行动作、读取结果,再决定下一步怎么做。
这个循环就是 Agent Loop。
一个可靠的 Agent Loop 不能只是:
while True:
call_llm()
这只是无限调用模型,既不会判断目标是否完成,也不会控制成本,更无法处理工具失败、重复尝试、上下文膨胀等问题。生产级 Agent Loop 至少要具备四个能力:
| 能力 | 作用 |
|---|---|
| 状态管理 | 把任务进展、工具结果、重要事实传到下一轮 |
| 行动选择 | 让 LLM 根据上下文决定下一步动作,而不是硬编码固定流程 |
| 观察反馈 | 工具执行结果会改变后续推理路径 |
| 终止条件 | 在目标完成、预算耗尽、陷入重复或达到上限时停止 |
可以把 LLM 看成“大脑”,把 Agent Loop 看成“心跳”。心跳让系统持续感知和行动,但它必须有节律控制、异常处理和停止机制,否则 Agent 会在错误路径上越跑越远。
Agent Loop 解决什么问题
复杂任务很难靠一次模型调用完成。比如“调研三个竞品并生成对比报告”,里面至少包含搜索资料、筛选信息、提取特征、比较差异、组织结构、生成文档等步骤。单次推理只能给出一个静态答案,无法根据中间结果继续决策。
Agent Loop 让任务从“一次性生成”变成“分步推进”。
flowchart LR
U[用户目标] --> L[Agent Loop]
L --> T1[拆解任务]
T1 --> T2[调用工具]
T2 --> T3[读取结果]
T3 --> T4[调整策略]
T4 --> L
L --> R[最终结果]
它主要解决三类问题。
| 问题 | 没有 Loop 的表现 | 有 Loop 的处理方式 |
|---|---|---|
| 任务太复杂 | 一次生成容易遗漏步骤 | 拆成多轮执行,每轮根据结果推进 |
| 环境会变化 | 工具超时或返回空结果后直接失败 | 观察错误,换关键词、换工具或降级策略 |
| 成本会失控 | 不知道用了多少 token,也不知道何时停 | 设置迭代上限、预算上限和收敛检测 |
但 Loop 不是越长越好。没有约束的 Agent Loop 是一台持续消耗 token 的机器,尤其在多智能体场景中,多个 Agent 互相传递上下文,成本可能迅速放大。工程上真正要做的不是“让 Agent 一直跑”,而是“让 Agent 在必要时自主推进,在该停时可靠停止”。
Agent Loop 的五阶段模型
一个典型 Agent Loop 可以拆成五个阶段:感知、推理、规划、行动、观察。
flowchart TD
A[Perceive 感知<br/>接收用户输入、工具结果、错误信息] --> B[Reason 推理<br/>理解当前状态并评估选项]
B --> C[Plan 规划<br/>把推理结果转成可执行步骤]
C --> D[Act 行动<br/>调用工具、写文件、发请求或执行命令]
D --> E[Observe 观察<br/>收集执行结果并更新状态]
E --> A
每个阶段都承担不同职责:
| 阶段 | 输入 | 输出 | 常见问题 |
|---|---|---|---|
| 感知 | 用户目标、工具返回、错误信息 | 当前状态 | 输入太杂,关键信息被淹没 |
| 推理 | 当前状态、任务目标、历史记忆 | 下一步判断 | 模型只关注局部,忽略全局目标 |
| 规划 | 推理结论 | 操作计划 | 计划过细导致僵硬,计划过粗无法执行 |
| 行动 | 工具调用参数、命令、API 请求 | 执行动作 | 工具设计差,错误信息不可用 |
| 观察 | 工具结果、日志、异常 | 新事实和反馈 | 结果原样塞回上下文,导致窗口膨胀 |
并不是所有 Agent 都显式包含 Plan 阶段。ReAct 模式会把推理和行动交替进行,适合探索式任务;Plan-Execute 模式会先生成完整计划,再按顺序执行,适合流程明确的任务。
四种常见 Agent Loop 模式
Agent Loop 没有一个固定形态。不同任务的不确定性、延迟要求、成本预算和可审计要求不同,对应的循环模式也不同。
| 模式 | 核心思路 | 延迟 | 灵活性 | 适合场景 |
|---|---|---|---|---|
| ReAct | 边推理边行动 | 低 | 高 | 搜索、诊断、客服、调试 |
| Plan-Execute | 先规划再执行 | 高 | 中低 | 报告生成、审批流程、批处理 |
| Reflection | 生成后自我评估并修正 | 高 | 中 | 质量敏感的文档、代码、分析任务 |
| Multi-Agent | 多个 Agent 分工协作 | 中高 | 高 | 复杂调研、并行分析、多角色协作 |
ReAct:边想边做
ReAct 是 Reasoning and Acting 的缩写,意思是推理和行动交替发生。Agent 每一轮都会根据最新观察决定下一步,不提前写死完整路径。
sequenceDiagram
participant User as 用户
participant Agent as Agent
participant Tool as 工具
User->>Agent: 给出目标
Agent->>Agent: Thought:判断下一步
Agent->>Tool: Action:调用工具
Tool-->>Agent: Observation:返回结果
Agent->>Agent: Thought:基于结果重新判断
Agent->>Tool: Action:继续调用工具
Tool-->>Agent: Observation:返回结果
Agent-->>User: 输出答案
ReAct 的优势是响应快、适应性强。比如排查接口异常时,Agent 可以先查日志;如果日志为空,就改查监控;如果监控发现错误率升高,再继续查最近发布记录。
它的风险也很明显:缺乏全局规划。长链路任务中,Agent 可能被最近一次观察牵着走,逐渐偏离目标。上下文窗口也会承受压力,因为每一步的思考、动作和结果都可能被追加进去。
适合 ReAct 的任务通常有三个特征:
| 特征 | 示例 |
|---|---|
| 路径不确定 | “查一下为什么这个接口变慢” |
| 需要实时反馈 | “根据搜索结果继续追踪线索” |
| 每一步可以小步验证 | “运行测试,修一个错误,再运行测试” |
Plan-Execute:先规划再执行
Plan-Execute 会先把目标拆成步骤,再交给执行器按计划完成。它更像一个项目管理流程:先定路线,再逐项推进。
flowchart TD
A[用户目标] --> B[Planner 生成计划]
B --> C[Step 1 执行]
C --> D[Step 2 执行]
D --> E[Step 3 执行]
E --> F[汇总结果]
这种模式适合步骤清晰、目标稳定的任务,比如生成竞品分析报告、执行合规检查、批量处理数据。它的可审计性更好,因为每一步为什么存在、执行到哪里、失败在哪里都比较清楚。
代价是灵活性较低。如果环境中途变化,早期计划可能失效。比如计划里写着“调用接口 A 获取数据”,但接口 A 返回权限错误,Agent 不能只是反复执行原计划,而要触发重新规划。
一个更稳妥的 Plan-Execute 结构会在每个阶段加入检查点:
flowchart TD
A[生成计划] --> B[执行当前步骤]
B --> C{步骤成功?}
C -->|是| D{计划完成?}
C -->|否| E[局部修正或重新规划]
E --> B
D -->|否| B
D -->|是| F[输出结果]
Reflection:做完再检查
Reflection Loop 会在生成结果后加入评估和修正环节。它的重点不是“多做几步”,而是让 Agent 对自己的输出进行质量判断。
flowchart LR
A[生成初稿] --> B[评估质量]
B --> C{达到标准?}
C -->|否| D[指出问题并修正]
D --> B
C -->|是| E[输出最终结果]
它适合质量敏感任务,比如写技术设计文档、生成代码补丁、整理研究报告。评估器可以检查结构是否完整、事实是否一致、代码是否满足测试、输出是否符合格式约束。
Reflection 的主要风险是“验证循环”。如果没有明确标准,Agent 可能不断觉得“还能再改一点”,于是陷入生成、检查、微调、再检查的循环。解决办法是把“足够好”的标准写成可判断条件:
| 不好的停止标准 | 更好的停止标准 |
|---|---|
| 结果看起来不错 | 所有必填章节存在,表格字段完整 |
| 代码质量可以 | 单元测试通过,lint 无新增错误 |
| 报告足够完整 | 覆盖指定竞品、指标和结论 |
| 再检查一下 | 最多执行 2 轮评估修正 |
Multi-Agent:分工协作
Multi-Agent Loop 会把任务分配给多个 Agent,让它们分别承担研究、编码、审查、汇总等角色。常见结构是 Lead Agent 负责拆解和协调,Sub-Agent 负责具体执行。
flowchart TD
A[Lead Agent<br/>理解目标并拆解任务] --> B[Research Agent<br/>检索和整理资料]
A --> C[Code Agent<br/>实现或修改代码]
A --> D[Review Agent<br/>检查质量和风险]
B --> E[Lead Agent 汇总]
C --> E
D --> E
E --> F[最终输出]
它适合任务复杂、可以并行、角色边界清楚的场景。比如一个深度调研任务可以让多个 Agent 分别查不同信息源,再由 Lead Agent 合并结论。
Multi-Agent 的成本和复杂度都更高。每个 Agent 都有自己的上下文、工具调用和循环逻辑,彼此通信还会产生额外 token。如果任务本来单 Agent 就能完成,引入多智能体只会增加编排负担。
| 场景 | 是否适合 Multi-Agent | 原因 |
|---|---|---|
| 简单问答 | 不适合 | 编排成本高于收益 |
| 单文件代码修改 | 通常不适合 | 一个 Agent 足够完成理解、修改、验证 |
| 多来源研究报告 | 适合 | 可并行检索和交叉验证 |
| 大型代码迁移 | 可能适合 | 可拆成分析、修改、测试、审查角色 |
| 强实时对话 | 谨慎使用 | 多角色通信会增加延迟 |
终止条件是 Agent Loop 的刹车系统
让模型自己决定何时停止,并不是可靠策略。模型可以表达“任务完成”,但生产系统不能只依赖这句话。终止条件应该由多层机制共同控制。
flowchart TD
A[每轮 Loop 结束] --> B{目标已完成?}
B -->|是| Z[正常结束]
B -->|否| C{达到迭代上限?}
C -->|是| Y[返回部分结果并说明限制]
C -->|否| D{超过 token 或成本预算?}
D -->|是| Y
D -->|否| E{检测到重复或收敛?}
E -->|是| F[触发反思或换策略]
F --> G{仍然无进展?}
G -->|是| Y
G -->|否| H[继续下一轮]
E -->|否| H
常见终止条件可以分成四类。
| 类型 | 示例 | 作用 |
|---|---|---|
| 硬上限 | max_iterations=15、max_retries_per_step=3 |
防止无限循环 |
| 预算上限 | token_budget=50000、cost_limit=5.0 |
防止账单失控 |
| 目标达成 | 测试通过、文件生成、字段齐全 | 正常结束任务 |
| 收敛检测 | 多轮动作相似、结果无新增信息 | 识别卡住状态 |
收敛检测比精确匹配更重要。Agent 可能不是重复同一句话,而是换着说法做同一件事。比如连续几轮都在用相似关键词搜索同一个无结果主题,工具参数略有变化,但本质没有推进。此时可以用语义相似度、工具调用哈希、结果差异度来判断是否陷入循环。
一个实用的 stuck 处理策略可以分成四层:
| 层级 | 动作 | 目的 |
|---|---|---|
| 轻度干预 | 注入反思提示,要求说明重复原因 | 让 Agent 意识到卡住 |
| 策略切换 | 建议换工具、换关键词或换数据源 | 避免重复失败动作 |
| 上下文重置 | 压缩历史,只保留关键事实 | 降低上下文噪声 |
| 优雅退出 | 返回已完成部分和未解决原因 | 避免继续消耗成本 |
一个可落地的 ReAct Loop 骨架
下面的代码强调结构,不绑定具体框架。核心点是:每轮都要构建上下文、选择动作、执行工具、更新记忆,同时检查重复、预算和停止条件。
def run_agent_loop(goal, tools, llm, max_steps=15, token_budget=50_000):
memory = AgentMemory()
recent_calls = []
total_tokens = 0
for step in range(max_steps):
context = memory.build_context(goal=goal)
action = llm.decide_next_action(context=context, tools=tools)
total_tokens += action.token_usage
if action.type == "finish":
return action.final_answer
if total_tokens >= token_budget:
return memory.partial_result(reason="token budget exceeded")
if memory.is_converging(action):
reflection = llm.reflect(
goal=goal,
recent_steps=memory.recent_steps(),
problem="The loop appears to be repeating without progress."
)
memory.add_reflection(reflection)
continue
call_key = hash_tool_call(action.tool_name, action.arguments)
if call_key in recent_calls:
memory.add_observation({
"status": "duplicate_call",
"suggestion": "Use a different tool or change the arguments."
})
continue
recent_calls.append(call_key)
observation = tools.execute(
name=action.tool_name,
arguments=action.arguments
)
memory.add_observation(compress_observation(observation))
if memory.goal_satisfied(goal):
return memory.final_result()
return memory.partial_result(reason="max steps reached")
这段骨架里有几个生产系统必须重视的细节:
| 设计点 | 为什么重要 |
|---|---|
hash_tool_call |
避免同一个工具用同一组参数反复调用 |
compress_observation |
工具结果不原样塞入上下文,降低 token 消耗 |
is_converging |
识别语义重复和无进展循环 |
partial_result |
失败时返回已有成果,而不是只返回错误 |
token_budget |
用程序强制控制成本,不能依赖模型自觉 |
三层记忆:让上下文既够用又不爆炸
Agent Loop 跑到 5 到 10 轮后,上下文管理会变成核心问题。所有历史消息、工具返回、推理过程都塞进 prompt,看似信息完整,实际会带来两个后果:token 成本持续升高,模型更难定位真正重要的信息。
更稳定的做法是把记忆分成三层。
flowchart TD
A[工作记忆<br/>当前最相关事实] --> D[本轮上下文]
B[短期记忆<br/>最近几轮完整步骤] --> D
C[长期记忆<br/>压缩摘要和向量检索] --> D
D --> E[LLM 推理]
| 记忆层 | 保存内容 | 更新方式 | 用途 |
|---|---|---|---|
| 工作记忆 | 当前步骤最相关的少量事实 | 每轮重建 | 让模型专注眼前决策 |
| 短期记忆 | 最近几轮动作和观察 | 滑动窗口保留 | 保持推理连贯 |
| 长期记忆 | 压缩摘要、关键结论、检索索引 | 按需写入和读取 | 保存跨阶段知识 |
上下文窗口应该被当成受限资源,而不是无限日志。静态内容和动态内容要分开管理:系统规则、工具说明属于静态内容;工具结果、错误信息、阶段性结论属于动态内容。工具返回尤其要做摘要,只把对下一步决策有用的信息放进上下文。
一种常见省成本策略是:用便宜模型压缩工具输出,用更强模型做关键推理。比如搜索工具返回 20 条结果,不必把全部网页片段塞给主模型,可以先压成结构化摘要:
{
"status": "ok",
"facts": [
"Competitor A supports SSO and audit logs.",
"Competitor B offers lower pricing for small teams."
],
"uncertainties": [
"Enterprise pricing is not publicly available."
],
"suggested_next_step": "Search for customer case studies or pricing pages."
}
这样的结果比一大段网页文本更适合进入下一轮 Loop。
错误恢复的重点不是重试,而是换策略
很多 Agent 失败不是因为没有重试,而是因为一直重试同一个错误动作。工具超时后再次调用同一个接口、搜索无结果后继续用同一个关键词、权限不足后重复请求同一个资源,都会让 Loop 原地打转。
更合理的错误恢复应该是“少量重试 + 策略转向”。
flowchart TD
A[工具调用失败] --> B{是否临时错误?}
B -->|是| C[快速重试一次]
C --> D{成功?}
D -->|是| E[继续任务]
D -->|否| F[延迟后再试一次]
F --> G{成功?}
G -->|是| E
G -->|否| H[反思失败原因并换策略]
B -->|否| H
H --> I[换工具、换参数、降级或请求人工介入]
工具输出也要为 Agent 提供可行动线索。返回空数组或一句“请求失败”,模型很难判断下一步该做什么。结构化错误信封更有效:
{
"status": "no_results",
"reason": "No documents matched the exact keyword.",
"suggestion": "Try a broader keyword or search by product category."
}
再比如权限错误可以返回:
{
"status": "permission_denied",
"reason": "The current token cannot access billing data.",
"suggestion": "Ask the user to provide billing permission or continue with public pricing data."
}
好的工具输出会告诉 Agent 三件事:发生了什么、为什么失败、下一步可以尝试什么。Loop 的智能程度,很大一部分取决于工具反馈是否清晰。
如何选择合适的 Loop 模式
选择 Agent Loop 模式时,不要从框架或热门架构出发,而要从任务特征出发。
| 任务特征 | 推荐模式 | 原因 |
|---|---|---|
| 路径不确定,需要边查边判断 | ReAct | 每轮可以根据观察调整方向 |
| 步骤固定,结果需要可追踪 | Plan-Execute | 计划清晰,便于审计和回放 |
| 输出质量要求高 | Reflection | 能加入评估和修正 |
| 子任务可以并行,角色边界清楚 | Multi-Agent | 可以分工处理并汇总结果 |
| 成本预算很紧 | 简化 ReAct 或固定 Workflow | 减少多轮推理和角色通信 |
| 风险较高,需要人工确认 | Human-in-the-Loop | 在关键动作前加入人工审批 |
实际系统经常使用混合策略。例如,整体任务用 Plan-Execute 管理阶段,单个步骤内部用 ReAct 探索信息,最终输出前再跑一轮 Reflection 检查质量。
flowchart TD
A[用户目标] --> B[Plan-Execute<br/>拆成阶段]
B --> C[ReAct<br/>阶段内探索和工具调用]
C --> D[Reflection<br/>质量评估和修正]
D --> E{达到标准?}
E -->|否| C
E -->|是| F[输出结果]
这种混合结构比单一模式更贴近真实任务:全局需要计划,局部需要灵活,交付前需要验证。
生产级 Agent Loop 检查清单
一个 Agent Loop 能跑起来不难,难的是稳定、可控、可观测。上线前至少要检查这些点。
| 检查项 | 必要设计 |
|---|---|
| 目标表达 | 目标必须可判断完成,不能只写“尽量做好” |
| 工具协议 | 工具返回 status、reason、suggestion 等结构化字段 |
| 上下文管理 | 区分工作记忆、短期记忆、长期记忆 |
| 去重机制 | 对工具名和参数做哈希,避免重复调用 |
| 收敛检测 | 检查动作相似度、结果新增信息和多轮进展 |
| 成本控制 | 设置 token、金额、迭代次数和单步骤重试上限 |
| 错误恢复 | 重试有限次数,失败后换策略 |
| 优雅退出 | 到达限制时返回部分结果和未完成原因 |
| 可观测性 | 记录每轮输入、动作、工具结果、token 消耗 |
| 人工介入 | 高风险动作前暂停,等待确认 |
尤其要注意两个常见陷阱。
第一个陷阱是把框架默认值当成策略。很多 Agent 框架会提供 max_iterations 之类的参数,但这只是兜底,不等于完整终止逻辑。真正的停止条件还要覆盖目标达成、重复检测、预算熔断和质量标准。
第二个陷阱是用 Multi-Agent 掩盖工具设计问题。如果工具返回的信息含糊,多个 Agent 只会一起在含糊信息里打转。Agent 架构越复杂,对工具协议、状态管理和编排逻辑的要求越高。
小结
Agent Loop 的核心不是“多调用几次模型”,而是把 LLM 放进一个可观察、可控制、可恢复的执行循环里。感知、推理、规划、行动、观察构成了 Agent 自主工作的基础;ReAct、Plan-Execute、Reflection、Multi-Agent 则对应不同任务形态。
工程上最重要的部分往往不在模型本身,而在 Loop 的边界条件:什么时候继续,什么时候换策略,什么时候压缩上下文,什么时候停止。一个可靠的 Agent,不仅要能自己往前走,还要知道在无进展、超预算或达到目标时及时停下。