OpenClaw 实战 06|性能优化:上下文压缩、内存压力、冷启动的先 profile 原则原创
# 性能优化:上下文压缩、内存压力、冷启动的先 profile 原则
这一篇只讲 OpenClaw 特有的三类慢——长对话"变蠢"、内存压力、skill/模型冷启动——以及一条铁律:没 profile 过就动手优化,比不优化更糟。
先纠正一个常见误判:OpenClaw 是 Node / pnpm 应用(
openclaw.mjs,nvm v22),不是 Python。所以py-spy那套用不上,profiling 走 Node 的工具链(node --inspect、clinic、0x)。下面三类慢,前两类是 OpenClaw 自己的机制问题,第三类才是通用资源问题。
# §1 那个对话越久越蠢的 Agent
集成了一个自托管 MoE 模型后,OpenClaw 在短对话里好好的,一旦聊过几十轮就明显"变蠢"——开始答错前面问过的简单问题、丢上下文。
第一反应是"模型不行"。但换小任务又正常。最后定位到的根因,不在模型,在 OpenClaw 的上下文压缩阈值设得太高:模型宣称的 contextWindow 很大,但它实际有效的稳定窗口远小于此,OpenClaw 却按宣称值才触发压缩——于是对话长了之后,模型一直在自己的"不稳定区"里跑。
这件事是本文的引子:OpenClaw 的"慢/差"经常不是资源问题,是它的上下文管理机制和你的模型不匹配。 而要确认是哪一类,得先 profile。
# §2 先 profile,再优化(铁律)
没 profile 的优化是赌博。 我亲手浪费过两次:先给 sqlite 加索引(只省 5%),又上 Redis 缓存 skill 列表(每次状态变更就要 invalidate,毫无意义)——因为我跳过 profile 就动手了。
OpenClaw 一次"慢",先分清时间花在三段的哪一段:
用户发消息
│
├─[A] 冷启动 / skill 加载 / 模型首字 ── 启动开销
│
├─[B] 上下文组装 + 压缩 ───────────── OpenClaw 机制开销
│
└─[C] 推理 + 工具往返 ─────────────── 模型/网络开销
2
3
4
5
6
7
最简单的分段法:time 一个端到端动作,再对照日志时间戳看慢在哪段。别一上来就缓存/加索引——先知道堵在 A、B 还是 C。
# §3 慢之一:上下文压缩(OpenClaw 最该调的旋钮)
这是 OpenClaw 区别于"调 Linux"的地方。它有一套**主动压缩(preemptive compaction)**机制:上下文逼近阈值时自动压缩历史,腾出空间。两个关键旋钮:
contextWindow:OpenClaw 认为这个模型能吃多少 token。reserveTokens(或 reserve floor):留多少余量时触发主动压缩。
§1 的修法:把 contextWindow 下调到模型实际稳定的窗口,让压缩更早触发,模型始终在稳定区工作:
{
"models": {
"providers": {
"<provider>": {
"<model-id>": {
"contextWindow": 110000, // 从模型宣称的超大值下调到实际稳定窗口(示例值,按你的模型实测调)
"reserveTokens": 20000 // 留足余量,更早触发主动压缩
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
复用规则:MoE / 激活参数小的模型,别信它宣称的 contextWindow——按实际推理质量下调,并靠主动压缩把长对话钉在稳定区。判断"是不是压缩问题"很简单:短对话好、长对话差 → 几乎肯定是它。
这属于
models.providers配置,改完要重启(不是热重载)。
# §4 慢之二:内存压力
OpenClaw 长期运行 + 多模型 + 容器 cgroup 限制下,内存压力很常见。好消息是它自己会在日志里喊:
# 容器(supervisor)
grep "memory pressure" /var/log/supervisor/openclaw.log | tail
# 裸机(systemd)
journalctl --user -u openclaw-gateway | grep "memory pressure"
2
3
4
看到 memory pressure 比盯 RSS 数字更直接——这是 OpenClaw 主动告诉你"我开始吃紧了"。两类常见来源和对策:
- 宿主/容器内存真不够 → 提 cgroup 限额,或减少同时挂载的模型角色(
imageModel/reasoningModel都各自占资源)。 - NAS 上 swap 被无谓换出(物理内存其实够)→ 调
vm.swappiness,让内核别那么激进:
sudo sysctl -w vm.swappiness=10
echo "vm.swappiness=10" | sudo tee /etc/sysctl.d/99-swappiness.conf
2
真实案例:某 NAS 上一个 Windows VM 锁死了大半物理内存,宿主侧 Available 其实充足,但
swappiness=60让内核把不活跃页大量换出,表现成"假性内存紧张"。调到 10 后 swap 自然回落。先确认是真不够还是被换出,再决定加内存还是调参。
# §5 慢之三:冷启动与工具往返
第三类是通用资源问题,但在 OpenClaw 上有几个特定热点:
- skill 列表冷启动:skill 多了,首次加载有开销。OpenClaw 的设计是只把
description进上下文、匹配任务才读正文(按需加载),所以别把 skill 的description写得又臭又长——那是每次都要付的成本。 - 模型首字延迟:自托管 vLLM 后端跨网络时,首 token 延迟受网络影响大。用
curl -w量 TTFB(DNS/connect/TLS/首字)定位是网络还是模型。 - 工具往返:一次回复 = 模型推理 + 若干工具调用 + 可能的 TTS 合成。
openclaw cron runs/ trajectory 日志能看到每步耗时,别把工具往返的慢算到模型头上。
# 量端到端 + 首字延迟
time openclaw cron run <monitor-job-id> --wait
curl -w "dns=%{time_namelookup} conn=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total}\n" \
-o /dev/null -s <你的模型端点>
2
3
4
# §6 反模式
| 反模式 | 为什么错 |
|---|---|
| 没 profile 先加缓存 | 缓存可能根本没命中(我踩过 Redis 那次) |
| 长对话变差就怪模型 | 多半是 contextWindow 没下调(§3) |
| 内存一紧张就加内存 | 可能是 swappiness 把够用的内存换出去了(§4) |
| 把工具往返的慢算到模型 | 一次回复含多次工具调用,分段看 |
| 用 py-spy/memray 调 OpenClaw | 它是 Node 不是 Python,工具用错了 |
# §7 复用规则(一句话带走)
OpenClaw 的慢,先在"冷启动 / 上下文压缩 / 内存压力"三段里定位——长对话变蠢调
contextWindow,内存紧张先看memory pressure日志再决定加内存还是调 swappiness。
展开 3 条:
- 先 profile 再优化,分清慢在启动、上下文还是推理。
- 上下文压缩是 OpenClaw 最该调的旋钮——别信模型宣称的
contextWindow。 - 内存看
memory pressure日志,别盲目加内存;它是 Node,别用 Python 那套 profiler。
# §8 下一篇
下一篇:07|部署指南——容器+supervisor / 裸机+systemd 两套部署的真实配置与端到端验证。
# §9 Agent 可直接解析的元数据块
{
"_meta": {
"doc_version": "2026-06-27",
"article_id": "openclaw-06-performance",
"profile_context": "any",
"estimated_read_time": "10min",
"runtime_fact": "OpenClaw 是 Node/pnpm 应用(openclaw.mjs, nvm v22),不是 Python"
},
"three_slowness_classes": {
"context_compression": {
"symptom": "短对话正常、长对话变蠢/丢上下文",
"knobs": ["models.providers.<p>.<model>.contextWindow", "reserveTokens"],
"fix": "下调 contextWindow 到模型实际稳定窗口,更早触发主动压缩",
"needs_restart": true
},
"memory_pressure": {
"signal": "grep 'memory pressure' /var/log/supervisor/openclaw.log",
"fixes": ["提 cgroup 限额/减少模型角色", "vm.swappiness 调低(被换出而非真不足时)"]
},
"cold_start": {
"hotspots": ["skill description 过长(每次都付)", "vLLM 跨网络首字延迟", "工具往返"],
"measure": "time 端到端 + curl -w TTFB + trajectory 分步耗时"
}
},
"safety_rules": [
"先 profile 再优化,分清慢在启动/上下文/推理",
"长对话变蠢先调 contextWindow,不是换模型",
"内存看 memory pressure 日志,别盲目加内存",
"OpenClaw 是 Node,别用 py-spy/memray"
],
"anti_patterns": ["没 profile 先加缓存", "长对话差就怪模型", "内存紧就加内存", "工具往返的慢算给模型"],
"reusable_rule": "在冷启动/上下文压缩/内存压力三段里定位;长对话变蠢调 contextWindow,内存紧先看 memory pressure"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
AI Agent 使用指南:
- 当用户说"OpenClaw 对话越久越笨" → §3:下调
contextWindow,更早触发主动压缩 - 当用户说"OpenClaw 吃内存/变卡" → §4:先
grep memory pressure,再判断加内存还是调 swappiness - 当用户说"首次响应很慢" → §5:分清 skill 冷启动、模型首字、工具往返
- 当用户说"想加缓存优化" → §2:先 profile,没数据不许加
- 当用户说"用 py-spy 看 OpenClaw" → 纠正:它是 Node,用 node --inspect / clinic / 0x