claude.ai 其實有記憶功能。

它會自動整理你的對話歷史,每 24 小時更新一次,生成一份叫 User Synthesis 的個人摘要。付費用戶還能搜尋過去的對話,用 RAG 把相關的脈絡拉回來。聽起來很完整。

但搜尋是壞的。

有人在 GitHub 上開了 bug report:搜一個關鍵字,明明昨天的對話裡就有這個詞,搜不到。手動往下翻,找到了,點進去,關鍵字確實在裡面。搜尋引擎就是沒抓到。

有人實測,搜尋的可靠率大概六成。

六成。丟一個銅板都有五成。

而且不只一個平台——VS Code 插件壞、macOS app 也壞。有使用者確認這是退化,之前的版本是能用的。bug report 最後被關掉了,標了 "not planned"。

更荒謬的是,有人在 Threads 上寫了一段話,大意是:「搜尋自己的對話歷史這件事,在 Claude 和 ChatGPT 上都爛到令人震驚。連搜一個單字都不行。考慮到這些公司擁有的算力,這很諷刺。」

二十年前就解決的問題。全文搜尋。他們做不到。

不可靠比沒有更糟

如果 Claude 從頭就沒有記憶功能,我早就自己想辦法了。

問題是它有。它告訴你「我記得你」,它告訴你「你可以搜過去的對話」。所以你會依賴它。你花了一個小時跟它討論一個技術方案,想著「反正它記得,下次可以接著來」。

然後下次搜不到。

對大部分人來說,這是小麻煩。重新交代一下背景,三十秒的事。

但我用一根手指打字。

每次重新交代背景,對我來說是好幾分鐘。而且不是打一次——每個搜不到的對話都要重來。上週決定用 SQLite 不用 PostgreSQL 的理由?重新解釋。某個 bug 的除錯過程和最後的解法?重新描述。我的身體狀況、打字成本、工作流程偏好?一切從零開始。

不可靠的搜尋比沒有搜尋更糟,因為它讓你誤判成本。你以為資訊存著了,結果要用的時候拿不出來。

自己蓋

既然官方的方案不能信,那就自己來。

架構很簡單:一個跑在 Cloudflare Workers 上的 MCP 伺服器,後面接 D1(Cloudflare 的 SQLite 服務)。Claude 透過 MCP 協定連上來,就能在對話中存記憶、搜記憶、讀記憶。

跨對話。跨裝置。免費方案就夠用。

接上 claude.ai 的 connector 之後,Claude 在對話過程中會自動判斷什麼時候該存東西——你確認了一個事實、做了一個決定、解決了一個技術問題,它就呼叫 save_memory 存下來。下次開新對話,它呼叫 get_recent_context 把最近的記憶拉回來,就知道你是誰、在做什麼、上次聊到哪。

不用我打字提醒。這是關鍵。

原子事實,不是主題摘要

設計記憶格式的時候,我做了一個跟 claude.ai 內建記憶完全相反的決定。

claude.ai 的記憶是摘要式的——它把你的對話濃縮成一份「這個人大概是做什麼的、偏好什麼」的 profile。這種東西在回答「這個人是誰」的時候有用,但在回答「上週那個 bug 的解法是什麼」的時候完全沒用。

我的系統存的是原子事實。每筆記憶是一個自包含的、直接可搜的具體資訊。

「yanaginagi 2026 台北演唱會抽選落選(初回+復活都沒中)」是一筆。「yanaginagi 演唱會日期 2026-05-17」是另一筆。「場地:小巨蛋」是第三筆。

不做摘要。不做歸類。每筆都能獨立存在、獨立被搜到、獨立回答一個問題。

這跟人類記憶的運作方式其實很像——你不會把「跟某個人相關的所有事」存成一個檔案。你是在不同時間點記住不同的事實,需要的時候各自提取。

原子事實要有重量,不只有結構

結構對了之後,我發現還有另一層問題:內容太薄。

「某人抽了輪椅席卻沒去演唱會」是原子事實。「連續四次抽中、四次都沒去、特地去 7-11 把票領出來放進收藏匣、被指出來之後說『謝謝所有罵我的人』」也是原子事實。

兩筆都符合格式,但只有後者讓事件有重量。前者你讀完只知道「有這件事」,後者你讀完知道這個人是什麼人、為什麼重要、下次提到相關話題時你需要哪些背景。

同樣的問題出現在其他地方。「使用者對宗教持懷疑態度」和「不是學術無神論,是生存條件逼出來的務實——禱告不會讓腿站起來,所以意義只能在此刻找」,是完全不同層次的記憶。

差別在三件事:數字和頻率(一次還是四次,差的不只是量)、原話(對方說了什麼,比你描述他說了什麼更準確)、為什麼重要(這件事影響了什麼、跟哪些事有關聯)。

不是寫故事。還是要精簡。但精簡不等於丟掉讓事件「撐得起來」的細節。

今天把這個原則寫進了 Claude 的 system prompt,讓它在儲存記憶的時候自動套用。測試結果明顯——搜到的記憶不只是能找到,而且找到了就夠用,不需要再回頭翻對話。

搜尋:三條路同時跑

既然動機就是搜尋壞了,那搜尋架構得認真做。

我用中文和日文生活,用英文寫程式碼,標籤是中英雙語的。一次搜尋可能同時涉及「抽選」「ballot」「yanaginagi」「落選」「failed」這些不同語言的詞彙。只做全文搜尋是不夠的。

所以 search_memory 同時跑三條路:

  1. FTS5 全文搜尋——把查詢詞用 OR 展開,任何一個詞命中就算,給 3 分。FTS 沒結果就自動 fallback 到 LIKE 子字串比對,給 2 分。
  2. Entity 比對——在 entities 欄位裡找子字串,給 2 分。
  3. 日期範圍——按 event_date 篩選,給 1 分。

三路結果合併、加分、排序。同一筆記憶被多條路徑命中,分數疊加。

Claude 搜的時候會自動把問題展開成多個變體。你問「yanaginagi 抽選怎樣了」,它展開成 ["yanaginagi", "抽選", "落選", "沒中", "ballot", "concert"],同時丟進三條路徑。

不需要使用者自己想關鍵字。而且——這是重點——搜得到。每次都搜得到。因為資料就在我自己的 D1 裡面,SQL 查詢不會玄學失靈。

User Synthesis:自己的版本

claude.ai 的自動摘要是黑盒子。你不知道它記了什麼、什麼時候更新、有沒有漏掉重要的東西。

我做了自己的版本,叫 User Synthesis,分成七個區段:工作脈絡、個人脈絡、當前關注、近期動態、早期背景、長期歷史、行為指令。

格式參考了 claude.ai 的結構,但內容完全由我控制。我看得到裡面每一個字,我可以手動觸發整理,可以直接改任何一個區段。

存在資料庫裡,key 是 user-synthesis,用 upsert 更新,不會重複。Claude 讀取它就能快速理解「這個人是誰」,不需要翻遍所有記憶。

安全

伺服器跑在公開的 Cloudflare Workers 上,安全不能馬虎。

MCP 端點藏在 URL 路徑裡:/mcp/{一串隨機密鑰}。密鑰存在 Cloudflare Worker Secrets,不進版控。

錯的密鑰?404。不是 403,是 404。連端點存在這件事都不讓你知道。

密鑰比對用 constant-time comparison 防 timing attack。對個人專案來說有點 overkill,但寫都寫了。

為什麼不用現成的

GitHub 上有幾個 MCP memory server 的開源專案。但它們幾乎都是跑在本地的——Claude Desktop 連本地 server,資料存本機。代表你得開電腦才能用。

我的版本跑在 Cloudflare Workers 上,接的是 claude.ai 的遠端 connector。手機能用,躺在床上也能用。

而且我需要的搜尋策略跟大部分人不同——中英日三語混用、需要同義詞展開、需要跨語言比對。這些不是現成方案能解決的。

實戰:5G 網卡凌晨又斷線了

這套系統上線兩天後就碰到了一個完美的測試案例。

我的 Proxmox 伺服器插了一張 TCL IK512 5G USB 網卡當備援線路。前一天晚上才花了好幾個小時把整個 failover 架構從「斷線才連」改成「always-on 常駐連線」——改了 systemd service、watchdog 腳本、MBIM static IP 設定,除錯過程中還發現了 USB rebind、mmcli -m any、bearer JSON 解析等一堆眉角。所有這些都存進了記憶資料庫。

隔天早上,5G 又斷了。

我連進 Claude Code,說了一句「5G 網卡又來了」。就這樣。沒有解釋是哪張網卡、沒有交代架構、沒有複述昨天做了什麼。

Claude 搜了一下記憶,拉出昨天存的那筆記錄——裡面寫著「MBIM session 卡住(NotOpened)時需 USB rebind(echo 2-1 > /sys/bus/usb/drivers/usb/unbind 再 bind)」。它直接問我:要不要執行 USB rebind?

整個修復過程:USB rebind、等 ModemManager 重新 probe、enable、connect、設定 MBIM static IP、驗證連線。兩分鐘。

然後我們順著查下去,發現了真正的根因:USB Root Hub 的 autosuspend。Linux 預設會讓閒置的 USB hub 進入省電模式,hub 一睡,下面掛的 5G 網卡就跟著斷線。這台是伺服器不是筆電,USB 省電完全沒必要。一行 kernel 參數 usbcore.autosuspend=-1 解決。

如果沒有記憶系統,這個早上會是這樣的:我得重新解釋這是哪張網卡、用什麼協定、插在哪個 USB port、昨天改了什麼、當時的錯誤訊息長什麼樣、USB rebind 的指令是什麼。用一根手指打完這些,大概十分鐘。

有了記憶系統,我只需要六個字。

而且不只是「找到答案」——Claude 拿到的是完整脈絡。它知道這張網卡之前就有 GPS 廣告不實的問題,知道 always-on 架構的設計意圖,知道 watchdog 腳本的結構。所以它能直接往下挖到 USB autosuspend 這個根因,而不是停在「重連一下就好了」。

這就是原子事實加上搜尋的價值:不只是記住答案,而是記住脈絡,讓下一次的除錯能從上一次結束的地方開始。

結局

claude.ai 的搜尋功能壞了。bug report 被標 "not planned"。

所以我花了一個週末,在 Cloudflare Workers 上蓋了一個 300 行的 MCP 伺服器,接上 D1,寫了三路搜尋、FTS5 全文索引、自動同步的 trigger、原子事實的儲存架構。

現在 Claude 記得我是誰。每次都記得。不是因為它變聰明了,是因為我給了它一個不會壞的地方放東西。

搜尋也不會六成了。是一百。因為 SQL 不丟銅板。