當無記憶遇上多階段:LazyHole-Agent 跨輪狀態實驗報告

一個定位「極簡無記憶」的 Telegram AI Agent,能否在不帶對話歷史的架構下完成需要跨輪確認的多階段任務?

背景:一個架構性矛盾

LazyHole-Agent 的核心設計哲學是「無記憶、無狀態、隨插即用」。每次收到 Telegram 訊息,handle() 只組兩則訊息給 LLM:

const messages = [
  { role: 'system', content: systemPrompt },
  { role: 'user', content: text },  // 就這一句
];

這讓系統極簡,但也製造了一個矛盾:多階段 Skill 天生需要跨輪上下文

以 blog 發布為例,流程是「概念確認 → 細節審閱 → 發布」。Turn 1 確認了標題,Turn 2 傳來一句「好」——LLM 根本不知道「好」是在回應什麼。

概念分層:Draft ≠ History ≠ Memory

類型生命週期誰來管
Draft(草稿)單次任務內,完成即清Agent 主動存取
History(對話歷史)永久Telegram 本身
Memory(長期記憶)跨對話本專案不支援

黃金法則:若刪掉這個欄位,下一階段能從當前訊息重建嗎?能 → 不寫。不能 → 寫。

三次設計演進

第一版:Skill 直接存檔

src/utils/drafts.js 提供 loadDraft / saveDraft / clearDraft,Skill 直接 require。缺點:第三方 Skill 必須修改,違反零侵入目標。

第二版:Draft 升級為 Agent Tool

把 drafts 包成三個正式 agent tool:save_draft / load_draft / clear_draft,並在 BASE_SYSTEM_PROMPT 加規則「先 save_draft 再回覆用戶」。理論上第三方 Skill 零改動。

第三版:Pending Draft 注入 System Prompt

handle() 起始掃描 ~/.lazyhole/drafts/,有未過期草稿就注入 system prompt 尾段,讓下一輪 LLM 能把「好」解讀為「延續任務」。

A/B 測試結果(MiniMax-M2.7)

建立 blog-poster-minimal——只描述多階段意圖,完全不提 save_draft。

Turn 1

Turn 2(傳「好」):

核心發現

  1. Resume 機制邏輯是對的:LLM 確實願意在模糊訊息下去查草稿,問題在於沒草稿可找。
  2. Skill body 比 System Prompt 更能左右行為:MiniMax 更信 Skill 的具體描述,不信 System Prompt 的抽象規則。
  3. 模型能力是架構的隱形變數:「零改動第三方 Skill」對強模型成立,對中階模型不成立。

取捨框架

方向作法適用情境
A. 妥協Skill body 明寫 save_draft 指令自己維護的 Skill、穩定優先
B. Agent 反射有輸出但無 save_draft 時自動補存複雜,易誤判,不推薦
C. 換強模型Claude / GPT-4 遵從性更高有預算、Skill 生態要開放

目前選 A。

後記

這次最有價值的不是成功,而是「失敗的方式」——Turn 2 幾乎做對了所有事,只差一個 namespace。架構設計是對的,差的是 Turn 1 的存檔觸發。

分享