概述

Compaction 是 OpenClaw 在会话接近模型上下文窗口限制时,将旧消息摘要化以便对话继续的机制。摘要持久化写入 session transcript,完整历史始终保留在磁盘。


触发时机

自动触发(两种情况)

1. Overflow 恢复:模型返回 context overflow 错误时,立即压缩并重试。

识别的错误签名:

  • request_too_large
  • context length exceeded
  • input exceeds the maximum number of tokens
  • input token count exceeds the maximum number of input tokens
  • input is too long for the model
  • ollama error: context length exceeded

2. 阈值维护:一次成功 turn 结束后,当:

contextTokens > contextWindow - reserveTokens
  • contextWindow:模型上下文窗口大小
  • reserveTokens:为提示词和下一次模型输出预留的 headroom(默认 floor 20000 tokens)

3. 文件大小守卫(可选):当 maxActiveTranscriptBytes 设置且 active transcript 文件达到该大小时,在下一次 turn 开始前触发本地压缩(需同时开启 truncateAfterCompaction)。

4. 中途预检(可选,默认关闭):midTurnPrecheck.enabled: true 时,在工具结果追加后、下一次模型调用前估算 prompt 压力,若不够则中止当前提交并触发压缩重试。

手动触发

/compact
/compact Focus on the API design decisions

手动压缩若设置了 keepRecentTokens,会保留最近 tail;否则作为硬检查点,从新摘要重新开始。


压缩流程

触发压缩
  │
  ├─ [可选] Memory Flush(静默 turn,写记忆文件)
  │
  ├─ 分割 transcript 为压缩块
  │   └─ 保持 tool call + toolResult 配对(不拆散)
  │
  ├─ LLM 摘要旧对话(或调用自定义 provider)
  │
  ├─ 写入 compaction 条目到 transcript(含 firstKeptEntryId + tokensBefore)
  │
  └─ [若 truncateAfterCompaction] 创建新的 successor transcript
      └─ 旧 transcript 归档为 checkpoint

压缩后,后续 turn 看到的是:

  • 压缩摘要
  • firstKeptEntryId 之后的消息(保持完整)

Memory Flush(压缩前记忆写入)

压缩前,OpenClaw 会运行一个静默 turn,提醒 Agent 把重要上下文写入记忆文件,防止上下文丢失。

工作机制:

  1. 监控 session 上下文用量
  2. 达到”软阈值”(低于 Pi 压缩阈值)时,向 Agent 发送静默”立即写记忆”指令
  3. 使用 NO_REPLY token 抑制输出,用户不可见
  4. 每个压缩周期只运行一次(通过 sessions.json 中 memoryFlushAt 追踪)

跳过条件:

  • CLI backend(非嵌入式 Pi session)
  • workspace 为只读(workspaceAccess: "ro" 或 "none")

配置项(agents.defaults.compaction.memoryFlush):

配置项默认值说明
enabledtrue是否开启
model继承会话模型指定 flush turn 使用的模型(精确,不继承 fallback chain)
softThresholdTokens4000触发 flush 的软阈值(距压缩阈值的 headroom)
prompt内置flush turn 的用户消息
systemPrompt内置flush turn 的额外系统提示

Successor Transcript(后继 transcript)

开启 truncateAfterCompaction: true 后,压缩不再原地重写 transcript,而是:

  1. 从压缩摘要 + 保留状态 + 未摘要 tail 创建新的 active successor transcript
  2. 旧 transcript 保留为归档 checkpoint

额外效果:successor transcript 会去除短重试窗口内的重复长用户 turn,防止 channel 重试风暴被带入下一个 active transcript。

注意:maxActiveTranscriptBytes 文件大小守卫需要 truncateAfterCompaction: true 才能生效。


标识符保留策略

压缩摘要默认保留不透明标识符(identifierPolicy: "strict")。

值行为
"strict"(默认)保留所有 ID、哈希、配置键等
"off"不做特殊处理
"custom"配合 identifierInstructions 自定义

可插拔压缩 Provider

插件可通过 registerCompactionProvider() 注册自定义压缩 provider:

{
  "agents": {
    "defaults": {
      "compaction": {
        "provider": "my-provider"
      }
    }
  }
}
  • 设置 provider 会自动强制 mode: "safeguard"
  • Provider 失败或返回空结果时,自动回退到内置 LLM 摘要
  • Abort/timeout 信号会重新抛出(不吞掉),尊重调用方取消

Safeguard 模式默认开启摘要质量审计(qualityGuard.enabled: true),可设为 false 跳过。


完整配置参考

{
  agents: {
    defaults: {
      compaction: {
        // 压缩模型(不设则用会话模型)
        model: "openrouter/anthropic/claude-sonnet-4-6",
 
        // 标识符保留策略
        identifierPolicy: "strict",
 
        // 压缩前 memory flush
        memoryFlush: {
          enabled: true,
          model: "ollama/qwen3:8b",       // 可选:用本地模型做 flush
          softThresholdTokens: 4000
        },
 
        // 后继 transcript(防止文件无限增长)
        truncateAfterCompaction: true,
 
        // 文件大小守卫(需 truncateAfterCompaction: true)
        maxActiveTranscriptBytes: "20mb",
 
        // 中途预检(默认关闭)
        midTurnPrecheck: { enabled: false },
 
        // 保留最近 N tokens(手动 /compact 时生效)
        keepRecentTokens: 20000,
 
        // reserveTokens 安全 floor(默认 20000)
        reserveTokensFloor: 20000,
 
        // 压缩时通知用户
        notifyUser: false,
 
        // 自定义 provider(设置后强制 safeguard 模式)
        provider: "my-provider"
      }
    }
  }
}

Compaction vs Pruning

CompactionSession Pruning
做什么摘要旧对话裁剪旧工具结果
是否持久化是(写入 transcript)否(仅内存,per-request)
范围整个对话仅工具结果
触发时机接近 context limit每次 LLM 调用前
互补关系两者互补:Pruning 减少工具输出膨胀,延缓 Compaction 触发

可观测性

# CLI 状态
openclaw status                    # 显示 Compactions: <count>
openclaw sessions --json           # 查看 compactionCount 字段
 
# 日志(verbose 模式)
# 🧹 Auto-compaction complete
# embedded run auto-compaction start / complete
 
# 会话内
/status                            # 上下文用量、压缩次数

sessions.json 中的相关字段:

  • compactionCount:该 session key 的自动压缩次数
  • memoryFlushAt:最近一次 memory flush 的时间戳
  • memoryFlushCompactionCount:最近一次 flush 时的压缩计数

常见问题

问题原因解决方案
压缩太频繁模型 context window 小 / 工具输出大启用 session pruning
压缩后上下文感觉陈旧摘要丢失细节/compact Focus on <topic> 或启用 memory flush
需要全新开始—/new 开启新 session(不压缩)
reserveTokens 过高导致比必要更早触发压缩调低 reserveTokensFloor 或检查模型 context window
Silent turn 泄漏NO_REPLY token 未正确抑制确认构建版本包含流式抑制修复

相关页面

  • session-pruning — 工具结果裁剪(轻量级补充,与 Compaction 互补)
  • memory — Memory 持久化与 flush 机制
  • context — 上下文构建机制
  • context-engine — 可插拔上下文引擎
  • session — 会话管理与生命周期