存完之後——我怎麼讓記憶學會忘
每晚四點的夢境迴圈、知識體檢、興趣畫像。收進保險庫還不夠,要會忘掉過時的才健康。
人能學會遺忘是上天賜的禮物。每一個雜訊、每一個過時的資訊都會拉扯我們對真實世界的偏差。每一個你以為的事實都具有時效性,等待後續的論據推翻。所以不要抓著不放。
—— 設計 Background Track 時一直放在桌上的一句話
上一篇盤了 Write Track——三道 gate、雙軌寫入,把對話收進保險庫。這篇接下去:收進來之後還要有人(或某條 pipeline)去整理、去淘汰。這是 Background Track 的事,在背景跑,不動前台的 Write 跟 Read。
「作夢」這個名字不是我發明的。2026 年 3 月底 Claude Code 的 sourcemap 不小心洩了出來,裡面藏著一個還沒公開的 feature 叫 Auto Dream——背景的記憶整理子代理,觸發條件是「距上次超過 24 小時、累積 5 個以上 session」。這條件跟我原本在想的設計幾乎重疊,名字就乾脆借過來。神經科學那邊的類比也一樣:人睡覺時大腦會把白天的記憶壓縮、重組、選擇性遺忘。
先說一下當初的構想#
第一版的想法很粗暴——每天跑一次清理 job,把重複的、壞掉的處理掉。
規則版第二週就撞牆——「過時」不是規則能判的,要有人讀脈絡。加一層 LLM 反思才救回。
現在這條線有四件事在跑:夢境迴圈、知識體檢、興趣畫像,還有一串背景小件。下面分開講。
一、夢境迴圈 — 五階段#
五階段循序跑:
- 定位(Orient)——看今天累積多少新東西、上次做夢是什麼時候
- 訊號(Signal)——掃矛盾、找圖裡的中心節點
- 反思(Reflect)——LLM 讀統計快照,指出洞察和知識缺口
- 鞏固(Consolidate)——實際合併、取代、正規化格式
- 修剪(Prune)——清孤兒節點、處理過時記憶
夢境迴圈附帶的小事:時間衝突仲裁#
夢裡最常處理的一種狀況是——同一件事,你三個月前說一套,上禮拜又說一套。哪個算數?
系統不會自己選邊,做法像法官審理遺囑:把新舊兩份說法跟它們各自的時間戳一起攤在桌上,請一位裁判(也就是請一個更聰明的腦子來讀)判出三種結果其中之一:
- 合併——兩份其實在講同一件事,只是角度不同,併成一條
- 取代——新的把舊的覆蓋掉,舊的留時間戳當註腳
- 共存——其實是兩件不同的事,各自為政
遇到拿不定主意的,會升級請更聰明的裁判進來。寧可慢一點、寧可請外援,也不要把錯的版本當成事實寫死。判完之後,每條事實都會帶著「從哪天開始有效、到哪天作廢」的兩個時間戳,下次回想時才不會把舊版本當成現況。
觸發條件寫在上面的圖裡——雙閘門沒滿足就跳過。記憶還沒沉澱就動手整理,只會把雜訊當訊號。
跟 Claude Code 的 Auto Dream 對照一下:他們是四階段(Orient → Gather → Consolidate → Prune),我這邊在 Gather 跟 Consolidate 中間多塞一個 Reflect,讓 LLM 讀統計快照產出洞察跟知識缺口。另一個不一樣的地方:他們的作夢子代理是唯讀的,看看就好不會改東西;memvault 會實際動資料,靠三階段確認制當煞車。
二、知識體檢 — 四層遞進#
圖譜裡總有東西會壞掉。孤兒節點、指向不存在實體的關係、自相矛盾的三元組。
四層從便宜到貴循序檢查:
- 圖結構——孤兒、迴圈、格式問題。規則層能攔
- Ground Truth——用 canonical 定義檢查值域是否合法
- LLM 判斷——前兩層攔不下來的,例如「語意矛盾但結構合法」
- 三階段確認制——高影響力變更先標記、再複核、最後才動手,不直接 mutate
最後一層是撞了幾次加的。LLM 單輪判斷會 hallucination,直接下手會把好東西刪掉。
順便升級的:邊不是只看「有沒有同框」#
原本兩個概念只要在同一段對話出現過,系統就會在它們之間連一條線。後來發現這樣連太隨便——同一場會議被點到的兩個無關名詞,硬被綁在一起。
改成像在判斷兩個人是不是真的熟。光看一次同框不夠,要綜合五件事一起看:
- 同框次數——出現在一起幾回
- 同期重疊——是不是常常出現在同一段時間
- 共同朋友多不多——他們連到的其他點重不重
- 類型對不對盤——人跟地方的關聯強度,不能跟人跟人的等量齊觀
- 意思像不像——講的東西意思上是不是接近
五件事各有權重,加起來算總分。分數夠才連,不夠就先擱著。連上的線品質就比之前乾淨得多——這是邊權重升級之後最有感的差別。
圖譜不只記事實,也記偏好跟熟練度#
事實層只能回答「你做過什麼」。但你日常的一句話常常牽到「你偏好什麼風格」、「這件事你做到多熟」——這兩塊原本被丟進記事本不分類,後來各自獨立成一層。
偏好那層分十類:寫作風格、技術選型、設計原則、做事節奏、審美傾向⋯⋯每一類都有版本鏈,舊版本不刪只壓低,太久沒被佐證的會自己淡出。像你今天說「我比較喜歡簡潔」,三個月後沒再提,這條偏好的可信度會自動衰減,不會永久綁架未來的判斷。
熟練度那層更像角色扮演遊戲裡的等級表:第一級是基礎、第二級是熟練、第三級會創造。每次你實際運用某個技能,等級會慢慢升上去;長期沒練的會慢慢退。這樣它知道哪些是你「聽過」、哪些是你「做過」、哪些是你「會教人」。
不只清掃,還主動探勘#
體檢的本職是清,但同一張圖看久了會發現另一件事:你有些有趣的東西自己都沒注意到。例如你一直在聊兩個看似無關的領域,但圖上其實有條彎彎曲曲的路把它們連起來——你只是還沒想到。
探勘專門挖三種驚喜:
- 跨群連結——兩個從沒往來過的圈子之間冒出一條新通道
- 遠處的強連結——表面看八竿子打不著,但繞兩圈過去結結實實
- 你自己都沒發現的空缺——某個圈子明明該有的關鍵點你還沒填
挖到以後不會直接行動,會丟到一個「這個你可能會想看」的小信箱,等你哪天主動翻才出現,不打擾日常對話的節奏。
遇到模糊的,送回老師看#
體檢遇到拿不定主意的會自動先扣下來。像考場代為改卷的助教,大部分題目自己就能批,但有幾種情況一定要送回主考官手裡:信心分數太低、新舊兩說各有道理、影響範圍太大。
多數小題目助教按既定答案批改完直接過;只有真的拿不準的才會落到一個小審核區。等你哪天有空翻一下,按一個「對」或「不對」,這條判決就學起來,下次類似情況助教就能自己處理。
這樣做的好處是:自動化跑得快,但不會因為跑太快就把好東西誤刪。慢慢長出來的判斷力比一次寫死的規則耐用。
三、興趣畫像 — 7 / 30 / 90 天#
追蹤我最近在關心什麼、什麼在冷卻。三個時間窗疊著看:最近一週、最近一月、最近三月。
每天自動寫一頁日記#
每天凌晨系統會自己幫你寫一頁「今天的你」:今天最常想的那幾件事、最常被點到的人事物、跟昨天比是哪邊熱了哪邊冷了。你不用動手記。
這份日記不是給你看的——是給未來的你看的。半年後你想知道「我那段時間在忙什麼」,翻這一頁比翻所有對話省事太多。也是知識體檢的對照組,看出哪些東西你以為自己很在意、實際上一個月沒提。
有一個功能我沒想到會有用:知識缺口偵測——系統會注意到「你常聊 A,但從沒聊過相關的 B」,然後主動提醒。不是「你可能會喜歡」,而是「你好像漏了一塊」。
還有一種缺口:書架同一格永遠空著#
另一種缺口長得不太一樣——你反覆問同一件事,但每次系統都翻不到答案。像你常走到書架同一格找書,那一格永遠空的。一兩次可能只是巧合,但累積到第三次系統就會把這格標起來:「這裡你需要,但這裡沒東西。」
標出來不會自動補答案。它做的是讓你下次再來找的時候,系統知道「啊,這格之前空過、要不要先去找個東西放進來」。久了你會發現自己反覆在問同一個問題卻沒得到解,這個訊號比答案本身有用——它告訴你該去主動補哪一塊。
四、其他在背景偷偷跑的小件#
還有一堆不大不小但少了會出事的事:
- 慢思考——背景預測下一個可能的問題,預搜結果塞進快取
- 熱溫冷冰分級——常被叫的留全文,冷掉壓成摘要,冰封的只剩 summary(法律追溯保留)
- 格式正規化——encoding、空白、截斷處理(在鞏固階段順手做)
- 低信心審查——信心度低於某閾值的記憶自動進人工複核佇列
- 閉環回饋——按讚、點擊、事後的判斷(對/錯)會回寫進記憶權重
降級壓縮:老照片轉黑白縮圖存進倉庫#
記憶不是放著就好,會分四個溫度層:熱、溫、冷、冰。最近常被叫到的留全文;變冷的會被壓成一段大約四百字的摘要;冰封的只剩一個極短的標題式摘要,主要是法律或合規追溯用。
關鍵在於壓縮是單向的。從熱往冰走會壓,從冰往熱走不會自動還原——就像老照片洗成黑白縮圖存進倉庫,哪天再翻出來不會自動上色。原因很簡單:再展開也只是用今天的腦補去填過去的細節,那不是記憶,那是創作。要嚴謹的話寧可承認「我不記得了」。
為什麼「會忘」比「記得」更重要#
一個只記不忘的系統,時間久了同一件事會堆好幾個版本的答案。每個都是某時間點的事實,但拼在一起就失真。
Write Track 負責「收對的東西進來」,Background Track 負責「讓錯的退場」。兩個一起,系統才不會發瘋。
這條線我覺得收得差不多了。下一篇接 Read Track——記憶怎麼被叫回來。那邊是 memvault 最複雜的一環,光是 scoring 就疊了十一層。
初期構想#
初版是一支純規則的清理腳本,每日 cron(排程)跑一次。做下去發現規則層判不了「過時」跟「矛盾」,才加了一層 LLM(大型語言模型)反思。上線前先 dry-run(乾跑)看日誌品質,確認穩定再開實際寫入。
Background Track(背景軌道)目前有四條主線:Dream Loop(夢境迴圈)、Knowledge Lint(知識體檢)、Interest Profile(興趣畫像),加上一串雜務型背景任務。
一、Dream Loop(夢境迴圈)五階段#
五階段循序跑,在 dream.py 裡依序呼叫:
_orient()——本次 session 差異統計,讀 Redis 裡的last_dream_at_gather_signal()——矛盾掃描加上 PPR(Personalized PageRank)中心性偵測_reflect()——LLM 讀統計快照,產出洞察與知識缺口_consolidate()——批次resolve_conflict()、批次去重、內容正規化_prune_and_report()——孤兒節點整頓、過時條目清理
Temporal Conflict Resolution(時間衝突仲裁)#
夢裡的法官——同一個 subject 出現新舊矛盾時,由 LLM 三向裁判決定如何收斂。
- 路徑:
memvault.kg.temporal_conflict.resolve(),由_consolidate()批次呼叫 - 輸入 prompt 帶時態:
valid_at/invalid_at跟 source session 一起餵入,避免 LLM 用今日視角誤判舊事實 - 三向判決:
MERGE(語意可合併)/SUPERSEDE(新事實覆寫,舊條目降級保留)/COEXIST(互不衝突) - 低信心升級:
confidence < threshold時自動升級到 RLM(Reasoning Language Model)重判
verdict = await resolve(old_triple, new_triple, ctx)
match verdict.action:
case "MERGE": merge_triples(old, new)
case "SUPERSEDE": old.invalid_at = new.valid_at
case "COEXIST": keep_both(old, new)
Dual-Gate(雙閘門)條件:(now - last_dream_at) > 24h AND sessions_since >= 5。沒滿足就直接略過——記憶還沒沉澱時跑,雜訊會被當訊號處理。
跟 Claude Code 洩漏的 Auto Dream(自動夢境)架構對照:他們走四階段(Orient 定位 → Gather 收集 → Consolidate 鞏固 → Prune 修剪),memvault 在 Gather 跟 Consolidate 中間插入 Reflect(反思),讓 LLM 讀快照產出洞察與知識缺口。權限模型也不同:Claude Code 的 dream subagent(作夢子代理)是 read-only(唯讀)bash,memvault 會直接 mutate(變更)資料,靠三階段確認制做 safety gate(安全閘)。
二、Knowledge Lint(知識體檢)四層#
從便宜到昂貴循序檢查:
- 圖結構層——孤兒節點、迴圈、格式壞掉的三元組(純規則可判)
- Grounding(接地)層——用 canonical(標準化)定義檢查謂詞值域合不合法
- LLM 層——結構合法但語意矛盾的微妙問題,規則抓不到
- 三階段確認——高影響變更走「標記 → 複核 → 提交」,不直接改動
volatile predicate(易變謂詞)偵測跟孤兒實體清理都在這層跑。三階段確認是踩過幾次誤判之後加的——單輪 LLM 判斷不夠穩,高風險動作需要人工審核閘。
Multi-Signal Edges(多訊號邊權重)#
不只看「有沒有同框」——共現一次就連線會塞滿假邊,改成五訊號合成 composite_weight。
- 路徑:
memvault.kg.edge_ops(build_edge()+compute_composite()) - 5 signals:
co_occurrence— 共現頻次(log-scaled)session_overlap— Jaccard over session setsadamic_adar— 共同鄰居的反 log degree 加權(Adamic-Adar index)type_affinity— 來源 / 目標 entity_type 的 prior matrixsemantic_similarity— embedding cosine
- composite:weighted sum,下游 Leiden 分群直接讀此欄位當 edge weight
w_edge = (0.25 * co_occ_log
+ 0.20 * session_jaccard
+ 0.20 * adamic_adar_norm
+ 0.15 * type_affinity
+ 0.20 * semantic_cosine)
Attitude Layer + Skill Proficiency(人格化層)#
圖譜不只記 facts,還記 preferences 跟 mastery——這兩層脫離 generic entity table 獨立建模。
- Attitude Layer:10 類態度(writing_style / tech_choice / design_principle / pace / aesthetic ...),每條 attitude 帶
version_chain,舊版以superseded_at標註不硬刪 - Confidence decay:未被新證據佐證者,
confidence *= exp(-λ * Δt),避免永久綁架 - Skill Proficiency:L1(exposure) → L2(competent) → L3(generative),每次
record_skill_use()提供經驗值,半衰期式衰退 - 分離理由:preference 與 fact 的衝突解析規則不同(preference 容許共存歷史版本,fact 走 SUPERSEDE)
attitude.upsert(
category="tech_choice",
statement="prefer modular monolith",
confidence=0.85,
evidence=[session_id_1, session_id_2],
)
skill.record_use("rust_async_runtime", proficiency=L2, evidence=session_id)
Surprise Discovery(驚喜探勘)#
體檢順手做的反向工作——不只清掃,還主動探勘圖譜中的非顯性連結。
- 路徑:
memvault.discovery.surprise_ops,dream loop 的_signal()階段觸發 - 三類發現:
cross_community— Leiden 切出的不同社群之間新生 bridge edgeindirect_strong— 2-hop 路徑高分但 direct edge 缺失(透過 PPR 偵測)knowledge_gap— 結構上預期該存在的鄰居 entity 缺漏
- 觸發條件:Leiden weighted 分群後,跨社群新邊 + composite weight 超過動態閾值才入隊
- 不主動推送:寫入
discovery_inbox,由前台 Read Track 在 idle 時拉取,避免污染主對話
Review Queue(人工複審 fallback)#
助教改卷模式——大宗低風險自動 approve,模糊或高影響的進審核佇列等人類最終裁定。
- 路徑:
memvault.review_ops,介接 Knowledge Lint 與 Conflict Resolver - auto-approve rules:
confidence > 0.8且impact_score < threshold直接過 - 進佇列條件:低信心、conflicting verdict、batch size > N、或牽動 Attitude / Skill 等高敏感層
- human-in-loop fallback:佇列項目逾時未處理 → SUPERSEDE 退回 PENDING,不會無聲落地
- 學習回饋:人工裁決結果回灌進 auto-approve 的
impact_score校準
三、Interest Profile(興趣畫像)7 / 30 / 90 天#
滾動式的注意力窗口(7、30、90 日三層)加上知識缺口偵測跟每日快照。
Daily Snapshot(每日興趣報告)#
每天自動寫一頁日記——SQL 聚合一張當日剖面表,省掉每次查詢都重算 7/30/90 視窗。
- 路徑:
memvault.profile.daily_snapshot,dream loop 的_orient()之後寫入 - 欄位:
top_intents(top-N by frequency)、top_entities(PPR 中心性 top-N)、delta_vs_yesterday(出現 / 消失的 entity 集合) - 用途:Read Track recall 時直接 join 此表加速 fresh-bias;長期看可給 Knowledge Lint 比對「自稱在乎 vs 實際關注」
- 保留期:snapshot 不會被 dream loop prune,純讀寫分離,保留期跟 Block 不同生命週期
SELECT intent_label, COUNT(*) AS freq
FROM memvault.recall_log
WHERE created_at::date = CURRENT_DATE
GROUP BY intent_label
ORDER BY freq DESC LIMIT 10;
知識缺口偵測不是協同過濾。邏輯是圖譜結構上的「鄰居訪問不均」——你頻繁聊某個群集的 A 節點,但相連的 B 從沒被觸及,系統就標出「你好像漏了一塊」。
Knowledge Gap Detection(知識缺口偵測)#
另一條缺口偵測線——書架同一格永遠空著:使用者反覆查但 recall 失敗的 query。
- 觸發條件:同 intent / 同 entity 的 recall 中,
verdict = INCORRECT累積 ≥ 2 failures(CRAG 評判信號) - 標記:寫入
knowledge_gap表,欄位含query_signature、fail_count、last_fail_at - 不自動補:系統不會幻覺式生成內容填空,只在下次 recall 時提示前台「此問題歷史 fail,建議補資料」
- 跟結構式缺口的差異:上一段(鄰居訪問不均)來自圖譜拓樸,這段來自 recall 失敗 log,兩者互補
四、其他背景雜務#
SlowThinker(慢思考)——五步預測式預取管線,靈感來自 VoiceAgentRAG(語音代理 RAG,Salesforce AI Research)ContentNormalizer(內容正規化)——處理編碼、空白、截斷,寄生在_consolidate()裡GRCAdapter(治理/風險/合規閘)——信心閾值以下的記憶進人工審核佇列- 閉環回饋——Background 尊重三類權重訊號(不自行寫):
Feedback Boost(用戶 +/-)、Access Reinforcement(FG recall 時即時record_access,延長 effective half-life 最多 10x,30 天自衰減)、CRAG 評判。curate 讀這些訊號避免誤刪被點燃的 block TierDigest(降級壓縮)——老照片轉黑白縮圖存進倉庫的單向過程:- 路徑:
memvault.lifecycle.tier_digest - 觸發:lifecycle 生命週期
warm → cold、cold → frozen降級時呼叫 LLM 摘要 - 限制:摘要 ≤ 400 chars,寫入
BlockFrozen.summary - 單向性:上行(cold → warm)不解壓縮、不還原原文。理由:用今日 LLM 還原過去細節 = hallucination,違反 fidelity
- 路徑:
把「遺忘」當成架構原語#
只增不刪(append-only)的系統,隨時間累積的 drift(漂移)是必然的。每個事實有生存時效(TTL),每個謂詞有易變視窗(volatile window),每個實體都會跟過去的自己不一致。
Write Track(寫入軌道)負責寫入,Background Track 負責退場。兩條一起,圖譜才會收斂(converge)而不是發散。
背景這條線盤到這。下一段進 Read Track——查詢意圖分類、評分管線、注意力閘控重排、層疊召回。光評分就疊了 11 層。
複製給你的 AI Agent#
如果你在建自己的 AI 記憶層、或在煩惱記憶越堆越亂,把這段貼給它,讓它幫你檢查「有沒有學會忘」這一環。
延伸閱讀#
過程中實際參考過、影響過設計決策的資源。
| 資源 | 為什麼重要 |
|---|---|
| Claude Code Dreams: Anthropic's Auto Dream Feature | 把 Claude Code 洩漏出的 Auto Dream 設計整理得最完整的一篇——我的「夢境迴圈」名字跟雙閘門條件都從這邊借過來 |
| Piebald-AI: Auto Dream Leaked System Prompt | 洩漏後被整理出來的 Claude Code dream subagent 原始 prompt。看完才決定我要多加 Reflect 階段、並放寬 mutation 權限 |
| From Local to Global: A Graph RAG Approach(Microsoft) | Dream Loop 第三階段 Reflect 用 LLM 讀快照產出 insights 的思路來自這邊——Community detection + LLM summary 這條線。L1 / L2 的批次整合也是 |
| From Louvain to Leiden: guaranteeing well-connected communities | L1 社群偵測用的演算法。比 Louvain 保證連通性,multi-resolution 參數讓我可以在不同粒度掃社群 |
| LightRAG: Simple and Fast Retrieval-Augmented Generation | 輕量版的自我更新 KG 做法,對照著看讓我決定背景整理要分階段,而不是一次性 rebuild |
| memvault Write Track — 對話結束之後 | 三部曲第一篇。記憶怎麼進保險庫:三道 gate、雙軌寫入、L0 三元組抽取 |
| memvault Read Track — 想起來之後 | 三部曲第三篇。Background 整理完後,記憶怎麼被叫回——意圖分類、Cascade Recall、Slow Thinker 預取 |