4.5 Compaction:上下文窗口管理

模型: claude-opus-4-6 (anthropic/claude-opus-4-6) 生成日期: 2025-02-17


Compaction(上下文压缩)是 OpenCode 中解决 LLM 上下文窗口限制的关键机制。当对话历史过长时,Compaction 会自动清理旧内容,确保对话可以持续进行。

4.5.1 为什么需要 Compaction?

衍生概念:LLM 的上下文窗口(Context Window)

每个 LLM 都有一个上下文窗口限制——它在一次请求中能处理的最大 token 数。例如:

模型
上下文窗口

Claude Sonnet

200,000 tokens

GPT-4o

128,000 tokens

Gemini Pro

2,000,000 tokens

在 Agentic Coding 场景中,上下文很容易被填满:

  • System Prompt:~2,000 tokens

  • AGENTS.md 指令:~1,000-5,000 tokens

  • 每轮对话的消息:~500-2,000 tokens

  • 每次工具调用的输出:~500-50,000 tokens(读取大文件时可能很大)

一次 10 轮的 Agent 对话,可能就消耗 50,000+ tokens。当累计 token 超过上下文窗口时,LLM 会拒绝请求或产生错误。

Compaction 的目标就是:在不丢失关键信息的前提下,压缩对话历史以腾出上下文空间

4.5.2 溢出检测算法:isOverflow()

SessionCompaction.isOverflow() 判断当前对话是否即将超出上下文窗口:

关键参数

  • COMPACTION_BUFFER = 20,000:在上下文窗口末尾预留 20K tokens 的缓冲区。这确保即使检测到溢出,也还有足够的空间让 LLM 生成最后的回复和压缩摘要。

  • reserved:实际预留空间。取 COMPACTION_BUFFER 和模型最大输出 token 的较小值。

4.5.3 Prune 策略:工具输出的渐进式清理

在触发完整的 Compaction 之前,OpenCode 会先尝试 Prune(修剪)——一种更轻量的清理方式:

Prune 算法的核心思想

  1. 从后往前遍历消息历史

  2. 保护最近 2 轮对话的所有内容

  3. 保护最近 40K tokens 的工具输出

  4. 超过保护区的旧工具输出 → 替换为 "[output truncated by compaction]"

  5. skill 工具的输出永不清理(因为 Skill 内容对后续行为至关重要)

这种策略的直觉是:旧的工具输出(比如 10 轮前读取的文件内容)很可能已经不再相关,可以安全丢弃;而最近的工具输出仍然是当前推理的依据,必须保留

4.5.4 Compaction 执行流程

如果 Prune 后空间仍不够,就会触发完整的 Compaction——用 LLM 生成一段摘要来替代旧的消息历史:

Compaction 使用的 Prompt 模板在 agent/prompt/compaction.txt 中定义。

4.5.5 Token 估算工具

由于精确的 token 计数需要使用模型的 tokenizer(分词器),OpenCode 在某些场景下使用快速估算:

这个估算值不需要精确——它只用于 Prune 策略中判断"大约"清理了多少 token。而精确的 token 数来自 LLM Provider 的响应元数据(usage 字段)。

Last updated