OpenClaw 性能优化
浪费是指请求不需要执行的工作。大幅加速来自于删除浪费,而不是以更快的速度执行同样的工作。缓存是最后的手段:它会隐藏浪费,直到其键、失效或命中率出现问题,浪费便会重现。
1. 测量
在首次运行之前,将 PR 的接受规则写入:流程、工作负载、指标、冷启动或热启动、样本数,以及被视为胜利或回归的变化。
| 流程 | 已提交的工作负载 |
|---|---|
| CLI 启动 | pnpm test:startup:bench(:check 包含预算) |
| 网关启动/重启 | scripts/bench-gateway-startup.ts、scripts/bench-gateway-restart.ts、scripts/perf/post-restart-burst-measure.ts |
| 对话轮次,每轮帧数 | scripts/bench-channel-turn.mts、scripts/perf/transcript-broadcast-measure.ts |
| 控制 UI 冷加载 | scripts/bench-control-ui-cold-load.ts、pnpm ui:check-performance(:base 用于对比) |
| 会话列表,多智能体形态 | scripts/perf/team-shape-fixture.ts、src/gateway/session-list-viewers.perf.test.ts |
| 并发性,SQLite 状态 | scripts/bench-gateway-concurrency.ts、pnpm test:sqlite:perf |
- 先计数: 在记录墙时间之前,先统计每个操作的动作数量(SQL 语句、RPC 和帧、文件读取、目录或注册表加载、生成、渲染)。计数在负载主机上保持稳定。应为零的计数就是 bug。
- 真实流程: 在测试中的分支上使用隔离的网关、真实传输,并包含慢路径。使用模拟网关、过时的构建或开发服务器测量的是其他东西。
- 样本: 基线和候选交替(ABAB),每个至少 5 个样本,冷启动和热启动分开;记录中位数和第 95 百分位数及离散度,串行运行,记录主机负载。
- 可重运行: 只有已提交的脚本才算数;当没有适合的脚本时,扩展现有的脚本。
- 分析: 在热路径上,每个线程使用
node --cpu-prof或浏览器性能跟踪。
当流程具有已提交的工作负载、基线表和书面规则时完成。
2. 寻找浪费
对每个已计数的操作问:这个请求需要它吗?OpenClaw 中常见的浪费:
- 关键路径上的急切工作: 注册表查找导入了插件加载器(#133518,47.07 秒 → 10.36 秒);启动时加载了可选运行时(#119374)。
- 每行或每次调用重新计算: 每个归档行的同步读取(#156665,56,700 次读取 → 0);每帧解析日志模式(#150042,每 10,000 帧从 539 毫秒降为 17 毫秒)。
- 重复检查已承认的状态: 对热句柄的模式、准入或新鲜度检查(#166102,#172676;SQLite 准入链中的 14 个 PR)。
- 每个流式 delta 的完全重新扫描: 每个令牌都重新处理整个回复(#158526,256 KiB 时 CPU 从 5,342 毫秒降为 1 毫秒)。
- 重新读取自己的写入: 每次查找执行两次数据库备份(#161551,从 772.8 毫秒降为 7.7 毫秒);Doctor 重新扫描并备份了它刚刚检查过的内容(#174665,从约 26 秒降为 3.0 秒)。
- 重复的目录或注册表构建: 启动时为每个智能体重建目录(#116261,从 24.9 秒降为 5.0 秒);每次未命中或 TTL 后重建(#127178,#167008)。
- 等待可选数据: 使用情况页面等待提供商计划并重试不相关的读取(#176358)。
- 防御性拷贝和封装: 每轮
structuredClone(#172940,1.685 MiB → 0);每个值的边界包装(#163818,每事件从 11,571 纳秒降为 500 纳秒)。 - 每次调用的生成或扇出: 每次解析的子进程(#155779,100 → 0)。
- 渲染级联和完整负载: 每次更新的渲染(#159400,250 → 79);为了一次增量重新发送完整行(#165404,21.75 → 0.95 MiB)。
当每个主要计数都能追溯到发出它的代码,并明确回答“是否需要”时完成。
3. 按此顺序修复
- 删除 浪费。删除很少会回来;失败的删除移除了防护,因此请保留所有保护约定的检查,并证明约定仍然有效。
- 在持有者处执行一次: 调用者消费持有者记录的事实。
- 在热路径中传递准备就绪的事实。
- 批处理 独立的工作,并证明批处理保持帧率、延迟尾部和冷启动稳定:合并曾被回退了三次(#162560,#173901,#175092)。
- 缓存,并提供书面理由说明为什么步骤 1–4 不适用。遵循根本的“缓存身份”,从持有者的写入中失效,限制大小,并添加交错的工单计数测试。四个缓存重新修复中有三个是静默未命中:读取者相互驱逐(#115369 → #174741),导致抖动的预算(#149773 → #149879)。
将工作移动到工作线程或延迟执行会重新定位成本;同时计数主线程和总工作量。
当从计数中消除了浪费,或者 PR 说明了停止在哪一步以及原因时完成。
4. 落地
- 在相同的规则下,对基线和候选重新运行步骤 1 的工作负载。
- 每个面向用户的指标保持不变或改善: 延迟、p95/p99、帧率、冷启动、CPU、内存、计数。更差的指标需要在 PR 中获得所有者的明确接受。一个单元格移动 20% 就是停止信号,绝不是“在离散范围内”:六个回退的性能 PR 中有五个在其正文中显示了自己的回归。
- 回退没有可测量收益的变更。
- 证据存在于 PR 中,而不是新的测试中:前后计数就是证据。仅当这种浪费之前已经出现过时,才扩展现有流程的工单计数测试;test-audit 负责测试的价值。
- PR 证据:工作负载命令、接受规则、前后对比表(计数和时间、中位数和第 95 百分位数、样本数)、已删除的浪费,以及任何朝错误方向移动的指标。
当表格满足步骤 1 中编写的规则时完成。
相关
测试套件速度:openclaw-test-performance。测试堆增长:openclaw-test-heap-leaks。CI 容量:openclaw-ci-limits。