Agent 开发入门:从「会说」到「会做」,先搞懂 Agent Loop

0 阅读3分钟

本文是「从零构建 Coding Agent」系列的第一篇,适合想理解 Agent 核心原理的开发者。

先问一个问题

你知道 AI Agent 和普通 AI 对话助手有什么区别吗?

表面上看,都是聊天。但本质上,Agent 有一个循环,让它能把「想法」变成「行动」,把「行动结果」变成「新的思考依据」。

这个循环,就是今天要讲的核心:Agent Loop

语言模型的「天生缺陷」

语言模型(LLM)本质上是一个「文本生成器」。

给定一段文字,它能生成下一段。但它不会

  • 打开文件查看内容
  • 运行命令验证假设
  • 读取错误日志
  • 根据执行结果调整下一步

它只能「想」,不能「做」。

这就是 Agent 存在的意义——在模型外面套一层循环,让模型通过工具真正与外部世界交互。

Agent Loop 的最小回路

用一个图来表示:

用户输入
   │
   ▼
LLM(模型)
   │
   ├── 普通回答 ──────────────▶ 结束
   │
   └── tool_use ──────────────▶ 执行工具
                                    │
                                    ▼
                               tool_result
                                    │
                                    ▼
                               写回 messages
                                    │
                                    ▼
                               下一轮继续

关键点只有两个:

  1. 工具结果必须写回消息历史
  2. 下一轮模型能看到真实执行结果

如果少了第一步,模型就是在「盲猜」;如果少了第二步,模型就「看不到真实世界」。

几个必须搞懂的概念

Turn(一轮)

Agent 的一次完整交互,包含:

  1. 把消息发给模型
  2. 读取模型回复
  3. 如果调用了工具,执行工具
  4. 把工具结果写回消息历史

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」系列文章。