上下文压缩
OpenCowork 如何在长对话里控制 token 使用并保留可追溯历史。
上下文压缩 / Context Compression
OpenCowork 的上下文压缩不是一个“开关”,而是一组分层策略。目标是:在尽量保留推理上下文的前提下,避免对话历史把上下文窗口撑爆。
默认策略 / Default policy
src/renderer/src/lib/agent/context-compression.ts 里定义了几个关键默认值:
| 项 | 默认值 |
|---|---|
| 最大上下文长度 | 200_000 tokens |
| Full compression 阈值 | 0.8 |
| 预留输出预算 | 20_000 tokens |
| Pre-compress 阈值 | 0.65 |
| Auto buffer | 13_000 tokens |
| Pre buffer | 20_000 tokens |
| Pre gap | 8_000 tokens |
这些值会结合具体模型的
contextLength、maxOutputTokens和模型配置动态调整。
两级压缩 / Two-stage compression
1) Pre-compress
轻量级压缩,尽量不改写结构:
- 清理过旧的工具结果
- 清理部分 thinking 内容
- 保留消息骨架和调用痕迹
- 不额外发起一次模型摘要请求
适合“还没满,但已经开始臃肿”的对话。
2) Full compress
真正触发上下文窗口回收时会做完整压缩:
- 生成压缩摘要
- 用摘要替换旧消息
- 保留最近的消息和关键边界
- 把压缩后的 transcript 放回 loop 继续执行
触发条件 / Trigger logic
压缩是否发生由运行时配置决定,而不是一个固定全局值:
shouldPreCompress(inputTokens, config)shouldCompress(inputTokens, config)
这意味着不同模型、不同 provider、不同会话会有不同的压缩触发点。
压缩产物 / Compression artifacts
压缩后,消息会携带一些元数据,便于 UI 判断是否被压缩过:
compactBoundarycompactSummary
这些元数据会帮助界面显示“这里发生过上下文回收”,避免用户误以为历史消息丢失了。
和 Agent Loop 的关系 / Relation to the loop
Agent Loop 在每一轮开始前都会检查:
- 当前输入 token 是否接近阈值
- 是否先做 pre-compress
- 是否需要 full compress
- 压缩完成后继续发送下一轮请求
因此,上下文压缩是 loop 的一部分,而不是独立后台任务。
实际建议 / Practical advice
- 长对话尽量让模型尽早总结阶段性结果
- 大段日志、长文件、重复工具输出不要无节制地堆进上下文
- 如果你正在做复杂的代码工作,建议在关键节点主动让 Agent 总结阶段结果
- 如果你发现回答开始变慢或上下文变乱,通常说明该压缩了