原文:Agent Loop
核心流程
OpenClaw 的 Agent Loop 和 Claude Code 的 Agentic Loop 在概念上完全一致:
消息输入 → 上下文组装 → 模型推理 → 工具执行 → 流式回复 → 持久化
但实现细节因为”服务型”定位而有显著差异。
运行流程(详细)
1. 入口
- Gateway RPC:
agent和agent.wait - CLI:
openclaw agent命令
2. 请求处理
- 验证参数,解析会话(sessionKey/sessionId)
- 持久化会话元数据
- 立即返回
{runId, acceptedAt}(非阻塞!) - 后台启动 Agent 运行
3. Agent 运行
- 解析模型 + thinking/verbose 默认值
- 加载 Skill 快照
- 调用
runEmbeddedPiAgent(pi-agent-core 运行时) - 发射生命周期事件(start/end/error)
4. 流式输出
三个事件流:
lifecycle:开始/结束/错误assistant:模型输出的文本流tool:工具调用的开始/更新/结束
关键设计:队列化和序列化
每个 session 只能有一个运行中的 Agent Loop。请求被放入 per-session queue 串行执行。
这和 Claude Code 完全不同——Claude Code 是单用户 CLI,不需要队列。OpenClaw 是服务,可能同时收到多条消息:
WhatsApp 消息 1 ──→ ┐
WhatsApp 消息 2 ──→ ├──→ Session Queue ──→ 串行执行
Telegram 消息 ──→ ┘
队列模式(command-queue):
- collect:收集消息直到 Agent 空闲后一起处理
- steer:新消息可以中断当前运行
- followup:排队等待
Bootstrap 文件系统
OpenClaw 在首次运行时自动注入 6 个文件到 Agent 上下文:
| 文件 | 用途 | Claude Code 对应 |
|---|---|---|
AGENTS.md | 操作指令 | CLAUDE.md |
SOUL.md | 人格和边界 | 无对应(人格嵌入系统提示) |
TOOLS.md | 工具使用指引 | 无对应(内置) |
BOOTSTRAP.md | 一次性初始化仪式 | 无对应 |
IDENTITY.md | Agent 身份参数 | 无对应 |
USER.md | 用户档案 | 无对应 |
洞察:OpenClaw 把 Claude Code 的单一 CLAUDE.md 拆成了 6 个角色明确的文件。SOUL.md 是特别有趣的——它定义 Agent 的”人格”,这在 Claude Code 中是不存在的(Claude Code 不需要人格,它只是一个编程工具)。
Prompt 组装
系统提示由以下部分组装:
- OpenClaw 基础提示
- Skills 提示
- Bootstrap 上下文文件
- Per-run 覆盖
模型特定的 token 限制和压缩预留在组装时强制执行。
超时和中止
- Agent 运行超时:默认 600 秒(
agents.defaults.timeoutSeconds) agent.wait超时:默认 30 秒(仅等待超时,不停止 Agent)- 支持 AbortSignal 取消
与 Claude Code 的 Loop 对比
| Claude Code | OpenClaw | |
|---|---|---|
| 触发 | 用户在终端输入 | 任何渠道的消息 / RPC 调用 |
| 并发 | 单用户,无需队列 | 多用户,per-session queue |
| 返回 | 同步(等待完成) | 异步(立即返回 runId) |
| Bootstrap | CLAUDE.md(1 个文件) | 6 个角色文件 |
| 流式 | 终端实时打印 | WebSocket 事件流 |
| 中断 | Esc 键 | AbortSignal / 超时 |
| 工具审批 | 权限弹窗 | 无交互审批(服务端自动决策) |
知识检测
概念理解题
-
为什么 OpenClaw 的 Agent Loop 需要 per-session queue?如果不做串行化会出什么问题?
-
OpenClaw 把 CLAUDE.md 拆成 6 个文件(AGENTS.md / SOUL.md / TOOLS.md 等)。这个设计有什么好处?有什么不好的地方?
-
agent.wait的超时和 Agent 运行超时是两个不同的概念。为什么要分开?
应用题
- 你的 OpenClaw Agent 同时收到 WhatsApp 上 3 个用户的消息。画出消息从接收到回复的完整流程图(考虑 dmScope、session queue、Agent Loop)。
迁移思考题
- Claude Code 的 Agent Loop 没有”队列”概念——因为它是单用户 CLI。但如果用 Claude Code 的
-p模式写一个服务来处理多用户请求,你需要自己实现什么?OpenClaw 的设计给你什么启发?
参见
- 01-OpenClaw-Gateway-架构 — Loop 运行在 Gateway 内
- 03-OpenClaw-Session与Memory — Loop 如何管理状态
- Agentic Loop(SlipBox 卡片)— 通用概念
参考答案
1. 为什么需要 per-session queue
如果不串行化:用户快速连发 3 条消息,3 个 Agent Loop 并行运行在同一个 session 上——它们会读到相同的消息历史、可能同时写入相同的文件、工具调用互相竞争。最终 session 状态不一致(消息乱序、工具结果覆盖、上下文重复)。串行化保证每次只有一个 Loop 运行,前一个的结果是下一个的输入,状态始终一致。
2. 6 个 Bootstrap 文件的利弊
好处:(1) 关注点分离——修改人格不影响工具指引,修改操作指令不影响身份 (2) 不同角色可以有不同的写入权限(用户改 SOUL.md,系统生成 IDENTITY.md)(3) 更容易做条件化加载(某些场景不需要 BOOTSTRAP.md)。不好的地方:(1) 6 个文件比 1 个 CLAUDE.md 复杂——新用户上手成本高 (2) 文件之间可能出现冲突指令(AGENTS.md 说”简洁回复”,SOUL.md 说”详细解释”)(3) 需要维护 6 个文件的一致性。
3. agent.wait 超时 vs Agent 运行超时
分开是因为”等待结果”和”执行任务”是两个不同的操作。agent.wait 超时(默认 30s)是调用方的耐心上限——超时后调用方可以去做其他事,但 Agent 仍在后台运行。Agent 运行超时(默认 600s)是任务的资源上限——超时后 Agent 被强制中止。类比:你在餐厅点了菜(agent RPC),等了 30 分钟没上菜你先走了(agent.wait 超时),但厨房可能还在做(Agent 运行中);如果厨房 10 小时还没做完,餐厅关门了(Agent 运行超时)。
4. 3 个用户同时发消息的流程
WhatsApp 渠道接收 → Gateway 根据 dmScope 策略(假设 per-channel-peer)为每个用户创建独立 session → 消息进入各自的 session queue → 每个 queue 独立串行执行 Agent Loop → Loop 完成后通过 WhatsApp 渠道回复对应用户。三个用户的 Loop 互不干扰,可以并行执行(不同 session 不需要串行化)。如果同一用户快速发多条消息,按 queue 模式处理(collect/steer/followup)。
5. 用 Claude Code -p 搭建多用户服务需要什么
需要自己实现:(1) Session 管理(维护 user → session_id 映射)(2) 请求队列(同一用户的请求串行化)(3) 消息路由(从 HTTP/WebSocket 接收请求,调度到对应 session)(4) 流式输出转发(--output-format stream-json → WebSocket 推送)(5) 超时和错误处理。OpenClaw 的启发:这些基础设施占了 Agent 系统 70% 的工程量——模型调用只是其中一小部分。