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 钩子提取关键信息持久化完整会话返回 EmbeddedPiRunResultlifecycle: "end"发送最终回复

入口点

入口类型调用方式用途
Gateway RPCagent标准调用,立即返回 runId
Gateway RPCagent.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:工作空间准备与启动文件注入

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

序号文件名用途修剪策略
10AGENTS.md操作指令 + 记忆规则大文件截断
20SOUL.md人格定义、边界、语气大文件截断
30IDENTITY.md名称、风格、emoji小文件,完整加载
40USER.md用户档案小文件,完整加载
50TOOLS.md工具笔记中等文件
60BOOTSTRAP.md一次性启动仪式完成后删除
70MEMORY.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.timeoutSeconds172800s (48h)整个运行的最大时长
LLM 空闲agents.defaults.llm.idleTimeoutSeconds60s无响应 chunk 的空闲窗口
agent.waittimeoutMs 参数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>:mainagent: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_planecron, gateway控制平面操作,影响整个网关
exec_capablenodes, exec (部分)可执行系统命令
interactivewhatsapp_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当前回合完全结束后新回合开始保持回合完整性
collectdebounce/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~800runEmbeddedPiAgent()
工作空间管理src/agents/workspace.ts~600readWorkspaceFileWithGuards()
系统提示词src/agents/system-prompt.ts~300buildSystemPrompt()
启动钩子src/agents/bootstrap-hooks.ts~100applyBootstrapHookOverrides()
内部钩子src/hooks/internal-hooks.ts~400triggerInternalHook()
工具策略src/agents/tool-policy.ts~200applyOwnerOnlyToolPolicy()
会话管理器src/session/manager.ts~500resolveSessionKey()
记忆后端src/memory/qmd-backend.ts~350searchTranscripts()

性能优化建议

缓存策略

缓存对象策略失效条件
工作空间文件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: "请将此消息转发给用户",
});

与竞品对比

特性OpenClawBotpressRasaMicrosoft 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 Runtimedocs/concepts/agent.md运行时边界、启动文件、技能加载
Agent Loopdocs/concepts/agent-loop.md完整生命周期、钩子点、流式传输
Multi-Agentdocs/concepts/multi-agent.md路由规则、绑定配置、跨代理搜索
Sessiondocs/concepts/session.md会话键生成、DM 隔离、生命周期
System Promptdocs/concepts/system-prompt.md提示词构建、启动文件注入
Hooksdocs/automation/hooks.md内部钩子、插件钩子、决策规则
Streamingdocs/concepts/streaming.md块流式、 chunking、转向模式
Compactiondocs/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 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐