Agent 架构

行动循环:工具调用与环境交互

助手回合如何通过思考-行动-观察循环(ReAct)扩展为多次工具调用

03 - 行动循环

纯文本的局限

对话循环中的 Assistant 是纯文本的。它接收文本,生成文本。当用户问"今天天气怎么样?",它只能基于训练数据中的天气知识进行推测,无法获取实时信息。

这种局限不仅体现在信息时效性上,还体现在行动能力上。用户说"帮我把文件 A 重命名为 B",纯文本 Assistant 只能回复"我无法直接操作文件系统",然后给出命令示例。

为了让 Assistant 真正做事,我们需要给它手——工具(Tools)。

工具调用

工具是 Assistant 与外部环境交互的接口。一个工具定义包含:

  • 名称:工具的标识
  • 描述:工具的功能说明
  • 参数:输入参数的 Schema

当 Assistant 需要获取实时天气,它可以调用天气查询工具;当需要操作文件,它可以调用文件系统工具。工具的执行在外部环境完成,结果被格式化为文本,重新注入到对话上下文中。

用户: "今天杭州天气怎么样?"

Assistant 思考: 需要获取实时天气信息,我应该调用 weather 工具。
Assistant 行动: 调用 weather(location="杭州")

环境执行工具,返回: "杭州今天晴,气温 18-25°C"

Assistant 观察结果,生成回复: "杭州今天天气晴朗,气温在 18 到 25 度之间。"

嵌套循环的形成

工具调用的引入改变了 Turn 的内部结构。Assistant 不再是一次性生成完整回复,而是可能经历多轮思考-行动-观察的迭代:

User 输入
    │
    ▼
┌─────────────────────────────────────┐
│ Assistant Turn                      │
│                                     │
│   思考 → 需要更多信息?              │
│     │                               │
│     是 ↓                            │
│     行动 → 调用工具                  │
│     观察 → 接收结果                  │
│     ↑                               │
│     └──────── 再次思考 ──────────────┤
│                                     │
│   思考 → 可以回答?                  │
│     │                               │
│     是 ↓                            │
│     生成最终回复                     │
│                                     │
└─────────────────────────────────────┘
    │
    ▼
返回 User

这就是行动循环(Action Loop),有时也称为 ReAct 循环(Reasoning + Acting)。它嵌套在 Turn 内部,使 Assistant 能够在单次 Turn 内自主完成多步骤任务。

Step:单次工具调用

我们将单次工具调用及其结果反馈称为 Step。一个 Turn 可以包含多个 Step:

Turn:
  Step 1: 调用搜索工具查询信息
  Step 2: 调用浏览器工具访问网页
  Step 3: 调用文件工具保存结果
  → 生成最终回复

Step 是 Assistant 与环境的实际交互点。每个 Step 都会改变环境状态(如创建文件、发送请求、修改数据),因此是不可逆的。这也是 Agent 系统中最容易出问题的环节:工具调用可能失败、可能产生副作用、可能被循环滥用。

关于思考

在 ReAct 等早期框架中,思考(Thought)被显式设计为一个独立阶段——模型先输出推理文本,再决定调用什么工具。这种显式分离有助于调试和教学,但并非必需。

现代框架往往不再设计专门的思考阶段。原因有二:

第一,模型拥有内生的反思能力。 现代 LLM 在生成工具调用前,已经进行了充分的内部推理。强制要求它先输出一段"我正在思考..."的文本,再输出工具调用,只是增加了 Token 消耗,并不改变实际的推理质量。

第二,思考可以被模拟。 如果你确实需要模型显式地"停下来想一想",可以实现一个特殊的工具——例如名为 think 的工具,它接受一段文本参数,执行时不进行任何实际操作,只是将这段文本原样返回。从模型的视角看,这是一次正常的工具调用;从系统的视角看,它模拟了思考阶段。

调用: think(reasoning="我需要先确认用户的意图...")
返回: "我需要先确认用户的意图..."

这种设计的好处是统一了接口:思考和行动都是工具调用,无需特殊的分支逻辑。模型可以根据需要决定何时"思考"、何时"行动",甚至可以交替进行。

控制权边界的再审视

引入行动循环后,控制权的流转变得更加精细:

| 边界 | 控制权 | 特点 | |------|--------|------| | Turn 边界 | User ↔ Assistant | 宏观控制权交替 | | Step 边界 | Assistant ↔ Environment | 微观行动执行 |

在 Turn 内部,Assistant 拥有完全自主权。它决定调用什么工具、调用多少次、何时停止。User 无法干预,只能等待 Turn 结束看到最终结果。

这种设计是一把双刃剑。一方面,它解放了 User——不需要手动指导每一步操作;另一方面,它增加了风险——一个错误的循环可能导致大量无效调用甚至破坏性操作。

停止条件

行动循环需要一个停止条件。常见的策略包括:

  • 自然停止:Assistant 认为任务已完成,主动生成最终回复
  • 最大 Step 限制:超过阈值强制停止,防止无限循环
  • 预算限制:Token 消耗或 API 调用成本达到上限
  • 用户中断:提供机制让 User 在 Turn 进行中取消

这些停止条件构成了 Agent 系统的安全网。它们不在模型内部,而是在编排层实现——监视 Step 执行,在必要时强制介入。

从对话到行动

对话循环让我们能够与模型交谈。行动循环让模型能够做事。

当两者结合,我们得到了一个能够接收指令、自主规划、调用工具、返回结果的系统。这就是现代 Agent 的基本形态。

下一章将讨论另一个维度:会话(Session)——多个 Turn 如何组织成完整的任务生命周期,以及在任务开始和结束时需要处理的边界工作。