Agent 循环(OpenClaw)

Agent 循环是一次完整的 agent 运行过程:接收输入 → 组装上下文 → 模型推理 → 执行工具 → 流式回复 → 持久化。这是把用户消息转化为实际操作和最终回复的核心路径,同时保证会话状态的一致性。

在 OpenClaw 中,每个会话同一时间只能有一个串行运行的循环。循环在模型思考、调用工具和流式输出的过程中,会发出生命周期事件和流事件。本文讲的就是这个循环从头到尾是怎么串起来的。

入口

  • Gateway RPC:agentagent.wait
  • CLI:agent 命令

整体流程

  1. agent RPC 校验参数,解析会话(通过 sessionKey/sessionId),持久化会话元数据,然后立即返回 { runId, acceptedAt }
  2. agentCommand 执行 agent 运行:
    • 解析模型及 thinking/verbose 默认值
    • 加载 skills 快照
    • 调用 runEmbeddedPiAgent(pi-agent-core 运行时)
    • 如果嵌入循环没有发出生命周期结束/错误事件,这里会兜底发出
  3. runEmbeddedPiAgent
    • 通过会话级和全局队列串行化运行
    • 解析模型和认证配置,构建 pi 会话
    • 订阅 pi 事件,流式输出 assistant/tool 增量数据
    • 超时后强制中止运行
    • 返回输出内容和用量元数据
  4. subscribeEmbeddedPiSession 把 pi-agent-core 事件桥接到 OpenClaw 的 agent 流:
    • 工具事件 => stream: "tool"
    • assistant 增量 => stream: "assistant"
    • 生命周期事件 => stream: "lifecycle"phase: "start" | "end" | "error"
  5. agent.wait 使用 waitForAgentJob
    • 等待指定 runId生命周期结束/错误事件
    • 返回 { status: ok|error|timeout, startedAt, endedAt, error? }

队列与并发

  • 运行按会话 key 串行化(会话通道),也可以通过全局通道串行化。
  • 这避免了工具/会话竞争,保证会话历史的一致性。
  • 消息通道可以选择不同的队列模式(collect/steer/followup),这些模式会接入队列系统。详见 命令队列

会话与工作区准备

  • 解析并创建工作区;沙箱模式下可能重定向到沙箱工作区根目录。
  • 加载 skills(或复用快照),注入到环境变量和提示词中。
  • 解析 bootstrap/context 文件,注入到系统提示词报告中。
  • 获取会话写锁;在流式输出之前,SessionManager 完成打开和准备。

提示词组装与系统提示词

  • 系统提示词由 OpenClaw 基础提示词、skills 提示词、bootstrap 上下文和运行时覆盖参数构建。
  • 强制执行模型的 token 限制和 compaction 预留 token 数。
  • 详见 系统提示词

Hook 机制(拦截点)

OpenClaw 有两套 hook 系统:

  • 内部 hook(Gateway hook):基于事件的脚本,用于命令和生命周期事件。
  • 插件 hook:agent/工具生命周期和 Gateway 管线中的扩展点。

内部 hook(Gateway hook)

  • agent:bootstrap:在构建 bootstrap 文件、系统提示词最终确定之前执行。可以用来增删 bootstrap 上下文文件。
  • 命令 hook/new/reset/stop 等命令事件(详见 Hooks 文档)。

详见 Hooks

插件 hook(agent 与 Gateway 生命周期)

这些 hook 在 agent 循环或 Gateway 管线内部运行:

  • before_model_resolve:在会话创建前运行(此时没有 messages),用于在模型解析之前确定性地覆盖 provider/model。
  • before_prompt_build:会话加载后运行(此时有 messages),可注入 prependContextsystemPromptprependSystemContextappendSystemContextprependContext 适合每轮动态文本,system-context 字段适合需要放在系统提示词空间中的稳定指令。
  • before_agent_start:旧版兼容 hook,可能在上述任一阶段运行;建议优先使用上面两个明确的 hook。
  • agent_end:运行完成后,可检查最终消息列表和运行元数据。
  • before_compaction / after_compaction:观察或标注 compaction 周期。
  • before_tool_call / after_tool_call:拦截工具参数/结果。
  • tool_result_persist:同步转换工具结果,在写入会话记录之前执行。
  • message_received / message_sending / message_sent:入站和出站消息 hook。
  • session_start / session_end:会话生命周期边界。
  • gateway_start / gateway_stop:Gateway 生命周期事件。

详见 插件

流式输出与部分回复

  • assistant 增量数据从 pi-agent-core 流式传出,作为 assistant 事件发出。
  • 块级流式输出可以在 text_endmessage_end 时发出部分回复。
  • 推理过程可以作为单独的流发出,也可以作为块级回复发出。
  • 详见 流式输出

工具执行与消息工具

  • 工具的开始/更新/结束事件通过 tool 流发出。
  • 工具结果在记录/发出前会进行大小和图片载荷的清理。
  • 消息工具的发送会被追踪,以避免重复的 assistant 确认。

回复整形与抑制

  • 最终输出由以下部分组装:
    • assistant 文本(可选包含推理过程)
    • 内联工具摘要(verbose 模式且允许时)
    • 模型出错时的 assistant 错误文本
  • NO_REPLY 被视为静默标记,会从输出中过滤掉。
  • 消息工具产生的重复内容会从最终输出中移除。
  • 如果没有可渲染的输出且某个工具出错了,会发出一个兜底的工具错误回复(除非消息工具已经发送了用户可见的回复)。

Compaction 与重试

  • 自动 compaction 发出 compaction 流事件,可能触发重试。
  • 重试时会重置内存中的缓冲区和工具摘要,避免输出重复。
  • 详见 Compaction

事件流(当前实现)

  • lifecycle:由 subscribeEmbeddedPiSession 发出(兜底由 agentCommand 发出)
  • assistant:来自 pi-agent-core 的流式增量
  • tool:来自 pi-agent-core 的工具事件流

聊天通道处理

  • assistant 增量数据被缓冲为聊天 delta 消息。
  • 生命周期结束/错误时发出聊天 final 消息。

超时

  • agent.wait 默认超时:30 秒(仅等待阶段)。可通过 timeoutMs 参数覆盖。
  • Agent 运行时:agents.defaults.timeoutSeconds 默认 600 秒;在 runEmbeddedPiAgent 的中止计时器中强制执行。

可能提前结束的情况

  • Agent 超时(中止)
  • AbortSignal(取消)
  • Gateway 断开连接或 RPC 超时
  • agent.wait 超时(仅超时等待,不会停止 agent)