Openclaw 架构原理解析

Openclaw 架构原理解析与技术分析

前言

OpenClaw 是什么?

OpenClaw = AI 代理的"中枢神经系统" + "多通道通信网关"

核心定位:

  • 打通聊天应用(Telegram/WhatsApp/Discord/iMessage 等)与 AI Agent(如 Pi)之间的连接
  • 作为"代理原生操作系统",处理工具调用、会话记忆、多代理路由
  • 自托管部署,数据隐私可控,不依赖第三方云服务

近期看了一篇关于OpenClaw的架构原理分析,原文地址:V2EX 讨论帖

在这里我将通过我个人理解整理并记录下来。

整体架构概览

OpenClaw 的设计哲学可以概括为:"统一入口、插件扩展、记忆外化"

flowchart LR
    subgraph Input["输入层:多渠道接入"]
        A1[Telegram] --> P1[Channel Plugin]
        A2[Discord] --> P2[Channel Plugin]
        A3[WhatsApp] --> P3[Channel Plugin]
        A4[iMessage] --> P4[Channel Plugin]
        A5[Web UI] --> P5[Channel Plugin]
    end

    subgraph Core["核心网关:Gateway"]
        G1[消息归一化] --> G2[会话管理]
        G2 --> G3[路由决策]
        G3 --> G4[插件扩展]
        G4 --> G5[事件广播]
    end

    subgraph Output["输出层:能力执行"]
        O1[Pi Agent] --> O2[工具调用]
        O2 --> O3[记忆读写]
        O3 --> O4[结果返回]
    end

    P1 & P2 & P3 & P4 & P5 --> G1
    G5 --> O1
    O4 --> P1 & P2 & P3 & P4 & P5

    style Core fill:#e1f5fe,stroke:#01579b
    style Input fill:#f3e5f5,stroke:#4a148c
    style Output fill:#e8f5e9,stroke:#1b5e20

架构核心:所有外部消息先经过 Channel Plugin 归一化,再由 Gateway 统一调度,最后由 Agent 执行推理与工具调用,结果原路返回。


核心交互流程图解

1. 消息处理生命周期

sequenceDiagram
    participant User as 用户 (聊天渠道)
    participant GW as Gateway 网关
    participant Route as 路由解析器
    participant AgentCfg as Agent 配置
    participant Session as 会话存储
    participant Context as 上下文组装器
    participant Skills as Skills 能力中心
    participant LLM as 大模型 (无状态)

    User->>GW: 1. 发送一条入站消息
    GW->>Route: 2. 解析路由 (channel/account/peer/thread)
    Route-->>GW: 3. 返回 agentId + sessionKey
    GW->>AgentCfg: 4. 读取 Agent 默认策略 (人设/模型/规则)
    GW->>Session: 5. 按 sessionKey 读取会话

    alt 会话存在且未过期
        Session-->>GW: 6. 返回已有 sessionId + 会话元数据
    else 新会话或触发重置
        GW->>Session: 7. 创建/更新会话条目
        Session-->>GW: 8. 返回新 sessionId + 会话元数据
    end

    GW->>Context: 9. 开始组装本轮上下文
    Context->>Session: 10. 读取 transcript 历史片段 (按 sessionId)
    Context->>AgentCfg: 11. 合并 Agent 默认配置
    Context->>Session: 12. 合并会话级覆盖 (thinking/model/sendPolicy 等)
    Context->>Skills: 13. 解析本会话可用 skills (基于 session 快照)
    Skills-->>Context: 14. 返回本轮可见工具/技能
    Context-->>GW: 15. 产出最终上下文 (Prompt)

    GW->>LLM: 16. 发起模型请求 (context)
    LLM-->>GW: 17. 返回回复 + 工具事件 + usage

    GW->>Session: 18. 追加本轮记录到 transcript (sessionId.jsonl)
    GW->>Session: 19. 更新会话元数据 (updatedAt/lastChannel/usage 等)
    GW-->>User: 20. 按来源路由把回复发回原渠道/目标

    Note right of LLM: 大模型每次调用默认无状态
    Note left of Session: 会话连续性由会话存储维持

2. Agent 路由决策流程

flowchart TD
    Start[收到标准化消息] --> Extract{提取路由特征}

    Extract -->|peer | R1[精确匹配指定 Agent]
    Extract -->|parent| R2[继承父会话 Agent]
    Extract -->|guild | R3[服务器级默认 Agent]
    Extract -->|team  | R4[团队级默认 Agent]
    Extract -->|account|R5[账号级默认 Agent]
    Extract -->|channel|R6[渠道级默认 Agent]

    R1 & R2 & R3 & R4 & R5 & R6 --> Fallback{是否匹配成功?}

    Fallback -->|是 | Route[分发到目标 Agent]
    Fallback -->|否 | Default[使用 default Agent]

    Route & Default --> Execute[执行推理流程]

    style Start fill:#bbdefb
    style Execute fill:#c8e6c9

3. 记忆检索与注入流程

flowchart LR
    subgraph Load["启动时预加载"]
        L1[读取 memory/YYYY-MM-DD.md] --> L2[最近 2 天内容]
        L3[读取 MEMORY.md] --> L4[核心偏好/事实]
    end

    subgraph Runtime["运行时按需检索"]
        R1[新消息到达] --> R2{是否私密会话?}
        R2 -->|是 | R3[加载 MEMORY.md]
        R2 -->|否 | R4[跳过长期记忆]

        R3 & R4 --> R5[BM25 + 向量混合检索]
        R5 --> R6[Top-K 相关片段]
        R6 --> R7[拼接至 Prompt Context]
    end

    subgraph Persist["推理后持久化"]
        P1[新对话内容] --> P2[追加到当日 memory 文件]
        P2 --> P3[定期摘要归档到 sessions/]
    end

    Load --> Runtime --> Persist

关键机制深度拆解

统一安全机制

# 权限控制三层模型
security:
  role_based:      # 角色鉴权
    - admin: [所有方法]
    - user:  [chat.*, memory.read]
    - guest: [chat.send]

  method_whitelist: # 方法级白名单
    allowed: ["agent.chat", "memory.query"]
    denied:  ["system.shutdown", "config.update"]

  node_constraint:  # 节点二次约束
    require_tls: true
    ip_whitelist: ["192.168.1.0/24"]

插件热加载机制

// 伪代码:插件注册流程
func RegisterPlugin(p Plugin) error {
    // 1. 校验插件契约
    if !p.Implements(PluginInterface) {
        return errors.New("invalid plugin")
    }

    // 2. 动态注册事件处理器
    for event, handler := range p.EventHandlers {
        gateway.Subscribe(event, handler)
    }

    // 3. 注册扩展工具/方法
    for name, tool := range p.Tools {
        agent.RegisterTool(name, tool)
    }

    // 4. 热加载完成,无需重启网关
    log.Infof("Plugin %s loaded successfully", p.Name())
    return nil
}

优势:新增渠道或工具只需开发插件,核心网关零修改,符合开闭原则。


记忆系统设计亮点

设计哲学:磁盘是硬盘,上下文是缓存

大多数 AI Agent 的记忆方案依赖上下文窗口硬撑:把历史对话不断塞进 Prompt,既昂贵又容易超限遗忘。

OpenClaw 反其道而行:

  • 记忆外化:所有记忆持久化到磁盘纯 Markdown 文件
  • 文件即真相:.md 文件是唯一事实来源,模型只是读者
  • 按需加载:每次推理只 page in 真正需要的内容
  • 人工可干预:用任意文本编辑器即可修改、删除、备份记忆

类比人类记忆:

  • 短期记忆 = 今天的便签纸(随时翻阅最近内容)
  • 长期记忆 = 人生笔记精华本(只记关键事实与偏好)
  • 检索机制 = 想到什么翻什么,而不是把一生经历背在脑子里

三层记忆架构详解

flowchart TB
    subgraph Disk["磁盘存储(持久层)"]
        D1["memory/YYYY-MM-DD.md<br/>(短期/临时记忆)"] 
        D2["MEMORY.md<br/>(长期/精选记忆)"]
        D3["sessions/{sessionKey}/<br/>(完整会话归档)"]
    end

    subgraph Index["检索索引(加速层)"]
        I1["BM25 倒排索引"] 
        I2["轻量向量索引"]
        I3["混合检索融合器"]
    end

    subgraph Context["运行时上下文(缓存层)"]
        C1["最近 2 天短期记忆"]
        C2["私密会话加载长期记忆"]
        C3["检索命中片段 Top-K"]
    end

    D1 & D2 & D3 --> I1 & I2
    I1 & I2 --> I3
    I3 --> C1 & C2 & C3
    C1 & C2 & C3 --> LLM["LLM 推理输入"]

    style D1 fill:#fff9c4,stroke:#fbc02d
    style D2 fill:#ffcdd2,stroke:#c62828
    style D3 fill:#e1f5fe,stroke:#0277bd

第一层:短期记忆(Short-term Memory)

memory/
├── 2026-03-30.md   # 前天的对话摘要 + 关键决策
├── 2026-03-31.md   # 昨天的上下文 + 工具调用记录
└── 2026-04-01.md   # 今天的实时追加日志(写入中)

工作机制:

特性说明
格式纯 Markdown,人类可读可编辑
写入每条新对话/决策追加到当日文件末尾
加载会话启动时,自动读取 today.md + yesterday.md
目的提供最近连续感,支撑多轮对话不断层
清理超过 shortTermDays(默认 2 天)的旧文件自动归档

设计巧思:按天切分文件,既避免单文件过大,又天然支持时间窗口检索。


第二层:长期记忆(Long-term / 灵魂文件)

# MEMORY.md - OpenClaw 的核心人格

## 用户偏好
- 回复风格:优先简洁,技术问题时可展开细节
- 时区:Asia/Shanghai,工作时间 9:00-18:00
- 常用工具:GitHub, Slack, Notion, Figma

## 关键事实
- 项目 Alpha 的部署环境:K8s 集群,命名空间 prod-alpha
- 用户正在开发一个任务管理应用,技术栈:Go + PostgreSQL
- 偏好使用 Conventional Commits 规范

## 项目约定
- 代码风格:遵循语言官方 fmt 工具 + lint 检查
- 文档语言:中文为主,专业术语保留英文原文
- API 设计:RESTful 风格,版本号放 URL 路径

## 隐私边界
- 不记录密码/密钥/令牌等敏感信息明文
- 群聊/共享会话内容不写入此文件
- 涉及个人隐私的对话需用户显式标记才归档

加载策略(隐私优先):

flowchart LR
    Start[会话开始] --> Check{会话类型?}

    Check -->|私密 1v1| LoadLong[加载 MEMORY.md]
    Check -->|群聊/共享| SkipLong[跳过长期记忆]

    LoadLong --> Merge[合并到上下文]
    SkipLong --> Merge

    Merge --> Ready[开始推理]

    style LoadLong fill:#c8e6c9,stroke:#2e7d32
    style SkipLong fill:#ffcdd2,stroke:#c62828

隐私保护设计:群聊场景故意不加载 MEMORY.md,避免用户偏好/敏感事实泄露给其他参与者。


第三层:会话归档(Session Archive,可选)

sessions/
├── telegram_user_abc123/
│   ├── 2026-03.md      # 月度摘要 + 关键对话片段
│   └── raw/            # 完整原始日志(可选开启)
├── discord_guild_xyz789/
│   └── 2026-04.md
└── index.json          # 全局搜索索引元数据

核心价值:

  • 可搜索:支持按关键词/时间/渠道回溯历史
  • 可分析:定期生成对话摘要,沉淀知识
  • 可清理:归档文件可独立删除,不影响主记忆

检索机制:混合召回,透明可控

不依赖黑盒向量库的混合检索

graph LR
    A[用户/Agent 发起检索] --> B{检索策略}
    B -->|关键词优先| C[BM25 倒排索引]
    B -->|语义优先| D[轻量向量索引]
    C --> E[计算关键词相关度]
    D --> F[计算语义相似度]
    E --> G[加权融合]
    F --> G
    G --> H[重排序 + 去重]
    H --> I[返回 Top-K 文本片段]
    I --> J[拼接至 Prompt Context]

工具调用示例:

# Agent 主动检索记忆的 tool call
tool: memory_search
parameters:
  query: 之前讨论过的数据库连接池配置参数
  session: telegram_user_abc123  # 可选:限定会话范围
  top_k: 3
  include_long_term: true        # 是否搜索 MEMORY.md

返回结果:

<!-- 来自 memory/2026-03-28.md -->
> [2026-03-28 15:40] 讨论 PostgreSQL 连接池配置:
> - max_connections: 20
> - min_idle: 5
> - conn_max_lifetime: 30m
> - 建议监控 active_connections 指标

<!-- 来自 MEMORY.md -->
> [项目约定] 所有数据库配置项需写在 config.yaml 中,禁止硬编码

优势:检索过程完全透明,结果可追溯、可验证、可手动修正。


记忆的可编辑性

随时干预,无需重启

# 场景:用户发现 AI 记住了错误配置
$ vim memory/2026-04-01.md

# 修改前
- 数据库连接池 max_connections: 50

# 修改后
- 数据库连接池 max_connections: 20(生产环境限制)

# 保存后,下次对话立即生效,无需重启服务

Agent 主动管理记忆

# 伪代码:关键信息自动沉淀
def flush_to_long_term(important_facts: list):
    with open("MEMORY.md", "a", encoding="utf-8") as f:
        f.write(f"\n## {datetime.now()}\n")
        for fact in important_facts:
            f.write(f"- {fact}\n")

    # 同时压缩短期记忆,避免上下文膨胀
    compress_shortterm(days=2, keep_summary=True)

触发场景:

  • 用户显式说"请记住:..."

  • Agent 推理出关键结论(如技术方案确认、配置约定)

  • 对话中出现重复高频信息,自动提炼


实际效果:为什么感觉像活的

传统 AgentOpenClaw
重启=失忆,需重新配置重启后记忆完整,无缝续聊
上下文塞满历史,易超限只加载相关片段,token 高效
记忆黑盒,无法干预.md 文件直编,人类可修正
隐私依赖服务商承诺数据完全本地,可控可审计
新增记忆需改代码/配置写文件即生效,零代码扩展

场景演示:跨天连续对话

Day 1(3 月 31 日)
用户:帮我记一下,项目部署时用 prod 命名空间,测试用 staging
OpenClaw:追加到 memory/2026-03-31.md

夜间服务重启...

Day 2(4 月 1 日)
用户:刚才说的部署命令,命名空间用哪个?
OpenClaw:自动加载短期记忆 -> 精准回复"prod"
同时检索 MEMORY.md 中的项目约定 -> 补充 kubectl 参数建议

关键体验:用户感觉它真的记得,而非每次都要重新教。


总结

OpenClaw 的核心价值

  1. 工程化思维:将"聊天渠道适配"抽象为插件契约,避免硬编码
  2. 记忆可控:纯 Markdown 存储,可编辑、可搜索、可版本管理
  3. 隐私优先:自托管 + 本地记忆,敏感数据不出内网
  4. 扩展友好:新增能力只需实现插件接口,核心零侵入

评论


暂无评论

* 登录后即可评论