CtxFST CH23 - 讓 AI 記憶可以被看見、搜尋、修正:用 OpenClaw 做一個可除錯 memory loop
CtxFST CH23:讓 AI 記憶可以被看見、搜尋、修正,用 OpenClaw 做一個可除錯 memory loop
前一章 CH22,我做的是 retrieval benchmark。
那一章回答的是:
如果只是做檢索,entity-aware retrieval 到底比純文字相似度多了什麼?
但如果你真的把 AI 放進日常生活或工作流裡,下一個更痛的問題很快就會出現:
當 AI 記錯一件事時,你到底要怎麼把它修好?
這個問題,比 retrieval 本身更接近使用者真正會撞到的牆。
因為大部分人不是卡在「AI 找不到資料」。
而是卡在:
- AI 記住了一條錯的偏好
- AI 把舊資訊當成新事實
- AI 的 long-term memory 開始越長越歪
- 使用者知道它錯了,卻不知道錯在哪裡
如果一套 memory system 不能被檢查、不能被 debug、不能被修正,那它再聰明,最後都很難被長期信任。
這就是我想把 CH23 聚焦的地方。
先講一句最短的結論
這一章最重要的一句話是:
CtxFST的價值,不只是讓知識更容易檢索,而是讓 AI 的記憶第一次變成一個可以打開、搜尋、定位、修正的 artifact。
如果 CH22 證明的是 entity-aware retrieval 有用,
那 CH23 要證明的是另一件事:
當記憶出錯時,CtxFST 讓你有地方下手。
這件事對推廣很重要。
因為很多開發者不會先被「graph traversal」打動。
他們會先被這種場景打動:
我家的 AI 明明記錯了,為什麼我不能直接看到它到底記了什麼?
這個痛點,比 architecture diagram 更容易在前 30 秒讓人懂。
真正有共感的問題,不是檢索,而是「記錯了卻改不掉」
我想像的 demo 不是一個很抽象的 enterprise workflow。
它其實很生活化。
例如家庭群組裡,AI 長期在幫忙記偏好、安排晚餐、整理提醒。
某一天,它記錯了一條事實:
小明不吃牛肉。
結果 AI 卻記成:
小明喜歡牛肉。
接下來每次你問晚餐建議,它都沿著這條錯誤記憶往下推。
問題不只是答案錯。
真正糟的是,你很難知道:
- 它到底是從哪一段記憶得出這件事
- 那條記憶是原始對話錯了,還是摘要錯了
- 你改了之後,系統會不會真的用新的版本
這不是個案。在 AI 群組裡,抱怨這個問題的人非常多。很多人花了大量時間去「訓練」AI 記住家人習慣、工作偏好、溝通模式,但強力的訓練並沒有帶來好的結果。他們願意投入時間做必要的工作,因為他們太想得到正確的回應了——但現在沒有工具讓他們的努力有效。
這就是今天很多 memory system 的共同困境:
它們有寫入能力,但沒有足夠好的可觀測性。
這一章不是在做「更強的 AI」,而是在做「可除錯的 memory」
這裡我想刻意把邊界講清楚。
這一章不是要聲稱 CtxFST 已經變成 OpenClaw 的內建 memory backend。
也不是要說我現在已經把完整的雙向同步產品做完。
這一章更誠實的定位是:
利用 OpenClaw 現有的 memory 能力,加上一條外部的 CtxFST export / inspect / repair loop,證明 AI 記憶可以被 debug。
這個定位很重要,因為它決定了我們要怎麼設計 demo。
如果你一開始就想直接改 OpenClaw 核心,事情會很重。
但如果你先接受一個更務實的目標:
- 把現有 memory source 匯出
- 轉成 CtxFST
- 用 entity / vector / keyword 三種方式找問題
- 修正 source-of-truth
- 觸發 reindex
那整條路就會清楚很多。
OpenClaw 今天已經給了什麼
根據目前官方文件,OpenClaw 的 memory 機制已經提供了幾個很重要的基礎能力:
- memory 的 source-of-truth 是 Markdown,預設來自
MEMORY.md與memory/**/*.md - 這些 Markdown 會被 chunking 後做 semantic search
- index storage 是 per-agent SQLite,預設路徑在
~/.openclaw/memory/<agentId>.sqlite - SQLite 裡的
chunkstable 每條記錄是 ~300-800 tokens 的文字片段,附帶 embedding(sqlite-vecvirtual table,cosine distance)、metadata(JSON,含來源文件、timestamp、session ID、type)、LLM 生成摘要 fts5_chunks提供全文搜尋(BM25 keyword)sessionstable 存 JSONL 對話 log,delta sync 到 chunks- watcher 會在
MEMORY.md或memory/內容變動後,把 index 標記為 dirty openclaw memory index --force可以強制做 full reindexopenclaw memory search和openclaw memory status --deep --json可以用來觀察目前索引狀態
這些能力聽起來很基本,但它們其實已經足夠讓一條「可修正 memory loop」成立。
因為這代表:
我們不需要直接碰 OpenClaw 的核心 runtime,就能先從 source Markdown 走一條外部 debug loop。
這也意味著一件很重要的架構判斷:
第一版 demo 的正確做法,不是直接 patch SQLite,而是把 Markdown source 當作真正的修正入口。
直接改 SQLite 不是絕對不行,但它比較 brittle。
因為 index、watcher、重建時機、embedding 更新,都會讓 direct DB patch 變得不夠穩。
具體來說:
- SQLite 裡的 embedding 需要重算,手動改 text 欄位不會自動更新 vector
- watcher 的 debounce 機制(約 1.5 秒)可能忽略部分直接寫入的變更
- re-embed 邏輯在修改 embedding 時可能不觸發 reindex
如果目標是做一個能在影片裡穩定重現的 demo,那最穩的做法是:
改 source Markdown,再讓 OpenClaw 重建索引。
而最粗暴但最可靠的重建方式,是直接刪掉整個 SQLite index 再重啟——這個方法已經有社區實測過,成功率極高。
刪 Index 重建:完整指令
在正式走 demo 之前,先把「核彈級重建」的指令整理清楚。這是保底手段,確保任何修正都一定會生效:
# 1. 停 gateway(如果正在跑)
pkill -f "node.*openclaw.*gateway" # 或 Ctrl+C
# 2. 備份(安全第一)
cp ~/.openclaw/memory/{agentId}.sqlite ~/.openclaw/memory/backup.sqlite
# 3. 粗暴刪(SQLite + vec index)
rm ~/.openclaw/memory/{agentId}.sqlite \
~/.openclaw/memory/{agentId}.sqlite-shm \
~/.openclaw/memory/{agentId}.sqlite-wal \
~/.openclaw/index.sqlite # 若有分離 index
# 4. 重啟 gateway(自動 reindex MEMORY.md + memory/*.md)
openclaw gateway # 或 node dist/index.js gateway --port 8787
# 5. 強制觸發(確保完整重建)
openclaw memory index --force --verbose
openclaw memory status --deep # 驗證 chunks 數、embedding OK
注意:agentId 通常是 main 或 workspace 名稱。刪除後只剩 MEMORY.md 源檔,系統會全部重新 chunk 和 re-embed(需要幾分鐘)。
這個方法的好處是風險趨近於零——最壞的狀況就是重跑一次 demo。
所以,CH23 要證明的不是「神奇 magic」,而是一條可走通的 loop
這一章真正想證明的 loop 是:
OpenClaw memory source
→ export to CtxFST
→ inspect with graph / vector / FTS
→ identify the wrong memory
→ edit the source-of-truth
→ reindex
→ AI behavior changes
如果這條 loop 走得通,那意義其實很大。
因為它把今天常見的黑箱 memory,往前推成另一種東西:
一份可以被人類理解、也可以被工具操作的知識層。
這就是 CtxFST 很適合站的位置。
它不是取代聊天系統。
也不是取代模型。
而是變成那個中間層:
- 讓記憶能被解釋
- 讓錯誤能被定位
- 讓修正有明確入口
Demo 前置:環境確認
在跑 demo 之前,先確認 OpenClaw 環境正常:
# 確認 OpenClaw 路徑(agentId 通常 main 或 workspace 名)
OPENCLAW_MEM=~/.openclaw/memory/main.sqlite # 改成你的
echo "記憶庫: $OPENCLAW_MEM"
openclaw memory status # 應顯示 chunks 數 >0
Demo 完整五步:「小明不吃牛肉」
這個 demo 不是一個很抽象的 enterprise workflow。它刻意設計得很生活化,因為推廣的第一支影片,最重要的是:
路要短,成功率要高,觀眾要一眼就懂。
Step 1. 先故意讓 AI 記錯
在 MEMORY.md 裡放一條錯的內容:
家庭群確認:小明喜歡牛肉。
接著在對話裡跟 AI 聊幾輪讓它 index,然後問:
晚餐幫我排一下,小明那份可以吃什麼?
讓 AI 顯示出它真的沿用了這條錯誤記憶。
Step 2. 導出記憶,轉成 CtxFST artifact
這一步不是要重新發明 OpenClaw 的 memory。
而是把目前 memory source 抽出來,變成一份可以檢查的知識格式。
先從 SQLite 導出相關記憶:
sqlite3 "$OPENCLAW_MEM" "
SELECT id, text, json_extract(metadata, '$.session') as session, summary
FROM chunks
WHERE text LIKE '%小明%' OR text LIKE '%牛%' OR summary LIKE '%牛%'
" > wrong_memory.json
cat wrong_memory.json # 檢查:應看到錯記「小明愛吃牛」
導出結果範例:
["chunk_family_pref_001","家庭群討論晚餐:小明說愛吃牛排,媽媽點頭同意。下次買牛肉給他。","family_2026-03","小明偏好牛肉"]
然後用 skill-chunk-md 做 entity extraction:
# 用 Claude Code 或 OpenClaw,prompt 輸入 wrong_memory.json
# 或用本地 LLM:
claude "用 skill-chunk-md 處理以下 chunks: $(cat wrong_memory.json)"
產出的 CtxFST 格式:
entities:
- id: entity:小明
name: 小明
type: person
- id: entity:牛肉
name: 牛肉
type: food
pref: like # ← 這裡是錯的!
chunks:
- id: chunk:family-pref-beef
entities: [entity:小明, entity:牛肉]
context: "家庭飲食偏好記錄"
在這個格式裡,你至少會看到:
entity:小明entity:牛肉- 對應的 chunk context
- 這條記憶出現在什麼場景裡
如果未來 relation layer 更完整,還可以明確標成:
entity:小明
→ prefers / avoids
→ entity:牛肉
這時候記憶從黑箱變成了你能讀的結構。
Step 3. 用三種搜尋方式找出問題在哪
這裡的重點不是哪一種搜尋最強,
而是三種搜尋在 memory debugging 裡抓的是不同型別的錯。
FTS / keyword search
適合抓具體事實與字面衝突。
例如直接搜:
sqlite3 "$OPENCLAW_MEM" "SELECT * FROM chunks_fts WHERE chunks_fts MATCH '小明 牛肉'"
你會很快定位到那條記憶到底寫在哪一個 chunk。
Vector / semantic search
適合抓語意相近但文字不完全一樣的記憶。
例如同樣在講飲食偏好,但可能寫成:
- 不吃牛
- 避免紅肉
- 晚餐不要排牛排
這些文字不一定共享同一組 keyword,但語意上其實指向同一個問題區域。
用 OpenClaw 自己的對話介面驗證:
openclaw "小明吃牛肉嗎?" # 若回「愛吃」→ 確認 vector 也指向錯誤記憶
Entity graph
適合抓「哪裡的關係斷了、哪裡出現矛盾、哪裡缺 context」。
例如:
entity:小明有很多飲食偏好相關 chunkentity:牛肉也有多個關聯片段- 但目前圖上只有「like」邊,缺少「avoid」邊
# 若有 CtxFST validate plugin:
python validate_chunks.py output.md # 報孤立 entity 或衝突 relation
這時候 graph 的價值不是提供一個 fancy visualization。
而是讓你看到:
錯的不只是某一句話,而是它在整個知識層裡的位置。
三檢診斷結果:FTS 顯示錯誤文字、vector 無反例(假設目前沒有「不吃牛」的記憶)、graph 缺少 avoid 邊。三種搜尋互補:FTS 找字面、vector 找語意、graph 找結構。
Step 4. 修正 source-of-truth,而不是只修 AI 的當下回答
這是整個 demo 最重要的一步。
很多系統在表面上看起來也能修。
你跟它說一次:
不對,小明不吃牛肉。
它當下也許會道歉,也許下一句會答對。
但這不等於 memory 被修好了。
真正要修的是 source-of-truth。
所以這一步要做的不是 prompt 它再想一次,
而是直接修改底層資料。
方式 A:改 MEMORY.md(觸發 watcher,推薦)
echo '家庭群確認:小明不吃牛肉(媽媽糾正 2026-03)。' >> ~/.openclaw/MEMORY.md
方式 B:直接 UPDATE SQLite(精準定位,進階用法)
sqlite3 "$OPENCLAW_MEM" "
UPDATE chunks SET text='家庭群確認:小明不吃牛肉(媽媽糾正 2026-03)'
WHERE id='chunk_family_pref_001';
UPDATE chunks SET summary='小明避免牛肉' WHERE id='chunk_family_pref_001';
"
方式 B 更精準,但需要配合後面的刪 index 重建來確保 embedding 也更新。
如果需要更穩定,也可以在修正內容裡補一個帶時間戳的註記:
家庭群確認:小明不吃牛肉。(2026-03 媽媽糾正確認)
這樣未來當同一個人偏好又變動時,
知識層裡才有明確的版本語境。
Step 5. 刪 Index 重建,驗證行為改變
這一步的意義,是把「我改了檔案」和「AI 真的變了」連起來。
只要這一步能穩定成立,整個故事就成立了。
你不需要一開始就追求最優雅的同步機制。
# 停服務
pkill -f openclaw # 或 kill gateway PID
# 備份(安全第一!)
cp "$OPENCLAW_MEM" "${OPENCLAW_MEM}.backup"
# 粗暴刪(SQLite + vec index 全砍)
rm "$OPENCLAW_MEM"* # .sqlite .shm .wal
rm ~/.openclaw/index.sqlite # 若有分離 index
# 重啟(自動從 MEMORY.md 重建 index)
openclaw gateway & # background
sleep 10 # 等 index 重建
# 強制觸發完整 reindex
openclaw memory index --force --verbose
openclaw memory status # 驗證 chunks 數恢復、embedding 正常
然後再回頭問同樣的問題:
openclaw "小明牛肉偏好?" # 應回「不吃」!
晚餐幫我排一下,小明那份可以吃什麼?
如果 AI 的回答明顯改了,
這整個 demo 的核心價值就已經被證明了。
一鍵 Demo Script
如果要拍影片,可以把整個流程寫成一個 Python script,錄屏即影片:
#!/usr/bin/env python3
# demo_openclaw_ctxfst.py
import sqlite3, json, subprocess, time
from pathlib import Path
MEM_DB = Path.home() / ".openclaw/memory/main.sqlite"
def main():
# Step 1-2: 導出 + 模擬 CtxFST(實際用 LLM)
conn = sqlite3.connect(MEM_DB)
wrongs = conn.execute(
"SELECT id, text FROM chunks WHERE text LIKE '%牛%'"
).fetchall()
print("錯誤記憶:", wrongs)
conn.close()
# Step 3: 診斷(用 CLI 驗證 AI 回應)
subprocess.run(["openclaw", "小明牛?"])
# Step 4: 修正 MEMORY.md
with open(Path.home() / ".openclaw/MEMORY.md", "a") as f:
f.write("\n小明不吃牛肉(修正)。\n")
# Step 5: 刪 index 重建
subprocess.run(["pkill", "-f", "openclaw"], capture_output=True)
time.sleep(2)
MEM_DB.unlink(missing_ok=True) # 粗暴刪
subprocess.Popen(["openclaw", "gateway"])
time.sleep(15) # 等 reindex
subprocess.run(["openclaw", "memory", "index", "--force"])
# 驗證!
result = subprocess.run(
["openclaw", "小明牛?"], capture_output=True, text=True
)
print("修正後:", result.stdout)
if __name__ == "__main__":
main()
跑 python demo_openclaw_ctxfst.py,全程錄屏就是影片素材。
兩種修正方式,都需要
實際使用時,修正記憶有兩種情境:
一種是你知道確切哪裡錯——打開 CtxFST,看到「小明喜歡牛肉」那條 chunk,直接改 source Markdown。這就像你知道哪行 code 有 bug,直接改最快。
另一種是你只知道「AI 的回應不對」,但不確定錯在哪——這時候用自然語言跟 AI 說「小明其實不吃牛肉,幫我找到記錯的地方」,讓 AI 用 entity graph + vector search 定位問題,再幫你修正。
兩種都要有,因為使用者的技術背景不同,問題的明確程度也不同。
不會寫 code 的人,也會去看 code——他們不需要完全理解 CtxFST 的格式,但當他們看到一個 YAML 裡面寫著 entity:小明 和 pref: like 配上 entity:牛肉,他們知道問題在哪。知道哪裡有問題,就能想辦法解決。
這個 demo 真正的賣點
很多人看到這裡,可能會以為賣點只是:
哦,所以你把記憶存成 Markdown,然後可以手改。
但那其實不是最深的賣點。
真正的賣點是:
你第一次有能力把 AI 的錯,從「模糊地覺得它怪怪的」變成「明確定位到哪條記憶、哪個 entity、哪段 relation 出了問題」。
這個轉變很大。
因為只有當問題可以被定位,
修正才會有工程意義。
否則你做的永遠只是:
- 再問一次
- 換個 prompt
- 期待模型這次剛好答對
那不是 debug。
那只是祈禱。
為什麼這一章對推廣特別重要
如果我要把 CtxFST 推給其他開發者或社群,
我不會先從 schema 開始講。
我會先從這句話開始講:
你的 AI 如果記錯了一件事,你有沒有辦法打開它的記憶,看到錯在哪裡,然後修掉?
因為這個問題一出來,很多人會立刻懂。
尤其是有用過:
- long-term memory bot
- personal AI assistant
- 家庭群組助理
- Discord / Telegram 助理
- knowledge-grounded chat agent
的人,幾乎都會有共感。
這也是 CH23 比單純講 graph retrieval 更適合做推廣入口的原因。
CH22 證明的是技術價值。
CH23 講的是使用者痛點。
前者建立 credibility。
後者建立共感。
兩者都需要,但如果你要拍影片、發文、丟社群,
通常是後者比較能讓人先停下來看。
這一章的誠實邊界
我也想把現在還沒完成的部分講清楚。
目前最誠實的說法不是:
CtxFST 已經完整取代 OpenClaw memory backend。
而是:
CtxFST 已經足夠成為 OpenClaw memory 的外部檢查層與修正工作流骨架。
也就是說,今天我們已經可以很合理地做:
- 從 OpenClaw SQLite 導出記憶
- 用 skill-chunk-md 做 entity extraction 轉成 CtxFST
- 用 entity graph / vector / FTS 三種方式定位問題
- 修改 source Markdown 或精準 UPDATE SQLite
- 刪 index 重建確保記憶更新生效
- 驗證 AI 行為改變
但還沒有必要在這一章硬說:
- 已經有完美的自動 import pipeline
- 已經有 production-grade 的雙向同步
- 已經有完整的 conflict resolution policy
- 已經有 provenance tracking(誰在什麼時候改了什麼)
那些都可以是後面的 chapter。
例如:
CH24: export / import CLICH25: relation-aware memory repairCH26: memory diff、conflict 與 provenance
這樣整個系列會更穩,也更可信。
最後的結論
CH22 回答的是:
entity-aware retrieval 有沒有比純文字檢索更有用?
CH23 回答的是另一個更接近現實的問題:
當 AI 記錯了,我們能不能真的找到錯在哪,然後把它修好?
而我目前得到的答案是:
可以。最務實的第一步,不是重寫整個 agent runtime,而是先把 memory 變成一份可檢查、可搜尋、可修正的 CtxFST artifact。
當你能做到這件事時,
AI memory 就不再只是黑箱。
它會開始像 code、像 config、像資料庫 schema 一樣,
成為一個可以被工程化管理的東西。
這就是 CtxFST 最值得被看見的地方。
不是因為它讓 graph 看起來很酷。
而是因為它第一次讓一句很實際的話變得成立:
AI 的記憶,終於可以 debug 了。