你一定看過這種場景。
一個人本來還在很認真地做事,突然被打斷一下,回頭又接著做。理論上他應該記得自己剛剛在幹嘛,但實際上常常不是這樣。他會先停住,看看眼前,然後花幾秒甚至幾分鐘重新把腦袋接回來。
AI Agent 也是。
它有時候不是「真的忘記」,而是:
sessionId
所以第 10 天我想看的,就是這個很現實的問題:
Agent 為什麼會忘記自己在做什麼?
這一篇我想把它寫成「OpenClaw 怎麼處理任務中的連續性問題,以及它為什麼有時候還是會看起來像失憶」。
sessionId、transcript、session store 各自管什麼?/new、daily reset、idle reset 會讓 Agent 看起來像失憶?OpenClaw 其實不是把「正在做的事」放在一個地方。
它把狀態拆成幾個層次:
sessionId、最後活動時間是什麼、是否已經 reset、一些可重用的 metadataMEMORY.md、daily memory、dreaming promotion 結果Agent 會忘記自己在做什麼,通常就是這幾層沒有接好:
換句話說,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.
這裡就直接點出一個「為什麼會看起來像忘記」的根源:
所以如果你看到 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,讓下一輪至少還有地方可以找。
這是最核心的一句。
很多時候 Agent 不是不知道自己接了什麼事,而是不知道:
如果這些狀態沒有穩穩地留在 transcript、session store、memory 或 context 裡,下一輪就很容易重新開始。
看起來像失憶,本質上其實是狀態沒有接續。
/new、daily reset、idle reset 都像把工作桌換掉你可以把 reset 想成換桌子。
不是把腦袋洗掉,而是工作環境被切掉了。
當 /new 或 /reset 發生,OpenClaw 會建立新的 sessionId。
這表示下一輪雖然還是在同一個 agent 上,但已經是新的 session 了。
如果上一段工作的關鍵線索沒有寫進 memory,新的 session 就只能靠能被帶過去的那部分上下文恢復。
這也是為什麼第 8 天講的 startupContext 很重要。
它就是拿來把上一段的 daily memory 先補回來,避免新桌子一開就完全空白。
這點很像人類直覺會誤判的地方。
Heartbeat、cron、exec 這些系統事件會改 session metadata,但不代表任務真的往前走。
OpenClaw 明確說了:
換句話說,系統有在動,不代表任務有在前進。
這就是 Agent 容易自己騙自己的地方:畫面很忙,實際上沒進度。
compaction 不是壞東西,但它會改變「模型接觸到什麼」。
舊訊息被壓成摘要後,細節就不再是原文了。
這表示:
如果 summary 寫得好,Agent 就能繼續做事。
如果 summary 寫得不好,Agent 就會看起來像「忘了剛剛在幹嘛」。
所以 compaction 的品質,直接決定 Agent 的連續性。
這是很多人最容易混淆的地方。
OpenClaw 的 transcript 是 append-only 的,歷史都在。
但模型每一輪看到的是被組裝過的 prompt,不是整份檔案。
所以真正決定 Agent 記不記得的,不是「歷史有沒有存」,而是:
OpenClaw 其實在告訴我們一件很工程的事:
長任務不能只靠模型「自己記得」。
你要讓它把狀態分層存:
這樣任務才不會一長就散。
如果換成單一大腦式做法,也就是全都靠模型自己記住,短期可能看起來比較簡單。
但長任務一多,模型就會開始:
這就是為什麼 OpenClaw 不是把「記得自己在做什麼」交給模型單挑,而是用 session、transcript、memory、compaction 一起接力。
sessionId、transcript、context、memory 各管不同層次的連續性/new、daily reset、idle reset 都會切開 session,沒有補接就像失憶第 9 天我們看的是上下文太長時,OpenClaw 怎麼分層處理。
第 10 天再往前一點,問題就更具體了:
如果 Agent 真的把自己做過的事情忘掉了,它其實是在忘哪一層?
下一篇我想接著看:
子代理登場,讓工作不再只有一個人扛
因為當單一 Agent 容易忘事,下一個自然的方向,就是把任務拆給更小、也更專注的角色。