乐于分享
好东西不私藏

从 32K 到 200K:不同上下文窗口的 OpenClaw 配置完全指南

从 32K 到 200K:不同上下文窗口的 OpenClaw 配置完全指南

大家好,我是慧织罗兰。当你在使用 OpenClaw 管理大模型会话时,是否遇到过这样的困扰:

对话越来越长,AI 的记忆力却越来越差。明明前几轮说过的重要内容,突然就”消失”了。你怀疑是上下文窗口不够用,但又不知道该怎么配置那些神秘的参数——reserveTokensFloorsoftThresholdTokensmaxHistoryShare……

更让人困惑的是,官方文档说 Memory Flush 会在压缩之前触发,但实际测试时,两者几乎同时发生。是文档写错了,还是你配置错了?

这篇文章,就是来帮你解开这些困惑的。


01. 为什么上下文会”爆满”?

在使用 OpenClaw 管理大模型会话时,每一条消息都会占用模型的 context window(上下文窗口)。不同模型的上下文窗口大小不同:

模型
上下文窗口
GPT-4
128K
MiniMax-M2.7
200K
Claude
200K
本地小模型
32K

当对话越来越长,上下文会逐渐逼近模型的 context window 上限。这时候,OpenClaw 需要做两件事:

  1. 1. 压缩历史对话(Compaction):把旧消息压缩成摘要,释放空间
  2. 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 = 200KreserveTokensFloor = 80KsoftThresholdTokens = 4K 为例:

事件
计算
触发点
Memory Flush
200K – 80K – 4K
116K
Preflight Compaction
200K – 80K – 4K
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
压缩后至少保留的空间
contextWindow × 40%
softThresholdTokens
Memory Flush 的提前量
contextWindow × 15-25%
maxHistoryShare
压缩后历史最多占比
0.3
recentTurnsPreserve
最近几轮对话不压缩
5

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. 配置对照速查表

contextWindow
reserveTokensFloor
softThresholdTokens
说明
32K
8K
8K
小窗口,间距要合理
128K
40K-50K
20K-30K
中等窗口
200K
80K
30K-50K
大窗口(MiniMax-M2.7)

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

你好,我是慧织罗兰

世间万物终将消逝,某些价值、情感、美好的事物却能够脱离时间而永远存在

让生命不断追求生活的意义