乐于分享
好东西不私藏

OpenClaw 4.29 性能优化实录:从 40 秒到底要多久?

OpenClaw 4.29 性能优化实录:从 40 秒到底要多久?

最近用 OpenClaw 4.29 跑 agent,Gateway 模式下从发消息到收到回复总要 40 秒左右。作为一个对响应时间敏感的用户,我花了大半天跟踪这个问题,打了 6 轮 patch,最后发现——痛点不在我以为的地方

一、问题拆解:prep 阶段在做什么?

OpenClaw 在每次 agent run 时有一个 prep 阶段,它在模型接收用户消息之前完成所有准备工作。通过 embedded trace 日志,我把这个阶段拆成了几个部分:

阶段 耗时 占比
runtime-plugins ~9.4s 52%
core-plugin-tools ~8.8s 49%
system-prompt ~3.7s 20%
stream-setup ~3.5s 19%

注:百分比之和超过 100%,因为这些阶段有重叠。但可以清晰看出:runtime-plugins 和 core-plugin-tools 是大头

二、版本变化带来的挑战

这次跟踪是在 OpenClaw 4.29 上做的。这个版本有一个重大变化:

dist 目录结构从 chunks/ 子目录变成了扁平化的 hash-named ESM 模块。以前的 provider-runtime.js 现在叫 loader-CLyHx60E.js,且每次升级文件名 hash 都变。

这意味着:

  • 以前基于固定路径的 patch 全部失效
  • 每次升级都要重新定位目标函数在哪个 hash 文件里
  • 维护成本极高

三、调查过程:从假设到真相

1. 假设:cache 不生效

我以为是旧版的 cache: true patch 被覆盖了。但查了源码后发现:4.29 的 cacheEnabled 默认就是 true,问题不在这。

2. 发现:9 次重复加载

通过日志追踪,发现单次 agent run 中 loadOpenClawPlugins 被调用了 9 次,每次都是 CACHE MISS

原因:cache 是内存级的(pluginLoaderCacheState Map),每次 agent run 都是独立进程,进程结束后 cache 就清空了。跨进程不共享

3. 尝试:减少 plugin 数量

我在 openclaw.json 里配置了 plugins.allow 白名单,将 118 个 plugin 过滤到 13 个。

结果:loading 时间仍然是 ~7 秒

原因:瓶颈不在遍历数量,在单个 plugin 的 jiti 动态加载初始化开销。即使只加载 9 个 plugin,Gateway 启动时也需要 7-8 秒。

4. 尝试:统一 cache key

我想:如果 9 次调用的 cache key 不同,那统一它们就能复用了吧?

于是打了 4 轮 patch:

  • superset checking:检查已加载的 registry 是否包含请求的全部 plugin
  • full registry:始终传递 compatiblePluginIds: null,强制走 broad scope
  • broad scope bypass:跳过 hasExplicitCompatibilityInputs 检查
  • scope widening:合并现有和新请求的 plugin 集合

结果:都生效了,但总耗时几乎没变化

5. 发现:“隐形开销”

重启 Gateway 后测试耗时 ~1 分钟,不重启直接测试 ~40 秒。

差距 ~20 秒来自 Gateway 重启本身的开销(launchctl unload/load + 进程冷启动)。这意味着之前所有“重启后测试”都引入了 ~20 秒噪音。

四、核心发现:3 个平台级痛点

痛点 1:Plugin 加载机制设计限制

4.29 的 plugin cache 是纯内存级的,没有跨进程持久化方案。每次 agent run 都要重新做:

  • jiti 动态加载 JS 模块
  • 扫描和遍历所有 bundled plugin
  • 构建 runtime registry

这是架构层的设计选择,不是 bug,但确实影响了响应速度。

痛点 2:旧 patch 体系不可持续

4.29 的 hash-named ESM 构建产物意味着:

  • 每次升级后文件名全变
  • 函数名可能被 minify
  • 代码结构可能重构

这使得基于正则/字符串匹配的自动化 patch 恢复脚本几乎肯定失败。如果你以前也有类似的自定义 patch,需要重新评估维护策略。

痛点 3:优化收益存在天花板

即使把 plugin 加载优化到极致,还有两个大头吃掉了时间:

  • system-prompt(~6s):加载 skills、persona、构建 system prompt
  • stream-setup(~6s):流初始化、transport 解析、API key 解析

这两个阶段的优化需要更深入的代码改动,风险收益比不高。

五、OpenClaw 已知痛点汇总

除了本次跟踪的性能问题,OpenClaw 还有一些长期存在的平台级痛点:

痛点 影响 对策
Pricing fetch 阻塞 启动时从 OpenRouter 拉取定价,国内网络极慢 环境变量 OPENCLAW_SKIP_MODEL_PRICING=1
bundled-runtime-deps 重入锁 插件加载时 CPU 100% 卡死 打 patch 加进程级锁检测
plugin-runtime-deps 缓存失效 升级后每次重启都重装 63+ 个依赖 升级后清理旧缓存目录
内存占用 500MB+ 115 个插件即使什么都不做也占 500MB 定期 restart,无根治方案
event-dispatch 启动慢 启动时串行初始化,30+ 秒才 ready 启动后等 2 分钟再测
飞书 probe 超时 启动时 500ms 超时导致 bot 身份丢失 环境变量设 5000ms
WebSocket handshake 超时 Safari 连接被断开 环境变量设 60000ms

六、结论与建议

这次优化的收获

  • 弄清楚了 4.29 的 plugin 加载机制(内存级 cache、跨进程不共享)
  • 验证了“减少 plugin 数量”路径的收益天花板
  • 验证了“统一 cache key”路径的收益天花板
  • 发现了 Gateway 重启引入的 ~20s 测试噪音

建议

如果你也在用 OpenClaw,以下几点可能帮到你:

1. 不需要 Gateway 功能时,用 –local 模式
Gateway 模式 ~40s,Local 模式 ~15s,差距 ~24s。如果只是本地调试不需要消息投递,–local 是明智选择。

2. 升级前备份 patch,升级后重新评估
4.29 的 hash-named ESM 导致旧 patch 体系不可持续。升级前 stash 本地修改,升级后不要盲目相信自动恢复脚本,一定要人工检查是否仍有效。

3. 配置环境变量规避已知痛点
OPENCLAW_SKIP_MODEL_PRICING=1、OPENCLAW_FEISHU_STARTUP_PROBE_TIMEOUT_MS=5000、OPENCLAW_HANDSHAKE_TIMEOUT_MS=60000 这三个环境变量能解决大部分启动阶段的痛点。

技术栈的优化是没有终点的。这次跟踪不是为了打败某个耗时数字,而是为了弄清楚“痛点在哪里、为什么、能不能解”。有时候,知道什么不能做,比知道什么能做更有价值。