iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0

開場故事

你一定看過這種場景。

一個人本來還在很認真地做事,突然被打斷一下,回頭又接著做。理論上他應該記得自己剛剛在幹嘛,但實際上常常不是這樣。他會先停住,看看眼前,然後花幾秒甚至幾分鐘重新把腦袋接回來。

AI Agent 也是。

它有時候不是「真的忘記」,而是:

  • 前一輪做的事情沒有落到正確的狀態層
  • 中間被 compaction 摘要掉了
  • session reset 讓它換了一個新 sessionId
  • 工具輸出太多,真正的目標反而被淹沒
  • 上一輪的 context 根本沒進到下一輪

所以第 10 天我想看的,就是這個很現實的問題:

Agent 為什麼會忘記自己在做什麼?

這一篇我想把它寫成「OpenClaw 怎麼處理任務中的連續性問題,以及它為什麼有時候還是會看起來像失憶」。

今天要解的問題

  • Agent 的「正在做什麼」到底存在哪一層?
  • sessionId、transcript、session store 各自管什麼?
  • 為什麼 /new、daily reset、idle reset 會讓 Agent 看起來像失憶?
  • compaction 是怎麼保留連續性、又怎麼讓細節消失的?
  • 為什麼系統事件不算真正的「還在做事」?
  • OpenClaw 用什麼方法讓 Agent 不至於完全忘掉進度?

架構總覽

OpenClaw 其實不是把「正在做的事」放在一個地方。
它把狀態拆成幾個層次:

  1. Session store:這一條對話目前是哪個 sessionId、最後活動時間是什麼、是否已經 reset、一些可重用的 metadata
  2. Transcript:實際的對話歷史,包含訊息、工具呼叫、工具結果、compaction summary
  3. Context:這一輪真的送進模型的內容
  4. Memory:可以跨 session 保存的東西,例如 MEMORY.md、daily memory、dreaming promotion 結果

Agent 會忘記自己在做什麼,通常就是這幾層沒有接好:

  • transcript 還在,但 context 沒帶上
  • transcript 被 compaction 了,但 summary 沒寫出任務目標
  • session reset 了,但沒有把上一段的狀態交接好
  • session store 還有記錄,但下一輪根本沒看那個欄位

換句話說,OpenClaw 的「忘記」不是單一 bug,而是多層狀態協調失敗。

這也是為什麼它要把 agent loop、session lifecycle、compaction、memory flush 分開處理。

原始碼節錄

先看 agent loop 的骨架。OpenClaw 很明白地把一個 turn 拆成幾個步驟。

📄 文件:docs/concepts/agent-loop.md:9-11

The agent loop is the serialized, per-session run that turns a message into
actions and a reply: intake, context assembly, model inference, tool
execution, streaming, persistence.

📄 文件:docs/concepts/agent-loop.md:20-20

1. `agent` RPC validates params, resolves the session (`sessionKey`/`sessionId`), persists session metadata, and returns `{ runId, acceptedAt }` immediately.
2. `agentCommand` runs the turn: resolves model + thinking/verbose/trace defaults, loads the skills snapshot, calls `runEmbeddedAgent`, and emits a fallback lifecycle end/error if the embedded loop did not already emit one.
3. `runEmbeddedAgent`: serializes runs via per-session and global queues, resolves model + auth profile, builds the OpenClaw session, subscribes to runtime events, streams assistant/tool deltas, enforces the run timeout, and returns payloads plus usage metadata.
4. `subscribeEmbeddedAgentSession` bridges runtime events to the `agent` stream.
5. `agent.wait` waits for lifecycle end/error on a `runId`.

這段很重要,因為它其實把「記得自己做到哪」拆成了兩個不同問題:

  • 當前這一輪怎麼跑完
  • 跑完之後,下次怎麼接回來

OpenClaw 不是假設模型會自己記住。
它是靠 serialized run + session state + transcript 來維持連續性。

再看 session 的生命週期。

📄 文件:docs/concepts/session.md:69-69

Sessions are reused until they expire under `session.reset`:

- **Daily reset** (default `mode: "daily"`) - new session at a configured local hour
- **Idle reset** (`mode: "idle"`) - new session after `session.reset.idleMinutes` of inactivity
- **Manual reset** - type `/new` or `/reset` in chat

📄 文件:docs/concepts/session.md:82-82

When both daily and idle resets are configured, whichever expires first wins.
Heartbeat, cron, exec, and other system-event turns may write session metadata, but those writes do not extend daily or idle reset freshness.

這裡就直接點出一個「為什麼會看起來像忘記」的根源:

  • session 不是永遠活著
  • 它有 daily / idle 壽命
  • 系統事件不會幫它續命

所以如果你看到 Agent 突然換了一個 session,很多時候不是它故意翻臉,而是 session lifecycle 已經切開了。

再看 transcript 這層。

2. **Transcript (`<sessionId>.jsonl`)** - append-only, tree-structured (entries have `id` + `parentId`). Stores the conversation, tool calls, and compaction summaries; rebuilds model context for future turns.
Compaction summarizes older conversation into a persisted `compaction` entry in the transcript and keeps recent messages intact. After compaction, future turns see the compaction summary plus messages after `firstKeptEntryId`.

這裡就很像人在記會議紀錄。

只要 transcript 還在,理論上就能接回來。
但問題是模型每輪不是直接讀整份 transcript,而是讀當下被組裝出來的 context。

所以「資料存在」不等於「模型這一輪還看得到」。

最後看 memory flush。

Before compaction, 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 知道一件事:

有些「正在做的事」不該只活在 transcript 裡,因為 transcript 會被壓縮。

所以它先把重要狀態落到 memory,讓下一輪至少還有地方可以找。

白話拆解

1. Agent 不是忘記任務,而是忘記「任務狀態」放在哪

這是最核心的一句。

很多時候 Agent 不是不知道自己接了什麼事,而是不知道:

  • 上一步做到哪裡
  • 哪個工具剛剛已經試過
  • 哪個結果已經確認
  • 哪個地方還在等外部回應

如果這些狀態沒有穩穩地留在 transcript、session store、memory 或 context 裡,下一輪就很容易重新開始。

看起來像失憶,本質上其實是狀態沒有接續。

2. /new、daily reset、idle reset 都像把工作桌換掉

你可以把 reset 想成換桌子。

不是把腦袋洗掉,而是工作環境被切掉了。

/new/reset 發生,OpenClaw 會建立新的 sessionId
這表示下一輪雖然還是在同一個 agent 上,但已經是新的 session 了。

如果上一段工作的關鍵線索沒有寫進 memory,新的 session 就只能靠能被帶過去的那部分上下文恢復。

這也是為什麼第 8 天講的 startupContext 很重要。
它就是拿來把上一段的 daily memory 先補回來,避免新桌子一開就完全空白。

3. system event 不算真的進度

這點很像人類直覺會誤判的地方。

Heartbeat、cron、exec 這些系統事件會改 session metadata,但不代表任務真的往前走。

OpenClaw 明確說了:

  • 這些事件不會延長 daily / idle freshness
  • reset rollover 會把舊 session 的 queued notices 丟掉

換句話說,系統有在動,不代表任務有在前進。

這就是 Agent 容易自己騙自己的地方:畫面很忙,實際上沒進度。

4. compaction 是救命,也是遺忘的來源

compaction 不是壞東西,但它會改變「模型接觸到什麼」。

舊訊息被壓成摘要後,細節就不再是原文了。
這表示:

  • 任務的主線還在
  • 但很多細枝末節會被整理掉

如果 summary 寫得好,Agent 就能繼續做事。
如果 summary 寫得不好,Agent 就會看起來像「忘了剛剛在幹嘛」。

所以 compaction 的品質,直接決定 Agent 的連續性。

5. transcript 還在,不代表模型真的還記得

這是很多人最容易混淆的地方。

OpenClaw 的 transcript 是 append-only 的,歷史都在。
但模型每一輪看到的是被組裝過的 prompt,不是整份檔案。

所以真正決定 Agent 記不記得的,不是「歷史有沒有存」,而是:

  • 這一輪有沒有被帶進 context
  • 這一輪有沒有被 summary 接住
  • 下一輪有沒有從對的位置續接

6. 任務越長,越需要外部狀態,不要全靠模型腦內接力

OpenClaw 其實在告訴我們一件很工程的事:

長任務不能只靠模型「自己記得」。

你要讓它把狀態分層存:

  • session store 存 session 的生命週期與 metadata
  • transcript 存完整歷史
  • memory 存值得跨 session 保存的東西
  • context 只放這一輪真的需要的內容

這樣任務才不會一長就散。

設計取捨

  • 好處是每個層次各司其職,不用把所有責任塞給模型
  • 好處是 session reset 可以很乾淨,不會把所有東西黏死
  • 好處是 transcript 能完整保留,方便追查和重建
  • 好處是 memory flush 能把重要內容提前落地
  • 代價是狀態來源很多,理解起來不如單一聊天記錄直覺
  • 代價是 summary 品質很重要,一旦 compaction 寫差了,連續性就會受影響

如果換成單一大腦式做法,也就是全都靠模型自己記住,短期可能看起來比較簡單。
但長任務一多,模型就會開始:

  • 接錯線
  • 漏掉前提
  • 重複做過的事
  • 把系統事件誤認為進度

這就是為什麼 OpenClaw 不是把「記得自己在做什麼」交給模型單挑,而是用 session、transcript、memory、compaction 一起接力。

今天的結論

  • Agent 看起來會忘記,通常不是忘了任務本身,而是任務狀態沒有被正確接續
  • sessionId、transcript、context、memory 各管不同層次的連續性
  • /new、daily reset、idle reset 都會切開 session,沒有補接就像失憶
  • 系統事件會改 metadata,但不等於任務真的往前
  • compaction 能讓長對話繼續,但也可能把細節壓成摘要
  • memory flush 的價值,就是在 compaction 前先把重要狀態落地

下一步

第 9 天我們看的是上下文太長時,OpenClaw 怎麼分層處理。

第 10 天再往前一點,問題就更具體了:

如果 Agent 真的把自己做過的事情忘掉了,它其實是在忘哪一層?

下一篇我想接著看:

子代理登場,讓工作不再只有一個人扛

因為當單一 Agent 容易忘事,下一個自然的方向,就是把任務拆給更小、也更專注的角色。


上一篇
第 9 天:上下文太長怎麼辦,OpenClaw 的取捨
下一篇
第 11 天:子代理登場,讓工作不再只有一個人扛
系列文
30 天走進 OpenClaw:一個 AI Agent 的誕生、掙扎與進化14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言