Lesson 06 · 记忆

上下文满了,学会砍

「The agent can forget strategically and keep working forever.」策略性遗忘 = 工程能力。

⏱ 약 12 분 · 📝 3 개 인터랙티브 컴포넌트 · 🧑‍💻 기반 shareAI-lab · s06_context_compact.py

为什么要 compact?

agent 跑久了,messages[] 会膨胀:每个 read_file 回几千 token、每个 bash 回几百、每轮对话还有模型的思考文字。跑 50 轮,context 能塞到 100K+。两个后果:

  • 碰到模型上限:到了窗口大小就崩,或者每一次 API 调用价格线性上涨。
  • 注意力稀释:现在手头的任务淹没在 30 轮前的无关 tool_result 里,模型开始走神。

s06 的思路:让 agent 主动遗忘不重要的内容,但保留关键状态。三层机制,从轻到重。

Layer 1 · micro_compact(每轮静默运行)

最便宜的一层。每次 LLM 调用前跑一遍,把超过 3 个的旧 tool_result 替换成占位符:

# 第 10 轮往前,大部分 tool_result 变成:
{
  "type": "tool_result",
  "tool_use_id": "toolu_01A",
  "content": "[Previous: used bash]"   # 从几千字符缩到几十
}

有个特例:read_file 的结果不压缩。为什么?因为 read 的输出是参考资料,压了模型就得重读一遍,反而更贵。

PRESERVE_RESULT_TOOLS = {"read_file"}  # 永不压缩

看 micro_compact 按 turn 吃掉旧结果

下面按步骤模拟 10 轮交互,每一轮前让 micro_compact 跑一次。看 messages[] 里旧的 tool_result 变成 [Previous: ...],但最近 3 个保持原样。

Layer 2 · auto_compact(超过阈值触发)

即使 micro 一直跑,累到一定规模还是会爆。s06 设了个阈值(默认 50000 token):

  1. 估算 token 数 len(str(messages)) // 4(粗糙但够用)。
  2. 超过阈值 → 把完整 transcript 写盘到 .transcripts/transcript_TIMESTAMP.jsonl(留底)。
  3. 让 LLM 给整段对话写一个 summary。
  4. messages 整个替换成一条 "[compressed] SUMMARY..."

代价很明显——丢失了具体的工具输出、对话语气,只剩提纲。但 agent 能接着往下干,这是核心收益。

Layer 3 · 模型自己调 compact tool

auto_compact 是 harness 自动触发的,模型不知道。Layer 3 反过来:给模型一个 compact 工具,让它主动要求压缩——比如觉得前面的探索已经没用、要开新阶段。

模型调用:

tool_use("compact", focus="keep the API design decisions")

触发和 auto 一样,但能带一个 focus 参数告诉总结时重点保留什么。实战里非常实用——模型知道哪些是 "已结束的小任务",比 harness 的启发式更准。

哪层合适?判断题

下面几个场景,决定 micro / auto / manual 哪个触发更合理。

Interactive

Widget 1 · Micro Compact · 看 tool_result 按 turn 老化

Step 按步推进,观察旧 tool_result 如何被替换成 [Previous: used X],而最近 3 个保持完整。read_file 永不压缩(绿色高亮)。

Turn: 0 · Tokens: ~0
Interactive

Widget 2 · Threshold Simulator · token 上去后哪层被触发

拖动滑块改 token 数,看三层中哪层活跃。

3000
Interactive

Widget 3 · 哪层合适 · 6 个场景判断题

每个场景选 micro / auto / manual,说说各自适合在什么时候触发。

答对 0 / 6