Context Compaction 最容易犯的第一个错误,就是把所有内容一视同仁。
但实际上,Context 里的不同信息生命周期完全不同。
第一类:绝对不能因为历史太长就随便删掉的内容
这类通常包括:
System Prompt
Safety Rules
Agent Rules
Project Rules
Current Goal
Current Task
Working Memory
用户明确的硬约束
例如:
禁止修改 tests/
不允许新增依赖
必须在 workspace 内操作
高风险 Shell 需要审批
这些不是“旧消息”。
它们是当前执行边界。
所以 Compaction 过程中不应该被当作普通历史压缩掉。
第二类:适合做 Summary 的内容
例如:
旧 Conversation
旧 Tool Result
已完成排查过程
已解决错误
历史计划
这类信息的细节不一定每轮都重要,但它们产生的结论仍然重要。
例如:
旧历史:
连续 7 个 Tool Call 才确认入口文件是 src/main.py
下一轮 Context 只需要:
已确认入口文件为 src/main.py
即可。
第三类:适合只保留最近几轮原文的内容
例如:
最近的用户补充
最近的 Tool Result
刚刚发生的错误
刚刚修改的代码片段
因为它们很可能影响下一步。
所以常见策略是:
Old Context
→ Summary
Recent Context
→ Keep Raw
第四类:可以从当前 Context 中直接移除的内容
例如:
重复 Tool Result
无关日志
已经解决且没有长期价值的错误细节
重复文件列表
低价值调试输出
注意,从当前 Context 移除,不代表从 Trace 删除。
这两层要分开。
一个实用的四层保留策略
先配合这张图看,会更容易把“保留什么、压缩什么、移出什么”理顺。左边是完整历史,中间是四层保留策略,右边则是压缩后真正送进后续推理的 Context。这样一对照,整个思路会非常直观。
![图片[1]-小节一:Context Compaction 到底压缩什么——先区分“历史细节”和“当前决策所需信息”-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1564.png)
这张图最核心的一点,是把 Compaction 从“少放一点内容”升级成了“按价值分层处理内容”。真正要保留的,是会继续影响决策的信息;真正可以压的,是那些表达冗长、但事实已经明确的历史内容。
可以先记:
P0:永远保留
System / Safety / Project Rules / Current Goal
P1:结构化保留
Working Memory / Current Task / Key Decisions
P2:压缩保留
Old Messages / Old Tool Results / Old Errors
P3:直接移出当前 Context
重复日志 / 无关输出 / 已解决低价值细节
这套分层非常适合放进 ContextBuilder。
为什么“摘要”比“截断”更稳?
这一点特别值得单独看图。很多同学一开始会觉得,既然上下文太长,那直接 messages[-20:] 不就行了吗?但问题恰恰出在这里:截断是机械删内容,压缩则是有策略地重建 Context,两者完全不是一回事。
![图片[2]-小节一:Context Compaction 到底压缩什么——先区分“历史细节”和“当前决策所需信息”-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1565.png)
从图里你会很清楚地看到,截断最容易丢掉系统规则、关键约束、早期事实和 Tool 链路;而 Summary 的目标,是把这些仍有价值的信息重新组织成更紧凑的表达。所以我们后面一直强调一句话:压缩的是表达,不是事实。
假设旧历史有:
用户要求:不要修改 tests/
Agent 已确认:入口是 src/main.py
Agent 已确认:数据库正常
Agent 已确认:requests 缺失
如果按时间截断:
只留最近 10 条
很可能删掉第一条规则。
如果做语义 Summary:
Project Constraints:
- 禁止修改 tests/
Historical Findings:
- 入口 src/main.py
- 数据库已排除
- requests 缺失是当前主要根因
关键语义仍然存在。
这就是 Compaction 真正的价值,保留“决策价值”,而不是保留“文本原样”。
一个最小压缩结构
如果你想先抓住一个“最小可用版本”,建议先看下面这张结构图。它把压缩前的长历史、compact_context() 的处理逻辑,以及压缩后的最小 Context 结构放在了一张图里,基本能把全章主线串起来。
![图片[3]-小节一:Context Compaction 到底压缩什么——先区分“历史细节”和“当前决策所需信息”-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1566.png)
这里特别要注意最后一块:Summary ≠ Working Memory。历史摘要负责保留过去发生过什么,而当前任务状态负责描述此刻正在做什么、下一步准备做什么。两者看起来都像“总结”,但职责完全不同。
from dataclasses import dataclass, field
@dataclass
class CompactSummary:
key_facts: list[str] = field(
default_factory=list
)
completed: list[str] = field(
default_factory=list
)
resolved_errors: list[str] = field(
default_factory=list
)
important_files: list[str] = field(
default_factory=list
)
decisions: list[str] = field(
default_factory=list
)
if __name__ == "__main__":
summary = CompactSummary(
key_facts=[
"项目入口为 src/main.py",
"数据库配置正常",
],
completed=[
"已复现启动错误",
"已检查 requirements.txt",
],
resolved_errors=[
"config.py 路径错误已解决",
],
important_files=[
"src/main.py",
"requirements.txt",
],
decisions=[
"继续围绕 requests 缺失排查",
],
)
print(summary)
这比直接存一大段字符串更容易后续更新和测试。
Summary 不应该复制 Working Memory
这也是一个细节。
Working Memory 是:
现在最重要的认知
Historical Summary 是:
旧历史压缩后的背景
它们有重叠,但不应该完全重复。
例如:
Working Memory:
Next Action = 修改 requirements.txt 并验证
Historical Summary:
数据库方向已排除;入口已确认;曾发生 config.py 路径错误但已解决
这样各自有价值。
















请登录后查看评论内容