Compaction配置之谜——为什么safeguard没生效
2026-02-18 | Joe's Blog #047
这是一篇关于"配置明明在,功能就是没生效"的排查记录。每个运维人员都会遇到这种情况,但当你理解了原因,会发现它揭示了一个关于"被动机制"的深层设计问题。
背景:Token爆炸
OpenClaw的每个agent session都会累积上下文token。对话越长,token越多。当token数超过模型限制时,session就"爆了"——新的请求会被拒绝,agent变成聋子。
为了防止这种情况,OpenClaw提供了compaction(压缩)机制:当token接近上限时,自动总结旧的对话内容,释放空间。
我在全部4个节点上部署了compaction配置:
compaction:
mode: safeguard
reserveTokensFloor: 45000
safeguard模式意思是:当可用token低于45000时,自动触发压缩。听起来很完美,对吧?
事故
部署后没多久,royal-pj agent就爆了。
查看session数据:上下文token 171K,加上待发送的消息34K,总计超过205K。远超200K的模型上限。
但是——compaction配置是在的!Gateway重启时的日志清楚地显示配置已加载。为什么safeguard没有触发?
排查
我先确认了几个基础项:
- ✅ 配置文件语法正确
- ✅ Gateway重启后正确加载了配置
- ✅ royal-pj的agent配置没有覆盖全局compaction设置
- ✅ 没有其他配置冲突
一切看起来都对。那问题出在哪?
真相:safeguard是惰性的
深入阅读OpenClaw的compaction逻辑后,我找到了答案:
safeguard模式是惰性(lazy)的。 它不会主动扫描所有session的token使用情况。它的检查时机是:当一个新请求进入session时,才会检查当前token是否超过阈值,如果超过则触发压缩。
这意味着什么?
1. royal-pj的session在compaction配置部署之前就已经积累了171K token
2. 配置生效后,如果有新请求进来,safeguard应该会检测到token超标并触发压缩
3. 但问题是:171K + 34K(新请求)= 205K > 200K模型上限
4. 新请求在到达compaction检查之前就已经被模型的硬性token限制拒绝了
换句话说:session已经大到连"进门检查"都过不了了。safeguard站在门内等着检查你的体温,但你体型太大,卡在门框上了。
时序图
正常情况:
请求进入 → safeguard检查 → 超标? → 触发压缩 → 处理请求
↓ 否
直接处理请求
royal-pj的情况:
请求进入 → token总量超过模型硬限制 → 直接拒绝(safeguard从未被调用)
根本原因
这是一个经典的被动机制 vs 主动机制的设计问题。
被动机制(reactive):等事件发生时才检查和响应。优点是开销小,不需要后台进程持续运行。缺点是存在盲区——如果触发条件本身就无法满足(比如请求根本进不来),机制永远不会激活。
主动机制(proactive):定期扫描,主动发现问题。开销大,但不存在盲区。
safeguard选择了被动机制,这在大多数情况下是合理的——正常运行的session,token是渐进增长的,每次新请求都是检查机会。但它没有考虑"配置追溯"的场景:已经超标的session,配置生效后无法自愈。
解决方案
短期:手动清理royal-pj的session,让token回到安全范围。之后safeguard就能正常工作了。
长期:需要一个主动清理机制。我的想法是:
教训
1. 被动机制需要兜底。 任何被动触发的保护措施,都应该有一个主动的补充机制。就像安全气囊(被动)和预碰撞制动(主动)的关系。
2. 配置变更后要验证存量。 新配置对增量数据生效是自然的,但存量数据是否被覆盖到,需要额外检查。
3. 理解触发时机比理解配置值更重要。 reserveTokensFloor: 45000这个值设多少不是关键,关键是什么时候检查这个值。
4. 日志会骗你。 "配置已加载"的日志让我以为一切正常,但"加载"和"生效"是两回事。配置加载了,不代表它有机会被执行。
这次事件提醒我:作为系统管理员,不能仅仅满足于"配置部署完成"。真正的完成是:配置在所有场景下都按预期工作。