第 6 节 · Agent vs Chatbot:为什么需要循环
一句话回答
Chatbot 是"调用一次 LLM,生成一次回答";Agent 是"程序驱动一个循环,让 LLM 观察状态、选择工具、执行工具、再观察结果,直到完成或触发刹车"。
差别不在"用了多大的模型",而在有没有由程序控制的行动循环。
NOTE
这里的 Chatbot 指工程结构上的"单次裸 LLM 调用",不是产品界面上的"聊天框"。到 2026 年,很多看起来像聊天框的产品,内部其实已经接了搜索、代码执行、文件系统、浏览器或 MCP 工具,架构上更接近 Agent。

同一个问题,两种命运
"请帮我抓取 https://example.com 的内容,告诉我它有多少字节,并把这个字节数除以 7。"
Chatbot 视角
如果只做一次裸 LLM 调用:
resp = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": question}],
)
print(resp.choices[0].message.content)模型没有网络访问权,也不能真的执行除法工具。结果通常只有两种:
- 老实承认:"我无法访问网络,请你贴上网页内容。"
- 自信编造:"
example.com大概有 1256 字节,1256 / 7 ≈ 179.43。"(数字是编的)
Agent 视角
Agent 不把这道题当成"一次生成",而是把它拆成一个循环:
for turn in range(max_iters): # ① 必须有刹车
msg = llm.chat(messages, tools=tools) # ② 调 LLM
messages.append(msg) # ③ 记住本轮决定
if not msg.tool_calls: # ④ 不再要工具?
return msg.content # ⑤ 结束
for call in msg.tool_calls: # ⑥ 执行每个工具
result = run_tool(call.name, call.args)
messages.append(tool_result(call.id, result))
# ⑦ 带着工具结果进入下一轮
return "达到最大轮次,停止"跑出来是这样:
第 1 轮:LLM 说:调 fetch_url("https://example.com")
工具返回:1256 字节
第 2 轮:LLM 说:调 calculator("1256 / 7")
工具返回:179.43
第 3 轮:LLM 说:example.com 共 1256 字节,除以 7 ≈ 179.43
↑ 没有 tool_calls 了,结束同一个 LLM、同一道题,加了一个循环 + 两个工具 + 一个退出条件,命运完全不同。
Chatbot vs Agent 的工程差别
| 维度 | Chatbot | Agent |
|---|---|---|
| 主循环 | 没有 | 有循环,多轮反复调 LLM |
| 输入 | messages: list | messages: list + tools: list[Schema] |
| LLM 输出处理 | 直接 .content 显示 | 检查 tool_calls 字段,分两种走 |
| 外部世界 | 够不到 | 通过工具够得到 |
| 状态 | 上一轮回答 | 持续累积的 messages,含 tool 角色消息 |
| 退出条件 | 回答完就结束 | 不再请求工具 / 达到最大轮次 / 人工中止 |
| 成本与延迟 | 低 | 更高,因为会多次调用模型和工具 |
| 可控性 | 主要靠 prompt | 靠 prompt + 工具集 + 权限 + 循环边界 |
| 典型场景 | FAQ、改写、总结、单轮问答 | 查资料、跑代码、改文件、跨系统执行任务 |
一个关键认知:Agent 不是"更聪明的模型"
最常见的误解:以为换个更大的模型就有了 Agent。
不是。Agent 是程序给 LLM 搭了一套脚手架:工具、状态、循环、权限、日志和退出条件。
Chatbot: 用户 -> [LLM] -> 用户
Agent: 用户 -> [程序{ LLM, 工具, 状态, 循环, 刹车 }] -> 用户
↑
这一层,今天我们要亲手写后面 Day3 会讲 Agent 的不同思考范式(ReAct / Plan-and-Solve / Reflection),都是在这个循环里玩花样——但循环本身不会变。
Workflow vs Agent:不是所有多步调用都叫 Agent
Anthropic 在 2024-2026 年的工程文章里反复强调:最可靠的系统往往不是最复杂的系统。很多任务用单次 LLM 调用、RAG 或固定 workflow 就够了。
| 类型 | 谁决定下一步 | 例子 |
|---|---|---|
| 单次 Chatbot | 没有下一步 | 总结一段文本、改写一封邮件 |
| Workflow | 程序写死路径 | 先分类 → 再调用对应 prompt → 最后格式化 |
| Agent | LLM 在循环里动态决定 | 不知道要查几个文件、跑几次测试、改哪些代码 |
所以,判断是否需要 Agent 的关键不是"听起来高级",而是:
- 任务是否需要根据中间结果动态改变计划
- 是否需要连续调用多个工具
- 是否能接受更高的成本、延迟和不确定性
- 是否有足够的权限控制、日志和人工确认
如果答案是否定的,先用简单方案。
历史插曲:为什么 2023 年这件事突然爆发
while + LLM + 工具 的想法早在 2022 年的 ReAct 论文(Yao et al.)就提出来了,但当时大家只能让模型用 prompt 约定输出 "Action: xxx" 字符串,再用正则去解析——非常脆弱(Day3 会复盘这种写法)。
2023 年 6 月,OpenAI 推出 Function Calling,把"调工具"从 prompt 里搬到了结构化字段 tool_calls,再也不用正则解析。从那天起,写最小 Agent 的门槛骤降。
此后发展很快:
| 时间 | 事件 | 影响 |
|---|---|---|
| 2023.06 | OpenAI Function Calling | 工具调用结构化,Agent 门槛大降 |
| 2024.11 | Anthropic 开源 MCP | 工具和数据源的连接方式开始标准化 |
| 2025.03 | OpenAI Responses API / Agents SDK | 内置 web search、file search、computer use,并提供追踪与编排能力 |
| 2025.05 | OpenAI Codex 云端工程 Agent | 可在沙箱里并行处理代码任务、提 PR |
| 2025-2026 | Coding Agent 普及 | Claude Code、Codex、Cursor、Windsurf 等从补全走向任务委托 |
NOTE
2026 年的重点已经不是"能不能调工具",而是"能不能安全、可观察、可回滚地调工具"。官方产品说明里也越来越强调权限确认、沙箱、审计日志、自动测试和人工最终审核。
下一节我们就来看看这个 Function Calling 协议到底长什么样。
生产级 Agent 还多了什么
本节先讲骨架,但真实 Agent 不能只靠一个 while True:
| 能力 | 为什么重要 |
|---|---|
| 最大轮次 / 超时 | 防止模型反复调用同一个失败工具 |
| 工具权限 | 读文件、写文件、联网、执行命令的风险不同 |
| 沙箱与审批 | 高风险动作需要隔离或人工确认 |
| 错误兜底 | 工具失败时把错误转成可理解的 observation |
| 可观测日志 | 记录每轮决策、工具参数、工具结果,方便复盘 |
| 评测与回归测试 | Agent 会做多步动作,不能只看最终一句话 |
一句话:Agent 越能干,工程护栏越重要。
动手试试
运行 demo_06_chatbot_vs_agent.py,会看到同一道题的两种命运:
cd labs/02-tools-and-agent-loop
python demo_06_chatbot_vs_agent.py注意观察"实验 ② Agent"输出里的轮次日志——这就是今天的核心:循环。
TIP
这个 demo 故意使用"让模型输出 JSON,再由程序解析"的手写版工具调用。它不够稳定,但非常适合看清 Agent Loop 的本质。下一节会把这套手写 JSON 替换成 OpenAI 风格的 tool_calls 协议。
小结
| 概念 | 一句话理解 |
|---|---|
| Chatbot | 一次 LLM 调用 = 一次回答 |
| Workflow | 程序写死多步路径,LLM 只完成其中某些步骤 |
| Agent | LLM 在循环中动态决定下一步,并调用工具行动 |
| Agent Loop | LLM 调用 → 工具调用 → 工具结果写回上下文 → 再调用 LLM |
| 2026 关键词 | 工具权限、沙箱、观测、评测、MCP、后台 Coding Agent |
| 升级路径 | Chatbot + 工具 + 状态 + 循环 + 刹车 = 最小 Agent |
下一节:Function Calling 协议到底是什么样?4 种角色 / Tool Schema / 完整消息流,每一处都拆开看。