本文是「从零构建 Coding Agent」系列的第一篇,适合想理解 Agent 核心原理的开发者。
先问一个问题
你知道 AI Agent 和普通 AI 对话助手有什么区别吗?
表面上看,都是聊天。但本质上,Agent 有一个循环,让它能把「想法」变成「行动」,把「行动结果」变成「新的思考依据」。
这个循环,就是今天要讲的核心:Agent Loop。
语言模型的「天生缺陷」
语言模型(LLM)本质上是一个「文本生成器」。
给定一段文字,它能生成下一段。但它不会:
- 打开文件查看内容
- 运行命令验证假设
- 读取错误日志
- 根据执行结果调整下一步
它只能「想」,不能「做」。
这就是 Agent 存在的意义——在模型外面套一层循环,让模型通过工具真正与外部世界交互。
Agent Loop 的最小回路
用一个图来表示:
用户输入
│
▼
LLM(模型)
│
├── 普通回答 ──────────────▶ 结束
│
└── tool_use ──────────────▶ 执行工具
│
▼
tool_result
│
▼
写回 messages
│
▼
下一轮继续
关键点只有两个:
- 工具结果必须写回消息历史
- 下一轮模型能看到真实执行结果
如果少了第一步,模型就是在「盲猜」;如果少了第二步,模型就「看不到真实世界」。
几个必须搞懂的概念
Turn(一轮)
Agent 的一次完整交互,包含:
- 把消息发给模型
- 读取模型回复
- 如果调用了工具,执行工具
- 把工具结果写回消息历史
tool_result(工具结果)
工具执行完,不是打印到终端就完了。要包装成特定格式,写回消息历史:
{
"type": "tool_result",
"tool_use_id": "xxx", # 告诉模型这是哪次调用的结果
"content": "执行结果",
}
LoopState(循环状态)
主循环需要维护的状态,最简单也要包含:
state = {
"messages": [...], # 对话历史,模型下一轮要读
"turn_count": 1, # 当前第几轮
"transition_reason": None, # 为什么继续(比如:刚执行完工具)
}
最小实现
用一个完整的 Python 示例来演示:
def agent_loop(state):
while True:
# 1. 调用模型
response = client.messages.create(
model="claude-3-5",
system="你是一个编程助手",
messages=state["messages"],
tools=TOOLS,
max_tokens=8000,
)
# 2. 把助手回复写回历史(这一步很多人会忘!)
state["messages"].append({
"role": "assistant",
"content": response.content,
})
# 3. 如果模型没有调用工具,结束
if response.stop_reason != "tool_use":
return
# 4. 执行工具调用
results = []
for block in response.content:
if block.type == "tool_use":
output = run_tool(block)
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": output,
})
# 5. 把工具结果写回消息历史
state["messages"].append({"role": "user", "content": results})
state["turn_count"] += 1
这就是一个最小可用的 Agent Loop。
新手最容易犯的 5 个错
1. 工具结果只打印,不写回 messages
# ❌ 错误
print(run_bash(command)) # 模型看不到!
# ✅ 正确
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": run_bash(command),
})
messages.append({"role": "user", "content": results})
2. 不保存 assistant 消息
上下文会断掉,模型不知道「自己刚才说了什么」。
3. tool_result 不绑定 tool_use_id
模型分不清哪个结果对应哪次调用。
4. 第一章就上难度
不要一上来就搞流式、并发、错误恢复。先跑通最小回路。
5. 把 messages 当聊天记录
在 Agent 里,messages 不是「展示用的对话历史」,而是「模型下一轮的工作输入」。
为什么这很重要
因为 Agent 之所以「能干活」,不是因为模型有多聪明。
而是因为系统持续把真实执行结果喂回给模型。
就像人一样:光想不干,永远停在原地;干了之后看到结果,才能调整下一步行动。
下一章预告
有了 Loop 基础,下一章我们来看:如何给 Agent 添加更多工具(读文件、写文件、改文件...),让它从「只会执行命令」升级为「能操作项目」的真正 Coding Agent。
一句话总结:Agent Loop 的本质,是把「模型的动作意图」变成「真实执行结果」,再把结果送回模型继续推理。
如果觉得有帮助,欢迎关注,我会持续更新「从零构建 Coding Agent」系列文章。