智能体循环(agent loop)
智能体循环(agent loop)是一次完整的"真实"执行过程:接收输入 → 组装上下文 → 模型推理 → 执行工具 → 流式输出回复 → 持久化状态。这是将一条消息转化为具体行动和最终回复的核心流程,同时确保会话状态始终保持一致。
在 OpenClaw 中,每个会话的循环都是串行执行的。当模型在思考、调用工具、流式输出时,系统会发出相应的生命周期事件和流事件。本文档将带你深入了解这个循环是如何端到端运作的。
入口点
- 网关 RPC:
agent和agent.wait - 命令行:
agent命令
整体工作流程
整个过程可以分为以下几个关键步骤:
-
agentRPC 接收请求后,会验证参数、解析会话(通过sessionKey或sessionId)、持久化会话元数据,然后立即返回{ runId, acceptedAt },让调用方知道请求已受理。 -
agentCommand负责启动智能体:- 解析模型配置,设置思考模式/详细模式的默认值
- 加载技能快照
- 调用
runEmbeddedPiAgent(这是 pi-agent-core 运行时的核心) - 如果嵌入式循环没有发出生命周期结束/错误事件,则补充发出
-
runEmbeddedPiAgent是实际执行循环的地方:- 通过会话级队列和全局队列来串行化运行,避免并发冲突
- 解析模型和认证配置,构建 pi 会话
- 订阅 pi 事件,流式传输助手消息和工具增量
- 强制执行超时机制,超时则中止运行
- 返回执行结果和使用量元数据
-
subscribeEmbeddedPiSession负责将 pi-agent-core 的事件桥接到 OpenClaw 的agent流:- 工具事件 →
stream: "tool" - 助手增量 →
stream: "assistant" - 生命周期事件 →
stream: "lifecycle"(phase: "start" | "end" | "error")
- 工具事件 →
-
agent.wait通过waitForAgentJob等待指定的runId完成:- 等待生命周期结束/错误事件
- 返回
{ status: ok|error|timeout, startedAt, endedAt, error? }
队列与并发控制
为什么需要队列?因为智能体的运行必须有序。
- 每个会话键(session key)对应一个专属通道,运行在该通道内串行执行
- 可选的全局通道可以进一步控制整体并发
- 这种设计有效防止了工具执行和会话状态的竞争条件
- 消息通道可以选择不同的队列模式(
collect/steer/followup),这些模式最终都会馈送到上述队列系统
更多细节请参阅 命令队列。
会话与工作区准备
在智能体开始思考之前,系统需要做好准备工作:
- 工作区:解析并创建工作目录;沙盒运行可能会重定向到沙盒工作区根目录
- 技能:加载技能(或从快照复用),注入到环境变量和提示词中
- 引导上下文:解析引导文件和上下文文件,注入到系统提示中
- 会话锁:获取会话写锁,打开并初始化
SessionManager
提示词组装与系统提示
系统提示是如何构建的?
它由以下几个部分组装而成:OpenClaw 的基础提示 + 技能提示 + 引导上下文 + 本次运行的覆盖配置。组装完成后,会根据模型特定的上下文限制和压缩保留令牌数进行约束。
想了解模型实际看到的系统提示是什么样的?请参阅 系统提示。
钩子点:你可以在哪里拦截和扩展
OpenClaw 提供了两套钩子系统,让你可以在关键节点插入自定义逻辑:
- 内部钩子(Gateway hooks):基于事件的脚本,用于处理命令和生命周期事件
- 插件钩子:深入智能体/工具生命周期和网关管道内部的扩展点
内部钩子(网关钩子)
agent:bootstrap:在构建引导文件时运行,此时系统提示尚未最终确定。你可以用它来添加或移除引导上下文文件。- 命令钩子:
/new、/reset、/stop等命令事件触发。
设置方法和示例请参阅 钩子。
插件钩子(智能体与网关生命周期)
这些钩子运行在智能体循环或网关管道内部:
| 钩子 | 触发时机 | 用途 |
|---|---|---|
before_model_resolve | 会话创建前(无 messages) | 在模型解析前确定性地覆盖提供者/模型 |
before_prompt_build | 会话加载后(有 messages) | 在提交提示前注入 prependContext、systemPrompt、prependSystemContext 或 appendSystemContext。prependContext 适合每轮动态内容,系统上下文字段适合放在系统提示中的稳定指导 |
before_agent_start | 旧版兼容 | 可能在任一阶段运行,建议使用上述明确的新钩子 |
agent_end | 完成后 | 检查最终消息列表和运行元数据 |
before_compaction / after_compaction | 压缩前后 | 观察或注释压缩周期 |
before_tool_call / after_tool_call | 工具调用前后 | 拦截工具参数和结果 |
tool_result_persist | 持久化前 | 在工具结果写入会话记录前同步转换 |
message_received / message_sending / message_sent | 消息流转时 | 入站和出站消息钩子 |
session_start / session_end | 会话边界 | 会话生命周期事件 |
gateway_start / gateway_stop | 网关启停时 | 网关生命周期事件 |
钩子 API 和注册详情请参阅 插件。
流式传输与部分回复
当智能体在生成回复时,内容是如何流式输出的?
- 助手增量从 pi-agent-core 流式传输,以
assistant事件发出 - 块流式传输可以在
text_end或message_end时发出部分回复 - 推理流式传输可以作为独立流发出,也可以作为块回复的一部分
分块机制和块回复行为详见 流式传输。
工具执行与消息工具
工具是智能体与外部世界交互的重要方式:
- 工具的开始、更新、结束事件通过
tool流发出 - 工具结果在记录或发出前,会进行大小裁剪和图像载荷处理
- 消息工具的发送会被跟踪,以避免重复的助手确认消息
回复的组装与抑制
最终回复是如何组装的?
最终载荷由以下部分构成:
- 助手文本(以及可选的推理内容)
- 内联工具摘要(当启用详细模式且允许时)
- 模型出错时的错误提示文本
特殊处理:
NO_REPLY被视为静默标记,会从输出载荷中过滤掉- 消息工具的重复项会从最终载荷中移除
- 如果没有可渲染的载荷且工具出错,会发出后备工具错误回复(但如果消息工具已发送了用户可见的回复,则不会重复发送)
压缩与重试
当上下文过长时,系统会自动压缩:
- 自动压缩会发出
compaction流事件,并可能触发重试 - 重试时,内存缓冲区和工具摘要会被重置,避免重复输出
压缩管道的详细说明请参阅 压缩。
事件流
当前支持的事件流类型:
lifecycle:生命周期事件,由subscribeEmbeddedPiSession发出(agentCommand作为后备)assistant:助手增量,来自 pi-agent-core 的流式输出tool:工具事件,来自 pi-agent-core 的流式输出
聊天通道处理
对于聊天通道(如 Slack、Discord 等):
- 助手增量会被缓冲成聊天
delta消息 - 在生命周期结束/错误时,发出聊天
final消息
超时设置
不同场景有不同的超时配置:
agent.wait默认 30 秒(仅影响等待行为)。可通过timeoutMs参数覆盖。- 智能体运行时默认 600 秒,通过
agents.defaults.timeoutSeconds配置,在runEmbeddedPiAgent的中止计时器中强制执行。
可能提前终止的情况
以下情况可能导致循环提前结束:
- 智能体超时:运行时间超过限制,被中止
- AbortSignal:外部取消信号
- 网关断开或 RPC 超时:网络或服务问题
agent.wait超时:仅影响等待,不会停止智能体运行