前三篇讲了 Agent 是什么、模型如何工作、消息长什么样。这一篇进入 Agent 最核心的部分:循环。几乎所有 Agent 框架,不管包装得多复杂,内核都是同一个循环。
一、最简单的 Agent Loop
Agent Loop 只有四步:
- 调用模型:把目前为止的全部消息发给模型。
- 检查输出:如果模型请求调用工具,进入第 3 步;如果没有,说明它给出了最终回答,循环结束。
- 执行工具:由你的程序真正去执行,拿到结果。
- 回填结果:把工具结果作为新消息追加到消息列表,回到第 1 步。
用伪代码表示:
messages = [{"role": "user", "content": user_question}]
for step in range(MAX_STEPS):
reply = call_model(system_prompt, messages, tools)
messages.append(reply)
if not reply.tool_calls: # 没有工具调用,任务完成
return reply.text
for call in reply.tool_calls: # 可能一次请求多个工具
result = run_tool(call.name, call.arguments)
messages.append({"role": "tool",
"tool_call_id": call.id,
"content": result})
return "超过最大步数,任务未完成"
就这么多。所谓「Agent 自主完成任务」,就是模型在这个循环里一轮一轮地决定下一步做什么,直到它认为任务完成。
二、谁决定循环何时结束
正常情况下,模型自己决定结束:当它认为信息足够、不再需要调用工具时,就直接输出最终回答。
但不能完全依赖模型,程序还需要几道保险:
| 保护机制 | 作用 |
|---|---|
| 最大步数 | 防止无限循环,通常设置在十几到几十步 |
| 最大 token / 费用上限 | 防止一个任务把预算烧光 |
| 总超时 | 防止任务卡住不返回 |
| 重复调用检测 | 同一个工具、同样参数连续调用多次,说明模型陷入了死循环 |
| 人工中断 | 用户可以随时停止 |
触发保护时,不要只是简单报错。更好的做法是让模型基于已有信息做一次总结,告诉用户「查到了什么、还缺什么」。
三、ReAct:边想边做
ReAct 是 Reasoning + Acting 的缩写,是 Agent Loop 背后最有影响力的思路。它的核心是:不要一次性想好所有步骤,而是想一步、做一步、看结果,再决定下一步。
一个 ReAct 过程大致是这样的:
思考:用户问今天下单量为什么下降,我先看每小时的数据。
行动:query_orders(hours=24)
观察:10 点到 11 点下单量比平时少 70%。
思考:问题集中在 10 点之后,看看下单流程哪个环节出错。
行动:query_api_errors(start="10:00", end="11:00")
观察:支付接口错误率 60%,主要是超时。
思考:支付接口超时,看看支付服务的日志。
行动:read_logs(service="payment", start="10:00")
观察:10:05 起连接第三方支付网关持续超时。
思考:原因已经清楚,可以回答了。
回答:……
现在的模型大多不需要你在提示词里显式要求「思考 / 行动 / 观察」格式,工具调用机制本身就实现了这个模式。但理解 ReAct 有助于你设计工具:每个工具的返回结果,都是模型决定下一步的依据,结果越清晰,下一步越准确。
四、ReAct 与一次性规划的对比
| 一次性规划 | ReAct | |
|---|---|---|
| 做法 | 先列出全部步骤,再依次执行 | 每一步根据上一步的结果决定 |
| 优点 | 过程可预期,容易审查 | 能应对中途发现的新情况 |
| 缺点 | 计划赶不上变化 | 可能走弯路,步数难以预估 |
| 适合 | 步骤相对明确的任务 | 排查、调研这类探索性任务 |
实际中两者常结合使用:先列一个粗略计划,执行过程中按 ReAct 方式调整。第 10 篇会专门讲规划。
五、循环里容易出的问题
- 死循环:工具返回的错误信息不清楚,模型反复用同样的参数重试。解决办法是让错误信息说清楚原因和正确用法,并做重复调用检测。
- 过早结束:模型没查完就急着给结论。可以在 System Prompt 里说明「什么情况才算完成」。
- 上下文爆炸:每轮的工具结果都追加进消息列表,十几轮后上下文就满了。第 07 篇会讲怎么处理。
- 跑偏:循环久了,模型忘了最初的目标。可以在关键节点重申任务,或者用待办列表跟踪进度。
六、动手:一个能运行的最小 Agent
把上面的伪代码换成任意一家模型 API,再接一个最简单的工具,比如「获取当前时间」或「执行 ping」,就是一个真正的 Agent。建议亲手写一遍,代码不超过 50 行,但能让你彻底理解后面所有框架在做什么。
写的时候注意三点:
- 把每一轮的消息列表打印出来,观察它是怎么一步步增长的。
- 故意让工具返回一个错误,看模型如何应对。
- 把最大步数设成 2,观察任务被截断时的表现。
本篇小结
- Agent Loop:调用模型 → 有工具调用就执行 → 回填结果 → 再调用,直到模型不再请求工具。
- 结束由模型决定,但必须有最大步数、费用上限、超时等保护。
- ReAct 的核心是边想边做,每步根据观察结果决定下一步。
- 常见问题:死循环、过早结束、上下文爆炸、跑偏。
思考与练习
- 用你熟悉的模型 API 写一个最小 Agent Loop,工具只有一个:执行 ping,然后问它「百度和谷歌哪个延迟更低」。
- 如果模型连续 3 次用相同参数调用同一个工具,你的程序应该怎么处理?
上一篇:AI Agent原理篇03:消息结构与角色:System、User、Assistant、Tool
下一篇:AI Agent原理篇05:Tool Use / Function Calling 原理
返回系列总目录