本文基于 OpenClaw 开源仓库源码(4.5版本)进行深度分析,全面覆盖路由、会话隔离、安全边界、AI 推理执行引擎、上下文管理、ACP 协议、Cron 任务等核心模块,重点模块附有源码注解与 Mermaid 架构图,帮助读者系统性理解这套多渠道 AI 助手网关的设计原理。

适读人群:有一定 TypeScript / Node.js 经验,希望深入理解 AI 助手网关架构、消息路由系统、Agent 上下文管理机制的工程师。不需要 OpenClaw 使用经验,但了解基本的 LLM API 调用会有帮助。

文章结构

章节 内容 推荐人群
§1 项目概述 规模与定位 所有读者
§2 模块总览 架构分层图 + 模块速览表 快速了解全貌
§3.1 Channel 渠道机制 SessionKey、Binding 路由、安全防线 想理解消息如何进入系统
§3.2 消息处理全链路 端到端时序、信任边界、懒加载 想理解一条消息的完整生命周期
§3.3 AI 推理执行引擎 System Prompt 构建、队列仲裁、三阶段上下文管理 想深入 Agent 执行机制
§3.4 ACP 子 Agent 编排 会话状态机、Control-Plane 多 Agent 编排场景
§3.5-3.6 Cron + Tasks 定时任务调度、任务生命周期注册表 自动化任务场景
§3.7-3.9 Hooks / MCP / Secrets 事件钩子、MCP 双向集成、凭证管理 插件扩展开发者
§3.10-3.12 多模态 / 其他模块 / Plugin-SDK 媒体理解、生态全景 想扩展或集成 OpenClaw
§4 总结 架构亮点、设计哲学、产品护城河分析 所有读者,推荐最后阅读

一、项目概述

OpenClaw 是一个多渠道 AI 助手网关系统。可以把它理解为一个"AI 消息中枢":从 Telegram、Discord、Slack、WhatsApp、iMessage、Signal、Matrix、Line、Zalo 等任意聊天平台接收消息,统一路由给 AI 模型(Claude、GPT、Gemini、DeepSeek 等),再把回复投递回原渠道。

核心价值:一套 AI Agent,接入所有渠道,支持定时任务、子 Agent 编排、多模态理解。

项目规模:

  • src/ 核心模块:约 70 个子目录,数千个 TypeScript 源文件
  • extensions/ 插件生态:约 100 个 bundled 插件(AI Provider + 渠道 + 工具插件)
  • apps/ 原生客户端:iOS / Android / macOS

二、模块总览

2.1 整体架构图

插件生态

基础设施层

AI能力层

业务层

渠道层

接入层

客户端层

iOS App

Android App

macOS App

TUI 终端

Web UI

Gateway
HTTP/WebSocket

Pairing
设备配对

ACP Server
Agent控制协议

Channel Plugins
Telegram/Discord/Slack/...

Routing
8级路由匹配

Security
DM策略/白名单

Auto-reply
消息处理引擎

Cron
定时任务

Tasks
任务注册追踪

Hooks
事件钩子

ACP Control-Plane
子Agent编排

Agents
AI推理/工具调用

MCP
Model Context Protocol

Media Understanding
图像/音频/视频

TTS
语音合成

Image/Video Gen
AI生成

Config/Sessions
配置与会话持久化

Secrets
凭证管理

Plugin-SDK
插件公开合同

Infra
网络/TLS/出站

Daemon
守护进程

AI Provider 插件
OpenAI/Anthropic/Google/...

渠道插件
Telegram/Discord/...

工具插件
MCP/Search/Memory/...

2.2 模块分类速览

接入层

模块 目录 职责
Gateway src/gateway/ HTTP/WebSocket 服务,所有流量统一入口
Pairing src/pairing/ 移动端设备 QR 码配对认证
TUI src/tui/ 纯终端交互 UI,富文本渲染
ACP Server src/acp/ Agent Control Protocol 服务端,接受外部 Agent 调用

渠道与路由层

模块 目录 职责
Channels src/channels/ 渠道插件类型合同(Adapter 定义),不含具体实现
Routing src/routing/ SessionKey 计算,8 级 Binding 规则匹配
Security src/security/ DM Policy、allowlist、外部内容安全策略

业务逻辑层

模块 目录 职责
Auto-reply src/auto-reply/ 消息安全检查→上下文装配→队列→AI 回复全链路
Cron src/cron/ 定时任务引擎(cron 表达式 + every + at 三种模式)
Tasks src/tasks/ 任务注册表,跨 runtime 的任务生命周期追踪
Hooks src/hooks/ 5 类事件可插拔钩子(command/session/agent/gateway/message)
Flows src/flows/ Channel 配置引导流、Model 选择引导流
ACP Control-Plane src/acp/control-plane/ 子 Agent 会话生命周期管理与编排

AI 能力层

模块 目录 职责
Agents src/agents/ AI 推理循环、工具调用、上下文管理、模型路由
MCP src/mcp/ Model Context Protocol,暴露渠道工具给 AI 客户端
Media Understanding src/media-understanding/ 图像描述、音频转录、视频描述
TTS src/tts/ 文本转语音(ElevenLabs、Deepgram 等)
Image Generation src/image-generation/ AI 生图(fal、OpenAI DALL-E 等)
Video Generation src/video-generation/ AI 生视频
Canvas Host src/canvas-host/ 交互式 Canvas 渲染(A2UI 协议)
Memory Host SDK src/memory-host-sdk/ 外部记忆后端接入(LanceDB 等)
Realtime Voice src/realtime-voice/ 实时语音对话流
Context Engine src/context-engine/ 上下文感知与动态注入

基础设施层

模块 目录 职责
Config/Sessions src/config/ src/sessions/ 配置加载、会话持久化(JSONL Transcript)
Secrets src/secrets/ SecretRef 凭证管理(env/file/exec 三种来源)
Plugin-SDK src/plugin-sdk/ 给第三方插件暴露的稳定公开 API
Plugins src/plugins/ Plugin 发现、加载、注册表
Infra src/infra/ 网络、TLS、出站投递
Daemon src/daemon/ 后台守护进程管理
Logging src/logging/ 结构化日志体系
i18n src/i18n/ 国际化支持

插件生态(extensions/,约 100 个)

类别 代表插件
AI Provider anthropic、openai、google、xai、deepseek、qwen、minimax、mistral、moonshot、ollama、groq、openrouter、amazon-bedrock、github-copilot 等
消息渠道 telegram、discord、slack、whatsapp、signal、matrix、line、zalo、irc、feishu、msteams、googlechat、imessage、bluebubbles 等
搜索工具 exa、brave、tavily、duckduckgo、perplexity、searxng、xai(X-Search)
媒体理解 zai、groq、deepgram、elevenlabs
图像生成 fal、openai
记忆后端 memory-core、memory-lancedb
编程 Agent browser、kilocode、opencode、opencode-go、kimi-coding
其他扩展 voice-call、speech-core、diagnostics-otel、thread-ownership 等

三、核心模块详解

3.1 Channel 渠道机制

3.1.1 ChannelPlugin:组合式适配器设计

每个渠道(Telegram、Discord 等)以 Plugin 形式接入。核心类型 ChannelPluginsrc/channels/plugins/types.plugin.ts)是一个由多个可选适配器组成的配置对象:

// src/channels/plugins/types.plugin.ts
export type ChannelPlugin<ResolvedAccount = any> = {
  id: ChannelId;
  meta: ChannelMeta;                    // 展示信息(名称、文档、描述)
  capabilities: ChannelCapabilities;    // 能力声明(是否支持线程/投票/编辑等)

  config: ChannelConfigAdapter;          // 必选:账号配置管理
  security?: ChannelSecurityAdapter;     // 安全检查(allowFrom、DM 策略)
  outbound?: ChannelOutboundAdapter;     // 发送消息
  messaging?: ChannelMessagingAdapter;   // 会话 Key 解析、目标路由
  threading?: ChannelThreadingAdapter;   // 线程/回复语义
  agentPrompt?: ChannelAgentPromptAdapter; // 注入到 System Prompt 的渠道提示
  directory?: ChannelDirectoryAdapter;   // 用户/群组目录查找
  actions?: ChannelMessageActionAdapter; // 消息工具 Action(发送/编辑/删除等)
  lifecycle?: ChannelLifecycleAdapter;   // 启动/停止生命周期
};

这是典型的组合优于继承模式(类比 Java 中的 Strategy + Facade 组合):每个 Adapter 是一组可选函数,渠道插件按需实现,核心层通过接口调用。

3.1.2 SessionKey:会话的"坐标系"

每条入站消息都会被计算出一个 SessionKey,它唯一标识一段对话,是会话隔离的基础。

SessionKey 格式(src/routing/session-key.ts):

agent:<agentId>:<channel>:<peerKind>:<peerId>
agent:<agentId>:<channel>:<accountId>:direct:<peerId>   ← 多账号 + 按用户隔离
agent:<agentId>:main                                    ← 默认 DM,所有私信共享

关键:dmScope 控制 DM 会话的隔离粒度

// src/routing/session-key.ts
export function buildAgentPeerSessionKey(params) {
  if (peerKind === "direct") {
    switch (dmScope) {
      case "per-account-channel-peer":
        return `agent:${agentId}:${channel}:${accountId}:direct:${peerId}`;
        // 每个渠道账号下的每个用户,独立会话
      case "per-channel-peer":
        return `agent:${agentId}:${channel}:direct:${peerId}`;
        // 跨账号,但每个渠道下每个用户独立会话
      case "per-peer":
        return `agent:${agentId}:direct:${peerId}`;
        // 跨渠道、跨账号,同一用户共享会话
      default: // "main"
        return `agent:${agentId}:main`;
        // 所有 DM 共享同一个 Agent 会话(默认)
    }
  }
  // 群组/频道:每个群组独立
  return `agent:${agentId}:${channel}:${peerKind}:${peerId}`;
}

实际 SessionKey 示例:

场景 SessionKey
默认 DM(所有私信共享 Agent 会话) agent:main:main
Telegram 私信按用户隔离 agent:main:telegram:direct:123456
Discord 频道 agent:main:discord:channel:C456789
Telegram 群组 agent:main:telegram:group:-100123456
Slack 线程 agent:main:slack:channel:C123:thread:T456
多账号隔离的 DM agent:main:telegram:acc1:direct:123456

线程也有独立的 SessionKey,格式为 <baseSessionKey>:thread:<threadId>,并保存 parentSessionKey 用于继承父级上下文。

3.1.3 路由规则(Binding):8 级精细匹配

SessionKey 决定"这条消息属于哪个会话",Binding(绑定规则) 决定"这个会话交给哪个 Agent 处理"。

用户在配置文件中声明 Binding 规则,每条规则有 match 条件和目标 agentId

bindings:
  - match:
      channel: discord
      peer: { kind: channel, id: "123456789" }   # 匹配特定频道
    agentId: support-agent

  - match:
      channel: discord
      guildId: "987654321"
      roles: ["mod-role-id"]                     # 匹配特定服务器 + 角色
    agentId: mod-agent

  - match:
      channel: telegram
      accountId: bot2                            # 匹配特定账号下所有消息
    agentId: telegram-bot2-agent

路由匹配优先级(从高到低,src/routing/resolve-route.ts):

Tier 1
binding.peer
精确 peer ID 匹配

Tier 2
binding.peer.parent
线程继承父级 peer

Tier 3
binding.peer.wildcard
通配符 peer

Tier 4
binding.guild+roles
Discord 服务器+角色

Tier 5
binding.guild
Discord 服务器

Tier 6
binding.team
Slack 工作区

Tier 7
binding.account
渠道账号

Tier 8
binding.channel
该渠道所有消息

Default
全局默认 Agent

代码实现为按优先级遍历 tier 数组,在预建倒排索引中查找匹配,第一个命中即为结果:

// src/routing/resolve-route.ts(简化)
const tiers = [
  { matchedBy: "binding.peer",          candidates: bindingsIndex.byPeer.get(peerKey) },
  { matchedBy: "binding.peer.parent",   candidates: bindingsIndex.byPeer.get(parentPeerKey) },
  { matchedBy: "binding.peer.wildcard", candidates: bindingsIndex.byPeerWildcard },
  { matchedBy: "binding.guild+roles",   candidates: bindingsIndex.byGuildWithRoles.get(guildId) },
  { matchedBy: "binding.guild",         candidates: bindingsIndex.byGuild.get(guildId) },
  { matchedBy: "binding.team",          candidates: bindingsIndex.byTeam.get(teamId) },
  { matchedBy: "binding.account",       candidates: bindingsIndex.byAccount },
  { matchedBy: "binding.channel",       candidates: bindingsIndex.byChannel },
];

for (const tier of tiers) {
  const matched = tier.candidates?.find(
    (c) => tier.predicate(c) && matchesBindingScope(c.match, scope)
  );
  if (matched) return choose(matched.binding.agentId, tier.matchedBy);
}
return choose(resolveDefaultAgentId(cfg), "default");

路由结果通过 WeakMap<OpenClawConfig, Map<cacheKey, ResolvedAgentRoute>> 缓存,最多缓存 4000 条,超限整体清除。

3.1.4 入口安全措施

第一道防线:DM 策略(dmPolicy)

// src/channels/plugins/types.core.ts
export type ChannelSecurityDmPolicy = {
  policy: "pairing" | "allowlist" | string;
  allowFrom?: Array<string | number> | null;
};

两种核心策略:

  • pairing 模式:用户必须先完成 Pairing 握手(类似扫码授权),Pairing Store 条目与静态 allowFrom 合并
  • allowlist 模式:只有 allowFrom 列表中的用户 ID 才能对话,Pairing Store 条目被明确忽略(防止通过 Pairing 绕过严格白名单)
// src/channels/allow-from.ts
function mergeDmAllowFromSources({ allowFrom, storeAllowFrom, dmPolicy }) {
  // allowlist 模式下绝不合并 Pairing Store,防绕过
  const storeEntries = dmPolicy === "allowlist" ? [] : (storeAllowFrom ?? []);
  return [...(allowFrom ?? []), ...storeEntries];
}

第二道防线:消息去重(Inbound Dedupe)

防止同一条消息被处理两次(网络重试、多路由并发等场景):

// src/auto-reply/reply/inbound-dedupe.ts
export function buildInboundDedupeKey(ctx: MsgContext): string | null {
  // Key = provider | accountId | agentScope | peerId | threadId | messageId
  return [provider, accountId, sessionScope, peerId, threadId, messageId]
    .filter(Boolean).join("|");
}

去重缓存使用 TTL + maxSize 双重限制,并以 Symbol.for() 挂载到全局,确保即使从不同模块路径进入也命中同一个缓存实例。


3.2 消息处理全链路(Auto-reply)

3.2.1 端到端处理时序
渠道 Outbound Agent Runner getReplyRun Commands Routing Security Gateway 渠道 Plugin 渠道 Outbound Agent Runner getReplyRun Commands Routing Security Gateway 渠道 Plugin 解析 model/thinkLevel 读取/创建 SessionEntry 组装 System Prompt 懒加载 agent-runner 读 JSONL Transcript 调用 AI 模型(含fallback) 执行 Tool Call 流式输出 dispatchInboundMessage(MsgContext) dmPolicy + allowFrom 检查 通过 or 拦截 inboundDedupeKey 去重 resolveAgentRoute() agentId + SessionKey 命令检测(/reset /new /think...) getReplyRun() ~590行前置装配 runReplyAgent() 回复内容 + token 用量 写 JSONL Transcript 通过 outbound Adapter 投递 发送回原渠道
3.2.2 MsgContext:消息的标准化"信封"

每条消息进入系统后,被标准化为 MsgContext,是贯穿整个处理链路的核心数据结构:

export type MsgContext = {
  // 消息正文(三种视图)
  Body?: string;           // 原始正文,用于 UI 显示
  BodyForAgent?: string;   // 给 AI 的版本(注入了时间戳等)
  CommandBody?: string;    // 用于命令检测的纯净文本(去掉@提及等)

  // 路由标识
  From?: string;           // "telegram:user:123"
  SessionKey?: string;     // 已计算好的 SessionKey
  AccountId?: string;      // 多账号标识

  // 消息元数据(来自平台,不可信)
  MessageSid?: string;     // 消息 ID(用于去重)
  ReplyToId?: string;      // 被回复消息 ID
  InboundHistory?: Array<{ sender; body; timestamp }>; // 群聊近期消息

  // 发送者信息(不可信)
  SenderName?: string;
  SenderId?: string;

  // 安全与权限
  CommandAuthorized?: boolean;
  UntrustedContext?: string[];  // 需要隔离的不可信内容块
};
3.2.3 信任边界:System(可信)vs User(不可信)双层注入

这是 OpenClaw 中最关键的安全设计。给 AI 的输入被明确分为两个层次:

System Prompt 层(可信):由系统生成,攻击者无法控制

// src/auto-reply/reply/inbound-meta.ts
export function buildInboundMetaSystemPrompt(ctx: TemplateContext): string {
  // 注意:发件人名字、群组名等用户可控字符串绝不放这里
  // 原因1:防止 Prompt Injection 攻击
  // 原因2:这些字段变动频繁,会破坏 prompt cache 前缀稳定性
  const payload = {
    schema: "openclaw.inbound_meta.v1",
    chat_id: ctx.OriginatingTo,  // 系统路由信息,可信
    account_id: ctx.AccountId,   // 系统账号 ID,可信
    channel: channelValue,       // 系统判断的渠道,可信
    chat_type: chatType,         // 系统判断的会话类型,可信
    response_format: resolveInboundFormattingHints(ctx),
  };
  return `## Inbound Context (trusted metadata)\n...\`\`\`json\n${JSON.stringify(payload)}\n\`\`\``;
}

User 消息层(不可信):用户可控内容,明确标注来源

// src/auto-reply/reply/inbound-meta.ts
export function buildInboundUserContextPrefix(ctx: TemplateContext): string {
  blocks.push("Conversation info (untrusted metadata):\n```json\n" + JSON.stringify({
    sender: ctx.SenderName,          // 用户可控,放 User 层
    group_subject: ctx.GroupSubject, // 用户可控
  }) + "\n```");

  if (ctx.ReplyToBody) {
    blocks.push("Replied message (untrusted, for context):\n...");
  }
  if (ctx.InboundHistory?.length) {
    blocks.push("Chat history since last reply (untrusted, for context):\n...");
  }
}

这套设计核心目标是防御 Prompt Injection:攻击者无法通过在消息里写 ## Inbound Context 来欺骗 AI,因为这些字段只在 System 层出现,用户输入只出现在 User 层的 untrusted 块中。

同时这也是 Prompt Cache 优化:把每条消息都不同的变量(时间戳、发件人名等)排除在 System Prompt 之外,使同一 Agent 在同一渠道的所有对话的 System Prompt 前缀保持字节级不变,最大化 Claude 等模型的 Prompt Cache 命中率,直接降低 API 成本

3.2.4 懒加载边界设计
// src/auto-reply/reply/get-reply-run.ts
let agentRunnerRuntimePromise: Promise<typeof import("./agent-runner.runtime.js")> | null = null;

function loadAgentRunnerRuntime() {
  // ??= 保证只初始化一次(单例 Promise 模式)
  agentRunnerRuntimePromise =
    agentRunnerRuntimePromise ?? import("./agent-runner.runtime.js");
  return agentRunnerRuntimePromise;
}

const { runReplyAgent } = await loadAgentRunnerRuntime();

最重的 AI 推理模块延迟到真正有消息需要处理时才加载,降低 Gateway 冷启动时间,同时让测试可以精确 mock 这个边界。

3.2.5 Session 历史持久化

Session 历史以两层结构持久化在磁盘:

索引文件(sessions.json,Key 就是 SessionKey:

{
  "agent:main:main": {
    "sessionId": "uuid-abc123",
    "sessionFile": "uuid-abc123.jsonl",
    "updatedAt": 1710000000000,
    "totalTokens": 12345,
    "model": "claude-sonnet-4-6"
  }
}

Transcript 文件(<sessionId>.jsonl,完整对话历史,每行一条:

{"type":"session","id":"uuid-abc123","version":1}
{"type":"message","id":"msg-1","message":{"role":"user","content":[{"type":"text","text":"你好"}]}}
{"type":"message","id":"msg-2","message":{"role":"assistant","content":[{"type":"text","text":"你好!"}],"usage":{"input":50,"output":10}}}

Session 有完善的老化淘汰机制(pruneAftermaxEntriesmaxDiskBytes),旧文件重命名为 .jsonl.deleted.<timestamp> 归档而非直接删除。

3.2.6 Context Window 管理

随着对话变长,Token 使用量接近模型 Context Window 上限时,系统会主动触发上下文压缩,防止超限报错。这套压缩机制分为三个阶段(Preflight Compaction → Memory Flush → in-turn Auto Compaction),在 AI 推理执行引擎层实现——详见 §3.3.5 三阶段上下文管理

3.2.7 群聊消息历史的内存索引

群聊场景下,系统维护内存中的群组消息历史 Map,当机器人被 @ 触发时,把"自上次回复以来的群聊消息"作为上下文注入:

// src/auto-reply/reply/history.ts
export const DEFAULT_GROUP_HISTORY_LIMIT = 50; // 最多 50 条
export const MAX_HISTORY_KEYS = 1000;          // 最多 1000 个群组的历史

3.3 AI 推理执行引擎:上下文构建与执行调度

src/auto-reply/reply/ 目录解决的核心问题是:一条消息是如何变成一次 AI 推理调用,并安全地把回复送回去的

这个执行引擎由两层组成:

层次 文件 角色
装配层 get-reply-run.ts 懒加载、前置安全检查、FollowupRun 构建
执行层 agent-runner.ts 队列仲裁、上下文管理、AI Turn 驱动、回复投递
3.3.1 System Prompt 的 8 层拼接顺序

attempt.ts 负责组装每次 AI 调用的 System Prompt。拼接顺序设计有严格的缓存稳定性约束:越靠前的内容越稳定(字节级不变),越靠后的内容越动态:

层次 来源 稳定性
1. 核心指令 agentPrompt / 工作区 AGENTS.md ★★★★★ 最稳定
2. 渠道上下文 ChannelAgentPromptAdapter 注入 ★★★★☆
3. 工作区文件 workspaceDir 下的上下文文件 ★★★★☆
4. Context Engine 注入 动态感知的环境上下文 ★★★☆☆
5. Memory Hook 注入 外部记忆后端检索结果 ★★★☆☆
6. Session Hook 注入 会话级 Hook(session-memory 等) ★★☆☆☆
7. Extra System Prompt 压缩后刷新内容(Post-compaction refresh) ★★☆☆☆
8. 渠道元数据 当前时间戳、发送者信息等 ★☆☆☆☆ 最动态

设计哲学:稳定内容放前面,可以复用 Provider 的 Prompt Cache(Anthropic/OpenAI 都支持前缀缓存);动态内容放后面,避免破坏缓存前缀,显著降低 API 费用。

3.3.2 FollowupRun:可序列化的运行快照

在执行引擎中流转的核心数据结构是 FollowupRunsrc/auto-reply/reply/queue/types.ts)。它是一个可序列化的运行快照,把执行一次 AI 对话所需的全部参数打包在一起,可以安全地入队、出队、重写:

// src/auto-reply/reply/queue/types.ts
export type FollowupRun = {
  prompt: string;            // 用户原始消息
  messageId?: string;        // 渠道消息 ID(用于去重)
  summaryLine?: string;      // 队列丢弃时的摘要行
  enqueuedAt: number;        // 入队时间戳(毫秒)

  // 回复路由:把回复送回哪个渠道/账号/目标
  originatingChannel?: OriginatingChannelType;
  originatingTo?: string;
  originatingAccountId?: string;
  originatingThreadId?: string | number;

  run: {
    agentId: string;           // Agent 标识
    sessionId: string;         // 会话 ID(对应 JSONL Transcript 文件)
    sessionFile: string;       // Transcript 绝对路径
    workspaceDir: string;      // 工作区目录(Agent 工具的工作目录)
    config: OpenClawConfig;    // 整个运行时配置快照
    skillsSnapshot?: SkillSnapshot; // 技能快照(保证运行期间技能不会变化)
    provider: string;          // AI Provider(anthropic / openai / ...)
    model: string;             // 模型名称
    thinkLevel?: ThinkLevel;   // 思考深度(low / medium / high)
    timeoutMs: number;         // 超时(毫秒)
    // ...其他执行参数
  };
};

FollowupRun 是纯数据对象(无方法),可以跨队列传递,也可以在运行中被安全地重写(例如 Session 轮转后更新 sessionId)。

3.3.3 装配层:get-reply-run.ts

getReplyRun() 是进入执行引擎的大门。它的职责是"把一条入站消息准备好,变成可执行的 FollowupRun"。

拒绝

通过

入站消息
AutoReply

安全检查

丢弃/记日志

resolveSessionKey
计算会话坐标

loadSessionStore
加载会话状态

resolveProvider & Model
选择 AI 模型

resolveQueue
确定队列策略

buildFollowupRun
构建运行快照

prepareSessionManager
预创建 JSONL 文件

runReplyAgent
交给执行层

关键细节:prepareSessionManagerForRun 会在 AI 推理开始之前就创建好 Transcript 文件(touch 操作),保证后续追加写入时文件一定存在,避免并发竞争。

3.3.4 执行层:队列仲裁策略

进入 runReplyAgent() 后,第一个决策点是队列仲裁:当前有没有正在运行的 AI Turn?如果有,这条新消息应该怎么处理?

这个逻辑封装在 resolveActiveRunQueueAction()src/auto-reply/reply/queue-policy.ts):

// src/auto-reply/reply/queue-policy.ts
export type ActiveRunQueueAction = "run-now" | "enqueue-followup" | "drop";

export function resolveActiveRunQueueAction(params: {
  isActive: boolean;      // 当前是否有 AI Turn 正在运行
  isHeartbeat: boolean;   // 是否是心跳消息
  shouldFollowup: boolean;// 是否是后续跟进消息
  queueMode: QueueSettings["mode"]; // 队列策略
}): ActiveRunQueueAction {
  if (!params.isActive) return "run-now";      // 空闲:立即执行
  if (params.isHeartbeat) return "drop";       // 心跳+忙碌:直接丢弃
  if (params.shouldFollowup || params.queueMode === "steer") return "enqueue-followup";
  return "run-now";
}

五种队列模式(QueueMode)在"有并发"时的行为:

模式 并发时行为 适用场景
interrupt 中断当前 Turn,立即执行新消息 高优先级打断场景
steer 入队,并把新消息注入当前 Turn 的 Steering 通道 流式期间修正方向
followup 入队,等当前 Turn 结束后顺序执行 多轮跟进消息
collect 入队,等待并合并多条消息一起执行 防抖合并(去重+聚合)
steer-backlog Steer + 维护积压队列 高频输入场景

run-now

steer(注入消息)

enqueue-followup

Turn 结束

出队 drain

drop(心跳丢弃)

空闲

执行中

等待队列

3.3.5 三阶段上下文管理

仲裁通过后,在真正发起 AI 调用之前,执行层会依次执行三个上下文管理阶段,确保模型始终在有效的 Context Window 内运行:

runAgentTurnWithFallback runMemoryFlushIfNeeded runPreflightCompactionIfNeeded agent-runner.ts runAgentTurnWithFallback runMemoryFlushIfNeeded runPreflightCompactionIfNeeded agent-runner.ts 检查 token 使用量\n超过 softThreshold 则压缩 调用专用 AI Agent\n把对话历史"写入记忆"\n再压缩 Transcript 流式输出\n工具调用\n自动压缩(in-turn) 第一阶段:Preflight Compaction 更新 SessionEntry(含新 sessionId) 第二阶段:Memory Flush 更新 SessionEntry 第三阶段:AI Turn 执行 runResult(含 autoCompactionCount)

阶段一:Preflight Compaction(运行前压缩)

在 Turn 开始前检查 Token 使用量。如果 totalTokens >= contextWindowTokens - reserveTokensFloor - softThresholdTokens,则触发 compactEmbeddedPiSession(),调用内嵌 Pi Agent 对 Transcript 进行摘要压缩。压缩后会将 [Post-compaction context refresh] 注入到下一次请求的 extraSystemPrompt,防止 Agent "遗忘"自己的工作流程。

阶段二:Memory Flush(记忆写入刷新)

这是比 Preflight Compaction 更重量级的操作:专门调用一次 AI Agent,让它把当前对话的重要信息写入磁盘记忆文件memoryFlushWritePath),再压缩 Transcript。这样就算后续会话重置,关键信息也已持久化。每个 compaction 周期只触发一次(通过 compactionCountmemoryFlushCompactionCount 对比判断是否重复):

// src/auto-reply/reply/memory-flush.ts
export function hasAlreadyFlushedForCurrentCompaction(
  entry: Pick<SessionEntry, "compactionCount" | "memoryFlushCompactionCount">,
): boolean {
  const compactionCount = entry.compactionCount ?? 0;
  const lastFlushAt = entry.memoryFlushCompactionCount;
  // 幂等保护:本轮压缩已经 Flush 过则跳过
  return typeof lastFlushAt === "number" && lastFlushAt === compactionCount;
}

阶段三:in-turn Auto Compaction

Turn 执行完成后,如果 AI 模型在流式输出过程中自动触发了压缩autoCompactionCount > 0),执行层会同步更新 SessionEntrysessionId,并把新的 sessionId 广播给等待队列中的所有 FollowupRunrefreshQueuedFollowupSession),确保积压消息不会继续使用过期的 Transcript 文件。

// agent-runner.ts:自动压缩后刷新队列中已入队消息的会话信息
refreshQueuedFollowupSession({
  key: queueKey,
  previousSessionId,
  nextSessionId: refreshedSessionEntry.sessionId,
  nextSessionFile: refreshedSessionEntry.sessionFile,
});
3.3.6 流式输出与回复投递

AI Turn 执行时,reply-dispatcher.ts 负责异步投递回复。它维护了一个引用计数的发送链sendChain),确保:

  1. 工具调用结果(sendToolResult)、Block 回复(sendBlockReply)、最终回复(sendFinalReply)按序不交叉投递
  2. 调用 markComplete() 后,等所有 pending 发送任务完成才触发 onIdle
  3. 外部超时(BLOCK_REPLY_SEND_TIMEOUT_MS = 15_000ms)兜底,防止渠道发送卡死

AI 流式输出

reply-dispatcher

sendToolResult
工具结果

sendBlockReply
Block 流式分块

sendFinalReply
最终完整回复

渠道适配器
Outbound

用户

3.3.7 设计总结

执行引擎的核心范式是**「快照驱动 + 不可变参数传递 + 幂等去重 + 三阶段上下文管理」**:

  1. FollowupRun 是完整的执行快照,运行中不修改原始入参,只通过 refreshQueuedFollowupSession 在必要时重写队列数据
  2. 每个决策点(队列仲裁、压缩触发、Memory Flush)都有幂等保护,防止同一周期内重复执行
  3. 上下文窗口管理是主动的:不等模型报错,在 Turn 开始前主动检测、压缩,并在压缩后注入刷新提示,确保 Agent 不会「失忆」

3.4 ACP:子 Agent 控制协议

3.4.1 ACP 是什么

ACP(Agent Control Protocol) 是 OpenClaw 的子 Agent 编排层,基于 @agentclientprotocol/sdk,实现两大场景:

  1. 外部 AI 接入:Claude Desktop、Cursor 等 AI 客户端通过 ACP 直接操作 OpenClaw 管理的渠道(发消息、读历史等)
  2. 内部 Agent 编排:OpenClaw 内部 Agent 通过 ACP 派生子 Agent 会话,实现并行任务分发
3.4.2 ACP 会话状态机

无 ACP 会话

initializeSession()

后端异常

runTurn(text)

turn 完成

运行时错误

重新初始化

closeSession()

closeSession()

none

ready

stale

running

3.4.3 Control-Plane:会话管理器核心操作
// src/acp/control-plane/manager.core.ts 核心接口
initializeSession(input: AcpInitializeSessionInput)
  // 创建或恢复一个 ACP 子 Agent 会话
  // 向 Tasks 注册表记录一个 "running" Task Run

runTurn(input: AcpRunTurnInput)
  // 向子 Agent 发送一轮对话
  // 通过 onEvent 回调流式接收事件(支持 AbortController 取消)

closeSession(input: AcpCloseSessionInput)
  // 关闭会话,清理运行时缓存
  // 从 Tasks 注册表标记任务完成

Session 类型:

export type AcpSession = {
  sessionId: SessionId;
  sessionKey: string;      // 与主 SessionKey 体系对齐
  cwd: string;             // 工作目录
  abortController: AbortController | null; // 支持中途取消
  activeRunId: string | null;
};

运行时缓存(RuntimeCache) 管理所有活跃 ACP 会话,空闲 TTL 到期后自动驱逐,防止资源泄漏。可观测性快照提供 activeSessionsturns.activeturns.queueDeptherrorsByCode 等指标。

3.4.4 Provenance Mode(溯源模式)
export type AcpProvenanceMode = "off" | "meta" | "meta+receipt";
  • off:不记录任何溯源信息
  • meta:在 ACP 响应中附带元数据(哪个 Agent 生成的)
  • meta+receipt:元数据 + 回执(已投递确认)

3.5 Cron:定时任务引擎

3.5.1 Cron 概述

OpenClaw 内置了一个完整的定时任务调度系统,让 AI Agent 可以按计划自动执行任务,并把结果投递到指定渠道。这不是简单的 setInterval,而是支持持久化、容错重试、跨 Session 执行的完整调度引擎。

3.5.2 三种调度模式
// src/cron/types.ts
export type CronSchedule =
  | { kind: "at"; at: string }           // 一次性:指定时间点执行
  | { kind: "every"; everyMs: number; anchorMs?: number } // 间隔执行
  | {
      kind: "cron";
      expr: string;                       // 标准 cron 表达式
      tz?: string;                        // 时区
      staggerMs?: number;                 // 随机抖动,防止惊群效应
    };
3.5.3 任务 Payload:两种执行类型
export type CronPayload =
  | { kind: "systemEvent"; text: string }   // 系统事件,不调用 AI
  | {
      kind: "agentTurn";
      message: string;          // 发给 AI 的提示词
      model?: string;           // 可覆盖 Agent 默认模型
      fallbacks?: string[];     // 自定义 fallback 模型链
      thinking?: string;        // 思维深度(low/medium/high)
      timeoutSeconds?: number;
      toolsAllow?: string[];    // 工具白名单
      lightContext?: boolean;   // 轻量 bootstrap 上下文
    };
3.5.4 投递系统(Delivery)

任务执行完毕后,结果可以通过多种方式投递:

export type CronDelivery = {
  mode: "none" | "announce" | "webhook"; // 不投递/发渠道消息/HTTP 回调
  channel?: CronMessageChannel;          // 目标渠道(如 telegram)
  to?: string;                           // 目标地址(如群组 ID)
  threadId?: string | number;            // 线程/话题 ID
  accountId?: string;                    // 多账号场景指定账号
  bestEffort?: boolean;                  // 投递失败是否容忍
  failureDestination?: CronFailureDestination; // 失败通知单独地址
};
3.5.5 Cron 执行生命周期

成功

失败

CronService.start

加载持久化 Job 列表

计算所有 Job 的 nextRunAtMs

等待最近的 Job 到期

Timer 触发

Job 是否 due?

执行 Job
isolated/main/current Session

执行成功?

lastRunStatus = ok

consecutiveErrors++

超过 failureAlert.after?

发送故障告警到渠道

有 Delivery 配置?

投递结果到目标渠道

3.5.6 四种 Session 目标
type CronSessionTarget =
  | "main"               // 使用 Agent 的主 Session
  | "isolated"           // 每次执行创建独立 Session(无历史污染)
  | "current"            // 复用当前活跃 Session
  | `session:${string}`; // 指定 Session Key

isolated 模式最为常用:每次 Cron 执行都在全新的 Session 中运行,避免历史对话污染定时任务的执行结果。


3.6 Tasks:任务生命周期注册表

3.6.1 Tasks 的作用

src/tasks/ 是一个跨 Runtime 的任务状态追踪系统。无论任务是通过 Cron、ACP、CLI Runner 还是 Sub-Agent 发起的,都统一在 Tasks 注册表中记录和追踪。

3.6.2 任务状态机

创建任务

执行器拾取

完成

异常

超时

用户取消

执行器崩溃

queued

running

succeeded

failed

timed_out

cancelled

lost

// src/tasks/task-registry.types.ts
export type TaskRuntime = "subagent" | "acp" | "cli" | "cron";

export type TaskStatus =
  | "queued"    // 已入队,等待执行
  | "running"   // 正在执行
  | "succeeded" // 执行成功
  | "failed"    // 执行失败
  | "timed_out" // 超时
  | "cancelled" // 被用户取消
  | "lost";     // 执行器丢失(进程重启等)
3.6.3 任务记录(TaskRecord)结构
export type TaskRecord = {
  taskId: string;
  runtime: TaskRuntime;           // 执行器类型
  requesterSessionKey: string;    // 发起者的 SessionKey
  ownerKey: string;               // 任务归属 Key
  scopeKind: "session" | "system";// 会话级或系统级任务
  childSessionKey?: string;       // 子 Agent 的 SessionKey
  parentFlowId?: string;          // 所属 Flow(任务流)
  parentTaskId?: string;          // 父任务 ID(支持嵌套)
  label?: string;                 // 人类可读标签
  task: string;                   // 任务描述
  status: TaskStatus;
  deliveryStatus: TaskDeliveryStatus;
  notifyPolicy: "done_only" | "state_changes" | "silent";
  progressSummary?: string;       // 进度摘要(用于 UI 显示)
  terminalSummary?: string;       // 最终结果摘要
};

Tasks 还支持 TaskFlow(任务流):多个 Task 组成一个有依赖关系的 Flow,统一管理生命周期,实现复杂的 Agent 工作流编排。


3.7 Hooks:可插拔事件钩子

3.7.1 5 类事件类型
// src/hooks/internal-hooks.ts
export type InternalHookEventType =
  | "command"   // 命令处理前/后
  | "session"   // Session 创建/更新
  | "agent"     // Agent bootstrap(工作空间初始化)
  | "gateway"   // Gateway 启动
  | "message";  // 消息接收/发送
3.7.2 内置 Bundled Hooks
Hook 位置 功能
boot-md src/hooks/bundled/boot-md/ Gateway 启动时注入 Markdown 文件到 Agent 上下文
command-logger src/hooks/bundled/command-logger/ 记录所有命令调用日志
session-memory src/hooks/bundled/session-memory/ Session 级别记忆注入(跨 Session 保留关键信息)
bootstrap-extra-files src/hooks/bundled/bootstrap-extra-files/ 启动时注入额外文件到 Agent 工作空间
3.7.3 高级用法:Gmail Watcher Hook

src/hooks/gmail-watcher.ts 展示了 Hook 系统的高级用法:监听 Gmail 收件箱,当有新邮件时触发 message Hook 事件,由 AI Agent 处理邮件内容并自动回复或归档。


3.8 MCP:Model Context Protocol 集成

3.8.1 作为 MCP 服务端

src/mcp/ 实现了 MCP 服务端,把 OpenClaw 管理的渠道能力暴露为 MCP 工具,供支持 MCP 的 AI 客户端(Claude Desktop、Cursor 等)直接调用:

// src/mcp/channel-server.ts
export async function createOpenClawChannelMcpServer(opts) {
  const server = new McpServer({ name: "openclaw", version: VERSION });
  const bridge = new OpenClawChannelBridge(cfg, opts);
  bridge.setServer(server);

  // 注册渠道工具:send_message、list_channels、get_history 等
  registerChannelMcpTools(server, bridge);

  return { server, bridge, start, close };
}
3.8.2 作为 MCP 客户端

OpenClaw 的 Agents 模块也支持作为 MCP 客户端连接到外部 MCP 服务器,通过三种传输方式:

传输方式 文件 适用场景
stdio src/agents/mcp-stdio.ts 本地子进程 MCP 服务
SSE src/agents/mcp-sse.ts HTTP Server-Sent Events
HTTP src/agents/mcp-http.ts HTTP Streamable MCP

3.9 Secrets:统一凭证管理

3.9.1 SecretRef 体系

src/secrets/ 实现了统一的密钥引用体系,API Key 等敏感信息不直接存储在配置文件中,而是通过 SecretRef 描述来源:

// 三种密钥来源
type SecretRefSource = "env" | "file" | "exec";

// 示例:从环境变量读取 OpenAI API Key
{ source: "env", provider: "openai", id: "OPENAI_API_KEY" }

// 示例:从文件读取(支持 JSON Pointer 路径)
{ source: "file", provider: "anthropic", id: "/credentials/api_key" }

// 示例:执行外部命令获取(集成 1Password、Vault 等)
{ source: "exec", provider: "custom", id: "op read op://vault/item/field" }

运行时通过 src/secrets/runtime.ts 动态解析 SecretRef,支持凭证矩阵(多组 API Key 轮换)和 OAuth Token 自动刷新。


3.10 Media Understanding:多模态理解

3.10.1 三类多模态能力

src/media-understanding/ 统一管理三类多模态理解:

能力 类型 支持 Provider
音频转录 audio.transcription Deepgram、ElevenLabs、Groq (Whisper)
视频描述 video.description Zai、自定义 Provider
图像描述 image.description OpenAI、Anthropic、Google Vision
3.10.2 统一 Provider 接口
export type MediaUnderstandingProvider = {
  id: string;
  capabilities?: MediaUnderstandingCapability[];
  transcribeAudio?: (req: AudioTranscriptionRequest) => Promise<AudioTranscriptionResult>;
  describeVideo?: (req: VideoDescriptionRequest) => Promise<VideoDescriptionResult>;
  describeImage?: (req: ImageDescriptionRequest) => Promise<ImageDescriptionResult>;
};

媒体文件被转录/描述后,文本内容作为上下文注入到 AI 对话中,实现"发一张图片/音频/视频,AI 能理解并回答"的多模态交互。


3.11 其他模块简述

3.11.1 TUI 终端界面(src/tui/

实现了功能完整的终端聊天 UI:

  • 富文本 Markdown 渲染(代码高亮、表格、列表)
  • 实时流式输出(token 逐字显示)
  • Tool Call 可视化(执行中/执行结果展示)
  • Session 切换与管理
  • OSC8 超链接支持(终端可点击链接)

组件基于 @inkjs 构建,采用类 React 的声明式组件模型。

3.11.2 Daemon 守护进程(src/daemon/
  • macOS 通过 launchd 管理 Gateway 进程
  • entry.respawn.ts 实现监控重启逻辑,进程崩溃后自动拉起
  • 支持优雅停机(SIGTERM 信号处理,等待活跃请求完成)
3.11.3 TTS 语音合成(src/tts/

统一的 TTS 抽象层,支持 ElevenLabs、Deepgram 等 Provider,配合 voice-call 插件实现语音通话 AI 助手。

3.11.4 Image/Video Generation(src/image-generation/ src/video-generation/

AI 生图/生视频的核心抽象,Provider 实现在 extensions/fal/extensions/image-generation-core/ 等插件中。

3.11.5 Canvas Host(src/canvas-host/

实现 A2UI 协议的交互式 Canvas 渲染,允许 AI Agent 渲染结构化 UI 组件到客户端(图表、表单、交互按钮等)。

3.11.6 Memory Host SDK(src/memory-host-sdk/

外部向量数据库记忆后端接入层,extensions/memory-lancedb/ 实现了基于 LanceDB 的向量记忆,支持语义搜索历史对话。

3.11.7 Pairing 配对(src/pairing/

移动端设备(iOS/Android)通过 QR 码扫描与 Gateway 建立 WebSocket 长连接的配对认证流程。

3.11.8 Flows 引导流(src/flows/

Channel 配置向导流、Model 选择流等引导界面逻辑,用于首次设置时的交互式配置。


3.12 Plugin-SDK 与 Extensions 生态

3.12.1 三类插件合同

src/plugin-sdk/ 是第三方插件的唯一公开合同,定义了三种插件类型:

插件类型 入口文件 说明
Channel Plugin channel-contract.ts 接入新的消息渠道
Provider Plugin provider-entry.ts 接入新的 AI 模型 Provider
General Plugin plugin-entry.ts 通用扩展(工具、Hook、能力扩展等)
3.12.2 插件命名规范

每个 bundled 插件遵守严格的命名约定,确保多处 ID 对齐:

// extensions/<id>/openclaw.plugin.json
{
  "id": "telegram",                    // 插件 ID
  "openclaw.install.npmSpec": "@openclaw/telegram", // npm 包名
  "openclaw.channel.id": "telegram"   // 渠道 ID(Channel 插件必须)
}
3.12.3 Extensions 生态全景

OpenClaw\nExtensions

AI Provider

OpenAI系

openai

azure-openai

github-copilot

openrouter

Anthropic系

anthropic

anthropic-vertex

Google系

google

vertex

国内

deepseek

qwen

minimax

moonshot

byteplus

volcengine

stepfun

开源/本地

ollama

vllm

sglang

litellm

云服务

amazon-bedrock

groq

chutes

together

fireworks

nvidia

venice

消息渠道

境外主流

telegram

discord

slack

whatsapp

signal

企业协作

msteams

feishu

googlechat

mattermost

nextcloud-talk

synology-chat

亚洲

line

zalo

zalouser

qqbot

xiaomi

其他

irc

matrix

tlon

nostr

twitch

imessage

bluebubbles

工具扩展

搜索

exa

brave

tavily

duckduckgo

perplexity

searxng

编程Agent

browser

kilocode

opencode

kimi-coding

媒体

deepgram

elevenlabs

zai

fal

记忆

memory-core

memory-lancedb

语音

voice-call

speech-core

talk-voice

其他

diagnostics-otel

thread-ownership

device-pair

phone-control


四、总结:技术与产品的双重视角

4.1 架构设计亮点速览

读完全部源码,有 13 个设计决策值得重点标记——它们不是孤立的技巧,而是 OpenClaw 能够在"100+ 插件、15+ 消息渠道、30+ AI Provider"规模下依然稳定运行的结构性原因:

设计点 实现方式 核心价值
渠道扩展性 ChannelPlugin 组合式适配器 新渠道无需修改核心代码,按需实现 Adapter
会话隔离 多粒度 dmScope(4 种),SessionKey 体系 精确控制 DM 隔离策略,支持多账号场景
路由精细化 8 级 Binding 规则 + 倒排索引缓存 多 Agent 场景灵活分发,缓存加速
安全防护 dmPolicy + allowFrom + 信任边界分层 防未授权访问 + Prompt Injection 双重防护
Prompt Cache 稳定性 System Prompt 8 层拼接,动态字段后置 降低 API 成本,字节级前缀稳定
子 Agent 编排 ACP + Tasks 注册表 跨 Runtime 统一任务追踪,支持嵌套 Agent
定时任务 Cron 三种调度模式 + Delivery 投递 AI 定时执行并推送结果到任意渠道
凭证安全 SecretRef 三种来源 + 运行时解析 密钥不落配置文件,支持外部密钥管理器
多模态能力 Media Understanding + TTS + 生成 图像/音频/视频统一接入,多 Provider 可选
插件生态 Plugin-SDK + ~100 个 bundled 插件 开放生态,第三方插件零侵入接入
懒加载 动态 import 边界 + 单例 Promise 降低冷启动延迟,测试可精确 mock
历史持久化 JSONL Transcript + 生命周期维护 可靠对话历史,支持 Memory Flush 压缩
Agent Harness FollowupRun 快照 + 三阶段上下文管理 + 队列仲裁 并发安全、Context 自动管理、记忆持久化

4.2 设计哲学:边界即架构

OpenClaw 最值得深究的,是它对边界的执着——这不是代码风格偏好,而是整个系统能否扩展的根本。

边界类型 体现 为什么重要
模块边界 Plugin-SDK 是唯一公开合同,核心从不调用插件内部实现 100+ 插件不会随便"污染"核心逻辑,插件可独立迭代
信任边界 System Prompt 只放可信内容,用户消息严格标注 untrusted Prompt Injection 攻击面大幅缩小
类型边界 大量使用 discriminated union 和 closed error code 消灭 magic string 分支,IDE 可全量静态检查
运行时边界 懒加载 + *.runtime.ts 命名约定 测试可精确隔离重量级模块,冷启动性能有保障

四类边界各自解决了一种"扩散风险":

  • 模块边界 阻止插件实现细节渗入核心——新增或修改一个插件,不需要理解核心代码,也不会意外破坏其他插件
  • 信任边界 阻止用户输入污染系统指令——攻击面被收窄到明确标注的 untrusted 区域,而不是整个 Prompt
  • 类型边界 阻止错误的控制流在运行时才暴露——编译期就能发现,改一处代码影响的范围由 TypeScript 全量告知
  • 运行时边界 阻止重量级模块在不需要时被加载——测试只引入必要的部分,冷启动不因某个插件膨胀而变慢

叠加起来,任何局部改动的影响范围都被明确限定:加一个新渠道插件不需要回归全部 30+ Provider,修一个 Provider Bug 不需要担心破坏 Cron 或 Hooks。这正是为什么一个个人开源项目,在没有大型工程团队支撑的情况下,能稳定维护 100+ 插件、15+ 渠道的庞大生态。


4.3 产品护城河:被低估的形态优势

理解了技术设计之后,有一个更重要的问题值得正视:OpenClaw 各个技术模块单独看,并不存在特别高的壁垒。

  • LLM 调用本质是 SDK 封装;消息路由是成熟的规则引擎思路;JSONL 持久化是标准日志模式;Plugin Registry 模式在企业中间件领域早已普及。

如果只看技术实现,同类开源项目都有覆盖。OpenClaw 的真正护城河,建立在三个产品层面的选择上。

① 消除上下文切换:AI-in-your-inbox
传统 AI 助手:  用户 → 打开新 App → 输入问题 → 等待回复
OpenClaw:      用户 → 照常发 Telegram/iMessage → AI 自动回复,就在对话里

这个差异触达了用户行为最深层的惰性——人不愿意切换上下文。不需要记住新入口,不需要学习新 UI,AI 就活在你每天已经打开的聊天窗口里。这是任何纯技术优化都无法替代的产品决策。

② 渠道覆盖的积累型壁垒

OpenClaw 接入了 15+ 消息渠道:Telegram、Discord、Slack、Signal、iMessage、WhatsApp Web,以及插件扩展的 Matrix、Zalo、Voice Call 等。

渠道覆盖不是线性叠加,而是网络效应型的护城河:

  • 每新增一个渠道,所有已有用户立刻获得新接入点,无需迁移数据
  • 每个渠道适配背后都是深度的工程投入(消息格式差异、图片上传 API、Thread 模型、速率限制……)——复制一个容易,复制 15 个需要数年积累
  • 对企业场景,内部 Slack Bot + 外部 Telegram Bot 共用同一套 AI 配置和记忆,这是横向平台才能做到的
③ 管道化架构 + 私有部署:数据主权与粘性双锁定

OpenClaw 的架构是管道优先的:AI 模型本身是可替换的组件,而消息管道——接收、路由、执行、回复、持久化——才是稳定的核心资产。

用户侧-强绑定

OpenClaw管道-稳定资产

AI层-可替换

对话记忆留存

能力持续扩展

Claude 4

GPT-5.4

Gemini 2.5

Routing 路由

Agent Harness 执行

Session/Memory 记忆

Plugin Ecosystem 插件

Telegram

iMessage

Discord

Slack...

这带来两个粘性来源:

数据粘性:用户的 Transcript 历史、Memory 文件、技能配置都沉淀在自己的 OpenClaw 实例里。换一个 AI 助手产品,这些积累全部清零。

主权粘性:OpenClaw 天然支持完全私有化部署。gateway.mode = local 让整个 Gateway 跑在本地机器;Session JSONL 和 Memory 文件落在 ~/.openclaw/,从不经过任何第三方服务器;API Key 通过 SecretRef 体系以 env(环境变量)、file(本地文件)或 exec(调用外部密钥管理器如 1Password/Vault)的方式读取,密钥从不明文写入配置文件。官方甚至专门提供了树莓派部署文档——35 美元的设备 + 自己的 API Key,就能搭建一个 24 小时在线、数据完全自有的 AI 助手,成本远低于任何 SaaS 订阅。


4.4 结语

OpenClaw 给出了一个有趣的答案:AI 时代最有价值的不一定是"最聪明的 AI",而是"让 AI 最容易被用上的基础设施"。

从源码层面看,它的边界设计、懒加载策略、三阶段上下文管理、幂等保护,全都在服务同一个产品目标:让 AI 在用户已有的消息流里稳定、低成本、无感地存在。技术架构的每一个决策,都是在降低"使用 AI"的摩擦系数。

从产品层面看,它选择了一个独特的竞争位置——不做"更强的模型",不做"更好看的聊天框",而是做人与 AI 之间的连接层:把用户已有的沟通习惯(发消息)直接变成与 AI 交互的方式,同时让用户的数据和记忆沉淀在自己手里。

当大模型能力趋于同质、AI 产品竞争白热化,OpenClaw 的这种定位反而越来越清晰:它不是在和 ChatGPT 竞争谁更聪明,而是在占据一个 LLM 厂商天然无法直接复制的位置——每个人消息流的入口。

Logo

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

更多推荐