你應該看過這種場景。
一開始大家都只是在講重點,會議很快、很清楚、很像有在往前走。可是聊到後面,歷史開始堆上來,前因後果越補越多,文件、截圖、工具輸出、舊決策、臨時修正全部擠進來。到最後不是沒資訊,而是資訊太多,誰都不知道現在到底該看哪一段。
AI Agent 也一樣。
當它越做越多,問題就不是「有沒有記住」而已,而是:
這就是第 9 天要看的事:
上下文太長怎麼辦?OpenClaw 的取捨
我想把這篇寫成「OpenClaw 怎麼在不丟失關鍵資訊的前提下,讓模型視窗維持可用」。
compaction 和 pruning 的差別是什麼?MEMORY.md、daily memory、tool results 各自該怎麼進場?OpenClaw 對 context 的理解很直接:
Context = system prompt + conversation history + tool calls/results + attachments
也就是說,只要模型看得到,幾乎都算 context。
這裡最重要的不是名詞,而是邏輯:
所以 context 是即時消耗品,memory 是可重載資產。
如果把這兩個混在一起,就很容易以為「只要有寫進記憶就沒問題」,但其實不是。記憶檔案可以存在磁碟上,context 卻還是會被 token window 卡住。
OpenClaw 的做法是把壓力拆成三種:
然後分別用不同機制處理它們:
這樣看起來比較複雜,但其實更接近真實問題。
因為「太長」不是一種單一病因,而是很多種肥胖一起發生。
先看最核心的定義。OpenClaw 明講了:context 就是這一輪送給模型的一切。
📄 文件:
docs/concepts/context.md:10-16
"Context" is **everything OpenClaw sends to the model for a run**. It is bounded by the model's **context window** (token limit).
Beginner mental model:
- **System prompt** (OpenClaw-built): rules, tools, skills list, time/runtime, and injected workspace files.
- **Conversation history**: your messages + the assistant's messages for this session.
- **Tool calls/results + attachments**: command output, file reads, images/audio, etc.
這段很值得反覆看,因為它直接把 context 的邊界畫清楚了。
接著看系統 prompt 會被塞什麼。
📄 文件:
docs/reference/token-use.md:14-47
OpenClaw assembles its own system prompt on every run. It includes:
- Tool list + short descriptions
- Skills list (metadata only; instructions load on demand with `read`)
- Self-update instructions
- Workspace + bootstrap files (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md` when new, plus `MEMORY.md` when present)
- Time (UTC + user timezone)
- Reply tags + heartbeat behavior
- Runtime metadata (host/OS/model/thinking)
這裡的重點是:
MEMORY.md 會進 system promptmemory/*.md 不會像 bootstrap 那樣每次全塞也就是說,OpenClaw 不是只有在聊天內容上做取捨,它連「系統自己要先說多少話」都要控制。
再看 daily memory 和 startupContext 的界線。
`memory/*.md` daily files are not part of the normal bootstrap prompt; they stay on-demand via memory tools on ordinary turns. Reset/startup model runs can prepend a one-shot startup-context block with recent daily memory for that first turn.
這句幾乎就是整篇的核心之一。
意思很簡單:
這就避免了最常見的問題:為了保留歷史,把每一輪都塞到快爆。
再看 compaction。
📄 文件:
docs/concepts/compaction.md:9-9
Every model has a context window: the maximum number of tokens it can process. When a conversation approaches that limit, OpenClaw **compacts** older messages into a summary so the chat can continue.
📄 文件:
docs/concepts/compaction.md:13-15
1. Older conversation turns are summarized into a compact entry.
2. The summary is saved in the session transcript.
3. Recent messages are kept intact.
也就是說,compaction 不是刪記錄,而是把舊對話壓縮成可延續的摘要。
這點很重要,因為它跟 pruning 不一樣。
Session pruning trims **old tool results** from the context before each LLM call. It reduces context bloat from accumulated tool outputs ... without rewriting normal conversation text.
| Pruning | Compaction |
| ------------------ | ----------------------- |
| Trims tool results | Summarizes conversation |
| No (per-request) | Yes (in transcript) |
| Tool results only | Entire conversation |
這裡的差別非常關鍵:
再看壓縮前的保護機制。
Before compacting, OpenClaw automatically reminds the agent to save important notes to memory files. This prevents context loss.
Before compaction, OpenClaw can run a **silent memory flush** turn to store durable notes to disk.
這其實是在說同一件事:
這是很務實的順序,因為壓縮最怕的就是把剛講到、但還沒保存的關鍵資訊一起折掉。
最後補一個更硬的實作細節:OpenClaw 還有 maxActiveTranscriptBytes 這種前置保護。
When `agents.defaults.compaction.maxActiveTranscriptBytes` is set, OpenClaw triggers normal local compaction before a run if the active JSONL reaches that size.
這表示它不只等 token 爆掉才處理,連本地 transcript 變太大也會提前拉警報。
這是最容易搞混的地方。
記憶可以存檔,context 不行。
模型每一輪看到的都是當下的 prompt 包裝,這包東西太大,就會燒更多 token,甚至直接超過 window。
所以 context 管的是「這次能不能塞得下」,不是「這些東西值不值得長期保存」。
很多人會直覺覺得:既然模型常常忘東忘西,那就把更多規則塞進 system prompt。
這聽起來合理,但實際上很容易過頭。
因為 system prompt 是每一輪都會被送進去的東西。你每多塞一段,都是每一輪都在付費、都在佔空間。
所以 OpenClaw 才會把 MEMORY.md 保持在「精選摘要」層,而不是讓它長成一本百科全書。
這個比喻我覺得蠻準。
如果你只做 pruning,不做 compaction,對話歷史還是會一直長大。
如果你只做 compaction,不清工具結果,工具輸出還是會把 prompt 撐爆。
所以兩者是互補,不是替代。
這句是我對它設計最深的感受。
很多系統在面對 context 壓力時,第一反應是把東西藏起來。
OpenClaw 比較像在做維持秩序:
它不是想把所有資訊都永久留住,而是想讓「還在工作中的資訊」保持可用。
因為 compaction 是一種整理,不是補救。
你如果先壓縮,再回頭想「欸剛剛那個偏好好像很重要」,通常就晚了。
所以 OpenClaw 會先做 memory flush,讓重要內容先進檔案,再放心去做摘要。
這個順序很像你整理筆記時先把待辦寫到正式清單,再把舊草稿丟進歸檔箱。
我覺得這是最值得記住的一點。
如果你把所有東西都塞進一個層,遲早會長到失控。
但如果你把東西分層:
那上下文就比較不會亂成一團。
OpenClaw 的每個機制,說穿了都在幫你做一件事:讓不同生命週期的資訊待在不同地方。
memory/*.md 不會每輪亂入,避免 bootstrap 過肥如果換成最偷懶的做法,就是什麼都不分:
短期看起來好像最簡單,長期就是 token 先死。
startupContext 只在 bare /new、/reset 的第一輪補最近 daily memoryMEMORY.md 是長期底座,memory/*.md 平常不直接進 bootstrap第 8 天我們已經把短期記憶和長期記憶的上場順序排開了。
第 9 天再往前一步,就會碰到更現實的問題:
不是所有東西都該留,也不是所有東西都該摘要。
有些東西應該立刻清掉,有些東西應該先壓縮,有些東西則應該先寫進記憶。
下一篇我想接著看:
Agent 為什麼會忘記自己在做什麼?
因為當上下文夠長,真正危險的常常不是「沒資訊」,而是「資訊太多,反而忘了現在到底要做哪一步」。