# 三行速读

  1. 压缩不是删历史,而是重排历史:热数据留在窗口、冷数据落盘。
  2. 三层策略(持久化 / 微压缩 / 摘要压缩)要配合使用才稳定。
  3. 目标是 “可继续执行”,不是 “文本最短”。

# 先修知识

  • 已理解 s05 的上下文预算概念。
  • 会区分 “原始证据保存” 和 “模型输入简化” 两件事。

# 读完后你应该能做到(可检验清单)

# 本篇要解决什么

长任务里,工具输出会迅速堆满上下文。模型不是无限窗口,超过阈值后就会出现重复、遗忘、偏航等问题。

s06 的目标是:在不丢关键线索的前提下,把活跃上下文保持在可工作范围内。

# 用一个类比先理解

像整理工作台:

  • 常用工具放手边(最近结果);
  • 大件资料放档案柜(落盘文件);
  • 超长历史做摘要便签(summary compact)。

不是把东西扔掉,而是分层收纳。

# 为什么这一步必须现在做

如果没有压缩机制,后面所有高级能力都会被上下文预算拖垮。先解决 “能长期跑”,再谈 “跑得更复杂”。

# 关键代码怎么读

# 1) 压缩参数与状态

1
2
3
4
5
6
7
8
9
CONTEXT_LIMIT = 50000
KEEP_RECENT_TOOL_RESULTS = 3
PERSIST_THRESHOLD = 30000

@dataclass
class CompactState:
has_compacted: bool = False
last_summary: str = ""
recent_files: list[str] = field(default_factory=list)

这些参数决定压缩策略的力度, CompactState 记录压缩后的连续性线索。

# 2) 大输出落盘

1
2
3
4
5
def persist_large_output(tool_use_id: str, output: str) -> str:
if len(output) <= PERSIST_THRESHOLD:
return output
stored_path = TOOL_RESULTS_DIR / f"{tool_use_id}.txt"
...

重点是 “保留全量,缩短回写”。上下文里放预览,原文在文件中可追溯。

# 3) 微压缩老 tool_result

1
2
3
def micro_compact(messages: list) -> list:
...
block["content"] = "[Earlier tool result compacted ...]"

只保留最近热数据,让模型把算力集中在当前决策上。

# 4) 全量摘要压缩

1
2
3
4
def compact_history(messages: list, state: CompactState, focus: str | None = None) -> list:
transcript_path = write_transcript(messages)
summary = summarize_history(messages)
return [{"role": "user", "content": "..." + summary}]

先落 transcript,再生成可续跑摘要,这是 “可回放 + 可继续” 的组合。

# 你可以怎么复现

  1. 让 agent 连续执行多次大输出命令。
  2. 观察 .task_outputs 是否按预期落盘。
  3. 检查压缩后模型是否仍能连续推进任务。

# 常见误区

  • 误区 1:把压缩当删除历史。
  • 误区 2:只做摘要不落原文,导致后续无法追查。
  • 误区 3:压缩阈值写死且不监控,难以调优。

# 一句话总结

s06 的价值是把 “上下文焦虑” 变成 “分层存储策略”,让系统能稳定跑长任务。

# 补充解读:s06 的三层压缩如何配合

很多人第一次实现 compact 会只做 summary。实际更稳的做法是三层配合:持久化、微压缩、全量摘要。

# A. collect_tool_result_blocks 的作用

1
2
def collect_tool_result_blocks(messages: list) -> list[tuple[int, int, dict]]:
...

这个函数是在定位 “哪些 block 可以压缩”。它让压缩更精准,不会误伤普通文本消息。

# B. track_recent_file 为什么要维护最近文件

1
2
3
4
def track_recent_file(state: CompactState, path: str) -> None:
...
if len(state.recent_files) > 5:
state.recent_files[:] = state.recent_files[-5:]

压缩后模型容易忘 “刚刚在哪些文件工作”。保留最近文件列表能显著提高续跑准确性。

# C. write_transcript 是回放保障

1
2
3
def write_transcript(messages: list) -> Path:
...
handle.write(json.dumps(message, default=str) + "\n")

这是工程上非常关键的一步:压缩前先留原始证据。后续出现异常时可以回放,而不是只能看摘要猜历史。

# D. compact 触发后的最小续跑消息

1
2
3
4
return [{
"role": "user",
"content": "This conversation was compacted ...\n\n" + summary,
}]

这相当于 “重新开局但带着摘要说明书”。它不是回到零,而是回到 “足够继续” 的最小状态。

# 进阶练习

  1. 调整 KEEP_RECENT_TOOL_RESULTS ,比较信息完整性与上下文体积。
  2. persist_large_output 增加 hash 标识,方便对照原始输出文件。
  3. 对比 “仅 summary” 与 “三层压缩” 在长任务成功率上的差异。

# 你应该带走的结论

  • 压缩不是删历史,是重排历史。
  • 可回放和可继续必须同时保证。
  • compact 的目标是维持执行连续性,不是追求最短文本。

# 统一术语口径(本章)

  • Micro Compact :对较旧工具结果做轻量占位压缩。
  • Summary Compact :对全会话做摘要压缩以续跑。
  • Persisted Output :将大体量输出落盘并在上下文里仅放预览。

# 章节衔接(从易到难)

  • 本章解决 “能否长期稳定跑”。
  • 下一章 s07 进入 “执行意图在安全管道里如何被决策”。