搭建我的专属AI助手:OpenClaw云服务器部署实战指南.md 52 KB


title: 搭建我的专属AI助手:OpenClaw云服务器部署实战指南 author: Gamehu tags:

  • OpenClaw
  • AI
  • DevOps
  • 部署
  • 记录系统优化 categories:
  • 工具 date: 2026-02-27 22:30:00 updated: 2026-03-06 14:10:00 ---

📢 更新日志

  • 2026-03-06 新增 Step-3.5-Flash 接入与会话级 /model 切换说明,补充默认模型不切全局、只切当前会话的使用方式。
  • 2026-03-03 新增"记录系统优化"章节,解决会话文件膨胀问题,添加自动归档和结构化存储方案。
AI提效 实战踩坑

写在前面

最近刷到不少 OpenClaw 的文章,演示零成本安装、智能体集群、国内部署经验。我手头正好有台 2 核 3G 的云服务器闲置着,决定动手搭建一个专属 AI 助手。

但这篇文章不是推广,是真实的部署踩坑记录。整个过程历时数小时,遇到了 OOM 内存不足、配置验证失败、防火墙规则冲突等一系列问题,把完整的解决过程记录下来。

先说结论:OpenClaw 确实能跑起来,但需要对 Docker、网络和 Linux 有一定了解,且内存配置要充足。


OpenClaw 是什么

OpenClaw 是一个开源的个人 AI 助手框架,核心价值在于:它不是只聊天的 AI,而是能动手干活的 AI

核心能力:

  • 在 Telegram、Discord、Slack 等平台接收指令
  • 操作文件系统、执行 Shell 命令、浏览网页
  • 调用 API、读写数据库
  • 跨会话持久化记忆

最重要的是——运行在自己的服务器上,数据完全掌控。


我的环境

搬瓦工买的一台机器,配置不高,平时捣鼓各种东西的。

配置项 实际环境
系统 Ubuntu 24.04.2 LTS
CPU 3 核
内存 2GB RAM
磁盘 39GB SSD
Docker 29.2.1
Docker Compose v5.1.0
公网 IP your-server-ip

⚠️ 重要提示:2GB 内存对于源码构建来说不够,需要配置 Swap。


部署过程实录

第一步:安装 Docker

Ubuntu 24.04 下安装 Docker 很顺利:

# 更新系统
apt update && apt upgrade -y

# 安装 Docker
curl -fsSL https://get.docker.com | sh

# 验证安装
docker --version  # Docker version 29.2.1
docker compose version  # Docker Compose version v5.5.1

国内用户建议配置镜像加速,编辑 /etc/docker/daemon.json

{
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://dockerhub.icu"
  ]
}

第二步:源码构建(第一个坑:OOM)

官方提供了 Docker 镜像,但我选择从源码构建以获得最新功能:

mkdir -p /opt/openclaw
cd /opt/openclaw
git clone https://github.com/openclaw/openclaw.git
cd openclaw

开始构建:

docker build -t openclaw:local -f Dockerfile .

🚨 第一个大坑:构建到 pnpm install 时容器被杀

查看日志发现是 OOM(内存不足)。2GB RAM 在构建 Node.js 项目时不够用,pnpm install 直接占满内存导致进程被系统杀死。

解决方案:添加 Swap 空间

# 创建 5GB Swap 文件
dd if=/dev/zero of=/swapfile bs=1G count=5
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# 验证
free -h
# 显示:Swap: 5.0Gi

添加 Swap 后重新构建,成功完成。

📷 安装过程 - 添加 Swap 解决 OOM

安装过程


第三步:配置 OpenClaw

创建 docker-compose.yml

version: '3.8'

services:
  openclaw-gateway:
    image: openclaw:local
    container_name: openclaw
    restart: unless-stopped
    environment:
      - HOME=/home/node
      - NODE_ENV=production
    volumes:
      - ./.openclaw:/home/node/.openclaw
      - ./.openclaw/workspace:/home/node/.openclaw/workspace
    ports:
      - "127.0.0.1:18789:18789"
      - "127.0.0.1:18790:18790"
    command: ["node", "dist/index.js", "gateway", "--bind", "lan", "--port", "18789"]

🚨 第二个坑:配置验证极其严格

OpenClaw 对 openclaw.json 配置文件的校验非常严格,很多字段在官方文档中没有明确说明,但缺失会导致启动失败。

我遇到的错误:

✖ Configuration validation failed:
  - gateway.mode is required
  - gateway.controlUi.allowedOrigins is required when using non-loopback bind

正确的最小配置openclaw.json):

{
  "gateway": {
    "port": 18789,
    "mode": "local",
    "controlUi": {
      "allowedOrigins": ["http://localhost:18789", "http://127.0.0.1:18789"]
    },
    "auth": {
      "token": "your-secure-token-here"
    }
  }
}

📷 OpenClaw Web UI 界面

OpenClaw Web UI

关键注意点

  • gateway.mode 必须显式设置为 "local"
  • gateway.controlUi.allowedOrigins 在使用非 localhost 绑定时是必需的
  • gateway.bind 不能写在 JSON 中(无效字段),必须通过 CLI 参数 --bind lan 设置

第四步:配置阿里云百炼模型

我选择使用阿里云百炼的 Coding Plan,配置 kimi-k2.5 作为主力模型:

{
  "models": {
    "mode": "merge",
    "providers": {
      "bailian": {
        "baseUrl": "https://coding.dashscope.aliyuncs.com/v1",
        "apiKey": "YOUR_BAILIAN_API_KEY",
        "api": "openai-completions",
        "models": [
          {
            "id": "kimi-k2.5",
            "name": "kimi-k2.5",
            "input": ["text", "image"],
            "contextWindow": 262144,
            "maxTokens": 32768
          },
          {
            "id": "qwen3.5-plus",
            "name": "qwen3.5-plus",
            "input": ["text", "image"],
            "contextWindow": 1000000,
            "maxTokens": 65536
          }
        ]
      }
    }
  },
  "agents": {
    "defaults": {
      "model": {
        "primary": "bailian/kimi-k2.5"
      }
    }
  }
}

第五步:配置 Telegram Bot

@BotFather 创建 Bot 并获取 Token。

🚨 第三个坑:配对码过期与 dmPolicy 冲突

{
  "channels": {
    "telegram": {
      "enabled": true,
      "botToken": "YOUR_BOT_TOKEN_HERE",
      "allowFrom": ["YOUR_TELEGRAM_USER_ID"]
    }
  }
}

初始配置时我加了 "dmPolicy": "open",结果与 allowFrom 白名单冲突,报错:

dmPolicy: open requires allowFrom: ["*"]

解决方案:删除 dmPolicy 字段,直接使用 allowFrom 白名单。

启动服务:

docker compose up -d
docker compose logs -f

看到日志显示 Telegram channel started 且没有错误,说明 Bot 已上线。

📷 Telegram Bot 配置成功


第六步:Google Workspace 集成(扩展能力)

这是 OpenClaw 真正强大的地方——通过 Google Workspace 集成,AI 可以帮你管理邮件、日历、文档。

OpenClaw 使用 gog skill 来访问 Google 服务(Gmail、Calendar、Drive、Docs、Sheets)。

6.1 创建 Google Cloud 项目

  1. 访问 Google Cloud Console
  2. 创建新项目(例如:openclaw-integration
  3. 启用以下 API:
    • Gmail API
    • Google Calendar API
    • Google Drive API
    • Google Docs API
    • Google Sheets API

6.2 配置 OAuth 凭据

  1. 进入 APIs & Services > Credentials
  2. 点击 Create Credentials > OAuth client ID
  3. 选择 Desktop app 类型
  4. 记下 Client IDClient Secret

6.3 配置 MCP 服务器

OpenClaw 通过 MCP (Model Context Protocol) 集成 Google Workspace。

在服务器上创建 MCP 配置文件:

mkdir -p /opt/openclaw/.openclaw/mcp
cat > /opt/openclaw/.openclaw/mcp/google-workspace.json << 'EOF'
{
  "mcpServers": {
    "google-workspace": {
      "command": "npx",
      "args": ["-y", "@gongchangio/mcp-google-workspace"],
      "env": {
        "GOOGLE_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
        "GOOGLE_CLIENT_SECRET": "your-client-secret",
        "GOOGLE_REDIRECT_URI": "http://localhost:18790/oauth2callback"
      }
    }
  }
}
EOF

6.4 重启 OpenClaw 并授权

cd /opt/openclaw
docker compose restart

# 查看日志等待授权提示
docker compose logs -f | grep -i google

首次启动会显示 OAuth 授权链接,在浏览器中打开并授权后,会获得一个 code,将其填回即可。

6.5 实际使用场景

配置完成后,你可以通过 Telegram 让 AI 帮你:

管理邮件

"帮我查看今天的重要邮件,并回复需要处理的"

操作日历

"帮我查一下下周的会议安排,把周五下午的会议改到周四"

读写文档

"读取 Drive 里的 '项目计划.docx',帮我总结要点并更新状态"

⚠️ 注意:Google OAuth 有权限范围限制

  • 个人 Gmail 账户:直接可用
  • Google Workspace(企业账户):需要管理员授权
  • 敏感范围(如删除邮件)需要额外验证

第七步:安全加固(重中之重)

🚨 第四个坑:Docker 绕过 INPUT 链的防火墙规则

我最初的防火墙配置:

iptables -I INPUT 1 -p tcp --dport 18789 -s 127.0.0.1 -j ACCEPT
iptables -I INPUT 2 -p tcp --dport 18789 -j DROP

测试发现:公网仍然可以访问 Web UI!

原因:Docker 在 DOCKER 链中插入了 ACCEPT 规则,且该链在 INPUT 链之前被处理。

正确的解决方案:使用 DOCKER-USER

# 在 DOCKER-USER 链中插入规则(在 Docker 规则之前执行)
iptables -I DOCKER-USER 1 -p tcp -s 127.0.0.1 --dport 18789 -j ACCEPT
iptables -I DOCKER-USER 2 -p tcp --dport 18789 -j DROP
iptables -I DOCKER-USER 3 -p tcp -s 127.0.0.1 --dport 18790 -j ACCEPT
iptables -I DOCKER-USER 4 -p tcp --dport 18790 -j DROP

# 保存规则
iptables-save > /root/iptables-rules.txt

最终安全策略

项目 状态
配置文件权限 容器运行用户可读(避免 EACCES
公网 Web UI 通过 DOCKER-USER 链完全阻止
本地 Web UI 127.0.0.1 可访问
Telegram 访问 仅白名单用户 ID 可用
外部访问方式 SSH 隧道

📷 最后安全检查 - 安全加固结果

安全检查

SSH 隧道访问命令

ssh -N -L 18789:127.0.0.1:18789 root@your-server-ip
# 然后在本地浏览器访问 http://localhost:18789

进阶玩法:持久记忆配置(第9步)

OpenClaw 的持久记忆系统让它能跨会话记住你的偏好、项目信息和个人习惯。这是从"工具"升级为"助手"的关键。

记忆文件目录结构

路径 用途 文件类型
/home/node/.openclaw/memory/ 数据库存储(自动) main.sqlite - 对话历史
/home/node/.openclaw/workspace/ 结构化记忆文件 MEMORY.md, USER.md
/home/node/.openclaw/workspace/memory/ 每日记忆归档 YYYY-MM-DD.md

核心记忆文件

1. USER.md - 用户档案

# USER.md - About Your Human

- **Name:** Gamehu
- **What to call them:** Gamehu
- **Timezone:** Asia/Shanghai (UTC+8)

## Context
- **职业:** IT 行业,编程 + 团队管理
- **需求:** 个人助手
- **风格偏好:** 简单直接,不绕弯子

2. MEMORY.md - 长期记忆

# MEMORY.md - Long-term Memory

## Technical Stack
- **Primary Languages:** Java, JavaScript, Python, Go
- **Frameworks:** Spring Boot, React
- **Cloud:** Alibaba Cloud, AWS

### Preferences
- **Code Style:** Clean, well-documented
- **Learning Style:** Hands-on, project-based
- **Dislikes:** Repetitive small talk

### Current Projects
- Building personal AI assistant
- Managing development team

如何工作

  1. 自动记忆:所有对话自动存入 SQLite,跨会话保持上下文
  2. 结构化记忆:AI 主动读取 MEMORY.md 了解你的背景和偏好
  3. 持续更新:OpenClaw 会定期根据对话更新记忆文件

测试持久记忆

给 Bot 发送:

"记住我喜欢用 Go 语言写后端服务"

过一段时间再问:

"我之前告诉你我喜欢用什么语言?"

如果配置正确,Bot 应该能回答出 Go


进阶玩法:记录系统优化(第9.5步,新增)

在解决 compaction 卡死问题后,我意识到 OpenClaw 的会话记录管理还有很多优化空间。之前的经历是:会话文件在两天内膨胀到 1.4MB(603 条消息),导致系统卡死。为了防止类似问题再次发生,我设计并部署了一套结构化的记录管理系统

为什么需要记录系统优化

问题 优化前 优化后
会话文件膨胀 1.4MB(603条消息) 每日自动归档,单文件 < 100KB
数据管理 所有文件混在一起 结构化分类存储
查找历史 翻找 JSONL 文件 Markdown 摘要,一目了然
数据备份 手动复制 自动归档 + 一键导出

优化后的目录结构

我在 workspace 下创建了完整的分类存储结构:

/root/.openclaw/workspace/
├── memory/                    # 记忆类数据
│   ├── daily/                # 每日摘要 (YYYY-MM-DD.md)
│   ├── weekly/               # 每周汇总
│   └── archived/             # 长期归档
├── records/                   # 记录类数据
│   ├── conversations/        # 对话记录 (按月归档)
│   │   └── 2026-03/
│   │       ├── 2026-03-03/   # 当日完整会话
│   │       └── 2026-03-03-sessions.tar.gz
│   ├── tasks/                # 任务记录
│   │   ├── completed/        # 已完成任务
│   │   └── failed/           # 失败任务
│   ├── browser/              # 浏览器操作记录
│   │   ├── screenshots/      # 网页截图
│   │   └── page-dumps/       # 页面快照
│   └── files/                # 文件操作日志
├── outputs/                   # 输出类数据
│   ├── generated/            # AI 生成的文档
│   ├── exports/              # 导出文件
│   └── reports/              # 定时报告
└── logs/                      # 日志类
    ├── system/               # 系统日志 (archive-YYYY-MM-DD.log)
    ├── model/                # 模型调用记录
    └── errors/               # 错误日志

自动归档脚本

创建 /root/.openclaw/workspace/archive-daily.sh

#!/bin/bash
WORKSPACE="/root/.openclaw/workspace"
SESSIONS_DIR="/home/node/.openclaw/agents/main/sessions"
DATE=$(date +"%Y-%m-%d")
MONTH=$(date +"%Y-%m")

# 创建归档目录
mkdir -p "$WORKSPACE/records/conversations/$MONTH/$DATE"
mkdir -p "$WORKSPACE/memory/daily"

# 归档会话文件
if [ -d "$SESSIONS_DIR" ]; then
    cp "$SESSIONS_DIR"/*.jsonl "$WORKSPACE/records/conversations/$MONTH/$DATE/" 2>/dev/null || true
    SESSION_COUNT=$(ls -1 "$SESSIONS_DIR"/*.jsonl 2>/dev/null | wc -l)
    SIZE=$(du -sb "$SESSIONS_DIR" 2>/dev/null | cut -f1)
else
    SESSION_COUNT=0
    SIZE=0
fi

# 生成每日摘要 Markdown
cat > "$WORKSPACE/memory/daily/${DATE}.md" << DAILYMD
---
date: ${DATE}
type: daily-summary
sessions_count: ${SESSION_COUNT}
sessions_size_kb: $((${SIZE} / 1024))
---

# 📅 ${DATE} 对话摘要

## 📊 今日统计
- **日期**: ${DATE}
- **星期**: $(date +%A)
- **会话数**: ${SESSION_COUNT}
- **数据大小**: $((${SIZE} / 1024)) KB

## 🏷️ 重要标签
- 

## 💡 今日收获
- 

## 📌 待办事项
- [ ] 

---
DAILYMD

# 记录归档日志
echo "[$(date)] 归档完成: ${DATE}, ${SESSION_COUNT} 个会话" >> "$WORKSPACE/logs/system/archive-${DATE}.log"

赋予执行权限:

chmod +x /root/.openclaw/workspace/archive-daily.sh

配置定时任务

添加每天 23:00 自动执行归档:

# 添加定时任务
(crontab -l 2>/dev/null | grep -v archive-daily; echo "0 23 * * * /root/.openclaw/workspace/archive-daily.sh >> /root/.openclaw/workspace/logs/system/cron.log 2>&1") | crontab -

# 查看已配置的定时任务
crontab -l

快捷命令配置

创建 /root/.openclaw/.aliases.sh,方便快速查看记录:

# 查看今日记录
alias oc-today='cat /root/.openclaw/workspace/memory/daily/$(date +%Y-%m-%d).md 2>/dev/null || echo "今日记录不存在"'

# 查看昨日记录
alias oc-yesterday='cat /root/.openclaw/workspace/memory/daily/$(date -d yesterday +%Y-%m-%d 2>/dev/null || date -v-1d +%Y-%m-%d).md 2>/dev/null || echo "昨日记录不存在"'

# 手动执行归档
alias oc-archive='/root/.openclaw/workspace/archive-daily.sh'

# 查看统计
alias oc-stats='echo "=== OpenClaw 统计 ===" && echo "会话文件: $(ls -1 /home/node/.openclaw/agents/main/sessions/*.jsonl 2>/dev/null | wc -l)" && echo "每日摘要: $(ls -1 /root/.openclaw/workspace/memory/daily/*.md 2>/dev/null | wc -l)"'

# 查看目录大小
alias oc-size='du -sh /root/.openclaw/workspace/*/ 2>/dev/null | sort -h'

使用方法:

# 加载快捷命令
source /root/.openclaw/.aliases.sh

# 查看今日记录
oc-today

# 手动归档
oc-archive

# 查看统计
oc-stats

Docker 容器内配置

为了让 OpenClaw Bot 也能执行归档,在 Docker 容器内创建归档脚本:

# 在容器内创建归档命令
docker exec openclaw-openclaw-gateway-1 bash -c 'cat > /tmp/oc-archive.sh << "EOF"
#!/bin/bash
WORKSPACE="/home/node/.openclaw/workspace"
SESSIONS="/home/node/.openclaw/agents/main/sessions"
DATE=$(date +"%Y-%m-%d")
MONTH=$(date +"%Y-%m")
mkdir -p "$WORKSPACE/records/conversations/$MONTH/$DATE"
COUNT=0
if [ -d "$SESSIONS" ]; then
  cp "$SESSIONS"/*.jsonl "$WORKSPACE/records/conversations/$MONTH/$DATE/" 2>/dev/null || true
  COUNT=$(ls -1 "$SESSIONS"/*.jsonl 2>/dev/null | wc -l)
fi
cat > "$WORKSPACE/memory/daily/$DATE.md" << DAILY
---
date: $DATE
type: daily-summary
sessions_count: $COUNT
---

# 📅 $DATE 对话摘要

## 📊 统计
- 会话数: $COUNT

## 🏷️ 标签
- 

## 💡 收获
- 
DAILY
echo "✅ 归档完成: $DATE, $COUNT 个会话"
EOF
chmod +x /tmp/oc-archive.sh'

Telegram Bot 使用

配置完成后,你可以直接在 Telegram 中对 Bot 发送:

指令 功能
"归档今天的对话" 手动触发归档
"查看今天的记录" 显示今日摘要
"查看昨天的记录" 显示昨日摘要
"统计我的对话数量" 显示统计报告

每日摘要示例

生成的 Markdown 文件 (memory/daily/2026-03-03.md):

---
date: 2026-03-03
type: daily-summary
sessions_count: 5
sessions_size_kb: 45
---

# 📅 2026-03-03 对话摘要

## 📊 今日统计
- **日期**: 2026-03-03
- **星期**: Tuesday
- **会话数**: 5
- **数据大小**: 45 KB

## 🏷️ 重要标签
- OpenClaw 配置
- 技能开发

## 💡 今日收获
- 配置了自动归档系统
- 解决了会话文件膨胀问题

## 📌 待办事项
- [ ] 测试归档功能
- [ ] 配置 Web 画廊

这种结构化的记录管理方式,让你可以:

  1. 快速回顾 - 每天打开 Markdown 文件即可看到当日概况
  2. 防止膨胀 - 自动归档避免会话文件无限增长
  3. 便于导出 - 重要记录可以轻松导出分享
  4. Telegram 管理 - 直接通过 Bot 指令管理记录

进阶玩法:自定义 Skill(第10步)

OpenClaw 的 Skill 系统让你可以扩展 AI 的能力。我把自己的 Hexo 博客做成了 Skill,让 Bot 可以直接帮我创建博客文章。

我的 Hexo 博客 Skill

1. 创建脚本

在服务器上创建文章生成脚本 /opt/hexo-blog/create-post.sh

#!/bin/bash
# Hexo Blog Post Creator

BLOG_DIR="/opt/hexo-blog"
POSTS_DIR="$BLOG_DIR/source/_posts"

# 参数
TITLE="${1:-新建文章}"
CATEGORY="${2:-随笔}"
TAGS="${3:-日常}"
DATE=$(date +"%Y-%m-%d %H:%M:%S")
FILENAME=$(echo "$TITLE" | sed 's/ /-/g' | tr '[:upper:]' '[:lower:]')-$(date +"%Y%m%d").md

# 创建目录
mkdir -p "$POSTS_DIR"

# 创建文章
cat > "$POSTS_DIR/$FILENAME" << EOF
---
title: $TITLE
author: Gamehu
date: $DATE
tags:
EOF

# 添加标签
IFS=',' read -ra TAG_ARRAY <<< "$TAGS"
for tag in "${TAG_ARRAY[@]}"; do
    echo "  - $(echo $tag | xargs)" >> "$POSTS_DIR/$FILENAME"
done

# 添加分类和正文
cat >> "$POSTS_DIR/$FILENAME" << EOF
categories:
  - $CATEGORY
---

## 写在前面

$TITLE

<!-- more -->

## 正文

开始写作...

---
EOF

echo "✅ 文章创建成功: $POSTS_DIR/$FILENAME"

赋予执行权限:

chmod +x /opt/hexo-blog/create-post.sh

2. 创建 Skill 文件

OpenClaw 使用 SKILL.md 文件(不是 YAML),创建 ~/.openclaw/skills/hexo-blog/SKILL.md

---
name: hexo-blog
description: Create and manage Hexo blog posts via shell script
---

# Hexo Blog Skill

Create new blog posts with proper front matter for Hexo.

## Usage

Ask me to create a blog post:
- "帮我创建一篇博客文章,标题是《XXX》,分类是技术,标签是 OpenClaw,AI"
- "写一篇新文章,关于 Docker 使用心得"

## Tools

This skill uses the `shell` tool to execute `/opt/hexo-blog/create-post.sh`.

## Example

bash /opt/hexo-blog/create-post.sh "文章标题" "分类" "标签1,标签2"

3. 重启 OpenClaw 加载 Skill

docker restart openclaw-openclaw-gateway-1

验证 Skill 是否加载:

openclaw skills list
# 应该显示: ✓ ready │ 📦 hexo-blog │ Create and manage Hexo blog posts...

3. 实际使用

@gamehu_kb_bot 里直接说:

"帮我创建一篇博客文章,标题是《OpenClaw 使用心得》,分类是工具,标签是 OpenClaw,AI"

Bot 会自动:

  1. 生成文件名 openclaw-shi-yong-xin-de-20260302.md
  2. 创建带完整 Front Matter 的 Markdown 文件
  3. 返回文件路径

Skill 核心概念

组件 作用 示例
Script 执行实际任务 Shell/Python 脚本
SKILL.md Skill 定义和说明 Markdown 文件(带 YAML frontmatter)
Directory Skill 存放位置 ~/.openclaw/skills/<skill-name>/

更多 Skill 想法

  • Git Helper: 自动提交、查看状态、创建分支
  • Docker Manager: 查看容器日志、重启服务
  • File Organizer: 整理下载文件夹、重命名文件
  • Daily Reporter: 生成每日工作总结

进阶玩法:浏览器控制(第12步)

OpenClaw 内置了浏览器控制功能,让 AI 能够操作真实浏览器执行网页任务,比如搜索信息、填写表单、抓取数据等。

🚨 坑位 14:Docker 镜像默认不包含浏览器

问题

Docker 部署后尝试使用浏览器功能时,报错:

[tools] browser failed: Error: No supported browser found 
(Chrome/Brave/Edge/Chromium on macOS, Linux, or Windows).

原因

默认的 Dockerfile 不会安装 Chromium/Playwright 浏览器,需要通过 --build-arg OPENCLAW_INSTALL_BROWSER=1 参数构建带浏览器的镜像。

解决方案:重新构建带浏览器的镜像

1. 停止当前服务

cd /opt/openclaw
docker compose down

2. 构建带浏览器的新镜像

# 构建时间约 15-30 分钟,增加约 300MB
docker build -t openclaw:local-browser -f Dockerfile \
  --build-arg OPENCLAW_INSTALL_BROWSER=1 \
  --build-arg OPENCLAW_DOCKER_APT_PACKAGES="chromium xvfb" \
  .

3. 修改环境变量使用新镜像

编辑 .env 文件:

# 修改前
OPENCLAW_IMAGE=openclaw:local

# 修改后
OPENCLAW_IMAGE=openclaw:local-browser

4. 启动服务

docker compose up -d

5. 验证浏览器安装

# 进入容器检查
docker exec openclaw-openclaw-gateway-1 \
  ls -la /home/node/.cache/ms-playwright/

# 应该看到:
# chromium-1208/
# chromium_headless_shell-1208/
# ffmpeg-1011/

浏览器控制功能

功能 说明
网页浏览 访问指定 URL,获取页面内容
表单填写 自动填写并提交网页表单
信息搜索 在搜索引擎或电商网站搜索
数据抓取 提取网页中的结构化数据
截图保存 截取网页画面

使用示例

在 Telegram 中直接发送以下指令:

搜索信息

"打开浏览器,访问 GitHub,搜索 'openclaw',告诉我前 3 个结果"

商品比价

"帮我在京东上搜索 '机械键盘',找到评分最高的 3 个产品,记录价格"

数据抓取

"访问 https://news.ycombinator.com/,提取首页前 10 条新闻的标题和链接"

浏览器控制原理

用户指令 → OpenClaw Agent → 浏览器控制服务 → 无头 Chrome → 网页操作 → 结果返回

浏览器控制服务默认监听:http://127.0.0.1:18791/

注意事项

  1. 无头模式:Docker 部署默认使用 headless 模式(无界面),适合服务器环境
  2. 访问限制:受限于服务器网络,无法访问需要登录的页面(除非提供 Cookie)
  3. 执行时间:复杂页面加载可能需要 10-30 秒
  4. 安全提醒:避免让 Bot 访问敏感网站或输入真实账号密码

实践任务

尝试让 Bot 完成以下任务:

  • ✅ 信息收集:从某个网站抓取数据并整理
  • ✅ 表单填写:自动填写一个在线表单
  • ✅ 价格比较:在多个网站比较同一商品的价格

进阶玩法:多 Bot 配置(第11步)

OpenClaw 支持配置多个 Telegram Bot,每个 Bot 可以绑定不同的 Agent,实现分工协作。
注意:仅配置 channels.telegram.accounts 还不够,想要真正隔离上下文,必须再加 agents.list + bindings

我的多 Bot 架构

Bot 用户名 职责 对应 Agent
主助手 @GameHuOpenclaw_bot 通用对话、代码、写作 main
新闻助手 @gamehu_news_bot 科技新闻、每日简报 news
成长助手 @gamehu_growth_bot 学习计划、习惯追踪 growth
知识库助手 @gamehu_kb_bot 文档查询、笔记整理 kb

配置步骤

1. 在 @BotFather 创建多个 Bot

每个 Bot 都需要独立的 Token:

/main_bot - 主助手
/news_bot - 新闻助手  
/growth_bot - 成长助手
/kb_bot - 知识库助手

2. 配置多账号

{
  "channels": {
    "telegram": {
      "enabled": true,
      "accounts": {
        "main": {
          "botToken": "YOUR_MAIN_BOT_TOKEN",
          "allowFrom": ["YOUR_TELEGRAM_USER_ID"]
        },
        "news": {
          "botToken": "YOUR_NEWS_BOT_TOKEN",
          "allowFrom": ["YOUR_TELEGRAM_USER_ID"]
        },
        "growth": {
          "botToken": "YOUR_GROWTH_BOT_TOKEN",
          "allowFrom": ["YOUR_TELEGRAM_USER_ID"]
        },
        "kb": {
          "botToken": "YOUR_KB_BOT_TOKEN",
          "allowFrom": ["YOUR_TELEGRAM_USER_ID"]
        }
      }
    }
  }
}

3. 增加 Agent 路由绑定(关键)

{
  "agents": {
    "list": [
      { "id": "main",   "default": true, "workspace": "/home/node/.openclaw/workspace" },
      { "id": "news",   "workspace": "/home/node/.openclaw/workspace-news" },
      { "id": "growth", "workspace": "/home/node/.openclaw/workspace-growth" },
      { "id": "kb",     "workspace": "/home/node/.openclaw/workspace-kb" }
    ]
  },
  "bindings": [
    { "agentId": "main",   "match": { "channel": "telegram", "accountId": "main" } },
    { "agentId": "news",   "match": { "channel": "telegram", "accountId": "news" } },
    { "agentId": "growth", "match": { "channel": "telegram", "accountId": "growth" } },
    { "agentId": "kb",     "match": { "channel": "telegram", "accountId": "kb" } }
  ]
}

⚠️ workspace 字段必须显式指定:每个 agent 需要独立的 workspace 路径,否则多个 agent 共享同一个 workspace,记忆和配置会互相干扰。

这样每个 bot 会落到不同 agent,会话文件分目录保存,记忆文件也完全隔离。

4. 为每个 Agent 创建独立 Workspace

每个 agent 对应一个独立目录,在服务器上创建:

mkdir -p /root/.openclaw/workspace-news
mkdir -p /root/.openclaw/workspace-growth
mkdir -p /root/.openclaw/workspace-kb

每个目录下的结构:

workspace-news/
├── SOUL.md        # Agent 的身份定义
├── MEMORY.md      # 长期记忆
├── USER.md        # 用户信息
├── AGENTS.md      # Agent 行为规范
└── memory/        # 每日记忆文件

每个 AGENT.md 定义该 Bot 的专业领域和行为:

# News Agent

## Role
你是一个科技新闻助手,专注于提供最新、最有价值的科技资讯。

## Capabilities
- 追踪科技行业动态
- 总结技术文章要点
- 提供每日新闻简报

## Style
- 简洁明了,重点突出
- 提供信息来源链接
- 主动推送重要消息

4. 重启服务

docker compose restart

查看日志确认所有 Bot 启动:

[telegram] [main] starting provider (@GameHuOpenclaw_bot)
[telegram] [news] starting provider (@gamehu_news_bot)
[telegram] [growth] starting provider (@gamehu_growth_bot)
[telegram] [kb] starting provider (@gamehu_kb_bot)

实际使用效果

  • 上下文隔离:在 @gamehu_growth_bot 聊学习计划,切到 @gamehu_news_bot 问新闻,再回到 growth Bot,它还记得刚才的学习话题
  • 专业化分工:每个 Bot 专注于自己的领域,回复质量更高
  • 并行对话:可以同时和多个 Bot 对话,互不干扰

⚠️ 注意事项

  • 多账号配置时,不要在顶层设置 botToken,全部放在 accounts
  • 每个 accountId(如 main、news、growth、kb)必须是唯一的
  • 账号名不要用 default,会和系统默认账号冲突

进阶玩法:定时任务推送到指定 Bot(第11.5步)

配置好多 Bot 之后,你可能会发现一个问题:OpenClaw 里设置的定时任务(cron job),推送结果全都跑到了 main bot,而不是对应的 bot

🚨 坑位 17:定时任务 delivery 缺少 accountId

问题现象

在 OpenClaw Web UI 里配了新闻推送任务,时间一到,消息却出现在了 @GameHuOpenclaw_bot(main bot),而不是 @gamehu_news_bot

根本原因

OpenClaw 的定时任务存储在 ~/.openclaw/cron/jobs.json,每个任务的 delivery 字段控制推送目标。如果只写了 to(用户 ID),没有写 accountId,OpenClaw 不知道用哪个 bot 账户推送,默认走 main。

另外,to 只负责“推给谁”(用户 / 群 / 频道),accountId 负责“用哪个 bot 发”。这两个字段职责不同,缺一不可。

有问题的配置:

"delivery": {
  "mode": "announce",
  "channel": "telegram",
  "to": "YOUR_USER_ID"
}

解决方案

在每个 job 的 delivery 中加上 accountId,同时在 job 顶层加上 agentId。建议把执行超时提到 120 秒(字段 timeoutSeconds):

{
  "id": "xxx",
  "agentId": "news",
  "name": "每日新闻推送",
  "timeoutSeconds": 120,
  "payload": {
    "kind": "agentTurn",
    "message": "执行新闻脚本并发送结果给用户"
  },
  "delivery": {
    "mode": "announce",
    "channel": "telegram",
    "accountId": "news",
    "to": "YOUR_USER_ID"
  }
}

推送目标的两种正确姿势

方案 A(推荐):同一个用户,按不同 Bot 身份推送

这种方式最适合你当前“4 个 Bot 各司其职”的场景。to 全部写你的用户 ID,accountId 分别写 main/news/growth/kb,消息会显示来自对应 bot。

{
  "agentId": "news",
  "timeoutSeconds": 120,
  "delivery": {
    "mode": "announce",
    "channel": "telegram",
    "accountId": "news",
    "to": "YOUR_USER_ID"
  }
}

方案 B:推送到群 / 频道 / 话题

如果要发到频道,不要填 bot 用户名(如 @gamehu_news_bot),而是填频道 chat id(通常是 -100...)。并确保对应 bot 已加入目标群/频道且有发言权限。

{
  "agentId": "news",
  "timeoutSeconds": 120,
  "delivery": {
    "mode": "announce",
    "channel": "telegram",
    "accountId": "news",
    "to": "-1001234567890"
  }
}

各任务对应关系

任务 agentId accountId 推送到
每日新闻推送 news news @gamehu_news_bot
每日成长提醒 growth growth @gamehu_growth_bot
每周知识库总结 kb kb @gamehu_kb_bot
其他通用任务 main main @GameHuOpenclaw_bot

修改完 jobs.json 后重启服务即可生效:

cd /opt/openclaw && docker compose restart

进阶玩法:接入 Step-3.5-Flash,并支持会话级切换(第11.6步)

最近我把底层模型又补了一档:Step-3.5-Flash。但这里有个非常容易搞混的点,我一开始也踩了坑:

🚨 坑位 18:想要“随时切模型”,不等于要改全局默认模型

如果你直接把 agents.defaults.model.primary 全局切到 Step,看起来省事,实际上会把别的会话、别的 Bot,甚至定时任务一起带偏。
更稳的做法是:

  • 全局默认模型继续保持不变,我这里还是 bailian/kimi-k2.5
  • step/step-3.5-flash 注册成一个可选 provider
  • 需要的时候,直接在 当前 Telegram 会话 里发送 /model ... 切换

Step provider 配置示例

{
  "models": {
    "mode": "merge",
    "providers": {
      "bailian": {
        "baseUrl": "https://coding.dashscope.aliyuncs.com/v1",
        "apiKey": "YOUR_BAILIAN_API_KEY",
        "api": "openai-completions",
        "models": [
          {
            "id": "kimi-k2.5",
            "name": "kimi-k2.5",
            "contextWindow": 256000,
            "maxTokens": 8192
          }
        ]
      },
      "kimi": {
        "baseUrl": "https://api.moonshot.cn/v1",
        "apiKey": "YOUR_KIMI_API_KEY",
        "api": "openai-completions",
        "models": [
          {
            "id": "moonshot-v1-128k",
            "name": "moonshot-v1-128k",
            "contextWindow": 131072,
            "maxTokens": 8192
          }
        ]
      },
      "step": {
        "baseUrl": "https://api.stepfun.com/v1",
        "apiKey": "YOUR_STEP_API_KEY",
        "api": "openai-completions",
        "models": [
          {
            "id": "step-3.5-flash",
            "name": "Step 3.5 Flash",
            "contextWindow": 256000,
            "maxTokens": 8192
          }
        ]
      }
    }
  },
  "agents": {
    "defaults": {
      "model": {
        "primary": "bailian/kimi-k2.5"
      },
      "contextTokens": 131072
    }
  }
}

为什么我把 contextTokens 调到 131072

这不是说 kimi-k2.5step-3.5-flash 只能吃 128k,而是为了兼容我现在保留的第三档模型 moonshot-v1-128k

如果你想做到:

  • 默认走百炼
  • 需要时切 Step
  • 偶尔还能切回 Moonshot 做速度/成本对比

那最稳的双档/三档基线,就是把 contextTokens 先压在 131072。这样:

  • bailian <-> step 切换时,几乎不会因为窗口变化引发额外压缩
  • 切到 moonshot-v1-128k 时,也不会立刻超限

当前会话切换命令

直接在 Telegram 里发:

/models
/models step
/model status
/model step
/model bailian/kimi-k2.5
/model kimi/moonshot-v1-128k

这里要强调 3 个边界:

  1. 只影响当前会话
  2. 不会清空 SOUL.md / MEMORY.md / USER.md / AGENTS.md
  3. 不会影响 cron 定时任务

也就是说,这种切换本质上是“会话级模型覆盖”,不是“全局改配置”。

切模型会不会丢上下文

长期记忆不会丢,工作区画像也不会丢。真正会受影响的是短期上下文压缩

  • bailian/kimi-k2.5 切到 step/step-3.5-flash,因为两边都是大窗口,风险很低
  • bailianstep 切到 moonshot-v1-128k,因为窗口更小,下一轮可能触发更激进的 compaction

所以我现在的原则很简单:

  • 平时默认:bailian/kimi-k2.5
  • 需要测试 Step:/model step
  • 需要切回稳定默认:/model bailian/kimi-k2.5
  • 需要做小窗口对比:/model kimi/moonshot-v1-128k

⚠️ 如果你想支持“切换模型 step”这种中文自然语言,而不是 /model step,那是另外一层 parser 改造,不是 OpenClaw 开箱即用能力。


完整配置文件参考

openclaw.json(多 Bot 生产版本,已脱敏,包含 compaction 修复):

{
  "gateway": {
    "port": 18789,
    "mode": "local",
    "controlUi": {
      "allowedOrigins": ["http://localhost:18789", "http://127.0.0.1:18789"]
    },
    "auth": {
      "token": "your-secure-token-here"
    }
  },
  "models": {
    "mode": "merge",
    "providers": {
      "bailian": {
        "baseUrl": "https://coding.dashscope.aliyuncs.com/v1",
        "apiKey": "YOUR_BAILIAN_API_KEY",
        "api": "openai-completions",
        "models": [
          {
            "id": "kimi-k2.5",
            "name": "kimi-k2.5",
            "reasoning": false,
            "input": ["text", "image"],
            "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
            "contextWindow": 256000,
            "maxTokens": 8192
          }
        ]
      },
      "kimi": {
        "baseUrl": "https://api.moonshot.cn/v1",
        "apiKey": "YOUR_KIMI_API_KEY",
        "api": "openai-completions",
        "models": [
          {
            "id": "moonshot-v1-128k",
            "name": "moonshot-v1-128k",
            "reasoning": false,
            "input": ["text", "image"],
            "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
            "contextWindow": 131072,
            "maxTokens": 8192
          }
        ]
      },
      "step": {
        "baseUrl": "https://api.stepfun.com/v1",
        "apiKey": "YOUR_STEP_API_KEY",
        "api": "openai-completions",
        "models": [
          {
            "id": "step-3.5-flash",
            "name": "Step 3.5 Flash",
            "reasoning": false,
            "input": ["text", "image"],
            "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
            "contextWindow": 256000,
            "maxTokens": 8192
          }
        ]
      }
    }
  },
  "agents": {
    "defaults": {
      "model": {
        "primary": "bailian/kimi-k2.5"
      },
      "contextTokens": 131072,
      "compaction": {
        "mode": "safeguard",
        "reserveTokensFloor": 24000,
        "identifierPolicy": "strict",
        "memoryFlush": {
          "enabled": true,
          "softThresholdTokens": 6000
        }
      }
    },
    "list": [
      { "id": "main", "default": true },
      { "id": "news" },
      { "id": "growth" },
      { "id": "kb" }
    ]
  },
  "bindings": [
    { "agentId": "main", "match": { "channel": "telegram", "accountId": "main" } },
    { "agentId": "news", "match": { "channel": "telegram", "accountId": "news" } },
    { "agentId": "growth", "match": { "channel": "telegram", "accountId": "growth" } },
    { "agentId": "kb", "match": { "channel": "telegram", "accountId": "kb" } }
  ],
  "session": {
    "scope": "per-sender",
    "reset": {
      "mode": "idle",
      "idleMinutes": 30
    },
    "maintenance": {
      "mode": "enforce",
      "pruneAfter": "7d",
      "maxEntries": 120
    }
  },
  "channels": {
    "telegram": {
      "enabled": true,
      "dmPolicy": "pairing",
      "groupPolicy": "allowlist",
      "historyLimit": 30,
      "accounts": {
        "main": {
          "botToken": "YOUR_MAIN_BOT_TOKEN",
          "allowFrom": ["YOUR_TELEGRAM_USER_ID"],
          "dmPolicy": "pairing",
          "groupPolicy": "allowlist",
          "streaming": "off"
        },
        "news": {
          "botToken": "YOUR_NEWS_BOT_TOKEN",
          "allowFrom": ["YOUR_TELEGRAM_USER_ID"],
          "dmPolicy": "pairing",
          "groupPolicy": "allowlist",
          "streaming": "off"
        },
        "growth": {
          "botToken": "YOUR_GROWTH_BOT_TOKEN",
          "allowFrom": ["YOUR_TELEGRAM_USER_ID"],
          "dmPolicy": "pairing",
          "groupPolicy": "allowlist",
          "streaming": "off"
        },
        "kb": {
          "botToken": "YOUR_KB_BOT_TOKEN",
          "allowFrom": ["YOUR_TELEGRAM_USER_ID"],
          "dmPolicy": "pairing",
          "groupPolicy": "allowlist",
          "streaming": "off"
        }
      }
    }
  }
}

⚠️ 关键提示

  1. 如果你保留多档模型可切换,contextTokens 不要盲目拉满;我现在用 131072 作为三档模型共存时的安全基线。
  2. 浏览器功能:默认镜像不包含 Chromium,需要使用 --build-arg OPENCLAW_INSTALL_BROWSER=1 构建 openclaw:local-browser 镜像
  3. 多 Bot 场景必须配置 bindings,否则 direct chat 默认会落到主会话桶,容易串上下文。
  4. 如果你临时切到 moonshot-v1-128k,继续保持 contextTokens <= 131072,避免再次出现 compaction 超限。

单 Bot 简化版(含 compaction 修复):

{
  "gateway": {
    "port": 18789,
    "mode": "local",
    "controlUi": {
      "allowedOrigins": ["http://localhost:18789", "http://127.0.0.1:18789"]
    },
    "auth": {
      "token": "your-secure-token"
    }
  },
  "models": {
    "providers": {
      "bailian": {
        "baseUrl": "https://coding.dashscope.aliyuncs.com/v1",
        "apiKey": "YOUR_API_KEY",
        "models": [{
          "id": "kimi-k2.5",
          "contextWindow": 256000,
          "maxTokens": 8192
        }]
      }
    }
  },
  "agents": {
    "defaults": {
      "model": { "primary": "bailian/kimi-k2.5" },
      "contextTokens": 131072,
      "compaction": {
        "mode": "safeguard",
        "reserveTokensFloor": 24000
      }
    }
  },
  "session": {
    "reset": {
      "mode": "idle",
      "idleMinutes": 30
    },
    "maintenance": {
      "mode": "enforce",
      "pruneAfter": "7d",
      "maxEntries": 120
    }
  },
  "channels": {
    "telegram": {
      "enabled": true,
      "historyLimit": 30,
      "botToken": "YOUR_BOT_TOKEN",
      "allowFrom": ["YOUR_USER_ID"]
    }
  }
}

踩坑总结

坑位 问题 解决方案
1 构建时 OOM 添加 5GB Swap 空间
2 gateway.mode 缺失 必须显式设置 "mode": "local"
3 controlUi.allowedOrigins 缺失 非 localhost 绑定时必须配置
4 gateway.bind 配置无效 必须使用 CLI 参数 --bind lan
5 Telegram 配对失败 删除 dmPolicy,使用 allowFrom 白名单
6 防火墙不生效 使用 DOCKER-USER 链而非 INPUT
7 Google OAuth 授权失败 确保 Redirect URI 与配置完全一致
8 MCP 服务器无法启动 检查 npx 是否可用,网络是否通畅
9 多 Bot 配置时 default 账号冲突 避免使用 default 作为 accountId,改用 mainnews
10 多 Bot 顶层 botToken 被覆盖 使用 accounts 时,顶层不要设置 botToken
11 Skill 脚本权限不足 确保脚本有执行权限 chmod +x script.sh
12 Skill 中文字符处理 使用 `echo
13 Compaction 卡死导致无响应 配置合理 contextTokens + 设置 historyLimit + 启用 session.maintenance
14 Docker 镜像无浏览器 使用 --build-arg OPENCLAW_INSTALL_BROWSER=1 重新构建镜像
15 镜像体积过大 (5.7GB) 使用多阶段构建 + node:22-bookworm-slim 基础镜像
16 会话记录膨胀失控 部署结构化记录系统 + 每日自动归档 + 分类存储
17 定时任务推送全到 main bot jobs.json 每个 job 加 agentId + delivery.accountId
18 想切 Step 却误改全局默认模型 保持默认模型不动,使用 /model ... 做会话级切换

镜像优化指南(第15坑)

问题:镜像体积过大

OpenClaw 默认构建的镜像体积巨大:

  • openclaw:local: 4.4GB
  • openclaw:local-browser: 5.7GB

在 2GB 内存的服务器上,光是镜像就占满了磁盘。

原因分析

问题 说明 占用
单阶段构建 构建依赖和生产代码混在一起 ~1GB
未清理 devDependencies 开发依赖未删除 ~500MB
bookworm 基础镜像 完整 Debian 系统 ~1GB
Chromium + Playwright 浏览器全套 ~1.7GB

解决方案:多阶段构建

创建 Dockerfile.optimized

# ============================================================================
# 阶段1:构建阶段
# ============================================================================
FROM node:22-bookworm AS builder

WORKDIR /app
RUN corepack enable

# 复制依赖文件
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

# 复制源码并构建
COPY . .
RUN pnpm build && pnpm ui:build

# 关键:清理开发依赖,只保留生产依赖
RUN pnpm prune --prod

# ============================================================================
# 阶段2:生产阶段 - 使用精简基础镜像
# ============================================================================
FROM node:22-bookworm-slim AS production

# 只安装必需的系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates curl git \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# 从构建阶段只复制必要文件
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
COPY --from=builder /app/openclaw.mjs ./

# 使用非 root 用户运行
RUN groupadd -r nodeuser && useradd -r -g nodeuser nodeuser
RUN chown -R nodeuser:nodeuser /app
USER nodeuser

ENV NODE_ENV=production
EXPOSE 18789 18790

CMD ["node", "openclaw.mjs", "gateway", "--allow-unconfigured"]

构建优化版镜像

cd /opt/openclaw

# 构建轻量级版本 (2-3GB)
docker build \
  --target production \
  -t openclaw:slim \
  -f Dockerfile.optimized \
  .

# 构建浏览器版本 (3-4GB)
docker build \
  --target browser \
  -t openclaw:slim-browser \
  -f Dockerfile.optimized \
  .

优化效果对比

镜像 原体积 优化后 节省
openclaw:local 4.4GB openclaw:slim 2.5GB 43%
openclaw:local-browser 5.7GB openclaw:slim-browser 3.5GB 39%

使用优化版镜像

修改 .env 文件:

# 轻量级版本(推荐日常使用)
OPENCLAW_IMAGE=openclaw:slim

# 或浏览器版本(需要网页自动化时)
# OPENCLAW_IMAGE=openclaw:slim-browser

然后重启服务:

docker compose up -d

进一步优化建议

  1. 使用 Alpine 基础镜像(极致精简)

    FROM node:22-alpine
    # 可将体积降至 < 1.5GB
    # 但可能有兼容性问题
    
  2. 启用 Docker 镜像压缩

    docker build --compress ...
    
  3. 定期清理无用镜像

    docker image prune -a
    

重大坑位详解:Compaction 卡死问题(第13坑)

部署运行几天后,我遇到了一个极其隐蔽但致命的问题:Telegram Bot 突然不响应了,或者响应需要等 5 分钟以上。

现象

  • 发送消息后 Bot 无响应
  • 日志卡在 embedded run compaction start 不动
  • 服务重启后短暂正常,很快又卡死

根因分析

深度诊断后发现了两个根本原因

根因 1:contextTokens 不匹配

OpenClaw 默认上下文预算与实际模型窗口不一致时,会导致系统误判可用空间,compaction 后仍然超限(日志显示使用了 145.7%)。

所以一定要注意不同的模型一定要修改响应的配置。

根因 2:无 historyLimit 限制

所有历史消息(603 条)全部进入上下文,而不是只取最近的几十条。两天内会话文件膨胀到 1.4MB,每次 compaction 都要扫描全部历史。

触发因素:输出被频繁截断

maxTokens 配得过小会让长任务反复截断并补发,间接加速会话膨胀。它不是唯一根因,但会放大卡顿问题。

解决方案

需要添加三组关键配置:

{
  "agents": {
    "defaults": {
      "contextTokens": 131072,
      "compaction": {
        "mode": "safeguard",
        "reserveTokensFloor": 24000,
        "identifierPolicy": "strict",
        "memoryFlush": {
          "enabled": true,
          "softThresholdTokens": 6000
        }
      }
    }
  },
  "session": {
    "scope": "per-sender",
    "reset": {
      "mode": "idle",
      "idleMinutes": 30
    },
    "maintenance": {
      "mode": "enforce",
      "pruneAfter": "7d",
      "maxEntries": 120
    }
  },
  "channels": {
    "telegram": {
      "enabled": true,
      "historyLimit": 30,
      "accounts": {
        ...
      }
    }
  }
}

关键配置说明

配置项 作用
agents.defaults.contextTokens 131072 多档模型共存时更稳,切回 moonshot-v1-128k 也不容易超限
agents.defaults.compaction.mode safeguard 启用保护模式,预留安全空间
session.maintenance.mode enforce 强制清理 7 天前的旧会话
session.maintenance.maxEntries 120 最多保留 120 个会话
channels.telegram.historyLimit 30 每次请求最多带 30 条历史

多 Bot 配置注意

上面的 historyLimitsession 配置放在 channels.telegram 级别,会对所有 4 个 Bot 统一生效。如果需要不同 Bot 不同策略,可以在每个 account 下单独设置 historyLimit

多模型切换补充说明

后来我又把 step/step-3.5-flash 接进来了。这里最重要的经验是:
别为了切模型去改全局默认模型,直接用 /model ... 切当前会话就够了。

原因很简单:

  • 改全局会影响别的 Bot 和别的会话
  • 还可能把 cron 定时任务一起带偏
  • 当前会话切换则只影响自己这一条对话链

我现在的实际用法:

/model step
/model bailian/kimi-k2.5
/model kimi/moonshot-v1-128k
/model status

其中:

  • bailian <-> step 风险最低
  • 切到 moonshot-v1-128k 时,最容易触发短期上下文压缩
  • 但长期记忆文件不会丢

修复后的效果

  • 响应时间从 5 分钟+ 降至 3-20 秒
  • 会话文件大小控制在 10KB 以内
  • 服务连续运行 14 小时+ 无卡死

实际使用体验

部署完成后,通过 Telegram 与 Bot 对话:

修复前(问题阶段)

  • 响应速度:最初很快,2 天后变成 5 分钟+
  • 稳定性:运行 2 天后完全卡死
  • 原因:compaction 机制被大会话文件阻塞

修复后(当前状态)

  • 响应速度:3-20 秒,正常可用
  • 稳定性:连续运行 14 小时+ 无故障
  • 内存占用:约 800MB-1.2GB
  • 功能:文件操作、Shell 命令、网页浏览全部正常

关键优化点

配置 contextTokenshistoryLimitsession.maintenance 后,OpenClaw 从"两天必挂"变成"长期稳定运行"。这是生产环境部署的必选项,不是可选项。

📷 Telegram 实际对话效果

Telegram使用效果


安全建议

  1. 永远不要openclaw.json 提交到 Git
  2. 配置文件权限:最小权限原则,但必须保证容器运行用户可读
  3. Web UI 访问:仅通过 SSH 隧道,不要暴露在公网
  4. Telegram 白名单:严格控制 allowFrom 列表
  5. 定期更新:关注 OpenClaw 安全公告

参考资源