feat: 完成 C 群組 — 記憶子系統
- WorkingMemoryService:session 對話上下文緩衝,token 溢位時優先裁切最舊的低情緒段落 - JobQueue 抽象層(now/schedule(at)/every(cron))與 InProcessJobQueue 實作(node-cron), R-6 會換成 BullMQ 但呼叫端介面不變 - MemoryConsolidationService:睡眠固化,只有高情緒或重複提及的內容才寫入 EpisodicMemory - ForgettingSweepService:低情緒且長期未提取的記憶逐次降權、weight 過低後刪除, 已掛上每小時一次的 JobQueue.every 排程 - KeywordMemoryRetriever:關鍵字+時間近因+情緒權重排序,提取命中即更新提取次數/時間 - apps/api 新增 /memory/* 端點作為引擎驗證介面(H 群組會決定併入正式對話管線後的去留) - scripts/smoke/C.mjs:端到端驗證溢位裁切、只寫工作記憶、固化篩選、檢索排序、 提取即改寫、schedule(at) 準時觸發、遺忘衰減與刪除 npm run restart && npm run smoke -- C 皆通過(C-V),A/B 群組冒煙測試無回歸。
This commit is contained in:
@@ -143,13 +143,19 @@ flowchart TB
|
||||
|
||||
### C. 記憶子系統
|
||||
|
||||
- [ ] **C-1 工作記憶(S)**:實作 session 對話上下文緩衝,帶 token 上限與溢位裁切策略(保留最近與高情緒段落)。驗收:超過上限時最舊的低情緒段落先被裁掉。依據:§腦區→聊天系統元件對照「工作記憶=對話上下文視窗,有 token 上限」。
|
||||
- [ ] **C-2 對話期只寫工作記憶(S)**:明確禁止對話流程中寫入長期記憶表,所有長期寫入只能由固化程序觸發。驗收:一輪對話後三張長期記憶表筆數不變。依據:§核心機制設計 1「對話中不即時寫長期記憶」。
|
||||
- [ ] **C-3 排程抽象層(S)**:定義 `JobQueue` 介面(`now` / `schedule(at)` / `every(cron)`),以 in-process 計時器實作 `InProcessJobQueue`,並在 DI 容器註冊;session 結束事件推入固化工作。驗收:排入 5 秒後的工作會準時執行。註記:R-4 換成 BullMQ 時只換實作、不動呼叫端。依據:技術選型「BullMQ:睡眠固化/離線事件/提醒排程」。
|
||||
- [ ] **C-4 睡眠固化程序(M)**:實作 `consolidate(sessionId)`——回顧整段對話,只有情緒強度高於門檻或被重複提及的內容才寫入情節/語意/程序記憶,並寫入完整 metadata。驗收:一段含「一件高情緒事件+數句閒聊」的對話固化後,只有高情緒事件進 `EpisodicMemory`。依據:§核心機制設計 1「Session 結束觸發睡眠固化」。
|
||||
- [ ] **C-5 遺忘與提取即改寫(M)**:固化程序中對「情緒強度低且長期未被提取」的記憶降權或刪除;每次檢索命中即更新提取次數與最後提取時間。驗收:模擬時間推進後低權重舊記憶被清除,常被提取者保留。依據:§核心機制設計 2「記憶遺忘(自然衰減)」。
|
||||
- [ ] **C-6 記憶檢索器(M)**:定義 `MemoryRetriever` 介面並實作關鍵字版本,排序權重=關鍵字相關度+時間近因+情緒權重+(E-6 補上的)關係對象加權。驗收:查詢命中相關情節記憶且排序符合權重設計。註記:R-2 會加上 pgvector 語意檢索實作。依據:技術選型「pgvector:記憶語意檢索」。
|
||||
- [ ] **C-V 階段驗證(XS)**:`npm run restart && npm run smoke -- C`(C.mjs:模擬一段對話 → 觸發固化 → 驗證高情緒事件入庫、瑣事未入庫、檢索可命中、提取次數遞增)。
|
||||
- [x] **C-1 工作記憶(S)**:實作 session 對話上下文緩衝,帶 token 上限與溢位裁切策略(保留最近與高情緒段落)。驗收:超過上限時最舊的低情緒段落先被裁掉。依據:§腦區→聊天系統元件對照「工作記憶=對話上下文視窗,有 token 上限」。
|
||||
- [x] **C-2 對話期只寫工作記憶(S)**:明確禁止對話流程中寫入長期記憶表,所有長期寫入只能由固化程序觸發。驗收:一輪對話後三張長期記憶表筆數不變。依據:§核心機制設計 1「對話中不即時寫長期記憶」。
|
||||
- [x] **C-3 排程抽象層(S)**:定義 `JobQueue` 介面(`now` / `schedule(at)` / `every(cron)`),以 in-process 計時器實作 `InProcessJobQueue`,並在 DI 容器註冊;session 結束事件推入固化工作。驗收:排入 5 秒後的工作會準時執行。註記:R-4 換成 BullMQ 時只換實作、不動呼叫端。依據:技術選型「BullMQ:睡眠固化/離線事件/提醒排程」。
|
||||
- [x] **C-4 睡眠固化程序(M)**:實作 `consolidate(sessionId)`——回顧整段對話,只有情緒強度高於門檻或被重複提及的內容才寫入情節/語意/程序記憶,並寫入完整 metadata。驗收:一段含「一件高情緒事件+數句閒聊」的對話固化後,只有高情緒事件進 `EpisodicMemory`。依據:§核心機制設計 1「Session 結束觸發睡眠固化」。
|
||||
- [x] **C-5 遺忘與提取即改寫(M)**:固化程序中對「情緒強度低且長期未被提取」的記憶降權或刪除;每次檢索命中即更新提取次數與最後提取時間。驗收:模擬時間推進後低權重舊記憶被清除,常被提取者保留。依據:§核心機制設計 2「記憶遺忘(自然衰減)」。
|
||||
- [x] **C-6 記憶檢索器(M)**:定義 `MemoryRetriever` 介面並實作關鍵字版本,排序權重=關鍵字相關度+時間近因+情緒權重+(E-6 補上的)關係對象加權。驗收:查詢命中相關情節記憶且排序符合權重設計。註記:R-2 會加上 pgvector 語意檢索實作。依據:技術選型「pgvector:記憶語意檢索」。
|
||||
- [x] **C-V 階段驗證(XS)**:`npm run restart && npm run smoke -- C`(C.mjs:模擬一段對話 → 觸發固化 → 驗證高情緒事件入庫、瑣事未入庫、檢索可命中、提取次數遞增)。
|
||||
|
||||
> **實作記錄(C 群組)**:
|
||||
> - 記憶引擎全放在 `apps/api/src/memory/`(NestJS module),情緒標記(`emotionTag`/`emotionIntensity`)在此階段由**呼叫端提供**,不是自己判斷——因為執行順序圖 C/D/E 是同層平行,C 不能依賴 D 尚未建置的情緒標記器;F 群組整合時才會接上 D 的真實輸出。
|
||||
> - `POST/GET /memory/:characterId/sessions/:sessionId/messages`、`.../consolidate`、`GET /memory/:characterId/retrieve`、`POST /memory/forgetting-sweep` 這幾個端點目前是**工程內部驗證用**,不是使用者可見 API;H-1「`POST /chat/:characterId` 走完整管線」「`POST /session/:id/end` 觸發睡眠固化」上線後,這些端點的邏輯會被納入正式管線,屆時再決定是否保留、改名或整組移除。
|
||||
> - 高情緒門檻(`HIGH_EMOTION_THRESHOLD = 0.6`)與工作記憶 token 上限(`DEFAULT_TOKEN_LIMIT = 200`,粗略以「字元數 / 2」估算,非真實 tokenizer)都定義在 `apps/api/src/memory/constants.ts` 與 `working-memory.service.ts`,D 群組的情緒狀態機若要共用同一門檻語意,應該從這裡匯入而不是各自定一份。
|
||||
> - `JobQueue`(`now`/`schedule(at)`/`every(cron)`)介面在 `apps/api/src/memory/job-queue.ts`,`InProcessJobQueue` 用 `setTimeout`/`node-cron` 實作;`every()` 目前唯一的呼叫者是每小時跑一次的遺忘清掃(`memory.module.ts` 的 `onModuleInit`)。J 群組的提醒排程應直接複用同一個 `JOB_QUEUE`,不要另外自己接計時器。
|
||||
|
||||
### D. 情緒子系統
|
||||
|
||||
|
||||
Reference in New Issue
Block a user