---
title: "Agent Loop"
description: "理解 Claude Code 的核心循环机制——AI 如何自主决定工具调用、处理错误、管理上下文，直到任务完成。"
keywords: ["Agentic Loop", "tool_use", "状态机", "auto-compact", "streaming"]
---

## 什么是 Agentic Loop

传统聊天机器人：你问一句，它答一句。
Claude Code 不一样：你说一个需求，它可能连续执行十几步操作才给你最终结果。

这背后的机制叫做 **Agentic Loop**（智能体循环）。它是一个"思考→行动→观察"的不断循环，直到任务完成或遇到终止条件。

<Frame caption="Agentic Loop 循环示意">
  <img src="/docs/images/agentic-loop.png" alt="Agentic Loop 循环图" />
</Frame>

### 为什么需要循环而非一次回答

因为软件工程任务本质上是**探索性**的。AI 不可能在第一步就知道所有信息：

- 它需要先读代码才能知道怎么改
- 它需要先运行命令才能知道结果
- 它需要先搜索才能找到相关文件
- 它需要先修改才能验证是否正确

每一步工具执行都产生**真实信息**——命令输出、文件内容、错误信息——这些是 AI 在执行前不可能预知的。因此，AI 必须在每一步后根据新信息重新决策。

## 循环的四个阶段

每次循环迭代包含四个阶段，形成一个完整的"感知→决策→执行→反馈"周期。

### 阶段一：上下文预处理

在调用 API 之前，系统会依次检查和处理上下文。这是一个串行管道，每一步的输出是下一步的输入：

```
原始消息
  → 工具结果截断（单条输出过长时截断）
  → 历史压缩（Snip 压缩旧消息）
  → 微压缩（工具结果摘要化）
  → 自动压缩（对话接近 token 上限时触发 AI 摘要）
处理后的消息 → 发往 API
```

**设计考量**：为什么是串行管道而非一次性处理？因为每个步骤释放的 token 数会影响下一步的决策。例如，如果 Snip 压缩已经释放了足够的 token，自动压缩就不需要触发了。

### 阶段二：流式 API 调用

系统以流式方式调用 Claude API。流式传输不是"锦上添花"——它是核心设计决策：

- **用户体验**：用户看到 AI 逐字输出，而非等待数秒后一次性显示
- **工具并行执行**：AI 在流式输出过程中就可能发出工具调用，系统可以立即开始执行，不必等流结束
- **可取消性**：用户随时可以中断正在进行的流式响应

### 阶段三：工具执行

如果 AI 请求了工具调用，系统执行工具并将结果回传。这里有两个关键设计：

**并行执行**：当 AI 在一次响应中请求多个独立工具调用时（如同时读两个文件），系统并行执行它们。这直接减少了用户等待时间。

**权限检查**：每个工具执行前都经过权限验证。危险操作（如执行 shell 命令）需要用户确认，安全操作（如读文件）可以自动放行。

### 阶段四：终止或继续

每次迭代结束时，系统判断是否需要继续：

| 条件 | 结果 |
|------|------|
| AI 请求了工具调用 | 继续（下一轮迭代） |
| AI 只返回文本，没有工具调用 | 终止（任务完成） |
| 用户中断 | 终止（用户取消） |
| 达到最大 turn 数 | 终止（安全限制） |
| Token 预算耗尽 | 终止（成本控制） |

## 错误恢复：自愈的状态机

Agentic Loop 不是"正常路径走完就结束"的简单循环。它包含了多层错误恢复机制，使系统在各种异常情况下都能优雅处理。

### 输出截断恢复

当 AI 的响应被 token 上限截断时（AI 话说了一半被切断）：

1. **首次截断**：静默提升输出 token 上限，重试
2. **仍然截断**：注入提示消息让 AI "接着说"，最多重试 3 次
3. **恢复耗尽**：将截断的响应作为最终结果返回

### 上下文过长恢复

当对话历史超过 API 的 token 限制时（413 错误）：

1. **压缩重试**：即时压缩对话历史，生成摘要后重试
2. **压缩后仍过长**：返回错误信息，让用户决定如何处理

关键设计：系统通过标志位防止无限循环——每种恢复路径只尝试一次，不会在"压缩→失败→压缩"之间死循环。

### 模型降级

当主模型不可用时（过载、维护等）：

1. 已收集的响应被保留为历史记录
2. 自动切换到备用模型
3. 通知用户发生了降级
4. 从中断点继续，而不是从头开始

## 状态管理

每次迭代的状态是不可变更新的——系统创建新的状态对象而非就地修改。状态中包含：

- **对话消息**：当前所有消息的数组
- **压缩跟踪**：压缩操作的累计状态
- **恢复计数**：各种错误恢复已尝试的次数
- **继续原因**：上一轮为什么继续（用于检测和避免循环）

**设计考量**：状态中记录"继续原因"是一个关键的防循环机制。系统可以在后续迭代中检查"上一轮是因为压缩重试而继续的"，从而避免在同一个恢复路径上反复尝试。

## 为什么不是"一次规划，批量执行"

一个自然的疑问是：为什么不先让 AI 规划好所有步骤，然后一次性批量执行？

答案在于软件工程的**不确定性**：

- **每步结果影响下一步**：搜索结果决定了要改哪些文件，修改后的编译结果决定了是否需要进一步调整
- **错误需要即时修正**：如果某步失败，AI 需要立即调整策略，而非继续执行无效计划
- **用户可能中途干预**：循环架构允许用户随时打断和修正方向

这不是说 AI 不做规划——事实上系统内置了规划模式（Plan Mode）用于复杂任务。但规划的结果仍然是逐步执行的，每一步都有机会根据新信息调整。

## 一个完整的迭代示例

> 用户："帮我找到项目里所有未使用的导入语句，然后删掉它们"

```
迭代 1: 探索
  AI: 先找到所有 TypeScript 文件
  工具: Glob("**/*.ts") → 返回 42 个文件
  决策: 需要进一步分析 → 继续

迭代 2: 分析
  AI: 搜索这些文件中的 import 语句
  工具: Grep("import.*from") → 在 15 个文件中找到 120 条 import
  决策: 结果太多，需要进一步筛选 → 继续

迭代 3: 精确修改
  AI: 分析哪些 import 未被使用，删除它们
  上下文预处理: 120 条结果被微压缩为摘要
  工具: FileEdit × 3 → 删除 5 条未使用导入
  决策: 需要验证 → 继续

迭代 4: 验证与总结
  AI: 验证修改后编译通过
  工具: Bash("tsc --noEmit") → 编译通过
  决策: 任务完成 → 终止
```

注意这个过程中的关键特征：
- AI 在每一步后根据结果自主决定下一步
- 上下文在迭代过程中动态调整（微压缩被触发）
- 用户全程无需介入

## 接下来

- **流式响应** — 理解流式传输的设计细节和用户体验考量
- **多轮对话** — 跨迭代的上下文管理和会话持久化
- **上下文压缩** — 深入理解自动压缩的触发条件和策略
- **工具系统** — 了解 AI 可以调用哪些工具及其设计
