一句话定义
Agent 循环是"模型推理 → 发起工具调用 → 执行并回填结果 → 再次推理"直至产出最终回复的驱动机制——think、act、observe 三拍子无限反复,是所有 Agent 框架共同的心跳。
为什么重要
kp-001 说"Agent 是 while 循环",本篇把循环拆开看清楚。你要能精确回答:每一步模型实际收到了什么消息?工具结果如何回到上下文?循环何时终止、何时不终止?90% 的 Agent bug 定位发生在循环的消息流层面——工具结果没回填、终止条件缺失导致死循环、状态没保存导致重跑。理解了循环,框架(kp-021)对你而言只是语法糖。
前置知识
kp-001(四要件)、kp-002(上下文)、kp-005(结构化输出)。
核心概念
循环的消息流
以"查北京明天的天气并推荐穿搭"为例,消息数组在循环中的演化:
messages = [system, user] # 第 1 次调用
↓ 模型返回: tool_use(get_weather, {city:"北京"})
messages += [assistant(tool_use)] # 记录模型的调用意图
↓ 你的代码执行工具
messages += [user(tool_result)] # ★ 工具结果以 user/tool 角色回填
↓ 第 2 次调用(模型看见了天气数据)
↓ 模型返回: tool_use(get_forecast_advice, {temp:"-2~5℃"})
… 重复 …
↓ 第 N 次调用,模型返回: 纯文本回复
循环结束 → 文本展示给用户
三个不变式:
- 工具结果是消息:执行结果必须 append 回
messages再进入下一轮——忘了回填,模型会重复请求同一工具(经典新手 bug) - 历史全程在场:每次调用都携带完整历史(因此有 kp-003 的成本与腐烂问题)
- 终止由模型信号或代码条件决定:模型返回无
tool_use的纯文本 = "我认为做完了";代码侧必须有最大轮数/超时兜底(防死循环烧钱)
Agent 的状态(State)
循环之外,Agent 还有跨轮存活的状态:
- 消息历史(会话短期记忆)
- 持久状态:任务进度、变量、文件(checkpoint,kp-027 中的断点续跑)
- 环境状态:浏览器会话、工作目录、容器——它们不在上下文里,但影响工具结果
框架的差异大多体现在"状态如何组织":LangGraph 是显式图 + checkpoint,Responses API 是服务端托管状态,自研是消息数组 + 数据库(kp-021)。
单轮 vs 多轮调用
一次用户请求可能触发 1 次(纯问答)到 50+ 次(深度研究)模型调用。轮数是 Agent 的第一成本杠杆:每轮都重放全部历史(kp-027 的缓存与压缩策略都为此而生)。
原理与机制
为什么循环能"自我纠正"?因为每一步的条件分布里都包含了之前所有观察:工具报错 404 进入上下文后,模型下一步的概率质量明显移向"换一个 URL / 搜索一下"——纠错不需要显式编程,它是条件生成的涌现性质。同理,它也可能错上加错(错误观察诱导错误续写),所以要配合反思(kp-014)与护栏。
循环的伪代码骨架(完整可运行版见 kp-017):
pythonmessages = [system_prompt, user_task]
while steps < MAX_STEPS:
resp = llm(messages, tools=toolset)
if resp.stop_reason == "end_turn": # 模型宣布完成
return resp.text
for call in resp.tool_calls: # 可能一次多个调用
result = execute(call) # ★ 你写的胶水代码
messages.append(tool_result(call, result))
steps += 1
raise TaskTooLong() # 兜底:强制终止
直观类比
循环 = 医生问诊:问一句(act:化验单)、看报告(observe)、再决定下一步(think:加查一项还是下诊断)。化验结果会留在病历本上(消息历史),病历越厚医生越了解病情,但也越来越贵(每次都要重读整本病历)。好医生知道何时收手(终止条件),庸医会无限开单(死循环)。
实例与案例
三类典型循环故障与诊断:
| 症状 | 病因 | 修复 |
|---|---|---|
| 同一工具被连续调用 10+ 次 | 结果未回填 / 结果含糊使模型"再试一次" | 检查回填代码;工具返回明确成功/失败标志 |
| 永不终止,绕圈换参数重试 | 无最大轮数;错误信息无指导性 | MAX_STEPS + 工具错误写明"该怎么办"(kp-010) |
| 第 30 轮开始答非所问 | 上下文腐烂 | 压缩/隔离(kp-022/019) |
常见误区
- 误区一:"循环 = while True 简单得很"。循环本身 20 行,工程难点在终止、状态、错误传播与成本——这正是 kp-021 框架存在的理由。
- 误区二:把中间每步都展示给用户。用户要看的是最终答案与关键进度,不是 50 次工具调用流水。
- 误区三:并行调用不重要。模型一次可返回多个独立 tool_use(如同时查三个航班),串行执行是双倍延迟(kp-027)。
- 误区四:状态只存在内存。进程重启一切归零,生产要 checkpoint(kp-027)。
自测题
- 工具结果以什么角色、什么方式进入上下文?
- 循环的两个终止条件分别是什么?
- 为什么说"自我纠正"是条件生成的涌现性质?
(参考答案:1. 作为新消息(tool/user 角色)append 进消息数组;2. 模型返回纯文本(end_turn)或代码侧触发最大轮数/超时;3. 错误观察改变下一步的条件分布,纠错概率自然上升,无需显式错误处理分支。)
与其他知识点的关系
- 可运行实现 → kp-017;推理模式如何填充 think 拍 → kp-012
- 状态持久化 → kp-027;框架对循环的封装 → kp-021
- 上下文随循环膨胀的问题 → kp-003/022
延伸阅读
- Anthropic, Building Effective Agents(agent loop 一节)
- OpenAI, Responses API 文档(服务端循环的形态)