The Agent Loop - 理解 Agent 循环的本质
“One loop & Bash is all you need.”
这句话出自 Claude Code 的设计哲学,概括了 Agent 的本质。不是框架,不是复杂的提示词链,不是精心编排的工作流——只是一个循环,加上 Bash 工具。
这个循环长什么样?
def agent_loop(messages: list): while True: response = client.messages.create( model=MODEL, system=SYSTEM, messages=messages, tools=TOOLS, max_tokens=8000, ) messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use": return
results = [] for block in response.content: if block.type == "tool_use": output = run_bash(block.input["command"]) results.append({ "type": "tool_result", "tool_use_id": block.id, "content": output, }) messages.append({"role": "user", "content": results})就这么简单。while True 加一个 stop_reason 检测,这是 Agent Loop 的全部骨架。
谁在决策?
看这段代码,你可能会有疑问:循环这么简单,智能在哪里?
答案:循环本身没有智能。
| 概念 | 定义 | 职责 |
|---|---|---|
| Agent | 模型本身 | 决策、感知、推理、行动 |
| Harness | 工具 + 循环 + 反馈 | 执行、反馈、安全护栏 |
| Loop | while True + stop_reason | 完全服从模型决定 |
| Hook | 边界守护 | 安全护栏,不替模型决策 |
Agent 是模型——那个在行动序列数据上学会了感知、推理、行动的神经网络。不是框架,不是提示词链,不是工作流编排。
Harness 不替模型做判断。它只做三件事:
- 执行:运行工具,返回结果
- 反馈:把结果 append 到 messages
- 护栏:Hook 提供安全边界
决策权完全在模型。循环只是忠实地执行模型的意图。
stop_reason:唯一的退出条件
回到代码的关键行:
if response.stop_reason != "tool_use": return这是循环唯一的退出条件。stop_reason 有四种值:
| 值 | 含义 | 循环行为 |
|---|---|---|
tool_use | 模型调用了工具 | 继续循环,执行工具 |
end_turn | 模型主动结束 | 退出循环 |
max_tokens | Token 耗尽,被迫截断 | 退出循环 |
stop_sequence | 遇到停止序列 | 退出循环 |
为什么必须用 stop_reason 检测,而不是检测 tool_use 是否存在?
新手容易犯的错误:看到响应里有 tool_use block 就执行,没有就退出。这看起来合理,但会在 max_tokens 截断时出问题。
当 max_tokens 被触发时,响应可能包含一个未完成的 tool_use block。模型还没说完,工具调用可能缺少参数或格式错误。如果这时执行它,就会产生错误行为。
正确的做法:只有当 stop_reason == "tool_use" 时才执行工具——这表示模型完整地表达了调用意图。
验证你的理解
读到这里,用两个问题检验你的心智模型是否稳固:
Q1:循环能不能阻止模型重复调用同一个命令?
比如
ls → del → ls,模型连续两次调用 ls。:::details 答案 不能,也不应该。
ls → del → ls是合理的验证行为:删除后确认文件是否消失。循环不替模型做决策。Hook 可以提供安全护栏(比如”禁止删除系统文件”),但不是决策替代。 :::
Q2:如果要在循环里加”智能检测”防止无限循环,好主意吗?
:::details 答案 坏主意。这违背了职责分离原则。
Harness 的职责是执行、反馈、护栏——不是判断模型的意图是否”合理”。如果模型陷入无限循环,问题在模型(提示词、上下文、能力边界),不是循环。
Hook 可以设置超时或调用次数上限作为硬边界,但这是安全护栏,不是”智能判断”。 :::
如果这两个问题你都能答对,说明你已经理解了 Agent Loop 的本质:循环服从模型,Harness 不替模型决策。
messages:给模型”时间感”
还有一个关键机制:messages[] 的累积。
再看代码的两处 append:
# 第 8 行:记录模型的响应messages.append({"role": "assistant", "content": response.content})
# 第 17 行:记录工具执行结果messages.append({"role": "user", "content": results})每次循环,messages 都在增长。模型能看到完整的对话轨迹:
user: 请帮我列出当前目录assistant: [tool_use: ls]user: [tool_result: file1.txt, file2.txt, file3.txt]assistant: 文件列表如下:...这就是模型的”时间感”——它知道自己做过什么,看到了什么结果。没有这个累积,模型就像失忆了,每次调用都从零开始。
messages 是 Agent 的记忆载体。Context Compact(L06)会讲解当 messages 太长时如何压缩,但核心原理不变:累积历史,给模型上下文。
验证你的理解
Q3:如果每次循环都清空 messages,会发生什么?
:::details 答案 模型会”失忆”——每次调用都从零开始,不知道自己做过什么。
比如:模型调用
ls看到文件列表,然后调用del file.txt。如果 messages 被清空,模型就不知道刚才看到了什么文件,也不知道删除是否成功。messages 的累积是 Agent 能做复杂任务的前提:它需要知道自己”走到哪里了”。 :::
扩展视角:循环上的叠加
理解 Agent Loop 后,你会发现后续的课程都在这个循环上叠加机制——循环本身始终不变:
| 课程 | 叠加机制 | 循环的变化 |
|---|---|---|
| L02 | Tool Use | 加工具,不改循环 |
| L03 | TodoWrite | 循环上加规划 |
| L04 | Subagent | 循环派生子循环 |
| L05 | Skill Loading | 循环中注入知识 |
| L06 | Context Compact | 循环的上下文管理 |
| L07-L12 | 持久化与团队协作 | 循环的状态保存 |
核心洞察:无论机制多复杂,骨架始终是 while True + stop_reason。理解 L01,就理解了后续所有课程的根基。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!