Agent 原生设计 (Agent-Native)

核心洞察:OpenClaw 不是为了连接渠道而存在,而是为了让 Agent 能够在多渠道环境中有效工作而存在。

核心概念

OpenClaw 的核心设计哲学之四是"Agent 原生设计"——将整个网关架构围绕 AI 代理 (Agent) 的运行需求进行设计,而非将 Agent 作为附加功能。

Agent 原生 vs 传统机器人

维度 传统聊天机器人 Agent 原生系统 (OpenClaw)
交互模式 被动响应(等待用户输入) 主动协作(定时检查、条件触发)
会话管理 简单的对话历史 完整的会话生命周期(隔离 + 连续性)
工具调用 单次调用为主 多轮工具编排、自动故障转移
记忆系统 无或简单的键值存储 跨会话提取、QMD/Honcho 后端、转录搜索
身份定位 功能模块 第一公民(独立工作空间、人格定义)
执行模型 请求 - 响应循环 完整 Agent 循环(思考→行动→持久化)

Agent 原生设计的本质是以代理为中心的系统架构。网关、渠道、会话、工具、记忆系统等所有组件都服务于一个目标:让 Agent 能够安全、高效、持续地执行任务。这种设计哲学反映了 OpenClaw 对 AI 代理作为"数字员工"的定位——Agent 不是工具的使用者,而是系统的第一公民。

这一设计的深层含义是:传统聊天机器人是"响应式"的(等待用户输入后回复),而 Agent 原生的系统是"主动式"的(可以自主执行任务、定时检查、多轮工具调用)。OpenClaw 通过内建的 Agent 循环 (Agent Loop)、会话管理、工具编排等机制,将这种主动性变为默认行为。


设计原则

1. 代理即第一公民 (Agent as First-Class Citizen)

Agent 拥有独立的工作空间 (Workspace)、状态目录 (AgentDir)、会话存储和认证凭证。每个 Agent 是一个完整的"大脑",包含:

  • 人格定义SOUL.md(气质、边界、语气)
  • 操作指令AGENTS.md(启动流程、记忆规则、红线条款)
  • 用户档案USER.md(姓名、时区、偏好称呼)
  • 工具笔记TOOLS.md(SSH 主机、摄像头位置、TTS 偏好)
  • 身份信息IDENTITY.md(名称、生物类型、签名 emoji)
  • 启动仪式BOOTSTRAP.md(一次性引导,完成后删除)

2. 会话隔离与连续性 (Session Isolation & Continuity)

会话是 Agent 与用户交互的基本单位。OpenClaw 通过会话键 (SessionKey) 设计确保清晰的边界:

  • 直聊:默认共享主会话保持连续性
  • 群聊/频道:按 ID 隔离避免上下文混淆
  • 线程:追加到基础键,保持父子关系

3. 工具即能力扩展 (Tools as Capability Extension)

Agent 通过工具系统与外部世界交互:

  • 核心工具read/write/edit/exec 始终可用
  • 技能系统:领域特定能力(GitHub、Dima、语雀等)
  • 审批机制:高风险操作需要人工确认(Owner-Only 策略)
  • 钩子拦截before_tool_call / after_tool_call 提供审计点

4. 循环即执行模型 (Loop as Execution Model)

Agent 循环是完整的执行路径:

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

循环是序列化的,确保会话历史一致性和工具调用顺序正确。

5. 记忆即长期状态 (Memory as Long-Term State)

记忆系统让 Agent 能够跨会话保留信息:

  • 内置记忆:自动从对话中提取关键信息
  • QMD 后端:基于 QMD 格式的记忆存储,支持转录搜索
  • Honcho 后端:外部记忆服务集成,适合大规模存储
  • 跨代理搜索:一个 Agent 可搜索另一个 Agent 的会话转录

架构总览

双层架构图

┌─────────────────────────────────────────────────────────────┐
│               OpenClaw Gateway Layer                        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │   Session   │  │    Tool     │  │   Channel   │          │
│  │  Manager    │  │  Orchestrator│  │  Delivery   │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
│         │                │                │                  │
│         ▼                ▼                ▼                  │
│  ┌─────────────────────────────────────────────────┐        │
│  │         Embedded Pi Agent Core Runtime          │        │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐      │        │
│  │  │  Model   │  │   Tool   │  │  Prompt  │      │        │
│  │  │Inference │  │Execution │  │ Pipeline │      │        │
│  │  └──────────┘  └──────────┘  └──────────┘      │        │
│  └─────────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────────┘

核心组件职责表

组件层 组件名称 职责 源码路径
网关层 Session Manager 会话键生成、路由、持久化 src/session/
网关层 Tool Orchestrator 工具注册、审批、执行编排 src/agents/tool-policy.ts
网关层 Channel Delivery 渠道适配、消息发送 src/channels/
网关层 Hook System 生命周期事件拦截 src/hooks/internal-hooks.ts
运行时层 Pi Agent Core 模型调用、工具执行 pi-agent-core/
运行时层 Prompt Pipeline 系统提示词构建 src/agents/system-prompt.ts
运行时层 Memory Backend 记忆存储与检索 src/memory/

Agent 循环完整生命周期

执行流程图

记忆系统 工具系统 模型服务 Pi Agent 运行时 会话管理器 OpenClaw Gateway 渠道层 用户 记忆系统 工具系统 模型服务 Pi Agent 运行时 会话管理器 OpenClaw Gateway 渠道层 用户 获取会话写锁 AGENTS.md → SOUL.md → IDENTITY.md → USER.md → TOOLS.md → BOOTSTRAP.md → MEMORY.md 发送消息 转发消息 (agent RPC) 解析会话键 返回 sessionKey 持久化会话元数据 返回 { runId, acceptedAt } runEmbeddedPiAgent() 解析模型 + 思考级别 加载相关记忆 返回记忆片段 构建系统提示词 发送推理请求 流式返回思考内容 stream: "assistant" (推理) 流式返回工具调用 执行工具 返回工具结果 stream: "tool" 流式返回最终回复 stream: "assistant" 触发 agent_end 钩子 提取关键信息 持久化完整会话 返回 EmbeddedPiRunResult lifecycle: "end" 发送最终回复

入口点

入口类型 调用方式 用途
Gateway RPC agent 标准调用,立即返回 runId
Gateway RPC agent.wait 等待完成,返回最终状态
CLI 命令 openclaw agent 命令行调试
心跳系统 heartbeat.every 定时自主检查

执行阶段详解

阶段 1:参数验证与会话解析
// src/agents/pi-embedded-runner/run.ts
async function runEmbeddedPiAgent(params: EmbeddedRunParams) {
  // 1. 从 sessionId 回填 sessionKey(如需要)
  const sessionKey = await backfillSessionKey(params.sessionId);
  
  // 2. 解析会话键(考虑多代理路由)
  const resolvedKey = await resolveSessionKeyForRequest({
    sessionKey,
    senderPeer: params.senderPeer,
    accountId: params.accountId,
  });
  
  // 3. 立即返回 runId,异步执行
  return { runId: crypto.randomUUID(), acceptedAt: Date.now() };
}
阶段 2:模型解析与认证
// 模型引用解析规则
// 格式:provider/model 或 别名 → 实际模型

const modelRef = "anthropic/claude-sonnet-4-6";
// 解析过程:
// 1. 按第一个 "/" 分割 → provider: "anthropic", model: "claude-sonnet-4-6"
// 2. 检查是否为已配置的 provider
// 3. 如省略 provider,尝试:
//    a) 内置别名匹配
//    b) 唯一 configured-provider 匹配
//    c) 回退到默认 provider/model

关键配置

{
  agents: {
    defaults: {
      model: {
        primary: "anthropic/claude-sonnet-4-6",
        fallbacks: ["openai/gpt-5.4", "openrouter/moonshotai/kimi-k2"]
      }
    }
  }
}
阶段 3:工作空间准备与启动文件注入

启动文件加载顺序(按优先级排序):

序号 文件名 用途 修剪策略
10 AGENTS.md 操作指令 + 记忆规则 大文件截断
20 SOUL.md 人格定义、边界、语气 大文件截断
30 IDENTITY.md 名称、风格、emoji 小文件,完整加载
40 USER.md 用户档案 小文件,完整加载
50 TOOLS.md 工具笔记 中等文件
60 BOOTSTRAP.md 一次性启动仪式 完成后删除
70 MEMORY.md 长期记忆 大文件截断

文件缓存机制(避免陈旧读取):

// src/agents/workspace.ts
type WorkspaceFileIdentity = {
  path: string;
  identity: string; // `${canonicalPath}|${dev}:${ino}:${size}:${mtimeMs}`
};

async function readWorkspaceFileWithGuards(params: {
  filePath: string;
  workspaceDir: string;
}): Promise<WorkspaceGuardedReadResult> {
  // 通过 inode/dev/size/mtime 识别文件变化
  const opened = await openBoundaryFile({
    absolutePath: params.filePath,
    rootPath: params.workspaceDir,
    boundaryLabel: "workspace root",
    maxBytes: MAX_WORKSPACE_BOOTSTRAP_FILE_BYTES, // 默认 50KB
  });
  
  // 缓存命中检查
  const identity = workspaceFileIdentity(stat, canonicalPath);
  if (workspaceFileCache.has(identity)) {
    return workspaceFileCache.get(identity);
  }
  
  // ... 读取并缓存
}
阶段 4:钩子系统拦截

内部钩子事件类型

// src/hooks/internal-hooks.ts
type InternalHookEventType = 
  | "command"      // /new, /reset, /stop 等命令
  | "session"      // 会话生命周期
  | "agent"        // agent:bootstrap
  | "gateway"      // gateway_start/stop
  | "message";     // received/sent/transcribed

插件钩子完整列表

钩子名称 执行时机 返回值 用途
before_model_resolve 会话前(无 messages) {provider, model} 确定性覆盖模型选择
before_prompt_build 会话加载后 {prependContext, systemPrompt} 注入动态上下文
before_agent_reply 内联动作后、LLM 调用前 {reply, silence} 声明回合并返回合成回复
agent_end 完成后 检查最终消息列表和运行元数据
before_tool_call 工具调用前 {block: boolean, reason?} 拦截工具参数
after_tool_call 工具调用后 {modifiedResult?} 修改工具结果
before_compaction 压缩前 {annotate?} 标记压缩事件
after_compaction 压缩后 记录压缩结果
message_received 接收消息时 {preprocessed?} 消息预处理
message_sending 发送消息前 {cancel: boolean} 取消发送
message_sent 发送消息后 日志/确认
session_start 会话开始时 会话边界
session_end 会话结束时 会话边界
gateway_start 网关启动时 初始化
gateway_stop 网关停止时 清理

钩子决策规则

// before_tool_call: { block: true } 是终局的
if (ctx.toolName === "exec" && ctx.params.command.includes("rm -rf")) {
  return { block: true, reason: "危险命令被阻止" };
}

// message_sending: { cancel: true } 是终局的
if (ctx.message.content.includes("敏感信息")) {
  return { cancel: true, reason: "包含敏感信息" };
}
阶段 5:工具执行与流式回复

流式传输类型

type StreamEvent =
  | { stream: "lifecycle"; phase: "start" | "end" | "error" }
  | { stream: "assistant"; delta: string; reasoning?: string }
  | { stream: "tool"; type: "start" | "update" | "end"; toolName: string };

块流式配置

{
  agents: {
    defaults: {
      blockStreamingDefault: "off",  // 默认关闭
      blockStreamingBreak: "text_end",  // 或 "message_end"
      blockStreamingChunk: 1000,  // 800-1200 字符,优先段落断点
      blockStreamingCoalesce: true  // 减少单行垃圾消息
    }
  }
}

转向模式(Queue Mode):

模式 行为 适用场景
steer 入站消息注入当前运行,在当前工具执行完成后、下次 LLM 调用前交付 需要动态修正 Agent 行为
followup 入站消息保持到当前回合结束,然后新回合开始 保持回合完整性
collect 类似 followup,但可配置 debounce/cap 行为 高频消息聚合
阶段 6:超时与故障转移

超时层级

超时类型 配置项 默认值 说明
Agent 运行时 agents.defaults.timeoutSeconds 172800s (48h) 整个运行的最大时长
LLM 空闲 agents.defaults.llm.idleTimeoutSeconds 60s 无响应 chunk 的空闲窗口
agent.wait timeoutMs 参数 30s 仅等待超时,不中止 Agent

故障转移策略

// src/agents/pi-embedded-runner/run/failover-policy.ts
async function handleAssistantFailover(params: {
  runId: string;
  error: Error;
  sessionKey: string;
}) {
  // 1. 检查是否有备用模型
  // 2. 重试次数限制(默认 3 次)
  // 3. 记录失败原因
  // 4. 触发 lifecycle: "error" 事件
}

工作空间与启动文件

完整文件结构

~/.openclaw/workspace/
├── AGENTS.md           # 操作指令 + 记忆规则
├── SOUL.md             # 人格定义、边界、语气
├── IDENTITY.md         # 名称、风格、emoji
├── USER.md             # 用户档案
├── TOOLS.md            # 工具笔记(环境特定)
├── BOOTSTRAP.md        # 一次性启动仪式(完成后删除)
├── MEMORY.md           # 长期记忆(定期更新)
├── memory/
│   └── YYYY-MM-DD.md   # 每日原始日志
└── skills/             # 工作区特定技能(可选)

启动文件内容示例

AGENTS.md(操作指令):

# AGENTS.md - Your Workspace

## Session Startup
Before doing anything else:
1. Read `SOUL.md` — this is who you are
2. Read `USER.md` — this is who you're helping
3. Read `memory/YYYY-MM-DD.md` (today + yesterday)

## Red Lines
- Don't exfiltrate private data. Ever.
- Don't run destructive commands without asking.
- `trash` > `rm` (recoverable beats gone forever)

## Memory
- Write significant events to `memory/YYYY-MM-DD.md`
- Periodically review and update `MEMORY.md`

SOUL.md(人格定义):

# SOUL.md - Who You Are

## Core Truths
- Be genuinely helpful, not performatively helpful
- Have opinions. You're allowed to disagree.
- Be resourceful before asking.
- Earn trust through competence.

## Vibe
Be the assistant you'd actually want to talk to.
Concise when needed, thorough when it matters.

USER.md(用户档案):

# USER.md - About Your Human

- **Name:** 叶之越
- **What to call them:** 忠愈
- **Timezone:** Asia/Shanghai (杭州)
- **工号:** 420762
- **部门:** 蚂蚁集团 - 财富保险事业群 - 财保技术部
- **生日:** 12-28 (阳历)

Bootstrap 仪式

BOOTSTRAP.md 只在全新工作空间(无其他启动文件)时创建:

# BOOTSTRAP.md - Your First-Run Ritual

Welcome! This is your first run. Let's set things up:

1. Read SOUL.md and AGENTS.md
2. Update USER.md with your human's info
3. Delete this file when done

完成后删除此文件,后续重启不会重新创建。

禁用 Bootstrap

{
  agent: { skipBootstrap: true }  // 预种子工作空间使用
}

会话键设计与路由

会话键格式决策树

直聊 DM

群组/频道

线程

main 默认

per-peer

per-channel-peer

per-account-channel-peer

群组

频道

Slack/Discord

Telegram 论坛

收到消息

消息类型?

dmScope 策略

按 ID 隔离

追加 threadId

agent:main:main

agent:main:peer:userId

agent:main:channel:userId

agent:main:account:channel:userId

agent:main:channel:group:id

agent:main:channel:channel:id

基础键:thread:threadId

基础键:topic:topicId

会话键完整格式

场景 会话键格式 示例
直聊(默认) agent:<agentId>:main agent:main:main
直聊(per-peer) agent:<agentId>:peer:<userId> agent:main:peer:U123456
直聊(per-channel-peer) agent:<agentId>:<channel>:peer:<userId> agent:main:telegram:peer:U123456
群组 agent:<agentId>:<channel>:group:<id> agent:main:telegram:group:-1001234567890
频道 agent:<agentId>:<channel>:channel:<id> agent:main:discord:channel:987654321
线程 基础键:thread:<threadId> agent:main:discord:channel:123:thread:456
Telegram 话题 agent:<agentId>:telegram:group:<id>:topic:<topicId> agent:main:telegram:group:-100123:topic:42

DM 隔离策略详解

{
  session: {
    dmScope: "per-channel-peer"  // 多用户推荐设置
  }
}
行为 适用场景 会话键示例
main(默认) 所有 DM 共享一个会话 单用户设置 agent:main:main
per-peer 按发送者隔离(跨渠道) 多用户但同一人跨渠道共享上下文 agent:main:peer:U123456
per-channel-peer 按渠道 + 发送者隔离 推荐:多用户设置,安全边界清晰 agent:main:telegram:peer:U123456
per-account-channel-peer 按账户 + 渠道 + 发送者隔离 最严格隔离,多账户场景 agent:main:whatsapp:personal:peer:U123456

会话生命周期管理

会话重置配置

{
  session: {
    reset: {
      mode: "daily",      // 或 "weekly", "idle"
      atHour: 4,          // 凌晨 4 点重置
      idleMinutes: 120    // 空闲 2 小时后重置
    }
  }
}

会话存储位置

~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl

多代理路由系统

什么是"一个 Agent"?

一个 Agent 是一个完整 scoped 的大脑,拥有独立的:

  • 工作空间:文件、AGENTS.md/SOUL.md/USER.md、本地笔记、人格规则
  • 状态目录 (agentDir):认证凭证、模型注册表、每代理配置
  • 会话存储:聊天记录 + 路由状态

认证凭证是每代理的

~/.openclaw/agents/<agentId>/agent/auth-profiles.json

路径映射表

资源类型 单代理模式(默认) 多代理模式
配置 ~/.openclaw/openclaw.json 同左
状态目录 ~/.openclaw 同左
工作空间 ~/.openclaw/workspace ~/.openclaw/workspace-<agentId>
Agent 目录 ~/.openclaw/agents/main/agent ~/.openclaw/agents/<agentId>/agent
会话存储 ~/.openclaw/agents/main/sessions ~/.openclaw/agents/<agentId>/sessions

8 层路由优先级(从高到低)

渲染错误: Mermaid 渲染失败: Parse error on line 9: ...渠道级 | I[accountId: "*"] B -->|8. 默认 -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'STR'

绑定配置示例

场景:三个人格隔离的 Agent

{
  agents: {
    list: [
      {
        id: "home",
        name: "Home Assistant",
        workspace: "~/.openclaw/workspace-home",
        model: "anthropic/claude-sonnet-4-6",
        tools: {
          allow: ["read", "exec", "message", "weather", "calendar"],
          deny: ["write", "browser"]
        }
      },
      {
        id: "work",
        name: "Work Assistant",
        workspace: "~/.openclaw/workspace-work",
        model: "anthropic/claude-opus-4-6",
        tools: {
          allow: ["read", "write", "edit", "exec", "message", "github", "dima"],
          deny: []
        },
        sandbox: { mode: "all", scope: "agent" }
      },
      {
        id: "coding",
        name: "Coding Specialist",
        workspace: "~/.openclaw/workspace-coding",
        model: "anthropic/claude-sonnet-4-6",
        skills: ["github", "code-review", "pr-analysis"]
      }
    ]
  },
  bindings: [
    // 1. 精确匹配优先(Discord 特定频道)
    {
      agentId: "coding",
      match: {
        channel: "discord",
        peer: { kind: "channel", id: "999888777" }
      }
    },
    // 2. 账户级匹配(WhatsApp 双账户)
    { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },
    { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
    // 3. 渠道级回退
    { agentId: "home", match: { channel: "telegram" } }
  ]
}

一个 WhatsApp 号码,多个人(DM 拆分)

可以在一个 WhatsApp 账户上路由不同的 WhatsApp DM 到不同的 Agent。匹配发送者 E.164(如 +15551234567)使用 peer.kind: "direct"

关键细节:直聊会折叠到 agent 的主会话键,所以真正的隔离需要每人一个 agent

{
  agents: {
    list: [
      { id: "alex", workspace: "~/.openclaw/workspace-alex" },
      { id: "mia", workspace: "~/.openclaw/workspace-mia" }
    ]
  },
  bindings: [
    {
      agentId: "alex",
      match: {
        channel: "whatsapp",
        accountId: "shared-number",
        peer: { kind: "direct", id: "+15551234567" }  // Alex 的号码
      }
    },
    {
      agentId: "mia",
      match: {
        channel: "whatsapp",
        accountId: "shared-number",
        peer: { kind: "direct", id: "+15559876543" }  // Mia 的号码
      }
    }
  ]
}

跨代理 QMD 记忆搜索

如果一個 Agent 应该搜索另一个 Agent 的 QMD 会话转录:

{
  agents: {
    list: [
      {
        id: "main",
        workspace: "~/workspaces/main",
        memorySearch: {
          qmd: {
            extraCollections: [
              { path: "~/agents/family/sessions", name: "family-sessions" }
            ]
          }
        }
      },
      { id: "family", workspace: "~/workspaces/family" }
    ]
  },
  memory: {
    backend: "qmd",
    qmd: { includeDefaultMemory: false }
  }
}

工具策略系统

Owner-Only 工具审批级别

审批级别 包含工具 保护理由
control_plane cron, gateway 控制平面操作,影响整个网关
exec_capable nodes, exec (部分) 可执行系统命令
interactive whatsapp_login 交互式登录,涉及凭证

自动分类回退

const OWNER_ONLY_TOOL_APPROVAL_CLASS_FALLBACKS = new Map([
  ["whatsapp_login", "interactive"],
  ["cron", "control_plane"],
  ["gateway", "control_plane"],
  ["nodes", "exec_capable"],
]);

工具策略应用

// src/agents/tool-policy.ts
function applyOwnerOnlyToolPolicy(
  tools: AnyAgentTool[],
  senderIsOwner: boolean
): AnyAgentTool[] {
  const withGuard = tools.map((tool) => {
    if (!isOwnerOnlyTool(tool)) {
      return tool;
    }
    return wrapOwnerOnlyToolExecution(tool, senderIsOwner);
  });
  
  if (senderIsOwner) {
    return withGuard;  // Owner 发送者:保留所有工具,但包装保护
  }
  return withGuard.filter((tool) => !isOwnerOnlyTool(tool));  // 非 Owner:过滤掉
}

工具钩子拦截示例

// 插件注册
api.registerHook("before_tool_call", async (ctx) => {
  // 阻止危险命令
  if (ctx.toolName === "exec" && ctx.params.command.includes("rm -rf")) {
    return { block: true, reason: "危险命令被阻止" };
  }
  
  // 记录所有 cron 操作
  if (ctx.toolName === "cron") {
    await logAuditEvent({
      tool: "cron",
      action: ctx.params.action,
      userId: ctx.senderId,
    });
  }
  
  return { block: false };  // 不阻止
});

记忆系统

记忆后端对比

后端类型 存储格式 检索能力 适用场景
内置记忆 会话内提取 键值查找 简单场景
QMD 后端 QMD 格式 全文搜索、转录搜索 中等规模、需要搜索
Honcho 后端 外部服务 大规模、向量检索 企业级、海量记忆

QMD 记忆配置

{
  memory: {
    backend: "qmd",
    qmd: {
      includeDefaultMemory: false  // 不包含默认记忆
    }
  },
  agents: {
    list: [
      {
        id: "main",
        memorySearch: {
          qmd: {
            extraCollections: [
              { path: "notes", name: "notes-main" },  // 工作区内
              { path: "~/shared/transcripts", name: "shared-transcripts" }  // 共享
            ]
          }
        }
      }
    ]
  }
}

记忆提取与检索

自动提取时机

  • 对话结束时(agent_end 钩子)
  • 关键信息出现时(人名、日期、决策)
  • 用户明确要求"记住这个"

检索触发

  • 相关关键词在对话中出现
  • 跨会话引用(“上次我们说的那个…”)
  • 主动记忆搜索(memory.search 工具)

流式回复与转向

块流式传输详解

配置选项

{
  agents: {
    defaults: {
      blockStreamingDefault: "off",      // on/off
      blockStreamingBreak: "text_end",   // text_end / message_end
      blockStreamingChunk: 1000,         // 800-1200 字符
      blockStreamingCoalesce: true       // 合并碎片
    }
  }
}

块断点优先级

  1. 段落断点(双换行)
  2. 换行符
  3. 句子结束(。!?.!?)
  4. 字符数达到阈值

合并行为(Coalesce):

发送 chunk1 → 等待 idle 时间 → 有新 chunk → 合并 → 发送
发送 chunk → idle 超时 → 立即发送

转向模式对比

模式 交付时机 工具调用 适用场景
steer 当前工具执行完成后、下次 LLM 前 继续执行 需要修正 Agent 方向
followup 当前回合完全结束后 新回合开始 保持回合完整性
collect debounce/cap 后 新回合开始 高频消息聚合

转向流程

用户 消息队列 Agent 循环 用户 消息队列 Agent 循环 执行工具调用 1 发送转向消息 (steer 模式) 执行工具调用 2 完成当前工具序列 拉取转向消息 注入转向消息到上下文 进行下次 LLM 调用 返回修正后回复

心跳系统 (Periodic Check-ins)

心跳配置

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",           // 每 30 分钟
        target: "last",         // 发送到上次活跃的渠道
        directPolicy: "allow"   // 允许 DM 风格目标
      }
    }
  }
}

心跳期间自主检查

默认检查项

  • 📧 邮箱是否有紧急未读消息
  • 📅 日历未来 24-48 小时是否有即将开始的事件
  • 🌤️ 天气是否相关(如果用户可能外出)
  • 🔧 项目状态(git status 等)

心跳状态跟踪

// memory/heartbeat-state.json
{
  "lastChecks": {
    "email": 1703275200,
    "calendar": 1703260800,
    "weather": null
  }
}

心跳消息发送策略

时间窗口 策略 说明
08:00-23:00 正常发送 工作时间
23:00-08:00 仅紧急 深夜不打扰
上次检查 < 30min 跳过 避免重复
无新内容 HEARTBEAT_OK 静默回复

实战配置示例

最小可用配置

{
  agents: {
    defaults: {
      workspace: "~/.openclaw/workspace",
      model: {
        primary: "anthropic/claude-sonnet-4-6",
        fallbacks: ["openai/gpt-5.4"]
      },
      timeoutSeconds: 172800,  // 48 小时
      heartbeat: {
        every: "30m",
        target: "last"
      }
    }
  },
  session: {
    dmScope: "per-channel-peer",  // 多用户推荐
    reset: {
      mode: "daily",
      atHour: 4,
      idleMinutes: 120
    }
  }
}

企业级多租户配置

场景:一家公司有 3 个部门的 AI 助手,共享网关但隔离数据和人格。

{
  agents: {
    list: [
      {
        id: "hr-assistant",
        name: "HR 助手",
        workspace: "~/.openclaw/workspace-hr",
        model: "anthropic/claude-opus-4-6",
        tools: {
          allow: ["read", "message", "dingtalk-usage", "vacation"],
          deny: ["exec", "gateway"]
        }
      },
      {
        id: "it-helpdesk",
        name: "IT 服务台",
        workspace: "~/.openclaw/workspace-it",
        model: "anthropic/claude-sonnet-4-6",
        tools: {
          allow: ["read", "write", "exec", "message", "nodes"],
          deny: ["gateway", "cron"]
        },
        sandbox: { mode: "all", scope: "agent" }
      },
      {
        id: "finance-bot",
        name: "财务助手",
        workspace: "~/.openclaw/workspace-finance",
        model: "anthropic/claude-opus-4-6",
        tools: {
          allow: ["read", "xlsx", "message", "ant_search"],
          deny: ["exec", "write", "browser"]
        }
      }
    ]
  },
  bindings: [
    // HR 专属钉钉群
    {
      agentId: "hr-assistant",
      match: {
        channel: "dingtalk",
        peer: { kind: "channel", id: "hr-group-123" }
      }
    },
    // IT 服务台:所有工单频道
    {
      agentId: "it-helpdesk",
      match: { channel: "dingtalk", accountId: "it-bot" }
    },
    // 财务:仅私聊
    {
      agentId: "finance-bot",
      match: {
        channel: "dingtalk",
        accountId: "finance-bot",
        peer: { kind: "direct", id: "*" }
      }
    }
  ]
}

跨时区全球化支持

场景:公司在杭州、新加坡、旧金山有办公室,需要 24/7 支持。

{
  agents: {
    list: [
      {
        id: "asia-pacific",
        name: "亚太助手",
        workspace: "~/.openclaw/workspace-apac",
        model: "anthropic/claude-sonnet-4-6"
      },
      {
        id: "americas",
        name: "美洲助手",
        workspace: "~/.openclaw/workspace-us",
        model: "anthropic/claude-sonnet-4-6"
      }
    ]
  },
  bindings: [
    // 按时间路由(需要自定义钩子)
    // Asia/Pacific: 00:00-12:00 UTC
    { agentId: "asia-pacific", match: { channel: "slack", accountId: "global" } }
  ],
  // 自定义钩子实现时区路由
  hooks: {
    presets: ["timezone-router"]
  }
}

插件钩子完整示例

模型覆盖钩子

// plugins/vip-model-override.ts
export default {
  id: "vip-model-override",
  register(api) {
    api.registerHook("before_model_resolve", async (ctx) => {
      if (ctx.sessionKey.includes("vip-user")) {
        return {
          provider: "anthropic",
          model: "claude-opus-4-6"
        };
      }
      return null;  // 不覆盖,继续默认流程
    });
  }
};

上下文注入钩子

// plugins/user-context-injector.ts
export default {
  id: "user-context-injector",
  register(api) {
    api.registerHook("before_prompt_build", async (ctx) => {
      const userContext = await fetchUserContext(ctx.sessionKey);
      return {
        prependContext: `## 用户当前状态\n${userContext}`
      };
    });
  }
};

工具审计钩子

// plugins/tool-audit.ts
export default {
  id: "tool-audit",
  register(api) {
    api.registerHook("before_tool_call", async (ctx) => {
      await logAudit({
        timestamp: new Date(),
        sessionKey: ctx.sessionKey,
        toolName: ctx.toolName,
        params: sanitizeParams(ctx.params),
        senderId: ctx.senderId,
      });
      return { block: false };
    });

    api.registerHook("after_tool_call", async (ctx) => {
      await logAudit({
        timestamp: new Date(),
        sessionKey: ctx.sessionKey,
        toolName: ctx.toolName,
        result: sanitizeResult(ctx.result),
      });
    });
  }
};

自动欢迎钩子

// plugins/auto-welcome.ts
export default {
  id: "auto-welcome",
  register(api) {
    api.registerHook("before_agent_reply", async (ctx) => {
      if (ctx.messages.length === 1) {
        // 首条消息,返回欢迎语
        return {
          reply: {
            body: "你好!我是你的专属助手。我能帮你做什么?"
          },
          silence: false
        };
      }
      return null;  // 继续正常 Agent 回复
    });
  }
};

核心源码路径索引

功能模块 核心文件 代码行数 关键函数/类型
运行时入口 src/agents/pi-embedded-runner/run.ts ~800 runEmbeddedPiAgent()
工作空间管理 src/agents/workspace.ts ~600 readWorkspaceFileWithGuards()
系统提示词 src/agents/system-prompt.ts ~300 buildSystemPrompt()
启动钩子 src/agents/bootstrap-hooks.ts ~100 applyBootstrapHookOverrides()
内部钩子 src/hooks/internal-hooks.ts ~400 triggerInternalHook()
工具策略 src/agents/tool-policy.ts ~200 applyOwnerOnlyToolPolicy()
会话管理器 src/session/manager.ts ~500 resolveSessionKey()
记忆后端 src/memory/qmd-backend.ts ~350 searchTranscripts()

性能优化建议

缓存策略

缓存对象 策略 失效条件
工作空间文件 inode/dev/size/mtime 识别 文件变化
模型解析 会话级缓存 配置变更
技能快照 启动时加载 技能目录变化
认证凭证 内存缓存 + 定期刷新 凭证过期

并发控制

会话级序列化

  • 每个 sessionKey 一个执行队列
  • 防止工具/会话竞争
  • 保持会话历史一致性

全局队列(可选):

{
  agents: {
    defaults: {
      queue: {
        global: true,  // 启用全局队列
        maxConcurrency: 5  // 最大并发数
      }
    }
  }
}

内存优化

优化方向 措施 效果
工具结果裁剪 限制大小,移除大图片 减少内存峰值
会话压缩 自动 compaction 减少历史存储
钩子超时 设置钩子执行超时 防止阻塞

常见问题解答 (FAQ)

Q1: 如何调试 Agent 循环?

方法 1:启用详细日志

{
  logging: {
    level: "debug",
    categories: ["agent", "session", "tools"]
  }
}

方法 2:使用 CLI 调试

openclaw agent --session-key "agent:main:main" --verbose

方法 3:订阅 agent 事件

api.registerHook("agent_end", async (ctx) => {
  console.log("Agent run completed:", {
    runId: ctx.runId,
    duration: ctx.endedAt - ctx.startedAt,
    toolCalls: ctx.toolCalls.length,
  });
});

Q2: 多代理如何共享认证凭证?

不推荐直接共享 agentDir(会导致会话冲突)。

推荐做法:复制 auth-profiles.json

cp ~/.openclaw/agents/main/agent/auth-profiles.json \
   ~/.openclaw/agents/work/agent/auth-profiles.json

Q3: 会话键混乱怎么办?

重置会话

# 软重置(保留历史记录)
openclaw session reset agent:main:main

# 硬重置(删除历史)
openclaw session delete agent:main:main

检查会话键生成

openclaw session list --verbose

Q4: 如何阻止 Agent 执行特定命令?

方法 1:工具策略

{
  agents: {
    defaults: {
      tools: {
        deny: ["exec"]  // 完全禁止 exec
      }
    }
  }
}

方法 2:钩子拦截

api.registerHook("before_tool_call", async (ctx) => {
  if (ctx.toolName === "exec" && isDangerousCommand(ctx.params.command)) {
    return { block: true, reason: "危险命令" };
  }
});

方法 3:Owner-Only 保护

{
  agents: {
    defaults: {
      tools: {
        ownerOnly: ["exec", "gateway", "cron"]
      }
    }
  }
}

Q5: 记忆系统如何备份?

QMD 记忆备份

# 备份 QMD 文件
cp -r ~/.openclaw/agents/main/memory/qmd/ \
      ~/backups/qmd-$(date +%Y%m%d)/

会话转录备份

# 备份会话 JSONL
cp ~/.openclaw/agents/main/sessions/*.jsonl \
   ~/backups/sessions-$(date +%Y%m%d)/

Q6: 如何实现跨代理消息转发?

使用 sessions_spawn + sessions_send

// 在 agent A 中
import { sessions_send } from "@openclaw/sdk";

await sessions_send({
  agentId: "agent-b",
  message: "请将此消息转发给用户",
});

与竞品对比

特性 OpenClaw Botpress Rasa Microsoft Bot Framework
Agent 原生 ✅ 完整 Agent 循环 ❌ 对话流为主 ❌ NLU 为主 ⚠️ 部分支持
多代理路由 ✅ 8 层优先级 ❌ 单_bot_ ❌ 单_bot_ ⚠️ 需自定义
会话隔离 ✅ SessionKey 设计 ⚠️ 简单隔离 ⚠️ 简单隔离 ✅ 完善
记忆系统 ✅ QMD/Honcho ⚠️ 基础 ⚠️ 基础 ⚠️ 基础
钩子系统 ✅ 内部 + 插件双系统 ✅ 钩子 ✅ 中间件 ✅ 中间件
工具审批 ✅ Owner-Only 策略 ❌ 无 ❌ 无 ❌ 无
自托管优先 ✅ 完整离线能力 ✅ 支持 ✅ 支持 ⚠️ 部分云端
渠道统一 ✅ 多渠道路由 ✅ 支持 ⚠️ 需适配 ✅ 支持
心跳系统 ✅ 自主检查 ❌ 无 ❌ 无 ❌ 无
学习曲线 中等

踩坑经验与最佳实践

踩坑经验

坑 1:会话键冲突导致上下文混乱

症状:不同用户看到彼此的对话历史。

原因dmScope 设置为 main,所有直聊共享同一会话。

解决

{
  session: {
    dmScope: "per-channel-peer"  // 多用户必须设置
  }
}
坑 2:Agent 循环超时但未报错

症状:Agent 长时间无响应,但无错误日志。

原因:LLM 空闲超时未设置,模型无响应时卡住。

解决

{
  agents: {
    defaults: {
      llm: {
        idleTimeoutSeconds: 120  // 慢模型设置更长
      }
    }
  }
}
坑 3:钩子未触发

症状:注册的钩子从未被调用。

原因:钩子优先级冲突或注册时机过晚。

解决

  • 确保钩子在 Gateway 启动前注册
  • 检查钩子名称拼写
  • 使用 before_agent_start 代替legacy钩子
坑 4:多代理认证混乱

症状:Agent A 使用了 Agent B 的凭证。

原因:共享了 agentDirauth-profiles.json

解决:每个 Agent 使用独立的 agentDir,手动复制需要的凭证。

最佳实践

1. 会话键设计
  • 单用户:使用默认 main
  • 多用户:使用 per-channel-peer
  • 严格隔离:使用 per-account-channel-peer
2. 工具审批
  • 将所有控制平面工具设为 ownerOnly
  • 使用钩子记录所有 exec 调用
  • 对危险命令实现白名单
3. 记忆管理
  • 定期(每周)审查 MEMORY.md
  • 使用 QMD 后端进行会话搜索
  • 避免在记忆中存储敏感信息
4. 性能优化
  • 启用工作空间文件缓存
  • 配置合理的块流式阈值
  • 对高频钩子实现缓存
5. 调试策略
  • 开发环境启用 debug 日志
  • 使用 CLI 进行单次调试
  • 订阅 agent_end 钩子记录运行统计

设计权衡

优势

优势 说明
主动性 Agent 可以自主执行定时任务、检查条件、主动通知
连续性 会话管理和记忆系统支持长期关系建立
隔离性 多代理架构支持人格、数据、凭证的完全隔离
扩展性 钩子系统允许深度定制而无需修改核心代码
可观测性 完整的事件流和生命周期钩子

权衡

权衡 说明 缓解策略
复杂性增加 完整的 Agent 循环、钩子系统、会话管理增加了系统复杂度 提供详细文档和示例配置
资源消耗 每个 Agent 需要独立的工作空间、状态目录、会话存储 支持轻量化 Agent(共享技能)
配置难度 多代理路由、钩子注册、记忆配置需要深入理解架构 提供配置向导和模板
调试困难 钩子链路复杂时,问题定位需要追踪多个执行点 增强日志和事件追踪

关键洞察

Agent 原生设计不是简单的"聊天机器人 + 工具",而是重新思考了人机交互的范式。

传统范式

用户输入 → 机器人响应 → 等待下一次输入

Agent 原生范式

定时检查 → 条件触发 → 多轮工具调用 → 主动通知
    ↓
用户 interrupt → 动态修正 → 继续执行

这种设计哲学的核心假设是:AI 代理应该被视为"数字员工",具有自己的人格、工作空间、记忆和职责范围,而不仅仅是执行命令的工具。


相关文档引用

官方文档

文档 路径 关键内容
Agent Runtime docs/concepts/agent.md 运行时边界、启动文件、技能加载
Agent Loop docs/concepts/agent-loop.md 完整生命周期、钩子点、流式传输
Multi-Agent docs/concepts/multi-agent.md 路由规则、绑定配置、跨代理搜索
Session docs/concepts/session.md 会话键生成、DM 隔离、生命周期
System Prompt docs/concepts/system-prompt.md 提示词构建、启动文件注入
Hooks docs/automation/hooks.md 内部钩子、插件钩子、决策规则
Streaming docs/concepts/streaming.md 块流式、 chunking、转向模式
Compaction docs/concepts/compaction.md 会话压缩、重试机制

源码路径

src/
├── agents/
│   ├── pi-embedded-runner/      # 运行时核心
│   ├── workspace.ts             # 工作空间管理
│   ├── system-prompt.ts         # 提示词构建
│   ├── bootstrap-hooks.ts       # 启动钩子
│   └── tool-policy.ts           # 工具策略
├── hooks/
│   ├── internal-hooks.ts        # 内部钩子系统
│   └── plugin-hooks.ts          # 插件钩子 API
├── session/
│   ├── manager.ts               # 会话管理器
│   └── resolver.ts              # 会话键解析
└── memory/
    ├── qmd-backend.ts           # QMD 记忆后端
    └── honcho-backend.ts        # Honcho 后端

影响范围

Agent 原生设计哲学影响以下核心模块:

  1. 运行时层:嵌入式 Pi Agent Core 集成、Agent 循环执行模型、超时控制
  2. 会话管理层:会话键生成、DM 隔离策略、会话重置和维护
  3. 钩子系统:内部钩子、插件钩子、钩子决策规则、生命周期事件
  4. 工作空间管理:启动文件注入、Bootstrap 仪式、人格定义文件
  5. 多代理路由agents.list 配置、bindings 路由引擎、代理隔离
  6. 流式传输:块流式、推理流、转向模式、队列管理
  7. 记忆系统:内置记忆、QMD 后端、跨代理记忆搜索
  8. 工具编排:工具审批、技能加载、钩子拦截、沙箱隔离

本文档基于 OpenClaw 文档版本:openclaw-main/docs(截至 2026-04-11)
源码分析基于:openclaw-main/src(截至 2026-04-11)
上次优化时间:2026-04-11 13:14 (Asia/Shanghai)

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐