基础

Agent loop

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

入口点

  • Gateway 网关 RPC:agentagent.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.waitwaitForAgentRun)在 runId 上等待 生命周期结束/错误,然后返回 { status: ok|error|timeout, startedAt, endedAt, error? }

排队与并发

运行按会话键(会话通道)串行执行,并可选择再经过一个全局通道,从而防止工具/会话竞态。消息渠道选择一种队列模式(steer/followup/collect/interrupt)以将消息送入此通道系统;请参阅命令队列

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

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

会话与工作区准备

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

提示词组装

系统提示词由 OpenClaw 的基础提示词、Skills 提示词、引导上下文和按运行覆盖项构建。系统会强制执行特定于模型的限制和压缩预留 token。有关模型所见内容,请参阅系统提示词

Hooks

OpenClaw 有两套 Hook 系统:

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

内部钩子(Gateway 网关钩子)

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

有关设置和示例,请参阅 Hooks

插件钩子

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

Hook 运行时机
before_model_resolve 会话前(无 messages),用于在解析前以确定性方式覆盖提供商/模型。
before_prompt_build 加载会话后(含 messages),用于在提交前注入 prependContextsystemPromptprependSystemContextappendSystemContext。对于每轮动态文本,请使用 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 和注册详情,请参阅插件钩子

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

流式传输

  • 助手增量从智能体运行时以 assistant 事件形式流式传输。
  • 分块流式传输可在 text_endmessage_end 时发出部分回复。
  • 推理流式传输可以作为独立流,也可以阻止回复。
  • 有关分块和分块回复行为,请参阅流式传输

工具执行

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

回复成形

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

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

压缩与重试

自动压缩会发出 compaction 流事件,并可能触发重试。重试时,内存缓冲区和工具摘要会重置,以避免重复输出。请参阅压缩

事件流

  • lifecycle:由 subscribeEmbeddedAgentSession 发出(也会由 agentCommand 作为后备发出)。
  • assistant:来自智能体运行时的流式增量。
  • tool:来自智能体运行时的流式工具事件。

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

聊天渠道处理

助手增量会缓冲到聊天 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)

相关内容

  • 工具 - 可用的 Agent 工具
  • Hooks - 由 Agent 生命周期事件触发的事件驱动脚本
  • 压缩 - 如何总结长对话
  • Exec 审批 - shell 命令的审批门禁
  • 思考 - 思考/推理级别配置
Was this useful?
On this page

On this page