从 32K 到 200K:不同上下文窗口的 OpenClaw 配置完全指南
大家好,我是慧织罗兰。当你在使用 OpenClaw 管理大模型会话时,是否遇到过这样的困扰:
对话越来越长,AI 的记忆力却越来越差。明明前几轮说过的重要内容,突然就”消失”了。你怀疑是上下文窗口不够用,但又不知道该怎么配置那些神秘的参数——reserveTokensFloor、softThresholdTokens、maxHistoryShare……
更让人困惑的是,官方文档说 Memory Flush 会在压缩之前触发,但实际测试时,两者几乎同时发生。是文档写错了,还是你配置错了?
这篇文章,就是来帮你解开这些困惑的。
01. 为什么上下文会”爆满”?
在使用 OpenClaw 管理大模型会话时,每一条消息都会占用模型的 context window(上下文窗口)。不同模型的上下文窗口大小不同:
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
当对话越来越长,上下文会逐渐逼近模型的 context window 上限。这时候,OpenClaw 需要做两件事:
-
1. 压缩历史对话(Compaction):把旧消息压缩成摘要,释放空间 -
2. 保存重要记忆(Memory Flush):在压缩前,把关键信息写入磁盘
这两个机制的设计逻辑看似清晰,但在实际实现中,有一个重要的细节经常被忽略。
02. 什么是 Compaction(压缩)?
Compaction 是 OpenClaw 在会话接近 context limit 时自动执行的操作。
它做什么?
-
• 将较旧的历史对话压缩成一段摘要 -
• 把摘要保存到 session transcript 中 -
• 保留最近的消息不变
压缩后,模型看到的是什么?
[压缩摘要] + [最近的消息]
OpenClaw 支持两种压缩模式:
|
|
|
|
|---|---|---|
| default |
|
|
| safeguard |
|
|
03. 什么是 Memory Flush(内存预写)?
Memory Flush 是 OpenClaw 在自动压缩之前,运行的一个 静默的 agentic turn。
它的目的是什么?
在上下文被压缩之前,把重要信息提前写入磁盘的 memory 文件,防止这些信息在压缩时丢失。
关键特点:
-
• 它是静默的(silent turn),用户看不到过程 -
• 它发生在 compaction 之前,给记忆留出写入时间 -
• 写入路径通常是 memory/YYYY-MM-DD.md
04. 文档说的 vs 代码做的:一个关键差异
官方文档的描述
Compaction 触发条件:
contextTokens > contextWindow - reserveTokens
Memory Flush 触发条件(在 compaction 之前):
contextTokens > contextWindow - reserveTokens - softThresholdTokens
按照这个描述,Memory Flush 应该比 Compaction 更早触发,两者之间的间距由 softThresholdTokens 决定。
这听起来是一个很合理的”预警机制”设计。
代码实现的真实逻辑
通过分析 agent-runner.runtime-*.js,我们发现了一个重要细节:
Preflight Compaction(预压缩)的触发公式:
const threshold = contextWindowTokens - reserveTokensFloor - softThresholdTokens;
Memory Flush 的触发公式:
const flushThreshold = contextWindowTokens - memoryFlushPlan.reserveTokensFloor - memoryFlushPlan.softThresholdTokens;
两者使用的是完全相同的计算公式。
实际触发点对比
以 contextWindow = 200K,reserveTokensFloor = 80K,softThresholdTokens = 4K 为例:
|
|
|
|
|---|---|---|
|
|
|
116K |
|
|
|
116K |
两者同时触发,间距为 0K。
这与文档描述的”Flush 在 Compaction 之前”完全不符。
05. 问题的本质是什么?
softThresholdTokens 在这个实现中并没有产生一个有意义的”提前量”。它只是决定了两者在同一个 threshold 触发,而不是一前一后。
这是实现层面的设计问题:文档描述的是”提前预警”的概念,但实际代码中 flush 和 preflight compaction 共享了同一个触发阈值。
那该怎么办?
虽然 Preflight Compaction 和 Memory Flush 用了相同的公式,但 Pi 运行时本身也有 compaction 判断:
Pi 运行时 compaction 触发 = contextTokenBudget - reserveTokens
其中 reserveTokens 来自 Pi 设置,受 reserveTokensFloor 保障(不会低于 floor)。
因此,真正的间距来自:
实际间距 = softThresholdTokens + (reserveTokens - reserveTokensFloor)
配置要点:
-
• 把 softThresholdTokens设大 → flush 会更早触发 -
• 把 softThresholdTokens设小 → flush 和 compaction 几乎同步
06. 不同上下文窗口的配置指南
配置参数说明
|
|
|
|
|---|---|---|
reserveTokensFloor |
|
|
softThresholdTokens |
|
|
maxHistoryShare |
|
|
recentTurnsPreserve |
|
|
32K 上下文窗口配置
适用于本地小模型(如 Llama-3-8B):
{ "agents": { "defaults": { "compaction": { "mode": "safeguard", "model": "local-model", "reserveTokensFloor": 8000, "maxHistoryShare": 0.3, "recentTurnsPreserve": 5, "memoryFlush": { "enabled":true, "softThresholdTokens": 8000, "prompt": "Write any lasting notes to memory/YYYY-MM-DD.md; reply with NO_REPLY if nothing to store.", "systemPrompt": "Session nearing compaction. Store durable memories now." } } } }}
说明:
-
• 32K 窗口较小,间距要合理 -
• reserveTokensFloor = 8K(25%),确保压缩后有足够空间 -
• softThresholdTokens = 8K,让 flush 提前触发
128K 上下文窗口配置
适用于 GPT-4 等中等窗口模型:
{ "agents": { "defaults": { "compaction": { "mode": "safeguard", "model": "gpt-4", "reserveTokensFloor": 50000, "maxHistoryShare": 0.3, "recentTurnsPreserve": 5, "memoryFlush": { "enabled":true, "softThresholdTokens": 25000, "prompt": "Write any lasting notes to memory/YYYY-MM-DD.md; reply with NO_REPLY if nothing to store.", "systemPrompt": "Session nearing compaction. Store durable memories now." } } } }}
说明:
-
• 128K 属于中等窗口 -
• reserveTokensFloor = 50K(约 40%) -
• softThresholdTokens = 25K(约 20%)
200K 上下文窗口配置
适用于 MiniMax-M2.7、Claude 等大窗口模型:
{ "agents": { "defaults": { "compaction": { "mode": "safeguard", "model": "minimax2.7", "reserveTokensFloor": 80000, "maxHistoryShare": 0.3, "recentTurnsPreserve": 5, "memoryFlush": { "enabled":true, "softThresholdTokens": 40000, "prompt": "Write any lasting notes to memory/YYYY-MM-DD.md; reply with NO_REPLY if nothing to store.", "systemPrompt": "Session nearing compaction. Store durable memories now." } } } }}
说明:
-
• 200K 属于大窗口,配置更宽松 -
• reserveTokensFloor = 80K(40%) -
• softThresholdTokens = 40K(20%),让 flush 有足够的提前量
07. 配置对照速查表
|
|
|
|
|
|---|---|---|---|
| 32K |
|
|
|
| 128K |
|
|
|
| 200K |
|
|
|
08. 常见配置误区
误区1:softThresholdTokens = “提前多少开始压缩”
实际情况: 它决定的是 flush 和 compaction 的触发点差值。但如果两者用同一个公式,差值就是 0。
误区2:reserveTokensFloor 越小越好
实际情况: 太小会导致 compaction 非常频繁,每次压缩都会丢失上下文细节。太小也会让 reserve 空间不足,下一轮对话空间不够。
误区3:maxHistoryShare 越高越好
实际情况: 占比越高,能留给新对话的空间越少。建议 0.3 左右(30%)。
误区4:压缩后历史占比应该尽量高
实际情况:
-
• 50%:通常过于激进 -
• 75%:更平衡 -
• 80%-85%:更接近默认保守策略
09. 一张图看懂触发机制
┌─────────────────────────────────────────────────────────────────┐│ 模型上下文窗口 (contextWindow) ││ ││ 0 200K ││ |═════════════════════════════════════════════════════════════| ││ ││ ▲ ││ reserveTokensFloor ││ (假设为 80000) ││ │ ││ ┌─────────────────────────────────▼─────────────────────────┐ ││ │ reserveTokens = max(用户设置, reserveTokensFloor) │ ││ └─────────────────────────────────┬─────────────────────────┘ ││ │ ││ compaction 触发线 ││ contextTokens > ││ contextWindow - reserveTokens │└─────────────────────────────────────────────────────────────────┘ ▲ │ softThresholdTokens (memoryFlush 触发线) │ │ ┌─────────────────▼──────────────────────────────────────────┐ │ memoryFlush 区域 (softThresholdTokens) │ │ │ │ 当 contextTokens > contextWindow - softThresholdTokens │ │ → 触发预 compaction memory flush (写 memory/YYYY-MM-DD) │ └─────────────────────────────────────────────────────────────┘
10. 写在最后
OpenClaw 的 compaction 和 memory flush 机制设计合理,但存在一个重要的实现细节问题:文档描述的触发逻辑和实际代码逻辑不完全一致。
Memory Flush 并没有如文档所说”在 compaction 之前”触发,而是几乎同步触发。
理解这个机制后,配置的要点是:把 softThresholdTokens 设得足够大,让 flush 在 compaction 之前有足够的提前量运行,给记忆写入留出喘息时间。
代码不会骗人。当你发现文档和实际行为不一致时,读源码,才是最可靠的方式。
参考资料:
-
• OpenClaw 官方文档:session-management-compaction.md -
• OpenClaw 配置参考:gateway/configuration-reference.md

你好,我是慧织罗兰
世间万物终将消逝,某些价值、情感、美好的事物却能够脱离时间而永远存在
让生命不断追求生活的意义
夜雨聆风