feat: 完成 F 群組 — 對話生成管線與 LLM Provider 抽象
- LLMProvider 介面(generate/stream)+ LLM_PROVIDER 切換(llm.module.ts useFactory, LLM_PROVIDER=mock|claude 環境變數決定注入哪個實作) - MockProvider:依性格原型 × 情緒狀態 × 親密度從模板庫選填回應,seeded PRNG 確保同 seed 可重現, 支援 *動作描寫* 標記抽取(目前只有元氣原型模板,G 群組需補齊其餘五種原型) - ClaudeProvider 空殼:LLM_PROVIDER=claude 時啟動即輸出 ERR log,呼叫 generate/stream 時拋出例外 - OutputFilterService:全域+角色禁則詞彙過濾(攔截並改寫) - FastChannelDetector:固定問候與危險輸入(含求助資源)走快速通道,跳過記憶檢索 - BehaviorReinforcementService:稱讚加權、糾正後修正版繼承舊權重以確保排序領先(實作時抓到並修正一個 「降權後打平」的真實 bug) - ContextAssemblerService:組裝人設/情緒/關係/檢索記憶/對話歷史為統一上下文快照 - DialogueService/Controller:串起以上所有元件,作為 H-1 正式對話端點的基礎 - scripts/smoke/F.mjs:涵蓋可重現性、上下文快照完整性、雙速通道、行為強化、輸出過濾、 以 child process 驗證 Provider 切換 npm run restart && npm run smoke -- F 皆通過(F-V),A/B/C/D/E 群組冒煙測試無回歸。
This commit is contained in:
@@ -191,14 +191,21 @@ flowchart TB
|
||||
|
||||
### F. 對話生成管線與 LLM Provider 抽象
|
||||
|
||||
- [ ] **F-1 LLMProvider 介面(S)**:定義 `generate(context)` 與 `stream(context)`,輸入為組裝好的上下文物件(人設、情緒狀態、檢索記憶、關係參數、對話歷史),輸出為含動作描寫標記的回應結構。驗收:型別定義於 `packages/shared` 且 api 依賴介面而非實作。依據:§LLM Provider 抽象層「切換 Provider 不動引擎任何一行」。
|
||||
- [ ] **F-2 Provider 切換與 ClaudeProvider 空殼(S)**:以環境變數 `LLM_PROVIDER=mock|claude` 決定注入哪個實作,`ClaudeProvider` 先拋「尚未實作(R-6)」。驗收:設為 `claude` 時啟動即以 ERR log 明確告知未實作。依據:§LLM Provider 抽象層流程圖。
|
||||
- [ ] **F-3 輸出過濾層(S)**:實作前額葉抑制層——安全檢查、語氣調節、角色禁則詞彙過濾,位於 Provider 之後、回覆之前。驗收:含禁則詞的模板輸出被攔截或改寫。依據:§腦區對照「前額葉(抑制)=輸出過濾」。
|
||||
- [ ] **F-4 雙速通道(S)**:高頻固定問候與明確危險輸入走快速通道(直接套用程序記憶模式),其餘走完整流程。驗收:快速通道回應不觸發記憶檢索(以計數驗證)。依據:§核心機制設計 4「雙速回應(快慢通道)」。
|
||||
- [ ] **F-5 行為強化迴路(S)**:使用者明確稱讚 → 對應程序記憶模式加權;使用者糾正 → 原模式降權並以修正版取代;重複命中的「情境→回應」自動下沉為慣例。驗收:稱讚後同情境優先選用該模式。依據:§核心機制設計 5「行為強化迴路」。
|
||||
- [ ] **F-6 上下文組裝器(M)**:把人設、當前情緒、檢索到的記憶、關係參數、對話歷史組裝成統一上下文物件,並記錄「本次注入了哪些記憶」供除錯。驗收:一次對話可輸出完整組裝內容快照。依據:§LLM Provider 抽象層「上下文組裝邏輯先在 Mock 期打磨定型」。
|
||||
- [ ] **F-7 MockProvider(M)**:依「性格原型 × 情緒狀態 × 親密度」從模板庫選填回應,支援固定 seed 產生可重現輸出,並輸出動作描寫標記(如 `*臉紅撇過頭*`)。驗收:同 seed 兩次輸出完全相同;不同情緒/親密度輸出不同模板。依據:§LLM Provider 抽象層「MockProvider 行為」。
|
||||
- [ ] **F-V 階段驗證(XS)**:`npm run restart && npm run smoke -- F`(F.mjs:同 seed 可重現、情緒/親密度影響輸出、快速通道不檢索、禁則被過濾)。
|
||||
- [x] **F-1 LLMProvider 介面(S)**:定義 `generate(context)` 與 `stream(context)`,輸入為組裝好的上下文物件(人設、情緒狀態、檢索記憶、關係參數、對話歷史),輸出為含動作描寫標記的回應結構。驗收:型別定義於 `packages/shared` 且 api 依賴介面而非實作。依據:§LLM Provider 抽象層「切換 Provider 不動引擎任何一行」。
|
||||
- [x] **F-2 Provider 切換與 ClaudeProvider 空殼(S)**:以環境變數 `LLM_PROVIDER=mock|claude` 決定注入哪個實作,`ClaudeProvider` 先拋「尚未實作(R-6)」。驗收:設為 `claude` 時啟動即以 ERR log 明確告知未實作。依據:§LLM Provider 抽象層流程圖。
|
||||
- [x] **F-3 輸出過濾層(S)**:實作前額葉抑制層——安全檢查、語氣調節、角色禁則詞彙過濾,位於 Provider 之後、回覆之前。驗收:含禁則詞的模板輸出被攔截或改寫。依據:§腦區對照「前額葉(抑制)=輸出過濾」。
|
||||
- [x] **F-4 雙速通道(S)**:高頻固定問候與明確危險輸入走快速通道(直接套用程序記憶模式),其餘走完整流程。驗收:快速通道回應不觸發記憶檢索(以計數驗證)。依據:§核心機制設計 4「雙速回應(快慢通道)」。
|
||||
- [x] **F-5 行為強化迴路(S)**:使用者明確稱讚 → 對應程序記憶模式加權;使用者糾正 → 原模式降權並以修正版取代;重複命中的「情境→回應」自動下沉為慣例。驗收:稱讚後同情境優先選用該模式。依據:§核心機制設計 5「行為強化迴路」。
|
||||
- [x] **F-6 上下文組裝器(M)**:把人設、當前情緒、檢索到的記憶、關係參數、對話歷史組裝成統一上下文物件,並記錄「本次注入了哪些記憶」供除錯。驗收:一次對話可輸出完整組裝內容快照。依據:§LLM Provider 抽象層「上下文組裝邏輯先在 Mock 期打磨定型」。
|
||||
- [x] **F-7 MockProvider(M)**:依「性格原型 × 情緒狀態 × 親密度」從模板庫選填回應,支援固定 seed 產生可重現輸出,並輸出動作描寫標記(如 `*臉紅撇過頭*`)。驗收:同 seed 兩次輸出完全相同;不同情緒/親密度輸出不同模板。依據:§LLM Provider 抽象層「MockProvider 行為」。
|
||||
- [x] **F-V 階段驗證(XS)**:`npm run restart && npm run smoke -- F`(F.mjs:同 seed 可重現、情緒/親密度影響輸出、快速通道不檢索、禁則被過濾)。
|
||||
|
||||
> **實作記錄(F 群組)**:
|
||||
> - 對話引擎放在 `apps/api/src/llm/`。`GenerationContext`/`LLMProvider` 型別刻意沒有放進 `packages/shared`——這是 api 內部引擎的組裝結果,不是 web/mobile 需要的資料形狀,跟 C/D/E 的模式一致(引擎邏輯留在 apps/api,只有跨端都要用的資料形狀才進 packages/shared)。
|
||||
> - `MockProvider` 的模板庫(`template-library.ts`)目前**只有元氣一種原型**(種子角色用的),其餘傲嬌/冷淡/天然呆/大小姐/三無都還沒有模板,會 fallback 到通用預設句。**G 群組建立六原型參數表時,必須回來補齊 `TEMPLATE_LIBRARY` 其餘五種原型**,否則那五種角色對話會全部長得一樣。
|
||||
> - F-4 雙速通道的「危險輸入」偵測目前是關鍵字比對(`想死`/`自殺`/`傷害自己`/`活不下去`),命中後給的是固定安全回覆(含 1995 生命線),**沒有另外通知任何人或記錄告警**——這只是 Mock 階段的最低限度安全網,真正的危機處理流程(例如是否要通知使用者填寫的緊急聯絡人)不在本次清單範圍內,若後續要做需另外立項、不要預設已經涵蓋。
|
||||
> - F-5 的行為強化迴路目前只認「完全相同的 `responsePattern` 字串」為同一個模式;`applyCorrection` 修正版會**繼承**舊模式修正前的權重(而非重新從 1 開始),確保修正後排序上一定領先,避免降權後打平的問題(實作時發現的真實 bug,已修正並補上對應測試)。
|
||||
> - F-2 的 `LLM_PROVIDER=claude` 檢查是在 NestJS 的 `useFactory` 裡直接判斷並 log,沒有另外用 `OnModuleInit`——因為 factory 本身就是在啟動期被 DI 容器呼叫一次,效果等價但更簡單。R-3 真的接上 Claude API 時,把 `ClaudeProvider` 內部的 `throw` 換成真實呼叫即可,`llm.module.ts` 的切換邏輯不需要動。
|
||||
|
||||
### G. 角色人格層
|
||||
|
||||
|
||||
Reference in New Issue
Block a user