Agent 循环(OpenClaw)
Agent 循环是一次完整的 agent 运行过程:接收输入 → 组装上下文 → 模型推理 → 执行工具 → 流式回复 → 持久化。这是把用户消息转化为实际操作和最终回复的核心路径,同时保证会话状态的一致性。
在 OpenClaw 中,每个会话同一时间只能有一个串行运行的循环。循环在模型思考、调用工具和流式输出的过程中,会发出生命周期事件和流事件。本文讲的就是这个循环从头到尾是怎么串起来的。
入口
- Gateway RPC:
agent和agent.wait - CLI:
agent命令
整体流程
agentRPC 校验参数,解析会话(通过 sessionKey/sessionId),持久化会话元数据,然后立即返回{ runId, acceptedAt }。agentCommand执行 agent 运行:- 解析模型及 thinking/verbose 默认值
- 加载 skills 快照
- 调用
runEmbeddedPiAgent(pi-agent-core 运行时) - 如果嵌入循环没有发出生命周期结束/错误事件,这里会兜底发出
runEmbeddedPiAgent:- 通过会话级和全局队列串行化运行
- 解析模型和认证配置,构建 pi 会话
- 订阅 pi 事件,流式输出 assistant/tool 增量数据
- 超时后强制中止运行
- 返回输出内容和用量元数据
subscribeEmbeddedPiSession把 pi-agent-core 事件桥接到 OpenClaw 的agent流:- 工具事件 =>
stream: "tool" - assistant 增量 =>
stream: "assistant" - 生命周期事件 =>
stream: "lifecycle"(phase: "start" | "end" | "error")
- 工具事件 =>
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),可注入prependContext、systemPrompt、prependSystemContext或appendSystemContext。prependContext适合每轮动态文本,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_end或message_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)