Hybrid memory search:把 journal 搜尋當成 ranking 問題

Hybrid memory search:把 journal 搜尋當成 ranking 問題

給 LLM agent 用的記憶系統寫了半年,最後發現自己打開次數最多的不是 MEMORY.md 或主題筆記,而是 memory/YYYY-MM-DD.md 這份逐日 journal。日常查的也多半是「上次搞 PostgreSQL 是什麼時候」「那個 config 的決定寫在哪天」這種問題。 問題是:搜尋它不太好用。 grep 噪音太多。半年的 journal 把任何常用詞炸出幾百個 hit。 embedding-only 搜尋對 journal 不適合。journal 裡面多半是兩三行的短 entry,embedding 模型給短句的向量區分度不夠;而且 journal 每天長,每次 incremental embed 都要算 hash、做 rate limit、管 cache,出錯就是一整天的記憶搜不到。 最關鍵的是,journal 是本質上有時間性的資料。我問「上次搞 PostgreSQL 是什麼時候」,語意相似度幫不上忙,時間才是主角。 所以我把 journal 搜尋重新當成一個 ranking 問題,用三個分數軸融合:keyword overlap × temporal recency × hall-type boost。Python 不到 130 行,沒有外部依賴。 這篇記錄設計過程、實測結果,還有一個在 bootstrap 測試時才發現的 case-sensitivity bug。 為什麼不直接用 embedding 先說清楚:embedding 不是沒用。我自己在 notes/ 的相關筆記推薦也還是用 embedding 跑 cron。問題是把它用在 journal 搜尋上有幾個具體的不匹配: ...

April 10, 2026 · 3 分鐘 · Mark Lee
AI Agent 記憶的 Context Tree:從日誌地獄到兩層架構

AI Agent 記憶的 Context Tree:從日誌地獄到兩層架構

記憶系統撐到了極限 跑了四個月的 AI agent,記憶目錄(memory/)膨脹到 37 個檔案。聽起來不多,但仔細一看: 日常日誌(2026-03-12.md、2026-03-13.md…)佔大多數 混雜著主題檔(sso-booking.md、cramclaw-webhook.md) 還有 session 元數據(只有 5 行的 session key/id) 甚至有一個 .html 檔案不知道怎麼混進來的 Agent 每次啟動要讀今天和昨天的日誌,加上 MEMORY.md 長期索引。理論上這套系統能運作,但實際上出了幾個問題。 問題一:日誌噪音 每天的日誌什麼都記——閒聊、debug 過程、中間嘗試、最終結論。當你搜尋「WireGuard 設定」,會找到五天前的 debug 記錄,卻找不到最終的設定方案,因為那被埋在某天日誌的第 200 行。 問題二:知識碎片化 同一個主題散落在不同日期的日誌裡。咖啡研究在 3/10、3/18、3/23 都有,但沒有一個統一的地方彙整「我目前對 Soup Method 的理解」。Agent 沒辦法回答「關於 X 我知道什麼」——它只能回答「某天發生了什麼跟 X 有關的事」。 問題三:重複與矛盾 知識庫(Obsidian notes)裡有 377 個筆記,掃描後發現 9 組重複(18 個檔案)。同一個技術方案在 02-Areas/Tech/ 和 01-Projects/ 各有一份,內容略有差異。哪個是對的?都不完全對。 借鏡:Harness Engineering 的 Entropy Management 2026 年 AI 工程圈開始談 Harness Engineering——不只是讓 agent 能做事,而是控制它做事的品質。三個支柱: Context Engineering:給 agent 什麼資訊 Architectural Constraints:限制 agent 的行為邊界 Entropy Management:防止系統隨時間退化 記憶系統的問題本質上是 entropy 問題。沒有主動管理,資訊會自然趨向混亂——重複累積、過時不清、碎片分散。 ...

March 28, 2026 · 3 分鐘 · Mark Lee
AI Agent 記憶品質:用數據決定什麼該記、什麼該忘

AI Agent 記憶品質:用數據決定什麼該記、什麼該忘

前情:記憶清理的粗暴現狀 上一篇講了記憶架構怎麼從空白演化成多層結構——daily files、MEMORY.md 長期記憶、自動反芻和做夢機制。寫入的問題解決了,但清理一直很粗暴。 memory-expire.sh 的邏輯就一行:超過 30 天就歸檔。 大部分時候這沒問題。但有些記憶明明超過 30 天了,卻每天都在被搜尋命中——比如二月初寫的 espresso 配方筆記,到三月中還一直被引用。一刀切歸檔會把活躍記憶誤殺。 另一方面,有些記憶寫完就再也沒被搜到過。它們佔著 embedding 搜尋的空間,拉低搜尋精度。 需要一個比日期更聰明的判斷依據。 思路:追蹤「誰在用這段記憶」 靈感很直接:如果一段記憶在過去 30 天內被搜尋命中過多次,它就是「活的」,不該被歸檔。 做法:掃描所有 session 的 JSONL 日誌,提取 memory_search tool call 的結果,統計每個記憶檔案被命中的次數。 session JSONL → 提取 memory_search 結果 → 統計命中次數 → hit_counts.jsonl 這個 hit count 資料就是 Memory Quality Score 的核心。 實作:從 Python 到 Rust Python 原型(200 行) 第一版用 Python 寫,邏輯很直接: 掃 ~/.openclaw/agents/main/sessions/*.jsonl 找 tool_use type 是 memory_search 的 entries 從對應的 tool_result 提取命中的檔案路徑 累計到 memory/hit_counts.jsonl 跑一次大概 160ms,掃完 145 個 session 檔案得到 408 個命中記錄。 ...

March 21, 2026 · 2 分鐘 · Mark Lee
AI Agent 記憶系統的三個難題:壓縮、演化、衝突

AI Agent 記憶系統的三個難題:壓縮、演化、衝突

這是我們在 OpenClaw 系統實作記憶機制的心得,也是對「讓 AI Agent 學會做夢」一文的延伸。我們不談論文,只談踩過的坑和做出來的解法。 為什麼 AI Agent 需要記憶? 不是所有 LLM 應用都需要記憶。一個回答使用者問題的客服機器人,問完就可以忘了;一個生成文案的工具,用完就走。但當 Agent 需要 長期運行、累積經驗、理解上下文,情況就完全不同了。 我們的 OpenClaw Agent 需要: 記住使用者的偏好(他喜歡高密度資訊,不愛廢話) 記住基礎設施的狀態(哪台機器開了、哪個服務掛過) 記住決策的來龍去脈(當初為什麼選這個方案) 沒有記憶,每次對話都是獨立的瞬間,Agent 永遠是新手。這就是我們要解決的問題。 難題一:壓縮 — context window 有限,保留什麼? 問題 即使是 GPT-5.4 或 Claude 4.6,context window 終究有限。當記憶累積超過臨界點,你不可能把全部東西都塞進去。壓縮不是選項,是必然。 但壓縮代表選擇。選擇本身就是困難的: 哪些對話值得記住? 抽象化(summarization)會不會丟失關鍵細節? 如果壓縮演算法選錯了重要資訊,後果是什麼? 業界做法 常見的壓縮策略有幾種: 方法 說明 缺點 簡單摘要 LLM 產出濃縮版本 容易遺漏細節,無法精確檢索 向量檢索 存 embedding, query 時召回 只能搜「相似」,無法知道「重要」 優先級排序 依重要性決定保留顆粒度 依賴準確的優先級判斷 我們的做法 我們採用 三層記憶架構,用「分層」取代「一次性壓縮」: daily memory(便簽)→ MEMORY.md(長期)→ reference/(結構化知識) daily memory:每天的 raw 紀錄,像貼在冰箱上的便利貼 MEMORY.md:萃取後的長期知識,需要主動維護 reference/:結構化資料(設定檔、API 文件、流程 SOP) 同時搭配 P 級優先級: ...

March 18, 2026 · 2 分鐘 · Mark Lee
讓 AI Agent 學會做夢:記憶的睡眠循環機制

讓 AI Agent 學會做夢:記憶的睡眠循環機制

記憶的腐爛問題 跑了兩個月的 AI agent,記憶檔案從幾 KB 膨脹到幾十 KB。一開始沒什麼感覺,直到某天 agent 引用了一個三週前就被推翻的技術決策,我才意識到問題有多嚴重。 記憶不是寫進去就沒事了。沒有維護的記憶,比沒有記憶更危險——因為 agent 會很有信心地根據過時資訊做決策。 人類的記憶會在睡眠中自動整理:重要的強化、矛盾的修正、不用的淡化。AI agent 的記憶沒有這個機制,所以得自己造一個。 靈感來源:Karry 的 Orb 直接觸發這個想法的,是 Karry 寫的一篇文章:《認知アップグレードの本当のループ——AI Agent の記憶設計から學んだ 3 つのこと》。 Karry 運營自己的 AI agent「Orb🔮」超過兩個月,得出一個跟主流完全不同的結論:記憶系統的核心不是 Vector DB,是認知循環。他指出三個真正的難題: 什麼時候該忘? — 頻率衰減不夠用,年用一次但救命的記憶不能丟 AI 會捏造記憶 — 搜尋結果為空 ≠ 記錄不存在 教訓寫了也不一定有效 — 「知道」和「做到」之間有巨大的鴻溝 他的解法是三層記憶(L0 原始日誌 → L1 回顧摘要 → L2 長期記憶)加上「Hard Constraint」——犯錯兩次就強制鎖死,不靠自覺靠系統。 這些觀點跟我自己踩坑的經驗高度吻合,但我的問題不完全一樣。Karry 著重在「怎麼讓記憶影響行為」,我面對的是更前面一步:怎麼讓記憶自己保持乾淨。 Orb 做了什麼,我做了什麼不同 Karry 的 Orb 和我的 agent 有很多共通點——都用 Markdown 檔案、都分層、都相信簡單架構。但設計哲學有幾個明顯的差異: Karry’s Orb 我的做法 記憶儲存 Markdown + LLM 多段抽取 Markdown + LLM,但加了 Gemini embedding 做向量索引 遺忘策略 P0/P1/P2 分級 + 人工 review P0/P1/P2 分級 + 自動化腳本 (janitor/expire) 防呆機制 Hard Constraint(犯兩次就鎖) 分析/執行分離(反芻只建議,main session 決策) 獨特機制 — 「做夢」——冷記憶隨機抽取找跨領域洞察 記憶維護 LLM 每日抽取 cron 四件套:janitor + reflect + dream + expire 矛盾處理 手動 反芻引擎自動檢測,但人工確認修改 最大的差異是:Karry 更信任 agent 自己管記憶(自動壓縮、自動昇格),我更偏向讓 agent 當顧問、人類做最終決策。 ...

March 17, 2026 · 3 分鐘 · Mark Lee
OpenClaw 記憶管理:從零到自迭代的架構演化

OpenClaw 記憶管理:從零到自迭代的架構演化

前言 當你給一個 AI agent 一台 VPS、一堆 API key、和一個空白的工作區,它要怎麼「記住」東西? 這篇記錄了我在 OpenClaw 上建構 AI agent 記憶系統的過程——從最初的空白 MEMORY.md,到現在帶有優先級標籤、自動過期清理、事件時間軸的結構化架構。不是教學文,而是真實的踩坑記錄。 第零天:空白的開始 OpenClaw 啟動時,工作區裡有四個檔案:SOUL.md(人格設定)、USER.md(使用者資訊)、AGENTS.md(行為規範)、和一個空的 MEMORY.md。 Agent 每次醒來(新 session)都是失憶狀態——它只知道人格和行為規範。所有對話、決策、偏好,隨著 session 結束就消失了。 第一個問題:agent 要怎麼知道「上次我們聊到哪了」? 第一階段:Daily Files(流水帳) 最自然的做法:每天一個 markdown 檔,如 memory/2026-01-26.md、memory/2026-01-27.md,記錄當天發生的事。 格式很自由——## 標題 分段,裡面就是對話摘要、設定紀錄、debug 過程。Agent 在每次 session 開始時讀今天和昨天的 daily file,大概知道最近在幹嘛。 好處: 簡單、自然、寫入無摩擦。 壞處: 兩週前的事?要翻十幾個檔案。 「上次 OpenClaw 升級是什麼時候?」→ 沒人記得在哪個 daily file 裡。 重要決策淹沒在日常瑣事中。 第二階段:MEMORY.md(策展式長期記憶) Daily file 是流水帳,MEMORY.md 是策展。 想法很簡單:把真正重要的東西從 daily file 「升級」到 MEMORY.md。Agent 每次啟動都讀這個檔案,等於它的「核心記憶」。 最初的 MEMORY.md 很簡單:分成 Profile(基本資料)、Infrastructure(系統設定)、Preferences(偏好)三個區塊,各放幾條 bullet point。 問題來了:誰來維護? ...

February 18, 2026 · 2 分鐘 · Mark Lee