基础
Agent loop
智能体循环是按会话串行执行的运行流程,它将消息转化为操作和回复:接收、上下文组装、模型推理、工具执行、流式传输、持久化。
入口点
- Gateway 网关 RPC:
agent和agent.wait。 - CLI:
openclaw agent。
运行顺序
agentRPC 验证参数、解析会话(sessionKey/sessionId)、持久化会话元数据,并立即返回{ runId, acceptedAt }。agentCommand执行当前轮次:解析模型以及 thinking/verbose/trace 默认值、加载 Skills 快照、调用runEmbeddedAgent;如果嵌入式循环尚未发出相应事件,则发出兜底的生命周期结束/错误事件。runEmbeddedAgent:通过按会话队列和全局队列串行执行运行任务,解析模型和身份验证配置文件,构建 OpenClaw 会话,订阅运行时事件,以流式方式传输助手/工具增量,强制执行运行超时(到期时中止),并返回载荷及用量元数据。对于 Codex app-server 轮次,如果已接受的轮次在终止事件之前停止产生 app-server 进度,它也会中止该轮次。subscribeEmbeddedAgentSession将运行时事件桥接到agent流:工具事件发送到stream: "tool",助手增量发送到stream: "assistant",生命周期事件发送到stream: "lifecycle"(phase: "start" | "end" | "error")。agent.wait(waitForAgentRun)等待某个runId的生命周期结束/错误事件,并返回{ status: ok|error|timeout, startedAt, endedAt, error? }。
队列与并发
运行任务按会话键(会话通道)串行执行,并可选择再通过全局通道执行,以防止工具/会话竞态。消息渠道选择一种队列模式(steer/followup/collect/interrupt),将任务送入此通道系统;请参阅命令队列。
会话文件上的会话写入锁还会额外保护会话记录写入。该锁可感知进程并基于文件实现,因此能够捕获绕过进程内队列或来自其他进程的写入方。写入方最多等待 session.writeLock.acquireTimeoutMs(默认 60000 ms;可通过环境变量 OPENCLAW_SESSION_WRITE_LOCK_ACQUIRE_TIMEOUT_MS 覆盖),之后会报告会话正忙。
默认情况下,会话写入锁不可重入。如果某个辅助函数有意嵌套获取同一把锁,同时仍保持单一逻辑写入方,则必须通过 allowReentrant: true 选择启用。
会话和工作区准备
- 解析并创建工作区;沙箱隔离的运行可能会重定向到沙箱工作区根目录。
- 加载 Skills(或从快照复用),并将其注入环境和提示词。
- 解析引导/上下文文件,并将其注入系统提示词。
- 在流式传输开始之前获取会话写入锁,并准备会话记录目标。之后的任何会话记录重写、压缩或截断路径,都必须先获取同一把锁,再修改 SQLite 会话记录行。
提示词组装
系统提示词由 OpenClaw 的基础提示词、Skills 提示词、引导上下文和按运行设置的覆盖项构建而成。系统会强制执行模型特定的限制和压缩保留 token 数。有关模型所见内容,请参阅系统提示词。
Hooks
OpenClaw 有两套钩子系统:
- 内部钩子(Gateway 网关钩子):用于命令和生命周期事件的事件驱动脚本。
- 插件钩子:智能体/工具生命周期和 Gateway 网关管线中的扩展点。
内部钩子(Gateway 网关钩子)
agent:bootstrap:在系统提示词最终确定之前构建引导文件时运行。可用于添加或移除引导上下文文件。- 命令钩子:
/new、/reset、/stop和其他命令事件(请参阅 Hooks 文档)。
有关设置和示例,请参阅 Hooks。
插件钩子
这些钩子在智能体循环或 Gateway 网关管线内运行:
| 钩子 | 运行时机 |
|---|---|
before_model_resolve |
会话前(无 messages),用于在解析之前以确定性方式覆盖提供商/模型。 |
before_prompt_build |
加载会话之后(包含 messages),用于在提交前注入 prependContext、systemPrompt、prependSystemContext 或 appendSystemContext。将 prependContext 用于每轮动态文本,将系统上下文字段用于应置于系统提示词空间中的稳定指导。 |
before_agent_start |
可能在任一阶段运行的旧版兼容钩子;优先使用上述显式钩子。 |
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 和注册详情,请参阅插件钩子。
Harness 可以适配这些钩子。Codex app-server harness 将 OpenClaw 插件钩子作为已记录镜像表面的兼容性契约;Codex 原生钩子是独立且更底层的 Codex 机制。
流式传输
- 助手增量从智能体运行时以
assistant事件的形式流式传输。 - 分块流式传输可以在
text_end或message_end时发出部分回复。 - 推理流式传输可以使用单独的流,也可以阻塞回复。
- 有关分块和分块回复行为,请参阅流式传输。
工具执行
- 工具开始/更新/结束事件在
tool流中发出。 - 在记录日志/发出事件之前,会根据大小和图像载荷对工具结果进行清理。
- 系统会跟踪消息工具发送,以避免重复的助手确认消息。
回复整形
最终载荷由助手文本(以及可选的推理内容)、内联工具摘要(启用 verbose 且允许时)和模型出错时的助手错误文本组装而成。
- 精确的静默 token
NO_REPLY会从出站载荷中过滤掉。 - 消息工具产生的重复内容会从最终载荷列表中移除。
- 如果没有剩余的可渲染载荷且工具发生错误,系统会发出兜底的工具错误回复,除非消息工具已经发送了用户可见的回复。
压缩和重试
自动压缩会发出 compaction 流事件,并且可能触发重试。重试时,内存缓冲区和工具摘要会重置,以避免重复输出。请参阅压缩。
事件流
lifecycle:由subscribeEmbeddedAgentSession发出(agentCommand也会作为兜底发出)。assistant:来自智能体运行时的流式增量。tool:来自智能体运行时的流式工具事件。
Gateway 网关将生命周期事件以及工具开始/终止事件投影到有界、仅含元数据的审计账本中。此投影记录来源和结果代码,但不会将提示词、消息、工具参数、工具结果或原始错误从会话记录/运行时路径中复制出去。
聊天渠道处理
助手增量会缓冲到聊天 delta 消息中。在生命周期结束/错误时发出聊天 final。
超时
| 超时 | 默认值 | 说明 |
|---|---|---|
agent.wait |
30s | 仅等待;timeoutMs 参数可覆盖此值。不会停止底层运行。 |
Agent 运行时(agents.defaults.timeoutSeconds) |
172800s (48h) | 由 runEmbeddedAgent 的中止计时器强制执行。设为 0 可获得无限运行预算;模型流活跃性看门狗仍然适用。 |
| Cron 隔离的 Agent 轮次 | 由 cron 管理 | 调度器在执行开始时启动自己的计时器,在配置的截止时间中止运行,然后执行有界清理,之后再记录超时,以免过期的子会话导致该执行通道一直卡住。 |
| 模型空闲超时 | 云端 120s;自托管 300s | 如果在空闲窗口结束前没有收到响应分块,OpenClaw 会中止模型请求。对于较慢的本地/自托管提供商,models.providers.<id>.timeoutSeconds 可延长此空闲看门狗,但仍受任何更低的有限 agents.defaults.timeoutSeconds 或运行特定超时的约束,因为它们控制整个 Agent 运行。无限运行预算仍会保留按提供商类别设置的空闲看门狗。由 Cron 触发且未显式设置模型/Agent 超时的云端模型运行使用相同的默认值;如果显式设置了 Cron 运行超时,云端模型流停滞时间上限为 60s,以便配置的模型回退仍可在外层 Cron 截止时间前运行。由 Cron 触发且使用真正本地端点(loopback/私有 baseUrl)的运行会保留本地空闲超时退出机制;使用网络 baseUrl 的自托管提供商会获得隐式的 300s 看门狗。如果显式设置了 Cron 运行超时,本地/自托管停滞时间上限为该超时值。对于较慢的本地提供商,请设置 models.providers.<id>.timeoutSeconds。 |
| 提供商 HTTP 请求超时 | models.providers.<id>.timeoutSeconds |
涵盖连接、响应头、响应体、SDK 请求超时、受保护的 fetch 中止处理,以及该提供商的模型流空闲看门狗。在提高整个 Agent 运行时超时之前,请先将其用于较慢的本地/自托管提供商(例如 Ollama);如果模型请求需要运行更长时间,请确保 Agent/运行时超时至少与其相同。 |
卡住的会话诊断
启用诊断后,diagnostics.stuckSessionWarnMs(默认 120000 ms)会对长时间处于 processing 状态,且未观察到回复、工具、状态、分块或 ACP 进度的会话进行分类:
- 活跃的嵌入式运行、模型调用和工具调用报告为
session.long_running。由所有者管理的静默模型调用会保持session.long_running状态,直到达到diagnostics.stuckSessionAbortMs,避免过早将较慢或非流式提供商标记为停滞。 - 没有近期进度的活跃工作报告为
session.stalled。由所有者管理的模型调用会在达到或超过中止阈值时切换为session.stalled;无所有者的过期模型/工具活动不会被隐藏为长时间运行。 session.stuck专用于可恢复的过期会话记录状态,包括存在无所有者的过期模型/工具活动的空闲排队会话。
diagnostics.stuckSessionAbortMs 默认为至少 5 分钟,且为警告阈值的 3 倍。恢复门禁通过后,过期会话记录状态会立即释放受影响的会话执行通道;停滞的嵌入式运行仅会在达到中止阈值后执行中止并排空,因此排队工作可以恢复,而不会截断仅仅是运行较慢的任务。恢复过程会发出结构化的已请求/已完成结果;仅当同一处理代次仍为当前代次时,才会将诊断状态标记为空闲;会话保持不变期间,重复的 session.stuck 诊断会进行退避。
可能提前结束的位置
- Agent 超时(中止)
- AbortSignal(取消)
- Gateway 网关断开连接或 RPC 超时
agent.wait超时(仅等待,不会停止 Agent)