後端即時儲存
Luker 重新設計了資料持久化架構,將資料變更的儲存職責從前端轉移到後端,實現即時持久化,從根本上消除因瀏覽器當機、網路中斷或意外關閉導致的資料遺失風險。
問題背景
在 SillyTavern 中,資料儲存由前端觸發:前端將完整的聊天資料序列化後傳送到後端覆蓋寫入。這種模式存在嚴重的資料安全隱患:
- 瀏覽器當機 — 如果在儲存請求發出前瀏覽器當機,所有未儲存的修改都會遺失
- 網路中斷 — 儲存請求可能因網路問題失敗,而前端可能不會重試
- 生成中斷 — AI 生成過程中如果連線斷開,已生成的內容可能無法儲存
- 競態條件 — 多個儲存請求並行時可能產生資料覆蓋
Luker 透過後端即時儲存徹底解決了這些問題。
資料變更即時持久化
所有透過增量同步端點到達後端的資料變更,都會立即寫入磁碟。後端不使用記憶體快取或延遲寫入——每次追加、修補或更新中繼資料操作完成後,資料已經安全地持久化到檔案系統中。
寫入完成後,後端更新聊天狀態檔案,記錄新的 integrity UUID 和時間戳,確保後續操作能正確偵測並行衝突。
聊天狀態檔案
每個聊天檔案都有一個對應的狀態檔案,儲存在與聊天檔案相同的目錄中。狀態檔案記錄:
- integrity — 當前檔案的 integrity UUID,用於並行衝突偵測
- updated_at — 最後一次寫入的時間戳
狀態檔案與聊天檔案分離儲存,避免了在聊天檔案中頻繁更新 integrity 值導致的全檔案重寫。
如果狀態檔案不存在(例如從舊版本遷移的聊天),系統會自動回退處理,並在首次寫入時自動建立狀態檔案。
Generation Acknowledge
在 AI 生成場景中,Luker 的統一生成層實作了 Generation Acknowledge 機制。當後端完成一次生成並將結果持久化後,會在回應中確認生成結果已被伺服器端安全儲存。
這意味著即使前端在收到生成結果後立即當機,資料也不會遺失——因為後端已經在回傳回應之前完成了持久化。前端收到確認後更新本地的 integrity 狀態,保持與伺服器端的同步。
與傳統模式的對比
在 SillyTavern 中,AI 生成的結果先到達前端,由前端決定何時儲存。如果前端在儲存前當機,生成的內容就會遺失。Luker 的 Generation Acknowledge 將儲存時機提前到了後端回應之前,從根本上消除了這個窗口期。
序列化聊天寫入
為了防止並行寫入導致檔案損壞,Luker 在前端(透過 runSerializedChatWrite)對聊天寫入任務做串行化,同時由後端對每次寫入執行 integrity 校驗。
當多個寫入操作短時間內同時觸發時(例如使用者快速編輯多條訊息,或生成完成與手動編輯同時發生),流程為:
- 前端將寫入任務按到達順序排隊
- 按順序逐一呼叫增量端點執行寫入
- 每次寫入成功後,後端更新聊天狀態 sidecar 中的 integrity UUID
- 若排隊中的請求攜帶過期 integrity,後端回傳
409 Conflict
這種「前端串行 + 後端校驗」的組合可保障寫入順序與一致性,而不依賴後端記憶體寫入佇列。
與增量同步的協作
後端即時儲存與增量同步緊密配合:
- 增量同步負責「傳什麼」— 只傳輸變更的資料
- 後端即時儲存負責「怎麼存」— 確保資料安全持久化
- 聊天狀態檔案是兩者的橋樑 — 透過 integrity UUID 協調前後端狀態
兩者共同構成了 Luker 的資料安全基礎設施。