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