Context Compact - 上下文压缩与连续性保护
L06 要回答一个问题:如何在 L05 的基础上让 Agent 上下文可持续,而不丢失认知连续性?
L05 给了我们骨架:两层注入 + SkillLoader + 容错性设计。但真实 Agent 执行长任务时上下文会爆炸——读大文件、跑长命令、积累 tool_result。撞到上限就崩溃?还是压缩后丢失关键信息?怎么做?
本章讲三个机制:
| 机制 | 解决什么问题 | 核心代码 |
|---|---|---|
| 三层压缩策略 | 主动管理上下文,预防式压缩 | 大→磁盘、旧→占位、长→摘要 |
| 连续性保护 | 摘要保住关键信息,模型能继续 | 目标/已完成/文件/决定/下一步 |
| 控制权归属 | 决策成本低→Harness,高→模型 | 固定规则 vs compact工具 |
这三个机制叠加在 L05 的 Skill Loading 上,循环本身不变。理解 L06,就理解了 Agent 如何”压缩不丢失认知连续性”。
一、三层压缩策略:主动管理机制
“上下文压缩的核心,不是尽量少字,而是让模型在更短的活跃上下文里,仍然保住继续工作的连续性。”
这句话概括了 Context Compact 的本质。不是”撞到上限才压缩”,而是三层主动管理。看代码:
# Layer 1: 大结果写磁盘(立即)def persist_large_output(output): if len(output) > THRESHOLD: save_to_disk(output) return f"<persisted-output> Preview: {output[:2000]}..."
# Layer 2: 旧结果换占位符(静默)def micro_compact(messages): tool_results = collect_tool_results(messages) for result in tool_results[:-3]: # 只保留最近3个 result["content"] = "[Earlier tool result omitted]" return messages
# Layer 3: 整体过长生成摘要(阈值触发)def compact_history(messages): summary = summarize(messages) # 保住连续性5要素 return [{"role": "user", "content": f"Compacted.\n{summary}"}]三层时机不同:
| 层级 | 触发时机 | 执行者 | 保留什么 |
|---|---|---|---|
| Layer 1 | 工具输出超过阈值 | Harness(立即) | 写磁盘 + 留预览 2000 字 |
| Layer 2 | tool_result 超过 3 轮 | Harness(静默) | 占位符 + 最近 3 个完整 |
| Layer 3 | 上下文总大小超过阈值 | 模型或 Harness | 摘要(连续性 5 要素) |
压缩本质:不是删除,是换表示方式
| 误解 | 正确理解 |
|---|---|
| ”压缩就是把旧内容删掉” | 压缩是换一种表示方式保留关键信息 |
| ”撞到上限才压缩” | 三层主动管理,预防式压缩 |
| ”摘要就是简洁省字数” | 摘要保住推理链路,让模型能继续 |
压缩本质:可恢复损失 ↔ 可持续空间的权衡。所有压缩都是有损压缩,但损失可恢复——指针保留”可恢复性”,磁盘保留”内容”。
验证你的理解
Q1:三层压缩同时触发时,执行顺序是什么?为什么?
:::details 答案 执行顺序:Layer 1 → Layer 2 → Layer 3。
原因:压缩顺序原则——决策成本低、恢复成本低、影响面小优先压缩。
- Layer 1(大结果写磁盘):决策成本最低(固定阈值),恢复成本最低(磁盘有全文),影响面最小(单个 tool_result)
- Layer 2(旧结果换占位符):决策成本低(固定规则),恢复成本中等(需重新调用工具),影响面中等(多个 tool_result)
- Layer 3(整体生成摘要):决策成本高(需判断时机),恢复成本高(丢失推理细节),影响面最大(整个历史)
顺序错了会导致:Layer 3 先执行 → 摘要生成后上下文仍超限 → 无法完成压缩。 :::
二、连续性保护:摘要5要素
三层压缩解决”怎么压缩”,连续性保护解决”压缩后保留什么”。
如果摘要丢失关键信息,会发生什么?
场景:bug 调试时,已确定是新语法特性而非编码问题,压缩后丢失决策。 后果:模型偏向编码问题着手 → 重复排查错误方向 → 时间浪费。
本质:决策记录保住”为什么”,动作记录只保”做了什么”。
连续性5要素
摘要必须保住这5个要素,模型才能继续工作:
| 要素 | 内容 | 为什么重要 |
|---|---|---|
| 当前任务目标 | 用户要做什么 | 方向不偏离 |
| 已完成的关键动作 | 哪些步骤已执行 | 避免重复工作 |
| 已修改/查看过的文件 | 哪些文件被改动 | 知道当前状态 |
| 关键决定与约束 | 为什么选 A 不选 B | 决策追溯 |
| 下一步应该做什么 | 继续的方向 | 能立即恢复 |
类比:Git commit message——“为什么做这个改动”比”改了什么”更重要。
推理链路优先原则
压缩优先级:
推理链路优先 → 恢复成本 → 省空间| 优先级 | 内容 | 保留理由 |
|---|---|---|
| 最高 | 推理链路(为什么) | 决策追溯,避免方向偏离 |
| 中等 | 恢复成本高的内容 | 减少重新调用工具 |
| 最低 | 纯空间节省 | 可接受损失 |
验证你的理解
Q2:摘要丢失”关键决策”会发生什么?请举具体场景。
:::details 答案 具体场景:
Bug调试任务中,模型已经分析确认问题原因是”新语法特性不兼容”,而非”编码错误”。压缩时丢失这个决策。
后果:
- 模型恢复后偏向”编码问题”着手
- 重复排查错误方向(检查变量名、缩进、括号)
- 时间浪费,最终仍需重新分析
本质:决策记录保住”为什么”(新语法特性),动作记录只保”做了什么”(读了哪些文件)。丢失决策 → 方向偏离。 :::
三、控制权归属:决策成本决定分工
三层压缩谁来触发?Harness 还是模型?
控制权归属原则:决策成本决定控制权。
| 决策成本 | 控制权 | 示例 |
|---|---|---|
| 低(固定规则) | Harness | Layer 1/2 阈值检测,自动触发 |
| 高(时机判断) | 模型 | Layer 3 compact 工具,模型主动请求 |
Harness 控制层
Layer 1 和 Layer 2 的决策成本低:
- Layer 1:工具输出超过阈值 → 写磁盘。固定规则,不需要理解上下文。
- Layer 2:tool_result 超过 3 轮 → 换占位符。固定规则,静默执行。
Harness 的职责:执行层做固定规则,不需要模型参与。
模型控制层
Layer 3 的决策成本高:
- 需要理解上下文:何时压缩?保留什么?
- 需要判断时机:正在做关键决策时,不能压缩。
模型的职责:认知层做时机判断,通过 compact 工具主动请求。
验证你的理解
Q3:为什么 Layer 3 需要模型控制,而不是 Harness 自动触发?
:::details 答案 决策成本高,需要上下文理解。
Layer 3 摘要生成涉及:
- 时机判断:正在做关键决策时压缩会丢失推理链路
- 内容选择:保留什么取决于当前任务状态
- 连续性保护:需要理解”为什么”,不只是”做了什么”
这些决策需要模型参与——Harness 无法判断”当前是否在做关键决策”。
类比:自动驾驶分级——固定规则(车道保持)由系统做,时机判断(变道时机)由人或高阶系统做。 :::
四、特殊处理:read_file 保护
read_file 的 tool_result 有特殊保护——不压缩。
环境漂移问题
重新执行 read_file 可能读到修改后的内容:
# 第一次执行read_file("config.yaml") # 返回: "timeout: 30"
# 中间操作:修改了 config.yamledit_file("config.yaml", old="timeout: 30", new="timeout: 60")
# 重新执行(如果压缩后需要恢复)read_file("config.yaml") # 返回: "timeout: 60" ← 环境漂移!类比:MySQL 不可重复读——同一查询在不同时间返回不同结果。
read_file 特殊保护
| 工具 | 是否压缩 | 原因 |
|---|---|---|
| bash | 可以压缩 | 重新执行成本中等,结果可能变化但可控 |
| edit_file | 可以压缩 | 执行记录保住”改了什么”,不需要恢复原结果 |
| read_file | 不压缩 | 环境漂移风险 + 重新执行可能读到修改后的内容 |
权衡:加锁(阻止修改)vs 备份(保留副本)。当前设计选择备份——保留原 tool_result 不压缩。
验证你的理解
Q4:占位符为什么是”指针”而非”副本”?
:::details 答案 指针保留”可恢复性”,副本丢失”可恢复性”。
指针:
[Previous: used read_file]只指向工具名,不包含内容。全文在磁盘可恢复。副本:保留部分内容摘要。内容被截断,无法恢复完整信息。
所有压缩都是有损压缩,但指针保留了”可恢复性”的路径——需要时可以从磁盘恢复全文。
类比:Git 的
HEAD指针——指向某个 commit,不包含 commit 内容。内容在 Git 数据库可恢复。 :::
五、回顾:L06 在循环上叠加了什么
回到开头的问题:如何在 L05 的基础上让 Agent 上下文可持续,而不丢失认知连续性?
答案:
| 叠加机制 | 代码位置 | 循环的变化 |
|---|---|---|
| 三层压缩 | 工具执行后 + 上下文检查 | 不变——只是 messages 处理差异 |
| 连续性保护 | summarize() 摘要生成 | 不变——只是返回值内容策略 |
| 控制权归属 | Layer 1/2 Harness,Layer 3 模型 | 不变——只是触发机制差异 |
循环本身仍是 L01 的 while True + stop_reason + messages[]。L06 只是在”上下文管理层”叠加了压缩和连续性保护机制。
与后续课程的关系
理解 L06 后,你会发现后续课程都在 Context Compact 上叠加——循环本身始终不变:
| 课程 | 关系 |
|---|---|
| L04 Subagent | 摘要返回是压缩的特例——子 Agent 整个历史丢弃,只传摘要 |
| L05 Skill Loading | 第二层 tool_result 可压缩释放,两层注入价值在此体现 |
| L07 Permission System | 压缩后的上下文是否保留权限决策?设计权衡点 |
| L09 Memory System | 压缩解决当前会话,Memory 解决跨会话保留 |
核心洞察:Context Compact 是”可持续上下文”的机制。理解 L06,就理解了 Agent 如何”压缩不丢失认知连续性”。后续课程都在扩展压缩机制——权限保留、跨会话记忆。
六、心智模型升级:从 L0 到 L2
读完这篇文章,你的理解经历了怎样的升级?
L06 核心概念的理解升级路径
| 概念 | L0(表面) | L1(关联) | L2(深层) |
|---|---|---|---|
| 三层压缩 | ”大存旧替长摘要" | "主动管理,预防式压缩" | "压缩顺序原则——决策成本低、恢复成本低、影响面小优先。类比 TCP 拥塞窗口:扩张有触发,收缩有衰减” |
| 连续性保护 | ”保留5要素" | "摘要保住关键信息" | "推理链路优先——保住’为什么’(决策追溯),丢弃’做了什么’(动作记录)。丢失决策 → 方向偏离 → 重复错误” |
| 控制权归属 | ”Harness控制部分" | "固定规则vs模型请求" | "决策成本原则——低成本Harness(固定阈值),高成本模型(时机判断)。类比自动驾驶分级:车道保持(系统)vs 变道时机(人)“ |
| 环境漂移 | ”重新执行结果不同" | "read_file特殊保护" | "MySQL不可重复读类比——重新执行读到修改后内容。权衡:加锁(阻止修改)vs 备份(保留副本)。当前选备份” |
如何检验你达到了 L2?
用这个问题自测:
如何反驳”只要能干活,压缩随便做,省空间最重要”?
:::details L2 层级回答 反驳逻辑:压缩优先级 = 推理链路优先 → 恢复成本 → 省空间。
三个层面:
- 推理链路优先:丢失关键决策 → 方向偏离 → 重复错误排查 → 时间浪费。省空间换来的是认知偏移风险。
- 恢复成本:频繁压缩 → 恢复成本高(重新调用工具)→ 效率下降。省空间换来的是重新执行开销。
- 压缩本质:是认知连续性保护,不是删历史。目标是”可恢复损失 ↔ 可持续空间”的平衡,不是极端省钱。
正确做法:三层主动管理,保住连续性5要素,推理链路优先。 :::
本章目标:让每个核心概念都从 L0 升级到 L2。理解 L06,不只是记住代码,而是掌握”如何在循环上压缩不丢失连续性”的设计原则。
七、复习可视化
三层压缩流程
控制权归属决策
连续性5要素保护
环境漂移示意
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!