前言 链接到标题

Raspberry Pi 4(4GB 内存)跑了小半年的 OpenClaw(目前是 5.7),一直当我的个人助理使用。现在要开放给客户使用,但面临两个核心问题:

  • 数据隔离:每个人的对话、记忆不能混在一起
  • 执行安全:不能让客户在宿主机上乱跑命令

OpenClaw 从 6.x 开始引入了原生多 Agent 架构 + Docker 沙盒子系统,正好解决这两个问题。OpenClaw 的镜像也从 5.7 的 3.2GB 精简到 6.5 的 1.71GB,体积几乎减半。这篇文章记录从 5.7 升级到 2026.6.5-beta.12(代码与正式版几乎相同,GitHub 上稳定版标记为 2026.6.5、Docker Hub 上的 beta.12 镜像与正式版代码一致,可以放心使用)并配置多用户沙盒隔离的全过程。

为什么升级到 6.5 链接到标题

跟上节奏,避免大跳跃 链接到标题

5.7 到 6.5 跨越了多个大版本,核心架构有不少变化:

  • 多 Agent 系统openclaw agents 子命令,一个 Gateway 承载多个独立 Agent
  • Docker 沙盒子系统openclaw sandbox,不用自己写容器编排
  • CardKit 卡片 API:飞书从旧消息 API 迁移到卡片 API,支持更丰富的交互
  • SQLite 持久化:状态数据从 JSON 文件迁移到 SQLite,更可靠

性能和多用户场景 链接到标题

6.x 的性能改善对多用户场景是实打实的——Gateway 容器本身很轻量(~300MB 内存),多 Agent 不走额外进程,只是一个命名空间和路由逻辑。Pi 4 的 4GB 内存跑 1 个主人 + 3-4 个沙盒用户绰绰有余。

CardKit 的"美丽"与"遗憾" 链接到标题

6.x 引入的 CardKit 卡片 API 理论上支持流式打字效果——LLM 每生成一个 token,飞书卡片上就多一个字。实际体验上,如果流式正常,用户能看到 AI 实时"打字",心理等待感会大大降低。这是 5.7 时代没有的能力。

但有一个遗留 bug:飞书 CardKit streaming 的一个回归(PR #87896 引入)导致每个 streaming chunk 到达时替换整张卡片内容,而不是追加。最终卡片只显示 1-2 个字符。

根因在飞书插件的 FeishuStreamingSession.update() 方法——它发送增量文本而非累积文本给 CardKit API,而 CardKit API 的 PUT elements/content 是替换语义,不是追加语义。

当前临时方案:在 openclaw.json 中设 streaming: false,回复一次性出现。虽然失去了打字效果,但内容完整。其他渠道插件(Discord、Telegram、WhatsApp 等)使用整条消息编辑 API,不存在此问题,所以只有飞书用户受影响。

这个 bug 的核心修复(PR #90181)已在 main 分支合入,但仍有几个边缘 case(卡片显示不全、提前关闭、不自动撑高)在等待后续版本修复。等这些都关闭后,把 streaming 改回 true 即可恢复流式体验——那时候的用户体验将比 5.7 时代好很多。一次性出消息在当前场景下影响不算大,但确实有时让人以为机器人卡住了,如果能流式输出,用户体验会提升一大截。

部署架构总览 链接到标题

node1(Pi 4)上跑一个 OpenClaw Gateway Docker 容器,通过 DooD(Docker-out-of-Docker)模式在宿主机上创建 sibling 沙盒容器。主人(我)直接走 host 模式,其他用户每人一个独立的 Docker 沙盒容器。

graph TB subgraph 宿主机_node1_Pi4 OC["openclaw-gateway
2026.6.5
(~300MB 内存)"] DS["/var/run/docker.sock"] DC["/usr/bin/docker"] subgraph 数据卷_volume CFG[".openclaw/
openclaw.json
credentials/
state/openclaw.sqlite"] W0["workspace/
主人 workspace"] W1["workspace-my_test/
测试用户 workspace"] W2["workspace-xxx/
用户 workspace"] end subgraph 沙盒容器_懒加载 S1["openclaw-sbx-my_test
debian:bookworm-slim
/workspace -> host path
(~80-150MB idle)"] end end subgraph 飞书 FB["飞书 Bot
cli_xxxx..."] U0["主人
ou_1c1666d8..."] U1["测试用户
ou_93db2e6d..."] U2["用户
ou_8d6e942c..."] end U0 -- "DM" --> FB --> OC U1 -- "DM" --> FB --> OC --> S1 OC --> DS --> Docker_daemon OC --> DC --> Docker_daemon Docker_daemon --> S1

核心要点 链接到标题

组件 说明
单 Gateway + 多 Agent 一个容器,agents.list[] 里每个用户一个条目,bindings[] 路由
DooD 模式 容器内挂 /var/run/docker.sock + /usr/bin/docker,创建 sibling 容器
FS bridge 映射 .openclaw 目录必须按宿主路径同名映射进容器(踩坑重点!)
沙盒懒加载 用户首次发消息才创建容器,不占用 idle 资源
workspace 需用宿主路径 DooD 模式下 Docker daemon 按宿主命名空间解析路径

配置文件详解 链接到标题

docker-compose.yml 链接到标题

这是整个部署的入口。核心是 volumes 块——挂载了什么决定了沙盒能访问什么。

services:
  openclaw-gateway:
    image: ghcr.nju.edu.cn/openclaw/openclaw:2026.6.5-slim
    # 镜像与正式版 2026.6.5 代码几乎一致,放心使用
    volumes:
      - /home/user/openclaw/.openclaw:/home/node/.openclaw
      - /home/user/openclaw/.openclaw/workspace:/home/node/.openclaw/workspace
      - /home/user/.ssh:/home/node/.ssh:ro
      - /home/user/.config:/home/node/.config:ro
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/bin/docker:/usr/bin/docker:ro
      - /home/user/openclaw/.openclaw:/home/user/openclaw/.openclaw  # FS bridge!
    ports:
      - "18789:18789"
      - "18790:18790"
    init: true
    restart: unless-stopped

特别注意:最后一行 FS bridge 映射——Docker daemon 在创建沙盒容器时,按宿主机的文件系统解析 bind mount 源路径。如果 workspace 路径是 /home/node/...,宿主机上不存在此路径,沙盒容器的 /workspace 会挂载到空目录。必须将 .openclaw 再按宿主路径映射一次。

openclaw.json 三段核心配置 链接到标题

第一段:飞书认证 链接到标题

"channels": {
  "feishu": {
    "enabled": true,
    "dmPolicy": "allowlist",
    "allowFrom": [
      "ou_1c1666d8...",
      "ou_93db2e6d...",
      "ou_8d6e942c..."
    ],
    "streaming": false,
    "renderMode": "card"
  }
}

dmPolicy: "allowlist" 是关键——只有 allowFrom 列表中的用户能发消息,且重启后持久有效。OpenClaw 默认的 pairing 模式在容器重启后会丢失配对状态,让用户反复验证,体验很差。

第二段:Agent 列表 链接到标题

"agents": {
  "list": [
    { "id": "main" },
    {
      "id": "my_test",
      "workspace": "/home/user/openclaw/.openclaw/workspace-my_test",
      "sandbox": {
        "mode": "all",
        "scope": "agent",
        "workspaceAccess": "rw",
        "docker": {
          "image": "m.daocloud.io/docker.io/debian:bookworm-slim",
          "network": "openclaw-sandbox"
        }
      },
      "tools": {
        "sandbox": {
          "tools": {
            "alsoAllow": ["group:web"]
          }
        },
        "allow": [
          "read", "write", "edit", "apply_patch",
          "exec", "process",
          "group:messaging", "group:memory", "group:web", "group:fs"
        ],
        "deny": ["browser", "canvas", "nodes", "gateway", "cron"]
      }
    }
  ]
}
  • workspace 路径用宿主路径/home/user/...),不是容器路径
  • sandbox.mode: "all" 表示所有请求都在沙盒内执行
  • sandbox.scope: "agent" 每用户一个容器
  • 必须显式设置(默认 完全无网),设为 让沙盒能联网
  • 是沙盒下的额外工具放行层, 让 web_fetch/web_search 对沙盒 LLM 可见
  • sandbox.docker.network 必须显式设置(默认 "none" 完全无网),设为 "openclaw-sandbox" 让沙盒能联网
  • tools.sandbox.tools.alsoAllow 是沙盒下的额外工具放行层,group:web 让 web_fetch/web_search 对沙盒 LLM 可见
  • tools.allow 放开了 group:web(含 web_search/web_fetch)让沙盒用户也能联网

第三段:路由绑定 链接到标题

"bindings": [
  {
    "type": "route",
    "agentId": "my_test",
    "match": {
      "channel": "feishu",
      "accountId": "default",
      "peer": {
        "kind": "dm",
        "id": "ou_93db2e6d..."
      }
    }
  }
]

peer 过滤是关键——不加 peer 会匹配所有飞书 DM,导致主人消息也被路由到测试用户。openclaw agents add --bind 命令不支持 peer 级绑定,必须停 gateway 后手改配置。

沙盒用户邀请流程 链接到标题

sequenceDiagram actor Admin as 主人 actor User as 新用户 participant LH as 飞书管理后台 participant OC as OpenClaw Gateway Admin->>LH: 创建用户账号 LH-->>Admin: 用户创建完成 Admin->>OC: 让 AI Agent 查找 open_id OC->>LH: 飞书 API get_user LH-->>OC: 返回 ou_xxx 格式 open_id OC-->>Admin: 拿到 open_id Admin->>LH: 应用可见性设为"全部用户" Admin->>OC: 将 open_id 加入 allowFrom Admin->>OC: 创建 agent 条目 + sandbox 配置 Note over OC: 编辑 openclaw.json
docker compose down + up -d User->>LH: 手机上飞书搜索应用 User->>OC: 发送第一条消息 OC->>OC: dmPolicy: allowlist 检查通过 OC->>OC: bindings 路由到对应 agent OC->>Docker: 懒加载创建沙盒容器 Docker-->>OC: 容器就绪 OC-->>User: 回复消息

找用户 OpenID 的踩坑记 链接到标题

这是整个过程中最折磨人的环节。

飞书管理后台的坑:应用可见性必须设为"全部用户"。我之前设为"部分用户"可见,结果新用户始终无法通过飞书 API 查到。卡了整整一天。

OpenID 格式:飞书用户 ID 有两种——短名和长名(ou_xxx 格式)。API 只认长名格式。

尝试失败的方法

  • 飞书管理后台翻半天找不到 open_id 字段
  • 调试界面命令各种查不到
  • API Explorer 返回空列表

最终方案(两种方法)

方法一(最快):让新用户给 bot 发一条消息,bot 会自动回复 pairing 消息,其中就包含了用户的 open_id

Your Feishu user id: ou_xxx...

这种方法最简单,不需要任何 API 权限,适用于邀请任何用户。

方法二(AI 辅助):使用 AI 编程助手(如 OpenCode),给它提供飞书应用的 appId + appSecret。AI 通过飞书 API 工具(feishu_get_user),设置 user_id_type=open_id 列出所有用户,再根据姓名或手机号匹配目标用户。在飞书管理后台中,必须确保应用可见性设为"全部用户"(而不是"部分用户"),否则 API 会返回空列表。

拿到 open_id 后还不能直接使用,需要将 open_id 加入 channels.feishu.allowFrom[] 列表。

配置检查清单 链接到标题

拿到 open_id 后,检查以下三项:

  1. 飞书管理后台:应用可见性 > 全部用户(设为"部分用户"会导致 API 查不到人)
  2. openclaw.jsonchannels.feishu.allowFrom[] 追加 open_id
  3. openclaw.jsonagents.list[] 新增 agent 条目 + bindings[] 路由(含 peer 过滤)

沙盒隔离细节 链接到标题

网络 链接到标题

沙盒容器默认网络为 "none"(完全断网),必须显式设置 sandbox.docker.network 才能联网。将 network 设为 "openclaw-sandbox"(专用隔离网络 ),沙盒就能访问内外网。如果不设置,web_search/web_fetch 会因无网络而失败。

镜像 链接到标题

选用 debian:bookworm-slim(138MB),在保证基本工具链可用的前提下尽量轻量。用户如果需要 curl/wget 等网络工具,可在容器内自行安装,web_search 工具即可正常使用。

挂载隔离 链接到标题

沙盒容器只挂入了 workspace 目录(rw),其他数据不可见:

数据 沙盒容器内 说明
当前用户的 AGENTS.md/USER.md/MEMORY.md ✅ /workspace (rw) 可读写
内置技能文件 ✅ /workspace/.openclaw/…/skills (ro) 只读
其他用户的 workspace ❌ 不可见 数据隔离
Gateway 配置(openclaw.json) ❌ 不可见 防配置篡改
凭据(credentials/) ❌ 不可见 防凭据泄露
对话历史(sessions/) ❌ 不可见 隐私保护

懒加载 链接到标题

沙盒容器不会在 Gateway 启动时就创建。用户在飞书发送第一条消息时,OpenClaw 自动执行 docker run 创建容器。之后 persist,直到用户长时间不活跃或手动 sandbox recreate

资源评估 链接到标题

Pi 4 的 4GB 内存,实测情况:

组件 内存
openclaw-gateway ~300MB
alloy(日志采集) ~50MB
系统 + 其他 ~500MB
每个沙盒容器(idle) ~80-150MB
4 用户场景 余量充足

避坑总结 链接到标题

原因 解决方案
配对重启丢失 pairing 状态仅存内存 dmPolicy: "allowlist" + allowFrom
binding 拦截所有消息 agents add --bind 不支持 peer 过滤 停 gateway 后手改 JSON 加 peer
沙盒 workspace 为空 DooD 路径用容器路径 workspace 改宿主路径 + FS bridge 映射
容器内无 docker 命令 OpenClaw 沙盒 spawn docker 子进程 挂载 /usr/bin/docker:/usr/bin/docker:ro
飞书 streaming 异常 CardKit API 回归 bug streaming: false 临时关闭
找不到用户 open_id 应用可见性 = “部分用户” 改"全部用户",让用户发条消息即可
docker image ls 显示两个大小 Size 是完整镜像大小(5.7: 3.2GB, 6.x: 1.71GB),第二列是实际磁盘占用 Size 列,6.x 体积减半

结语 链接到标题

OpenClaw 6.5 的多 Agent + 沙盒架构非常实用。一个 Pi 4 就能跑起来,把 AI 助手开放给多个用户,还能确保数据隔离和执行安全。虽然 CardKit streaming 有个暂时的 bug,但一次性出消息在当前场景下影响不大。

最期待的改进还是飞书流式输出——现在回复一次性出现,用户体验不太好,有时让人以为机器人卡住了。等后续版本把 streaming 修好,飞书卡片上能看到 AI 实时"打字",体验会好很多。