OpenClaw 实现原理详解(三):Agent Loop 智能体循环与生命周期

4 阅读4分钟

3.1 什么是智能体循环?

智能体循环(Agent Loop)是 OpenClaw 的核心执行流程,定义了从"收到消息"到"生成回复"的完整路径:

接收消息 → 上下文组装 → 模型推理 → 工具执行 → 流式回复 → 持久化

它是将用户输入转化为操作和最终回复的权威路径,同时保持会话状态的一致性。


3.2 循环的完整生命周期

高层次流程

用户消息
    │
    ▼
┌─────────────────────┐
│  1. agent RPC       │  验证参数,解析会话
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  2. 队列排队         │  按会话键序列化
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  3. 工作区准备       │  加载 Skills、引导文件
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  4. 提示组装         │  构建系统提示 + 历史消息
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  5. 模型推理         │  LLM API 调用
└─────────────────────┘
    │
    ├──────────────────┐
    │                  │
    ▼                  ▼
┌─────────────┐  ┌─────────────┐
│ 文本输出    │  │ 工具调用    │
└─────────────┘  └─────────────┘
    │                  │
    │                  ▼
    │            ┌─────────────┐
    │            │ 执行工具    │
    │            └─────────────┘
    │                  │
    │                  ▼
    │            ┌─────────────┐
    │            │ 返回循环    │ ──→ 回到步骤 5
    │            └─────────────┘
    │
    ▼
┌─────────────────────┐
│  6. 流式输出         │  实时发送给用户
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  7. 会话持久化       │  保存到 JSONL 文件
└─────────────────────┘
    │
    ▼
回复完成

3.3 入口点与触发

RPC 入口

智能体循环通过 Gateway 的 RPC 方法触发:

方法说明
agent启动一次智能体运行,立即返回 runId
agent.wait等待指定的运行完成
// 启动智能体
const response = await gateway.request('agent', {
  sessionKey: 'channel:whatsapp:123456',
  message: '帮我整理文件',
  model: 'claude-3-5-sonnet',
  thinking: true,  // 启用思考模式
});

// 返回
// { runId: 'run_abc123', acceptedAt: '2024-01-15T10:30:00Z' }

CLI 入口

openclaw agent --message "帮我整理文件" --thinking

3.4 队列与并发控制

为什么需要队列?

智能体运行必须序列化,原因:

  1. 会话一致性:避免多个运行同时修改会话历史
  2. 工具竞争:防止工具之间的状态冲突
  3. 资源限制:控制 API 调用和计算资源

队列机制

┌─────────────────────────────────────────┐
│              会话通道队列                │
│                                         │
│  Run A ──→ Run B ──→ Run C ──→ 执行     │
│                                         │
└─────────────────────────────────────────┘

队列模式:

模式说明
collect收集消息,批量处理
steer引导当前运行的方向
followup作为后续任务排队

3.5 上下文组装

工作区准备

在运行开始前,OpenClaw 会:

  1. 解析工作区路径

    ~/.openclaw/agents/<agentId>/workspace/
    
  2. 加载 Skills 快照

    • Skills 定义了工具和提示扩展
    • 快照确保运行期间 Skills 不变
  3. 解析引导文件

    • AGENTS.md - 操作规则
    • USER.md - 用户档案
    • MEMORY.md - 长期记忆
    • HEARTBEAT.md - 定时任务

系统提示构建

┌─────────────────────────────────────────┐
│              系统提示                    │
├─────────────────────────────────────────┤
│  1. OpenClaw 基础提示                   │
│     - 身份定义                          │
│     - 工具使用规则                      │
│     - 安全边界                          │
├─────────────────────────────────────────┤
│  2. Skills 提示                         │
│     - 每个激活的 Skill 的指令           │
│     - 可用工具列表                      │
├─────────────────────────────────────────┤
│  3. 引导上下文                          │
│     - AGENTS.md 内容                    │
│     - USER.md 内容                      │
│     - MEMORY.md 内容                    │
├─────────────────────────────────────────┤
│  4. 运行时覆盖                          │
│     - 用户指定的额外指令                │
│     - 模型特定的调整                    │
└─────────────────────────────────────────┘

3.6 流式输出与事件

事件流

智能体运行过程中发出多种事件:

// 生命周期事件
{ type: 'event', event: 'agent', payload: { stream: 'lifecycle', phase: 'start' } }
{ type: 'event', event: 'agent', payload: { stream: 'lifecycle', phase: 'end' } }

// 助手增量
{ type: 'event', event: 'agent', payload: { stream: 'assistant', delta: '你好' } }

// 工具事件
{ type: 'event', event: 'agent', payload: { stream: 'tool', tool: 'read', phase: 'start' } }
{ type: 'event', event: 'agent', payload: { stream: 'tool', tool: 'read', result: '...' } }

流式回复

助手的文本输出实时流式传输给用户:

[模型输出] ──→ [缓冲] ──→ [事件推送] ──→ [用户看到]
     │
     └─→ "你" ──→ "好" ──→ "!" ──→ "有" ──→ "什" ──→ "么" ──→ ...

3.7 钩子系统:拦截与扩展

OpenClaw 提供了两层钩子系统:

内部钩子(Gateway 钩子)

钩子触发时机
agent:bootstrap系统提示最终确定之前
/new新建会话时
/reset重置会话时
/stop停止运行时

插件钩子

钩子说明
before_agent_start运行开始前,可注入上下文
agent_end完成后检查结果
before_tool_call工具调用前拦截参数
after_tool_call工具调用后处理结果
message_received收到消息时
message_sending发送消息前
session_start / session_end会话生命周期
// 钩子示例:拦截工具调用
registerHook('before_tool_call', async (context) => {
  if (context.tool === 'exec' && context.params.command.includes('rm')) {
    // 拦截危险的删除命令
    return { error: '删除操作需要用户确认' };
  }
});

3.8 超时与取消

超时配置

场景默认超时配置项
agent.wait30秒timeoutMs 参数
智能体运行600秒agents.defaults.timeoutSeconds

中止条件

运行可能提前结束的情况:

  • 超时:运行时间超过限制
  • 取消:用户发送 /stop 或 AbortSignal
  • 断开:Gateway 连接断开
  • 错误:模型 API 错误或工具异常

3.9 回复整形与抑制

NO_REPLY 机制

当智能体决定不回复时,输出 NO_REPLY

if (shouldStaySilent) {
  return 'NO_REPLY';
}

这会被过滤,不会发送给用户。

回复组装

最终回复可能包含:

  1. 助手文本:主要回复内容
  2. 工具摘要:工具执行的简要说明
  3. 推理内容:(可选)模型的思考过程

总结

智能体循环是 OpenClaw 的"心脏":

阶段职责
入口验证参数,分配 runId
排队序列化并发运行
准备加载 Skills 和上下文
组装构建完整的系统提示
推理调用 LLM,可能执行工具
流式实时输出给用户
持久保存会话历史

🦞 下一章预告:我们将深入会话管理系统,了解会话键设计、存储格式、修剪策略等细节。