OpenClaw 源码升级实录:版本迁移、Node 环境统一与飞书插件兼容修复

本文由 AI 辅助整理,基于 2026-10-06 至 2026-10-07 的实际维护记录。由作者人工审核技术事实、命令示例和脱敏内容。

一次 OpenClaw 升级涉及的不只是源码版本。Node、状态数据库、插件 SDK、服务配置和实际业务链路,都可能随着版本变化需要调整。

这次维护将一台 Debian 设备上的 OpenClaw 从 2026.6.10 升级至当时核实的稳定版 2026.9.8。最终验收方式是向现有飞书机器人发送指令,让它创建一篇飞书文档、读回正文并返回真实链接。

这个验收步骤揭示了一个关键问题:进程启动成功、插件加载成功、健康检查通过,仍然不能替代真实业务验收。

一、升级目标与约束

原安装运行在一个增加了 GPT-5.6 harness 支持的定制源码分支上,Node 版本为 nvm 管理的 22.22.1。

本次升级遵循四项约束:

  1. OpenClaw 保持源码安装,不通过 npm 安装 OpenClaw 本体。
  2. Node 版本继续由 nvm 管理。
  3. 依赖 Node 的 skills、plugins 和子进程应与 gateway 使用一致的 Node 环境。
  4. 一次性暂存文件在任务完成后清理,恢复备份和验证证据保留。

需要区分“OpenClaw 本体安装”和“源码依赖安装”。源码构建仍然需要按照仓库要求,通过固定版本的 pnpm 安装依赖。

最终主要变化如下:

项目 升级前 升级后
OpenClaw 2026.6.10 定制分支 2026.9.8 官方稳定版源码
源码提交 定制提交 fc23bc8
Node nvm 22.22.1 nvm 24.19.0
状态管理 旧配置和会话存储 官方迁移后的配置与 SQLite
Lark 插件 适配旧 SDK 保留原包版本,修复六个文件
托管服务 旧源码与旧 Node 新源码与 Node 24.19.0
默认模型 openai/gpt-5.6-sol 保持不变

升级软件提供了新的模型接入能力,但不会自动把现有机器人的默认模型切换到新型号。

二、先准备恢复条件,再开始迁移

这次没有直接覆盖原定制源码,而是保留原目录,在独立目录部署稳定版源码。

这样可以保留:

  • 原定制分支及本地修改;
  • 原目录中的未跟踪文档;
  • 原服务定义;
  • 升级前的配置和状态;
  • 对比和排查所需的历史证据。

同时创建并校验了完整状态备份,包含状态目录及其内部的 agent 工作目录。备份约 4.2 GB,恢复目录和备份文件使用限制访问的权限。

这里需要强调:原源码目录保留,并不代表随时切换回旧二进制就能安全回滚。

一旦状态数据库和配置完成迁移,回滚还需要评估旧版本是否能够读取新状态。恢复计划必须覆盖源码、Node、配置和数据库,而不能只保存 Git 提交。

三、跨版本升级需要经过迁移桥接版本

根据本次核对的官方升级指南,2026 年 7 月之前的版本需要先经过 2026.9.5,再升级至目标稳定版。

实际路径为:

2026.6.10
    ↓
2026.9.5:执行官方状态迁移
    ↓
2026.9.8:部署目标稳定版并验证

迁移不仅调整版本号,还处理了旧配置和存储结构。例如:

  • agent 配置由 agents.list 迁移至 agents.entries;
  • 历史数据导入 SQLite;
  • 旧心跳设置迁移为定时任务;
  • 多个旧配置字段由 Doctor 处理;
  • 工作区中的旧指令文件按官方迁移逻辑合并并保留原件。

迁移后,两个 agent 各选取五个近期会话标识进行检查,均确认保留。这个检查证明了所选样本的连续性,不等同于对全部历史数据逐条完成校验。

经验是:跨越存储或配置架构变化的版本时,应先阅读迁移要求,再安排构建与启动顺序。

四、构建遇到 SIGKILL:先确认参数在哪一层生效

目标稳定版第一次构建被 SIGKILL 终止。

当时的主要假设是内存压力,但当前身份无法读取内核日志,因此没有把 OOM 当作已确认结论。仅凭 SIGKILL,不能证明进程一定被 OOM killer 终止。

进一步检查构建脚本发现,通用 NODE_OPTIONS 中的堆限制会被构建链路覆盖,实际用于相关构建进程的上限约为 5,734 MB。

目标版本提供了针对 tsdown 的参数:

export OPENCLAW_TSDOWN_MAX_OLD_SPACE_MB=4608

经过确认后,使用 4,608 MB 上限重试,最终完成运行时、96 个插件包和控制界面的构建,耗时约 3 分 25 秒。

本次构建以部署运行时为目标,并跳过了 SDK 类型声明构建,因此这组构建设置不能直接当作开发或发布 SDK 的通用流程。

这里有两条经验:

  1. 环境变量被设置,不代表最终子进程一定采用它。
    要检查构建入口和脚本如何重写参数。

  2. 构建堆限制与 gateway 运行堆限制是两项独立设置。
    本次构建使用 4,608 MB;服务安装器后来为 gateway 计算出的上限是 3,922 MiB。二者用途不同,也不代表进程会立即占用对应大小的内存。

五、飞书插件兼容修复分三个阶段完成

原 Lark 插件包版本为 2026.6.10。

核查当时发布的厂商稳定版和 beta 后,发现它们仍包含相同的旧 SDK 导入路径。因此,单纯更新插件包不能直接解决这次接口兼容问题。

最终保留原插件包版本,对六个文件进行增量修复,并保存原件与补丁。

1. 修复已停止导出的 SDK 路径

文件 原导入 替代导入
index.js openclaw/plugin-sdk openclaw/plugin-sdk/channel-plugin-common
src/card/reply-dispatcher.js openclaw/plugin-sdk/channel-runtime openclaw/plugin-sdk/channel-outbound

替代路径依据目标版本实际导出的模块和插件使用的函数确定。

2. 修复 CommonJS 与 import.meta 混用

两个 JavaScript 文件使用 CommonJS,却混入了 import.meta.url:

  • src/core/version.js
  • src/core/token-store.js

修复思路是统一使用 CommonJS 已提供的 __filename 和 __dirname。

例如:

// 原写法
const _require = createRequire(
  typeof __filename !== "undefined" ? __filename : import.meta.url
);

// 修复后
const _require = createRequire(__filename);

这里不应只因为报错,就给整个插件包增加 type: module 或 type: commonjs。包级模块类型会影响更多文件,需要先确定实际发布产物的模块格式。

完成前四个文件的修复后,插件能够正常加载,注册了飞书通道和 39 个工具,诊断信息为空。

但这仍然没有覆盖消息处理回调。

3. 真实消息暴露配置读取 API 的变化

向机器人发送创建文档的指令后,gateway 收到了消息,却在处理阶段报错:

runtime.config.loadConfig is not a function

目标 SDK 提供的接口已经变为:

runtime.config.current()

受影响的实际调用位于:

  • src/channel/monitor.js
  • src/core/lark-client.js

修复这两个调用,并保留原有 fallback 逻辑后,消息才成功进入 agent。

这个过程说明:插件注册阶段的成功,只证明初始化路径可用;按需执行的消息回调和业务工具,还需要单独验证。

六、systemd 服务迁移与权限检查

新版安装器拒绝了原服务目录和文件,因为它们允许用户组写入。

排查过程中先后发现四个相关路径:

  • systemd 配置目录;
  • systemd 用户服务目录;
  • gateway 服务文件;
  • 同名 .service.bak 备份文件。

最后一个备份文件是在前面三个路径修正后才被安装器报告出来的。

这次权限调整逐个确认所有者和路径,只修改目标本身,没有递归修改整个配置目录,也没有通过 sudo 绕过检查。

服务重新生成后,服务文件及备份文件的最终权限为 0600。

部分服务策略也发生了变化:

策略 原值 新值
TimeoutStopSec 30 330
KillMode control-group mixed
StartLimitBurst 5 10
StartLimitIntervalSec 60 300
OOMPolicy 未显式设置 continue

这些策略为 gateway 排空正在执行的工作提供更充分的时间,并调整子进程退出和重启行为。

托管服务最终确认:

  • enabled;
  • active / running;
  • 用户 Linger 已启用;
  • IPv4 和 IPv6 回环监听正常。

七、Node 一致性不能只检查 node -v

服务切换成功后,出现了一处容易忽略的差异:

实际 gateway Node:24.19.0
PATH 首项:24.19.0
NVM_BIN:22.22.1

这时 gateway 已经运行在 Node 24 上。旧 NVM_BIN 不会自动改变正在运行的 Node 进程。

但如果某个脚本通过下面的方式启动 Node:

"$NVM_BIN/node"

它仍然会选择旧版本。

正常情况下,nvm use 会同步更新 PATH 和 NVM_BIN。systemd 服务拥有独立的运行环境,这次旧值来自服务继承的环境。

最终通过 systemd drop-in 统一该变量。脱敏示例如下:

[Service]
Environment=NVM_BIN=/home/<user>/.nvm/versions/node/v24.19.0/bin

重新加载并重启后,实际可执行文件、PATH 和 NVM_BIN 全部指向 Node 24.19.0。观察到的运行时子进程也使用相同版本。

检查服务环境时,可以分别查看实际可执行文件和目标变量:

gateway_pid=$(systemctl --user show \
  openclaw-gateway.service -p MainPID --value)

readlink "/proc/$gateway_pid/exe"

tr '\0' '\n' < "/proc/$gateway_pid/environ" |
  grep -E '^(PATH|NVM_BIN)='

不要完整打印服务环境,其中可能包含凭据。

另外,固定版本的 drop-in 是需要维护的配置。以后升级 Node 时,应同时检查服务命令、PATH 和这项覆盖值。

八、用业务结果完成最终验收

最终验收通过现有飞书私聊进行:

  1. 向机器人发送创建文档的指令;
  2. 确认 gateway 收到消息;
  3. 确认消息进入 agent;
  4. 由机器人实际创建飞书文档;
  5. 由机器人读回标题和正文;
  6. 返回真实文档链接;
  7. 再通过用户身份读取文档,核验访问权限和内容。

运行过程中还出现过模型提供方失败及自动重试,最终文档创建、读回和链接回复成功。因此,这次验收证明了该业务链路能够完成,不能据此宣称所有模型路由都已无异常。

最终只读 Doctor 检查的五项兼容性探针通过,findings 为空。

同时,观察到一个独立的工作区备份自动任务报告退出码 2。该问题未在本次文档验收中处置,原因尚未诊断,也不能直接认定由升级导致。

验收报告应保留这些边界,避免将“关键链路通过”写成“所有功能完全正常”。

九、清理暂存,同时保留恢复证据

本次清理的一次性材料包括:

  • 迁移桥接版本源码;
  • 候选插件包及解包副本;
  • 隔离插件验证目录和测试配置;
  • 备份 staging 数据;
  • 已失效的前台 gateway PID 标记。

清理前确认活动配置和入口没有引用这些位置,新稳定版 Git 仓库也没有通过对象 alternates 依赖临时源码目录。删除后再次确认 gateway 健康状态和飞书运行状态。

保留的材料包括:

  • 原定制源码及本地文档;
  • 正式部署的稳定版源码和依赖;
  • 升级前完整状态备份;
  • 插件修复前原件及补丁;
  • 构建、迁移和验收日志;
  • 设备已有的 pnpm、Corepack 等共享缓存。

临时目录应当可以随时删除。正式入口、恢复证据和长期文档不能依赖它。

十、这次升级留下的经验

升级路径由状态兼容性决定

源码能够构建,不代表旧状态可以直接被新版本安全使用。先核对官方迁移要求,再决定部署顺序。

原源码保留与状态备份缺一不可

定制分支提供代码层面的恢复和对比条件;完整状态备份提供配置与数据库层面的恢复条件。

构建参数要追到实际子进程

通用环境变量可能被脚本覆盖。遇到内存相关问题时,应先确认最终生效的参数,再调整限制。

插件加载成功只是一个检查点

初始化、消息接收、工具调用、鉴权和外部资源访问是不同阶段。最终应以真实业务结果验收。

Node 一致性需要检查多个入口

除了 gateway 的实际可执行文件,还应检查 PATH、NVM_BIN 和实际子进程。只查看当前终端的 node -v 不够。

本地补丁需要成为可维护资产

记录包版本、修复原因、原件和精确 diff。后续插件更新可能覆盖补丁,更新后必须重新验证兼容性。

验收结论要说明范围

本次完成的是源码升级、运行环境统一、插件兼容修复和飞书文档链路验证。未诊断的自动任务告警继续保留在待办中。

参考资料

posted @ 2026-10-07 03:08  LexLuc  阅读(63)  评论(0)    收藏  举报