緣起:為什麼 Agent 每天都會「忘記」?
凌晨 4:00,Auto-Dream Cron Job 如期運行。它檢查了過去三天的 daily log,發現所有檔案都已經標記了 <!-- consolidated -->,然後報告:
🌙 No new content today — skipped consolidation
但事實是:當日用戶在微信與 Agent 進行了 35 條對話,涵蓋電郵監控修復、DBS 銀行搜索、新材料上市公司調研、搜索引擎配置、Cross Search 插件設計等大量任務。
所有這些對話都完整保存在 Session Log(185MB, 380+ 檔案)中,但沒有一條被寫入結構化的 Daily Log。
這不是單一 Bug,而是一個系統性的架構缺陷。本文完整記錄了從發現問題到建立完整解決方案的過程。
一、問題全景:三個層面的系統性缺陷
經過完整調查,我們發現了三個獨立但互相疊加的技術問題:
1.1 架構層面:跨渠道 Session 隔離
OpenClaw 使用 dmScope: "per-channel-peer" 配置,每個渠道(飛書、微信、WhatsApp)生成完全獨立的 Session:
微信 Session (249c2bce) 飛書 Session (9780b3c4) WhatsApp Session
│ │ │
Agent 微信分身 Agent 飛書分身 Agent WA 分身
│ │ │
只看到微信對話 只看到飛書對話 只看到 WA 對話
│ │ │
❌ 不知道飛書做了什麼 ❌ 不知道微信做了什麼 ❌ 不知道任何渠道
關鍵發現: sessions_list API 只能返回當前渠道的 Session。即使微信有 101 個歷史 Session,飛書 Agent 調用 API 時返回 0 個微信 Session。
1.2 流程層面:Daily Log 寫入無強制機制
Daily Log 寫入依賴 Agent 自願執行。AGENTS.md 有「做完就寫」的規則,但當 Agent 專注於實際任務(寫 Code、部署、分析數據)時,Context Window 被工作內容填滿,「寫日誌」這個 Meta-Task 自然被忽略。
數據證明了這一點:
| 指標 | Session Log | Daily Log | 流失率 |
|---|---|---|---|
| 檔案數量 | 380 | 6 | 98.4% |
| 總大小 | 185MB | ~15KB | 99.99% |
| 當日內容 | 178 次交流 | 2 條記錄 | 98.9% |
1.3 實作層面:時區邊界 Bug
Cron Job 運行在 HKT 時區,Session JSONL 使用 UTC 時間戳。在 HKT 00:00-08:00 期間,UTC 日期仍是前一天:
HKT: May 12 22:00 ──────── May 13 00:00 ──────── May 13 08:00
UTC: May 12 14:00 ──────── May 12 16:00 ──────── May 13 00:00
│ │
用戶在微信聊天 Cron 運行,grep "2026-05-13"
Session: "2026-05-12" 但 Session 全是 "2026-05-12"
→ 0 match → 漏!
二、記憶架構設計:三層模型
為解決上述問題,我們設計了一個三層記憶模型,每層有不同的儲存格式、寫入機制和保障策略:
┌─────────────────────────────────────────────────┐
│ 第1層:Session Log(系統自動保存) │
│ agents/main/sessions/*.jsonl · 185MB · 380 files │
│ ✅ 每次對話自動保存,完整無遺漏 │
│ ⚠️ 原始 JSONL 格式,需要程式化讀取 │
├─────────────────────────────────────────────────┤
│ 第2層:Daily Log(跨渠道手動/自動整合) │
│ memory/daily/YYYY-MM-DD.md · Markdown │
│ ⚡ 三層防護:任務即寫 → Session 檢查 → Cron 兜底 │
│ 📝 結構化 Markdown,人類可讀 │
├─────────────────────────────────────────────────┤
│ 第3層:MEMORY.md(長期記憶整合) │
│ MEMORY.md · 凌晨 4:00 自動整合 │
│ 🧠 只合併已 consolidated 的 daily log │
│ 🔴 若第2層空白 → 第3層也空白(致命依賴) │
└─────────────────────────────────────────────────┘
關鍵設計決策
為什麼不把所有渠道合併到一個 Session?
去掉 per-channel-peer 會導致不同渠道的上下文混雜。例如微信的工作對話和飛書的技術討論會互相污染 Context Window,反而降低效率。
為什麼不讓 Auto-Dream 直接讀 Session Log?
Session Log 是原始 JSONL(185MB),包含大量 Tool Call、System Event、Model Change 等噪音。直接從中提取有意義的用戶對話需要複雜的 NLP 處理,不如在寫入 Daily Log 時就做好結構化。
三、三層防護機制
為確保 Daily Log(第2層)不再遺漏,我們設計了三層防護,每層有不同的觸發時機和可靠性:
| 層級 | 觸發時機 | 執行者 | 優點 | 缺點 |
|---|---|---|---|---|
| 1️⃣ 任務級 | 每完成一個有意義任務後立即 | 當前 Session Agent | 有上下文,最準確 | 依賴 Agent 自律 |
| 2️⃣ Session 結束 | 回覆最後一條用戶消息前 | 當前 Session Agent | 剛做完,記憶猶新 | 可能忘記 |
| 3️⃣ Cron 兜底 | 每 2 小時自動運行 | 獨立 Isolated Session | 自動化,不遺漏 | 無上下文,只能提取文字摘要 |
觸發規則:什麼是「有意義的任務」?
✅ 必須寫入:
- 部署網站、修復 Bug
- 撰寫報告、分析數據
- 創建/修改檔案、配置系統
- 搜索 + 整理資訊
- 安裝/設定工具、建立 Cron Job
- 任何耗費 >2 個 Tool Call 的操作
❌ 不需寫入:
- 簡單問答(「早晨」「OK」)
- 純閒聊
設計原則:防禦深度
任務即寫 (Layer 1) ──→ 漏了?
Session 檢查 (Layer 2) ──→ 又漏了?
Cron 兜底 (Layer 3) ──→ 絕不漏!
四、跨渠道整合管線
4.1 為什麼不能用 API?
dmScope: "per-channel-peer" 限制了 sessions_list API 只能返回當前渠道的 Session。從飛書無法發現微信的 Session。
4.2 解決方案:檔案系統級別掃描
Cron Job 直接讀取 agents/main/sessions/*.jsonl 檔案:
- 用
find -mmin -240找最近 4 小時修改過的 Session - 用 Pattern Matching 識別渠道(先檢查微信/WhatsApp,最後檢查飛書避免誤判)
- 提取用戶訊息,寫入共享 Daily Log
4.3 渠道識別策略
| 渠道 | 識別 Pattern | 優先級 |
|---|---|---|
| 微信 | openclaw-weixin 或 @tencent-weixin |
最高 |
whatsapp |
中 | |
| 飛書 | feishu 或 ou_142d6f(排除以上) |
最低 |
⚠️ 踩坑教訓: 不能直接用 ou_142d6f... 識別飛書,因為微信 Session 的 Delivery Config 中也包含此 ID(Cron Job 會引用它)。必須用排他性順序匹配。
4.4 完整管線架構
微信 Agent 飛書 Agent WhatsApp Agent
│ │ │
│ ① 做完即寫 │ ① 做完即寫 │ ① 做完即寫
│ │ │
└──────────┬─────────┴──────────┬──────────┘
│ │
共享 Daily Log ② Cron 每2h 跨渠道掃描
(memory/daily/YYYY-MM-DD.md) ← 檔案系統讀取
│ 所有渠道 Session JSONL
③ 凌晨4:00 Auto-Dream
│
MEMORY.md(長期記憶)
五、時區邊界問題深度分析
5.1 問題重現
Cron Job 在 HKT 00:01 運行,執行以下邏輯:
# 原始程式碼(有 Bug)
if grep -q "$(date +%Y-%m-%d)" "$SESSION_FILE"; then
echo "ACTIVE"
fi
此時:
date +%Y-%m-%d輸出2026-05-13(HKT)- Session JSONL 的時間戳是
2026-05-12T14:34:00Z(UTC) grep "2026-05-13"→ 0 個匹配- 結論:「無活躍 Session」→ 漏!
5.2 為什麼要 8 小時?
HKT 比 UTC 快 8 小時(UTC+8)。這意味著每天的 00:00-08:00 HKT,UTC 還在「昨天」。這 8 小時的窗口內,所有基於日期的 Session 匹配都會失效。
HKT 00:00 → UTC 還停留在前一天 16:00
HKT 04:00 → UTC 還停留在前一天 20:00
HKT 07:59 → UTC 還停留在前一天 23:59
HKT 08:00 → UTC 終於到了今天 00:00 ✅
5.3 修復方案:三日期匹配
# 修正後的程式碼
HKT_TODAY=$(TZ='Asia/Hong_Kong' date +%Y-%m-%d)
UTC_TODAY=$(date -u +%Y-%m-%d)
UTC_YESTERDAY=$(date -u -v-1d +%Y-%m-%d)
if grep -qE "$HKT_TODAY|$UTC_TODAY|$UTC_YESTERDAY" "$SESSION_FILE"; then
echo "ACTIVE" # 覆蓋所有時區邊界情況
fi
三個日期的 OR 匹配確保無論 Cron 何時運行,至少一個日期能命中 Session 中的時間戳。
5.4 額外修復:find -newer 依賴問題
原始的 find -newer memory/daily/$(date +%Y-%m-%d).md 在當日 Daily Log 尚未建立時行為不確定。改用:
find ... -mmin -240 # 過去 4 小時內修改過的檔案(無外部依賴)
六、Cron 管線設計
6.1 兩個 Cron Job 的分工
| Cron Job | 頻率 | 功能 | Timeout |
|---|---|---|---|
daily-log-autocheck |
每 2 小時 | 跨渠道掃描 Session → 補寫 Daily Log | 300s |
auto-memory-dream |
每日 04:00 | 從 Daily Log 整合 → MEMORY.md + 推送報告 | 600s |
6.2 每日運行時間線(HKT)
00:00 ─ autocheck
02:00 ─ autocheck
04:00 ─ autocheck + auto-memory-dream(雙重保險)
06:00 ─ autocheck
08:00 ─ autocheck
10:00 ─ autocheck
12:00 ─ autocheck
14:00 ─ autocheck
16:00 ─ autocheck
18:00 ─ autocheck
20:00 ─ autocheck
22:00 ─ autocheck
每日 13 次記憶檢查,確保 2 小時內的對話不遺漏。
6.3 Autocheck 執行流程
Step 1: 計算三個日期 (HKT_TODAY + UTC_TODAY + UTC_YESTERDAY)
↓
Step 2: find -mmin -240 找最近 4 小時活躍 Session
↓
Step 3: 三日期 grep 過濾(時區安全)
↓
Step 4: Pattern Match 識別渠道(排他性順序)
↓
Step 5: 提取用戶訊息 → 追加到 Daily Log(追加模式)
↓
Step 6: 靜默結束(無新內容不報告)
七、系統監控與健康指標
7.1 健康檢查項目
| 指標 | 檢查方式 | 正常值 |
|---|---|---|
| Daily Log 存在 | ls memory/daily/$(date +%Y-%m-%d).md |
必須存在 |
| Daily Log 大小 | wc -c |
>500 bytes |
| Session 涵蓋率 | 對比 Session 數量 vs Daily Log 條目 | >80% |
| Cron 運行狀態 | openclaw cron list |
lastRunStatus = ok |
| Dream Streak | dream-log.md | 連續天數 |
7.2 當前狀態
在本次修復完成後:
- 📊 記憶庫:~370 條記錄
- 🏥 健康度:75/100(之前因 Daily Log 缺失偏低,將逐步回升)
- 🔥 Dream Streak:24 天連續
- ⏱️ 記憶延遲:從「完全遺漏」降至 <2 小時
八、踩坑全記錄
本次記憶系統建設過程中遇到的 6 個關鍵問題:
| # | 問題 | 嚴重度 | 根因 | 修復 |
|---|---|---|---|---|
| 1 | Session 結束無 Checkpoint 致完全失憶 | 🔴 致命 | Meta-task 無自動觸發 | 三層防護機制 |
| 2 | 誤判微信 Plugin 狀態 | 🔴 高 | Config warning ≠ 實際狀態 | 先查數據再下結論 |
| 3 | sessions_list API 跨渠道盲點 |
🔴 高 | per-channel-peer 隔離 | 檔案系統直接讀取 |
| 4 | Channel Pattern 誤判 | 🟡 中 | 匹配順序不排他 | 排他性順序 |
| 5 | UTC/HKT 時區邊界漏失 | 🔴 致命 | 單日期 grep | 三日期 OR 匹配 |
| 6 | find -newer 依賴不存在檔案 |
🟡 中 | 外部檔案依賴 | -mmin -240 |
核心設計原則總結
| 原則 | 說明 |
|---|---|
| 防禦深度 | 單層失效不影響整體(三層防護) |
| 檔案系統 > API | 跨渠道時直接讀檔案,不依賴受限 API |
| 時間範圍 > 日期比對 | -mmin -240 比 -newer 更可靠 |
| 多日期匹配 | 跨時區場景必須兼容 UTC 和本地時間 |
| 排他性匹配 | Pattern 匹配先具體後泛化,避免誤判 |
| 先驗證再結論 | Config warning ≠ 實際狀態,先查數據 |
九、與 OpenClaw Auto-Dream 的協作
Memory Hub 是 Auto-Dream 的前置保障層:
- Memory Hub → 確保 Daily Log 完整(多渠道 + 跨日邊界)
- Auto-Dream → 從完整 Daily Log 整合入長期記憶
Memory Hub(第2層保障) Auto-Dream(第3層整合)
┌──────────────────────┐ ┌──────────────────────┐
│ 跨渠道掃描 │ │ 讀取 Daily Log │
│ 時區安全 │ ──→ │ 提煉關鍵決策 │
│ 自動補寫 │ │ 更新 MEMORY.md │
│ 2小時內保證完整 │ │ 推送整合報告 │
└──────────────────────┘ └──────────────────────┘
兩者協作形成完整記憶管道:從 Session Log → Daily Log → MEMORY.md,從即時記錄到長期記憶,層層保障。
結語
這次 Memory Hub 的建設源於一個看似簡單的問題:「為什麼 Agent 每天都會忘記?」。深入調查後發現,這不是單一 Bug,而是架構設計、流程機制、時區處理三個層面的系統性問題疊加。
最終方案的核心思想是 防禦深度:不依賴任何單一機制,而是通過任務即寫、Session 檢查、Cron 兜底三層防護,確保無論哪層失效,下一層都會補上。
更重要的是,我們學會了 先查數據、再下結論。從 Config Warning 誤判微信 Plugin 狀態,到時區邊界 Bug 的發現,每個問題的解決都來自於直接檢查 Session JSONL 檔案的原始數據,而不是依賴表面的錯誤訊息。
這套系統目前已在 UltraClaw 上運行,每日 13 次跨渠道自動整合,等待時間的考驗。