# Agent loop

> 智能体循环生命周期、流和等待语义

- 网址：https://funcoding.ai/agents/openclaw/concepts/agent-loop/
- 来源：OpenClaw 官方文档原文（中文），MIT 许可，同步于 2026-10-11
- 官方原文：https://docs.openclaw.ai/zh-CN/concepts/agent-loop

---
智能体循环是按会话串行执行的运行流程，它将一条消息转化为操作和回复：接收、上下文组装、模型推理、工具执行、流式传输和持久化。

## 入口点

- Gateway 网关 RPC：`agent` 和 `agent.wait`。
- CLI：`openclaw agent`。

## 运行顺序

1. `agent` RPC 验证参数、解析会话（`sessionKey`/`sessionId`）、持久化会话元数据，并立即返回 `{ runId, acceptedAt }`。
2. `agentCommand` 执行本轮：解析模型及思考/详细/追踪默认值、加载 Skills 快照、调用 `runEmbeddedAgent`；如果嵌入式循环尚未发出 **生命周期结束/错误** 事件，则发出一个后备事件。
3. `runEmbeddedAgent`：通过按会话队列和全局队列串行执行运行、解析模型及身份验证配置文件、构建 OpenClaw 会话、订阅运行时事件、流式传输助手/工具增量、强制执行运行超时（到期时中止），并返回有效载荷及用量元数据。对于 Codex app-server 轮次，如果已接受的轮次在终止事件前停止产生 app-server 进度，也会将其中止。
4. `subscribeEmbeddedAgentSession` 将运行时事件桥接到 `agent` 流：工具事件传到 `stream: "tool"`，助手增量传到 `stream: "assistant"`，生命周期事件传到 `stream: "lifecycle"`（`phase: "start" | "end" | "error"`）。
5. `agent.wait`（`waitForAgentRun`）在 `runId` 上等待 **生命周期结束/错误**，然后返回 `{ status: ok|error|timeout, startedAt, endedAt, error? }`。

## 排队与并发

运行按会话键（会话通道）串行执行，并可选择再经过一个全局通道，从而防止工具/会话竞态。消息渠道选择一种队列模式（steer/followup/collect/interrupt）以将消息送入此通道系统；请参阅[命令队列](https://funcoding.ai/agents/openclaw/concepts/queue/)。

会话文件上的会话写入锁还会额外保护对话记录写入。该锁可感知进程且基于文件，因此能捕获绕过进程内队列或来自其他进程的写入方。写入方默认最多等待 60 秒（可通过环境变量 `OPENCLAW_SESSION_WRITE_LOCK_ACQUIRE_TIMEOUT_MS` 覆盖），之后将会话报告为忙碌状态。

默认情况下，会话写入锁不可重入。如果辅助函数在维持单一逻辑写入方的同时有意嵌套获取同一把锁，则必须通过 `allowReentrant: true` 明确启用。

## 会话与工作区准备

- 解析并创建工作区；沙箱隔离的运行可能会重定向到沙箱工作区根目录。
- 加载 Skills（或从快照复用），并将其注入环境和提示词。
- 解析引导/上下文文件，并将其注入系统提示词。
- 在流式传输开始前获取会话写入锁并准备会话对话记录目标。之后任何对话记录重写、压缩或截断路径都必须在修改 SQLite 对话记录行之前获取同一把锁。

## 提示词组装

系统提示词由 OpenClaw 的基础提示词、Skills 提示词、引导上下文和按运行覆盖项构建。系统会强制执行特定于模型的限制和压缩预留 token。有关模型所见内容，请参阅[系统提示词](https://funcoding.ai/agents/openclaw/concepts/system-prompt/)。

## Hooks

OpenClaw 有两套 Hook 系统：

- **内部钩子**（Gateway 网关钩子）：用于命令和生命周期事件的事件驱动脚本。
- **插件钩子**：智能体/工具生命周期和 Gateway 网关管线中的扩展点。

### 内部钩子（Gateway 网关钩子）

- **`agent:bootstrap`**：在系统提示词最终确定之前构建引导文件时运行。使用它添加或移除引导上下文文件。
- **命令钩子**：`/new`、`/reset`、`/stop` 以及其他命令事件（请参阅 Hooks 文档）。

有关设置和示例，请参阅 [Hooks](https://funcoding.ai/agents/openclaw/automation/hooks/)。

### 插件钩子

这些钩子在智能体循环或 Gateway 网关管线中运行：

| Hook                                                    | 运行时机                                                                                                                                                                                                                                                                                        |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `before_model_resolve`                                  | 会话前（无 `messages`），用于在解析前以确定性方式覆盖提供商/模型。                                                                                                                                                                                                |
| `before_prompt_build`                                   | 加载会话后（含 `messages`），用于在提交前注入 `prependContext`、`systemPrompt`、`prependSystemContext` 或 `appendSystemContext`。对于每轮动态文本，请使用 `prependContext`；对于应属于系统提示词空间的稳定指导，请使用系统上下文字段。 |
| `before_agent_reply`                                    | 内联操作之后、调用 LLM 之前。允许插件接管本轮并返回合成回复，或完全静默该轮。                                                                                                                                                                |
| `agent_end`                                             | 完成后运行，可访问最终消息列表和运行元数据。                                                                                                                                                                                                                             |
| `before_compaction` / `after_compaction`                | 观察压缩周期或为其添加注解。                                                                                                                                                                                                                                                      |
| `before_tool_call` / `after_tool_call`                  | 拦截工具参数/结果。                                                                                                                                                                                                                                                              |
| `before_install`                                        | 操作员安装策略运行后，在暂存的 Skills/插件安装材料上运行，前提是当前进程已加载插件钩子。                                                                                                                                                           |
| `tool_result_persist`                                   | 在工具结果写入 OpenClaw 所有的会话对话记录前，同步转换工具结果。                                                                                                                                                                                      |
| `message_received` / `message_sending` / `message_sent` | 入站和出站消息钩子。                                                                                                                                                                                                                                                         |
| `session_start` / `session_end`                         | 会话生命周期边界。                                                                                                                                                                                                                                                               |
| `gateway_start` / `gateway_stop`                        | Gateway 网关生命周期事件。                                                                                                                                                                                                                                                                   |

出站/工具防护钩子的决策规则：

- `before_tool_call`：`{ block: true }` 是终止决策，并会阻止优先级较低的处理程序。`{ block: false }` 不执行任何操作，也不会清除之前的阻止决策。
- `before_install`：终止/无操作语义与上文相同。对于必须覆盖 CLI 安装和更新路径、由操作员所有的安装允许/阻止决策，请使用 `security.installPolicy`，而不是 `before_install`。
- `message_sending`：`{ cancel: true }` 是终止决策，并会阻止优先级较低的处理程序。`{ cancel: false }` 不执行任何操作，也不会清除之前的取消决策。

有关钩子 API 和注册详情，请参阅[插件钩子](https://funcoding.ai/agents/openclaw/plugins/hooks/)。

Harness 可以适配这些钩子。Codex app-server harness 将 OpenClaw 插件钩子作为已记录镜像表面的兼容性契约；Codex 原生钩子是独立且更底层的 Codex 机制。

## 流式传输

- 助手增量从智能体运行时以 `assistant` 事件形式流式传输。
- 分块流式传输可在 `text_end` 或 `message_end` 时发出部分回复。
- 推理流式传输可以作为独立流，也可以阻止回复。
- 有关分块和分块回复行为，请参阅[流式传输](https://funcoding.ai/agents/openclaw/concepts/streaming/)。

## 工具执行

- 工具开始/更新/结束事件在 `tool` 流上发出。
- 在记录日志/发出事件之前，会按大小和图像有效载荷对工具结果进行清理。
- 系统会跟踪消息工具的发送操作，以抑制重复的助手确认消息。

## 回复成形

最终有效载荷由助手文本（加上可选的推理内容）、内联工具摘要（启用详细模式且允许时），以及模型出错时的助手错误文本组装而成。

- 输出有效载荷会过滤完全匹配的静默 token `NO_REPLY`。
- 最终有效载荷列表会移除消息工具产生的重复项。
- 如果没有剩余的可渲染有效载荷且工具发生错误，则会发出后备工具错误回复，除非消息工具已经发送了用户可见的回复。

## 压缩与重试

自动压缩会发出 `compaction` 流事件，并可能触发重试。重试时，内存缓冲区和工具摘要会重置，以避免重复输出。请参阅[压缩](https://funcoding.ai/agents/openclaw/concepts/compaction/)。

## 事件流

- `lifecycle`：由 `subscribeEmbeddedAgentSession` 发出（也会由 `agentCommand` 作为后备发出）。
- `assistant`：来自智能体运行时的流式增量。
- `tool`：来自智能体运行时的流式工具事件。

Gateway 网关将生命周期事件及工具开始/终止事件投影到容量有限且仅含元数据的[审计账本](https://funcoding.ai/agents/openclaw/cli/audit/)中。此投影会记录来源和结果代码，但不会将提示词、消息、工具参数、工具结果或原始错误从对话记录/运行时路径复制出去。

## 聊天渠道处理

助手增量会缓冲到聊天 `delta` 消息中。发生 **生命周期结束/错误** 时，会发出聊天 `final`。

## 超时

| 超时                                             | 默认值                                 | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ------------------------------------------------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent.wait`                                     | 30s                                    | 仅等待；`timeoutMs` 参数会覆盖此值。不会停止底层运行。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| Agent 运行时（`agents.defaults.timeoutSeconds`） | 172800s (48h)                          | 由 `runEmbeddedAgent` 的中止计时器强制执行。设置 `0` 可获得无限运行时限；模型流活跃性看门狗仍然适用。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| CLI 后端无输出看门狗                   | 每次全新/恢复的 CLI 运行时计算     | 独立于 Agent 运行时，由已注册的后端插件负责。CLI 内部后台任务与父子进程共享生命周期，不会超过 Agent 的总体超时时间继续运行。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| 定时任务隔离的 Agent 轮次                         | 由定时任务负责                          | 调度器在执行开始时启动自己的计时器，在配置的截止时间中止运行，然后执行有界清理，再记录超时，避免陈旧的子会话使执行通道一直卡住。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| 模型空闲超时                               | 云端 120s；自托管 300s           | 如果空闲窗口结束前未收到任何响应分块，OpenClaw 会中止模型请求。`models.providers.<id>.timeoutSeconds` 会延长此空闲看门狗，以适配缓慢的本地/自托管提供商，但仍受任何更短的有限 `agents.defaults.timeoutSeconds` 或特定运行超时约束，因为这些超时控制整个 Agent 运行。即使运行时限无限，提供商类别对应的空闲看门狗仍然生效。由定时任务触发且未明确设置模型/Agent 超时的云端模型运行使用相同默认值；如果明确设置了定时任务运行超时，云端模型流停滞上限为 60s，以便配置的模型回退仍能在外层定时任务截止时间前运行。定时任务在真正的本地端点（loopback/私有 baseUrl）上触发的运行仍保留本地空闲超时退出机制；网络 baseUrl 上的自托管提供商则使用隐式的 300s 看门狗。如果明确设置了定时任务运行超时，本地/自托管请求停滞上限为该超时时间。为缓慢的本地提供商设置 `models.providers.<id>.timeoutSeconds`。 |
| 提供商 HTTP 请求超时                    | `models.providers.<id>.timeoutSeconds` | 涵盖连接、响应头、响应体、SDK 请求超时、受保护的 fetch 中止处理，以及该提供商的模型流空闲看门狗。在提高整个 Agent 运行时超时之前，将其用于缓慢的本地/自托管提供商（例如 Ollama）；如果模型请求需要运行更长时间，请确保 Agent/运行时超时至少与其相同。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |

### 卡住的会话诊断

启用诊断后，内置的两分钟阈值会对长时间没有观察到回复、工具、状态、分块或 ACP 进度的 `processing` 会话进行分类：

- 活跃的嵌入式运行、模型调用和工具调用报告为 `session.long_running`。由所有者管理但静默的模型调用会保持 `session.long_running` 状态，直至达到中止阈值，以免过早将缓慢或非流式提供商标记为停滞。
- 没有近期进度的活跃工作报告为 `session.stalled`。由所有者管理的模型调用在达到或超过中止阈值时切换为 `session.stalled`；无所有者的陈旧模型/工具活动不会被隐藏为长时间运行。
- `session.stuck` 专用于可恢复的陈旧会话记录，包括存在陈旧无所有者模型/工具活动的空闲排队会话。

中止阈值至少为 5 分钟，且为警告阈值的 3 倍。陈旧会话记录会在恢复门禁通过后立即释放受影响的会话执行通道；停滞的嵌入式运行仅在达到中止阈值后才会通过中止进行排空，因此排队的工作可以恢复，而不会切断仅仅运行缓慢的任务。恢复会发出结构化的已请求/已完成结果；仅当同一处理世代仍是当前世代时，才会将诊断状态标记为空闲，并且会话保持不变时，重复的 `session.stuck` 诊断会进行退避。

## 可能提前结束的情况

- Agent 超时（中止）
- AbortSignal（取消）
- Gateway 网关断开连接或 RPC 超时
- `agent.wait` 超时（仅等待，不会停止 Agent）

## 相关内容

- [工具](https://funcoding.ai/agents/openclaw/tools/) - 可用的 Agent 工具
- [Hooks](https://funcoding.ai/agents/openclaw/automation/hooks/) - 由 Agent 生命周期事件触发的事件驱动脚本
- [压缩](https://funcoding.ai/agents/openclaw/concepts/compaction/) - 如何总结长对话
- [Exec 审批](https://funcoding.ai/agents/openclaw/tools/exec-approvals/) - shell 命令的审批门禁
- [思考](https://funcoding.ai/agents/openclaw/tools/thinking/) - 思考/推理级别配置
