--- 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 很顺利: ```bash # 更新系统 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`: ```json { "registry-mirrors": [ "https://docker.1ms.run", "https://dockerhub.icu" ] } ``` --- ### 第二步:源码构建(第一个坑:OOM) 官方提供了 Docker 镜像,但我选择从源码构建以获得最新功能: ```bash mkdir -p /opt/openclaw cd /opt/openclaw git clone https://github.com/openclaw/openclaw.git cd openclaw ``` 开始构建: ```bash docker build -t openclaw:local -f Dockerfile . ``` 🚨 第一个大坑:构建到 `pnpm install` 时容器被杀 查看日志发现是 **OOM(内存不足)**。2GB RAM 在构建 Node.js 项目时不够用,`pnpm install` 直接占满内存导致进程被系统杀死。 **解决方案:添加 Swap 空间** ```bash # 创建 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**: > > ![安装过程](/images/openclaw/01-installation.jpeg) --- ### 第三步:配置 OpenClaw 创建 `docker-compose.yml`: ```yaml 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`): ```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](/images/openclaw/03-web-ui.jpg) > **关键注意点**: > - `gateway.mode` 必须显式设置为 `"local"` > - `gateway.controlUi.allowedOrigins` 在使用非 localhost 绑定时是必需的 > - `gateway.bind` **不能写在 JSON 中**(无效字段),必须通过 CLI 参数 `--bind lan` 设置 --- ### 第四步:配置阿里云百炼模型 我选择使用阿里云百炼的 Coding Plan,配置 kimi-k2.5 作为主力模型: ```json { "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](https://t.me/BotFather) 创建 Bot 并获取 Token。 🚨 第三个坑:配对码过期与 dmPolicy 冲突 ```json { "channels": { "telegram": { "enabled": true, "botToken": "YOUR_BOT_TOKEN_HERE", "allowFrom": ["YOUR_TELEGRAM_USER_ID"] } } } ``` 初始配置时我加了 `"dmPolicy": "open"`,结果与 `allowFrom` 白名单冲突,报错: ``` dmPolicy: open requires allowFrom: ["*"] ``` **解决方案**:删除 `dmPolicy` 字段,直接使用 `allowFrom` 白名单。 启动服务: ```bash 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](https://console.cloud.google.com/) 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 ID** 和 **Client Secret** #### 6.3 配置 MCP 服务器 OpenClaw 通过 MCP (Model Context Protocol) 集成 Google Workspace。 在服务器上创建 MCP 配置文件: ```bash 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 并授权 ```bash 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 链的防火墙规则 我最初的防火墙配置: ```bash 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` 链 ```bash # 在 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 隧道 | > 📷 **最后安全检查 - 安全加固结果**: > > ![安全检查](/images/openclaw/02-security-check.jpeg) **SSH 隧道访问命令**: ```bash 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 - 用户档案 ```markdown # USER.md - About Your Human - **Name:** Gamehu - **What to call them:** Gamehu - **Timezone:** Asia/Shanghai (UTC+8) ## Context - **职业:** IT 行业,编程 + 团队管理 - **需求:** 个人助手 - **风格偏好:** 简单直接,不绕弯子 ``` #### 2. MEMORY.md - 长期记忆 ```markdown # 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`: ```bash #!/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" ``` 赋予执行权限: ```bash chmod +x /root/.openclaw/workspace/archive-daily.sh ``` ### 配置定时任务 添加每天 23:00 自动执行归档: ```bash # 添加定时任务 (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`,方便快速查看记录: ```bash # 查看今日记录 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' ``` 使用方法: ```bash # 加载快捷命令 source /root/.openclaw/.aliases.sh # 查看今日记录 oc-today # 手动归档 oc-archive # 查看统计 oc-stats ``` ### Docker 容器内配置 为了让 OpenClaw Bot 也能执行归档,在 Docker 容器内创建归档脚本: ```bash # 在容器内创建归档命令 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`): ```markdown --- 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`: ```bash #!/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 ## 正文 开始写作... --- EOF echo "✅ 文章创建成功: $POSTS_DIR/$FILENAME" ``` 赋予执行权限: ```bash chmod +x /opt/hexo-blog/create-post.sh ``` #### 2. 创建 Skill 文件 OpenClaw 使用 `SKILL.md` 文件(不是 YAML),创建 `~/.openclaw/skills/hexo-blog/SKILL.md`: ```markdown --- 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 ```bash docker restart openclaw-openclaw-gateway-1 ``` 验证 Skill 是否加载: ```bash 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 想法 - **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. 停止当前服务 ```bash cd /opt/openclaw docker compose down ``` #### 2. 构建带浏览器的新镜像 ```bash # 构建时间约 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` 文件: ```bash # 修改前 OPENCLAW_IMAGE=openclaw:local # 修改后 OPENCLAW_IMAGE=openclaw:local-browser ``` #### 4. 启动服务 ```bash docker compose up -d ``` #### 5. 验证浏览器安装 ```bash # 进入容器检查 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. 配置多账号 ```json { "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 路由绑定(关键) ```json { "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 对应一个独立目录,在服务器上创建: ```bash mkdir -p /root/.openclaw/workspace-news mkdir -p /root/.openclaw/workspace-growth mkdir -p /root/.openclaw/workspace-kb ``` 每个目录下的结构: ```bash workspace-news/ ├── SOUL.md # Agent 的身份定义 ├── MEMORY.md # 长期记忆 ├── USER.md # 用户信息 ├── AGENTS.md # Agent 行为规范 └── memory/ # 每日记忆文件 ``` 每个 `AGENT.md` 定义该 Bot 的专业领域和行为: ```markdown # News Agent ## Role 你是一个科技新闻助手,专注于提供最新、最有价值的科技资讯。 ## Capabilities - 追踪科技行业动态 - 总结技术文章要点 - 提供每日新闻简报 ## Style - 简洁明了,重点突出 - 提供信息来源链接 - 主动推送重要消息 ``` #### 4. 重启服务 ```bash 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 发”。这两个字段职责不同,缺一不可。 **有问题的配置:** ```json "delivery": { "mode": "announce", "channel": "telegram", "to": "YOUR_USER_ID" } ``` ### 解决方案 在每个 job 的 `delivery` 中加上 `accountId`,同时在 job 顶层加上 `agentId`。建议把执行超时提到 120 秒(字段 `timeoutSeconds`): ```json { "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。 ```json { "agentId": "news", "timeoutSeconds": 120, "delivery": { "mode": "announce", "channel": "telegram", "accountId": "news", "to": "YOUR_USER_ID" } } ``` #### 方案 B:推送到群 / 频道 / 话题 如果要发到频道,不要填 bot 用户名(如 `@gamehu_news_bot`),而是填频道 chat id(通常是 `-100...`)。并确保对应 bot 已加入目标群/频道且有发言权限。 ```json { "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` 后重启服务即可生效: ```bash 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 配置示例 ```json { "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.5` 或 `step-3.5-flash` 只能吃 128k,而是为了兼容我现在保留的第三档模型 `moonshot-v1-128k`。 如果你想做到: - 默认走百炼 - 需要时切 Step - 偶尔还能切回 Moonshot 做速度/成本对比 那最稳的双档/三档基线,就是把 `contextTokens` 先压在 **131072**。这样: - `bailian <-> step` 切换时,几乎不会因为窗口变化引发额外压缩 - 切到 `moonshot-v1-128k` 时,也不会立刻超限 ### 当前会话切换命令 直接在 Telegram 里发: ```text /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`,因为两边都是大窗口,风险很低 - 从 `bailian` 或 `step` 切到 `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 修复): ```json { "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 修复):** ```json { "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,改用 `main`、`news` 等 | | 10 | 多 Bot 顶层 `botToken` 被覆盖 | 使用 `accounts` 时,顶层不要设置 `botToken` | | 11 | Skill 脚本权限不足 | 确保脚本有执行权限 `chmod +x script.sh` | | 12 | Skill 中文字符处理 | 使用 `echo | sed` 处理中文文件名,避免乱码 | | 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`: ```dockerfile # ============================================================================ # 阶段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"] ``` ### 构建优化版镜像 ```bash 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` 文件: ```bash # 轻量级版本(推荐日常使用) OPENCLAW_IMAGE=openclaw:slim # 或浏览器版本(需要网页自动化时) # OPENCLAW_IMAGE=openclaw:slim-browser ``` 然后重启服务: ```bash docker compose up -d ``` ### 进一步优化建议 1. **使用 Alpine 基础镜像**(极致精简) ```dockerfile FROM node:22-alpine # 可将体积降至 < 1.5GB # 但可能有兼容性问题 ``` 2. **启用 Docker 镜像压缩** ```bash docker build --compress ... ``` 3. **定期清理无用镜像** ```bash 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` 配得过小会让长任务反复截断并补发,间接加速会话膨胀。它不是唯一根因,但会放大卡顿问题。 ### 解决方案 需要添加三组关键配置: ```json { "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 配置注意 上面的 `historyLimit` 和 `session` 配置放在 `channels.telegram` 级别,会对所有 4 个 Bot 统一生效。如果需要不同 Bot 不同策略,可以在每个 `account` 下单独设置 `historyLimit`。 ### 多模型切换补充说明 后来我又把 `step/step-3.5-flash` 接进来了。这里最重要的经验是: **别为了切模型去改全局默认模型,直接用 `/model ...` 切当前会话就够了。** 原因很简单: - 改全局会影响别的 Bot 和别的会话 - 还可能把 cron 定时任务一起带偏 - 当前会话切换则只影响自己这一条对话链 我现在的实际用法: ```text /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 命令、网页浏览全部正常 ### 关键优化点 配置 `contextTokens`、`historyLimit` 和 `session.maintenance` 后,OpenClaw 从"两天必挂"变成"长期稳定运行"。这是生产环境部署的**必选项**,不是可选项。 > 📷 **Telegram 实际对话效果**: > > ![Telegram使用效果](/images/openclaw/04-telegram-usage.png) --- ## 安全建议 1. **永远不要**将 `openclaw.json` 提交到 Git 2. **配置文件权限**:最小权限原则,但必须保证容器运行用户可读 3. **Web UI 访问**:仅通过 SSH 隧道,不要暴露在公网 4. **Telegram 白名单**:严格控制 `allowFrom` 列表 5. **定期更新**:关注 OpenClaw 安全公告 --- ## 参考资源 - [OpenClaw 官网](https://openclaw.ai/) - [GitHub 仓库](https://github.com/openclaw/openclaw) - [阿里云百炼](https://bailian.console.aliyun.com/) - [X - @elvissun](https://x.com/elvissun/status/2025920521871716562) - [X - @stark_nico99](https://x.com/stark_nico99/status/2026235176150581282) - [X - @AI_Jasonyu](https://x.com/AI_Jasonyu/status/2026455606970954087)